diff --git a/.github/workflows/automated_integration_test.yml b/.github/workflows/automated_integration_test.yml
index 1e0d1054a..9b803a1f0 100644
--- a/.github/workflows/automated_integration_test.yml
+++ b/.github/workflows/automated_integration_test.yml
@@ -159,11 +159,8 @@ jobs:
- name: Build generated code
run: |
flutter --version
- flutter clean
- rm -rf .dart_tool
- rm pubspec.lock
flutter pub get
- ./model_generator.sh async
+ ./model_generator.sh
- name: Generate key properties
run: |
diff --git a/.github/workflows/compare_overrides.yml b/.github/workflows/compare_overrides.yml
new file mode 100644
index 000000000..b53eb7bb9
--- /dev/null
+++ b/.github/workflows/compare_overrides.yml
@@ -0,0 +1,55 @@
+name: Check for dependency changes
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ compare-overrides:
+ runs-on: ubuntu-24.04
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ ref: ${{ github.event.pull_request.head.sha }}
+
+ - uses: actions/setup-go@v5
+ with:
+ go-version: stable
+
+ - name: Compare pubspec overrides
+ id: compare
+ env:
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
+ run: |
+ git fetch origin "$BASE_REF"
+ base_sha=$(git rev-parse "origin/$BASE_REF")
+ head_sha="${{ github.event.pull_request.head.sha }}"
+
+ ./scripts/compare_overrides.sh "$base_sha" "$head_sha" > /tmp/compare_output.txt
+
+ if [[ ! -s /tmp/compare_output.txt ]]; then
+ echo "has_output=false" >> "$GITHUB_OUTPUT"
+ exit 0
+ fi
+
+ {
+ echo '### changes in dependencies'
+ echo
+ echo '```'
+ cat /tmp/compare_output.txt
+ echo '```'
+ } > /tmp/comment_body.md
+
+ echo "has_output=true" >> "$GITHUB_OUTPUT"
+
+ - uses: marocchino/sticky-pull-request-comment@v2
+ if: steps.compare.outputs.has_output == 'true'
+ with:
+ header: pubspec-overrides-compare
+ path: /tmp/comment_body.md
diff --git a/.github/workflows/pr_test_build_linux.yml b/.github/workflows/pr_test_build_linux.yml
index 11af9b2c7..37c2bcf3f 100644
--- a/.github/workflows/pr_test_build_linux.yml
+++ b/.github/workflows/pr_test_build_linux.yml
@@ -1,18 +1,21 @@
name: Cake Wallet Linux
-on: [pull_request]
-
permissions:
contents: read
packages: write
+on: [pull_request]
+
defaults:
run:
shell: bash
-
jobs:
PR_test_build:
+ # Fork PRs don't have access to repository secrets, so the generated
+ # lib/.secrets.g.dart would be empty and the build fails to compile.
+ # Skip for forks, mirroring the Android workflow's internal-build guard.
+ if: github.event.pull_request.head.repo.fork == false
runs-on: [Linux, amd64, forlinux]
container:
image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.41.9-ndkr28-go1.24.1-ruststablenightly
@@ -28,6 +31,7 @@ jobs:
- /opt/cw_cache_linux/root/.pub-cache/:/root/.pub-cache
- /opt/cw_cache_linux/root/go/pkg:/root/go/pkg
- /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache
+ - /var/run/docker.sock:/var/run/docker.sock
steps:
- name: Fix github actions messing up $HOME...
@@ -44,6 +48,14 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
+
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
- name: configure git
run: |
git config --global --add safe.directory '*'
@@ -85,7 +97,6 @@ jobs:
echo "${{ secrets.MAIN_SECRETS_FILE }}" | base64 --decode > lib/.secrets.g.dart
-
- name: Build dependencies utilizing ghcr cache
run: |
env \
@@ -93,7 +104,6 @@ jobs:
CW_DOCKER_USE_CLOUD=true \
./scripts/linux/docker/build.sh
-
- name: Execute Build and Setup Commands
run: |
pushd scripts/linux
@@ -107,12 +117,16 @@ jobs:
- name: Build generated code
run: |
- ./model_generator.sh async
+ ./model_generator.sh
- name: Generate localization
run: |
dart run tool/generate_localization.dart
+ - name: Compile graphics
+ run: |
+ ./compile_graphics.sh
+
- name: Build linux
run: |
flutter build linux --dart-define=hasDevOptions=true --release
diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/reusable-build.yml
index 269619cf3..4dc447573 100644
--- a/.github/workflows/reusable-build.yml
+++ b/.github/workflows/reusable-build.yml
@@ -125,12 +125,8 @@ jobs:
- name: Build generated code
run: |
- flutter --version
- flutter clean
- rm -rf .dart_tool
- rm pubspec.lock
- flutter pub get
- ./model_generator.sh async
+ ./model_generator.sh
+
- name: Generate key properties
run: |
diff --git a/.gitignore b/.gitignore
index cd064fc15..2b437f06e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -160,7 +160,6 @@ assets/images/app_logo.png
assets/new-ui/**/*.svg.vec
/pubspec.yaml
-/pubspec.lock
/android/app.properties
/android/app/src/main/AndroidManifest.xml
@@ -228,3 +227,5 @@ scripts/reown_flutter
*.salive
android/.kotlin
+scripts/.cache
+pubspec.lock
diff --git a/android/app/src/main/AndroidManifestBase.xml b/android/app/src/main/AndroidManifestBase.xml
index 0f15c75bc..a1d72a66d 100644
--- a/android/app/src/main/AndroidManifestBase.xml
+++ b/android/app/src/main/AndroidManifestBase.xml
@@ -90,7 +90,9 @@
+
+
diff --git a/assets/new-ui/changelog/text/changelog_ar.json b/assets/new-ui/changelog/text/changelog_ar.json
index 8cf3af6e4..f839ec75c 100644
--- a/assets/new-ui/changelog/text/changelog_ar.json
+++ b/assets/new-ui/changelog/text/changelog_ar.json
@@ -1 +1 @@
-[{"title":"مونيرو + تريزور","description":"قم بتأمين XMR الخاص بك من خلال دعم محفظة الأجهزة!"},{"title":"واجهة مستخدم WalletConnect الجديدة","description":"أصبح الاتصال بـ Web3 dApps أكثر أمانًا وسهولة"},{"title":"تحسينات واجهة المستخدم","description":"تمت إضافة بعض عناصر واجهة المستخدم الجديدة خصيصًا لك"},{"title":"تحسينات المزامنة","description":"المزامنة الأمثل للبيتكوين وLitecoin"},{"title":"إصلاحات الشوائب","description":"سحق المزيد من الأخطاء"}]
\ No newline at end of file
+[{"title":"تحسينات زي كاش","description":"بعد الترحيل الناجح إلى IronWood الجديد، أضفنا المزيد من التحسينات إلى محفظة zcash"},{"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 ac64d52d6..e8d541755 100644
--- a/assets/new-ui/changelog/text/changelog_bg.json
+++ b/assets/new-ui/changelog/text/changelog_bg.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Защитете своя XMR с поддръжка на хардуерен портфейл!"},{"title":"НОВ потребителски интерфейс на WalletConnect","description":"свързването към Web3 dApps стана по-безопасно и по-лесно"},{"title":"Подобрения на потребителския интерфейс","description":"Добавени са някои нови елементи на потребителския интерфейс само за вас"},{"title":"Подобрения при синхронизиране","description":"Оптимизирана синхронизация за Bitcoin и Litecoin"},{"title":"Поправки на грешки","description":"Смачкани още грешки"}]
\ No newline at end of file
+[{"title":"Подобрения на Zcash","description":"След успешната миграция към новия IronWood добавихме още подобрения към zcash портфейла"},{"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 6b63af608..80eeabebe 100644
--- a/assets/new-ui/changelog/text/changelog_cs.json
+++ b/assets/new-ui/changelog/text/changelog_cs.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Zabezpečte svůj XMR s podporou hardwarové peněženky!"},{"title":"NOVÉ uživatelské rozhraní WalletConnect","description":"připojení k Web3 dApps je bezpečnější a jednodušší"},{"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":"Vylepšení synchronizace","description":"Optimalizovaná synchronizace pro bitcoiny a litecoiny"},{"title":"Opravy chyb","description":"Zmáčkl další brouky"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_de.json b/assets/new-ui/changelog/text/changelog_de.json
index a5540aadc..5b3b29c05 100644
--- a/assets/new-ui/changelog/text/changelog_de.json
+++ b/assets/new-ui/changelog/text/changelog_de.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Sichern Sie Ihr XMR mit Hardware-Wallet-Unterstützung!"},{"title":"NEUE WalletConnect-Benutzeroberfläche","description":"Die Verbindung zu Web3-dApps wird sicherer und einfacher"},{"title":"Verbesserungen der Benutzeroberfläche","description":"Einige neue UI-Elemente wurden speziell für Sie hinzugefügt"},{"title":"Verbesserungen bei der Synchronisierung","description":"Optimierte Synchronisierung für Bitcoin und Litecoin"},{"title":"Fehlerbehebungen","description":"Weitere Bugs beseitigt"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_en.json b/assets/new-ui/changelog/text/changelog_en.json
index f095416e9..7914f086e 100644
--- a/assets/new-ui/changelog/text/changelog_en.json
+++ b/assets/new-ui/changelog/text/changelog_en.json
@@ -1,20 +1,16 @@
[
{
- "title": "MONERO + TREZOR",
- "description": "Secure your XMR with hardware wallet support!"
+ "title": "Zcash improvements",
+ "description": "After the successful migration to the new IronWood, we added more improvements to zcash wallet"
},
{
- "title": "NEW WalletConnect UI",
- "description": "connecting to Web3 dApps made safer and easier"
+ "title": "AnyPay as Intended",
+ "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"
},
{
"title": "UI improvements",
"description": "Added some fresh UI elements just for you"
},
- {
- "title": "Sync enhancements",
- "description": "Optimized sync for Bitcoin and Litecoin"
- },
{
"title": "Bug fixes",
"description": "Squashed more bugs"
diff --git a/assets/new-ui/changelog/text/changelog_es.json b/assets/new-ui/changelog/text/changelog_es.json
index d793c9850..cd8357218 100644
--- a/assets/new-ui/changelog/text/changelog_es.json
+++ b/assets/new-ui/changelog/text/changelog_es.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"¡Asegure su XMR con soporte de billetera de hardware!"},{"title":"NUEVA interfaz de usuario de WalletConnect","description":"conectarse a Web3 dApps es más seguro y sencillo"},{"title":"Mejoras en la interfaz de usuario","description":"Se agregaron algunos elementos nuevos de la interfaz de usuario solo para ti."},{"title":"Mejoras de sincronización","description":"Sincronización optimizada para Bitcoin y Litecoin"},{"title":"Corrección de errores","description":"Aplastado más errores"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_fa.json b/assets/new-ui/changelog/text/changelog_fa.json
index 6cb346f36..1ae3901ac 100644
--- a/assets/new-ui/changelog/text/changelog_fa.json
+++ b/assets/new-ui/changelog/text/changelog_fa.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"XMR خود را با پشتیبانی کیف پول سخت افزاری ایمن کنید!"},{"title":"رابط کاربری جدید WalletConnect","description":"اتصال به Web3 dApps ایمن تر و آسان تر شده است"},{"title":"بهبودهای رابط کاربری","description":"برخی از عناصر رابط کاربری جدید را فقط برای شما اضافه کرد"},{"title":"همگام سازی پیشرفت ها","description":"همگام سازی بهینه شده برای بیت کوین و لایت کوین"},{"title":"رفع اشکال","description":"اشکالات بیشتری را له کرد"}]
\ No newline at end of file
+[{"title":"بهبود Zcash","description":"پس از انتقال موفقیت آمیز به IronWood جدید، بهبودهای بیشتری را به کیف پول zcash اضافه کردیم"},{"title":"AnyPay همانطور که در نظر گرفته شده است","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 db4a4f8e7..399a014ce 100644
--- a/assets/new-ui/changelog/text/changelog_fr.json
+++ b/assets/new-ui/changelog/text/changelog_fr.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Sécurisez votre XMR avec la prise en charge du portefeuille matériel !"},{"title":"NOUVELLE interface utilisateur WalletConnect","description":"la connexion aux dApps Web3 rendue plus sûre et plus facile"},{"title":"Améliorations de l'interface utilisateur","description":"Ajout de nouveaux éléments d'interface utilisateur juste pour vous"},{"title":"Améliorations de la synchronisation","description":"Synchronisation optimisée pour Bitcoin et Litecoin"},{"title":"Corrections de bugs","description":"Écrasé plus de bugs"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_gn.json b/assets/new-ui/changelog/text/changelog_gn.json
index 3f5d50aac..5e26592d4 100644
--- a/assets/new-ui/changelog/text/changelog_gn.json
+++ b/assets/new-ui/changelog/text/changelog_gn.json
@@ -1 +1 @@
-[{"title":"MONERO + TEZOR GUARANI","description":"¡Eñangareko nde XMR pytyvõ billetera hardware reheve!"},{"title":"UI WalletConnect PYAHU","description":"oñembojoajúvo Web3 dApps rehe ojejapo seguro ha ndahasýiva"},{"title":"UI ñemyatyrõ","description":"Oñemoĩve peteĩ elemento UI pyahu ndéve g̃uarãnte"},{"title":"Ñembohekorã ñembotuichave","description":"Sincronización optimizada Bitcoin ha Litecoin-pe g̃uarã"},{"title":"Umi mba’e’oka ñemyatyrõ","description":"Oñembopupu hetave mba’e’oka"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_ha.json b/assets/new-ui/changelog/text/changelog_ha.json
index def18a416..3b7cbfada 100644
--- a/assets/new-ui/changelog/text/changelog_ha.json
+++ b/assets/new-ui/changelog/text/changelog_ha.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Kiyaye XMR ɗin ku tare da tallafin walat ɗin kayan aiki!"},{"title":"NEW WalletConnect UI","description":"haɗi zuwa Web3 dApps ya zama mafi aminci da sauƙi"},{"title":"UI inganta","description":"An ƙara wasu sabbin abubuwan UI don ku kawai"},{"title":"Haɓaka daidaitawa","description":"Ingantaccen aiki tare don Bitcoin da Litecoin"},{"title":"Gyaran kwaro","description":"Squashed karin kwari"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_hi.json b/assets/new-ui/changelog/text/changelog_hi.json
index ab8c99c4b..9294d04a3 100644
--- a/assets/new-ui/changelog/text/changelog_hi.json
+++ b/assets/new-ui/changelog/text/changelog_hi.json
@@ -1 +1 @@
-[{"title":"मोनेरो + ट्रेज़ोर","description":"हार्डवेयर वॉलेट समर्थन के साथ अपने एक्सएमआर को सुरक्षित करें!"},{"title":"नया वॉलेटकनेक्ट यूआई","description":"Web3 dApps से कनेक्ट करना सुरक्षित और आसान बना दिया गया है"},{"title":"यूआई सुधार","description":"केवल आपके लिए कुछ ताज़ा यूआई तत्व जोड़े गए हैं"},{"title":"सिंक संवर्द्धन","description":"बिटकॉइन और लाइटकॉइन के लिए अनुकूलित सिंक"},{"title":"कंप्यूटर प्रोग्राम या प्रणाली में बग को दूर करना","description":"अधिक कीड़ों को कुचल दिया"}]
\ No newline at end of file
+[{"title":"ज़कैश में सुधार","description":"नए आयरनवुड में सफल माइग्रेशन के बाद, हमने zcash वॉलेट में और सुधार जोड़े"},{"title":"इच्छानुसार कोई भी भुगतान करें","description":"अब किसी भी वॉलेट से किसी पते को चिपकाने या स्कैन करने से आपको स्वैपिंग या सही वॉलेट से भेजने का सही संकेत मिलेगा, और भी बहुत कुछ सुधार होगा"},{"title":"UI improvements","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 809a8d011..abcd21ca1 100644
--- a/assets/new-ui/changelog/text/changelog_hr.json
+++ b/assets/new-ui/changelog/text/changelog_hr.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Osigurajte svoj XMR podrškom za hardverski novčanik!"},{"title":"NOVO korisničko sučelje WalletConnect","description":"povezivanje s Web3 dApps postalo sigurnije i lakše"},{"title":"Poboljšanja korisničkog sučelja","description":"Dodani su novi elementi korisničkog sučelja samo za vas"},{"title":"Poboljšanja sinkronizacije","description":"Optimizirana sinkronizacija za Bitcoin i Litecoin"},{"title":"Ispravci grešaka","description":"Zgnječio još kukaca"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_hy.json b/assets/new-ui/changelog/text/changelog_hy.json
index 78006db80..4910b792b 100644
--- a/assets/new-ui/changelog/text/changelog_hy.json
+++ b/assets/new-ui/changelog/text/changelog_hy.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Ապահովեք ձեր XMR-ը ապարատային դրամապանակի աջակցությամբ:"},{"title":"ՆՈՐ WalletConnect UI","description":"Web3 dApps-ին միանալը դարձել է ավելի անվտանգ և հեշտ"},{"title":"UI բարելավումներ","description":"Ավելացրել է մի քանի թարմ UI տարրեր հենց ձեզ համար"},{"title":"Համաժամեցման բարելավումներ","description":"Օպտիմիզացված համաժամեցում Bitcoin-ի և Litecoin-ի համար"},{"title":"Սխալների շտկում","description":"Ճզմեց ավելի շատ սխալներ"}]
\ No newline at end of file
+[{"title":"Zcash բարելավումներ","description":"Նոր IronWood-ի հաջող տեղափոխումից հետո մենք ավելի շատ բարելավումներ ենք ավելացրել zcash դրամապանակում"},{"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 3498a4ef9..f9be2b41d 100644
--- a/assets/new-ui/changelog/text/changelog_id.json
+++ b/assets/new-ui/changelog/text/changelog_id.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Amankan XMR Anda dengan dukungan dompet perangkat keras!"},{"title":"UI WalletConnect BARU","description":"menghubungkan ke Web3 dApps menjadi lebih aman dan mudah"},{"title":"Peningkatan UI","description":"Menambahkan beberapa elemen UI baru hanya untuk Anda"},{"title":"Peningkatan sinkronisasi","description":"Sinkronisasi yang dioptimalkan untuk Bitcoin dan Litecoin"},{"title":"Perbaikan bug","description":"Membasmi lebih banyak bug"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_it.json b/assets/new-ui/changelog/text/changelog_it.json
index e1dc9c549..c8afeaae1 100644
--- a/assets/new-ui/changelog/text/changelog_it.json
+++ b/assets/new-ui/changelog/text/changelog_it.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Proteggi il tuo XMR con il supporto del portafoglio hardware!"},{"title":"NUOVA interfaccia utente di WalletConnect","description":"connettersi alle dApp Web3 diventa più semplice e sicuro"},{"title":"Miglioramenti dell'interfaccia utente","description":"Aggiunti alcuni nuovi elementi dell'interfaccia utente solo per te"},{"title":"Miglioramenti della sincronizzazione","description":"Sincronizzazione ottimizzata per Bitcoin e Litecoin"},{"title":"Correzioni di bug","description":"Eliminati altri bug"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_ja.json b/assets/new-ui/changelog/text/changelog_ja.json
index 2708fdea3..4af643e14 100644
--- a/assets/new-ui/changelog/text/changelog_ja.json
+++ b/assets/new-ui/changelog/text/changelog_ja.json
@@ -1 +1 @@
-[{"title":"モネロ + トレザー","description":"ハードウェアウォレットのサポートで XMR を保護してください!"},{"title":"新しい WalletConnect UI","description":"Web3 dApps への接続がより安全かつ簡単になりました"},{"title":"UIの改善","description":"あなたのためだけにいくつかの新しい UI 要素を追加しました"},{"title":"同期の機能強化","description":"ビットコインとライトコインの最適化された同期"},{"title":"バグ修正","description":"より多くのバグを潰しました"}]
\ No newline at end of file
+[{"title":"Zcashの改善","description":"新しい IronWood への移行が成功した後、zcash ウォレットにさらに改良を加えました。"},{"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 e9292b4c8..501612462 100644
--- a/assets/new-ui/changelog/text/changelog_ko.json
+++ b/assets/new-ui/changelog/text/changelog_ko.json
@@ -1 +1 @@
-[{"title":"모네로 + 트레저","description":"하드웨어 지갑 지원으로 XMR을 보호하세요!"},{"title":"새로운 WalletConnect UI","description":"Web3 dApp에 연결하는 것이 더 안전하고 쉬워졌습니다."},{"title":"UI 개선","description":"당신을 위한 새로운 UI 요소를 추가했습니다."},{"title":"동기화 향상","description":"비트코인과 라이트코인에 최적화된 동기화"},{"title":"버그 수정","description":"더 많은 버그를 해결했습니다."}]
\ No newline at end of file
+[{"title":"Zcash 개선","description":"새로운 IronWood로 성공적으로 마이그레이션한 후 zcash 지갑에 더 많은 개선 사항을 추가했습니다."},{"title":"의도한 대로 AnyPay","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 43da18f67..5d5905bee 100644
--- a/assets/new-ui/changelog/text/changelog_my.json
+++ b/assets/new-ui/changelog/text/changelog_my.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"ဟာ့ဒ်ဝဲပိုက်ဆံအိတ်ပံ့ပိုးမှုဖြင့် သင်၏ XMR ကို လုံခြုံအောင်ထားပါ။"},{"title":"WalletConnect UI အသစ်","description":"Web3 dApps သို့ ချိတ်ဆက်ခြင်းသည် ပိုမိုလုံခြုံပြီး ပိုမိုလွယ်ကူစေသည်။"},{"title":"UI တိုးတက်မှုများ","description":"သင့်အတွက်သာ လတ်ဆတ်သော UI အစိတ်အပိုင်းအချို့ကို ထည့်ထားသည်။"},{"title":"ထပ်တူပြုခြင်း မြှင့်တင်မှုများ","description":"Bitcoin နှင့် Litecoin အတွက် အကောင်းဆုံး စင့်ခ်လုပ်ထားသည်။"},{"title":"ချွတ်ယွင်းချက်ပြင်ဆင်မှုများ","description":"နောက်ထပ် ပိုးကောင်များကို နှိမ်နင်းခဲ့သည်။"}]
\ No newline at end of file
+[{"title":"Zcash တိုးတက်မှုများ","description":"IronWood အသစ်သို့ အောင်မြင်စွာ ပြောင်းရွှေ့ပြီးနောက်၊ ကျွန်ုပ်တို့သည် zcash ပိုက်ဆံအိတ်သို့ နောက်ထပ် တိုးတက်မှုများကို ထည့်သွင်းခဲ့သည်။"},{"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 65a54f8c1..6c551180a 100644
--- a/assets/new-ui/changelog/text/changelog_nl.json
+++ b/assets/new-ui/changelog/text/changelog_nl.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Beveilig uw XMR met hardware wallet-ondersteuning!"},{"title":"NIEUWE WalletConnect-gebruikersinterface","description":"verbinding maken met Web3 dApps is veiliger en eenvoudiger geworden"},{"title":"UI-verbeteringen","description":"Speciaal voor jou een aantal nieuwe UI-elementen toegevoegd"},{"title":"Synchronisatieverbeteringen","description":"Geoptimaliseerde synchronisatie voor Bitcoin en Litecoin"},{"title":"Bugfixes","description":"Nog meer bugs geplet"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_pl.json b/assets/new-ui/changelog/text/changelog_pl.json
index e2fb6fb7f..d78ba5818 100644
--- a/assets/new-ui/changelog/text/changelog_pl.json
+++ b/assets/new-ui/changelog/text/changelog_pl.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Zabezpiecz swój XMR dzięki obsłudze portfela sprzętowego!"},{"title":"NOWY interfejs użytkownika WalletConnect","description":"łączenie się z Web3 dApps stało się bezpieczniejsze i łatwiejsze"},{"title":"Ulepszenia interfejsu użytkownika","description":"Dodano kilka świeżych elementów interfejsu użytkownika specjalnie dla Ciebie"},{"title":"Udoskonalenia synchronizacji","description":"Zoptymalizowana synchronizacja dla Bitcoin i Litecoin"},{"title":"Poprawki błędów","description":"Zmiażdżono więcej błędów"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_pt.json b/assets/new-ui/changelog/text/changelog_pt.json
index a6268261c..6dee67564 100644
--- a/assets/new-ui/changelog/text/changelog_pt.json
+++ b/assets/new-ui/changelog/text/changelog_pt.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Proteja seu XMR com suporte de carteira de hardware!"},{"title":"NOVA IU do WalletConnect","description":"conectar-se a Web3 dApps tornou-se mais seguro e fácil"},{"title":"Melhorias na interface do usuário","description":"Adicionados alguns novos elementos de UI só para você"},{"title":"Melhorias de sincronização","description":"Sincronização otimizada para Bitcoin e Litecoin"},{"title":"Correções de bugs","description":"Esmagou mais bugs"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_ru.json b/assets/new-ui/changelog/text/changelog_ru.json
index 84470bff0..0b82474d2 100644
--- a/assets/new-ui/changelog/text/changelog_ru.json
+++ b/assets/new-ui/changelog/text/changelog_ru.json
@@ -1 +1 @@
-[{"title":"МОНЕРО + ТРЕЗОР","description":"Защитите свой XMR с помощью аппаратного кошелька!"},{"title":"НОВЫЙ интерфейс WallConnectConnect","description":"подключение к dApps Web3 стало безопаснее и проще"},{"title":"Улучшения пользовательского интерфейса","description":"Специально для вас добавлено несколько свежих элементов пользовательского интерфейса."},{"title":"Улучшения синхронизации","description":"Оптимизированная синхронизация для биткойнов и лайткойнов."},{"title":"Исправления ошибок","description":"Устранено больше ошибок"}]
\ No newline at end of file
+[{"title":"Улучшения Zcash","description":"После успешного перехода на новый IronWood мы добавили дополнительные улучшения в кошелек zcash."},{"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 946da8190..12b6844e3 100644
--- a/assets/new-ui/changelog/text/changelog_th.json
+++ b/assets/new-ui/changelog/text/changelog_th.json
@@ -1 +1 @@
-[{"title":"โมเนโร + เทรเซอร์","description":"รักษาความปลอดภัย XMR ของคุณด้วยการสนับสนุนกระเป๋าเงินฮาร์ดแวร์!"},{"title":"UI WalletConnect ใหม่","description":"การเชื่อมต่อกับ Web3 dApps ทำให้ปลอดภัยและง่ายขึ้น"},{"title":"การปรับปรุง UI","description":"เพิ่มองค์ประกอบ UI ใหม่สำหรับคุณโดยเฉพาะ"},{"title":"การปรับปรุงการซิงค์","description":"การซิงค์ที่ปรับให้เหมาะสมสำหรับ Bitcoin และ Litecoin"},{"title":"แก้ไขข้อบกพร่อง","description":"กำจัดข้อบกพร่องเพิ่มเติม"}]
\ No newline at end of file
+[{"title":"การปรับปรุง Zcash","description":"หลังจากการโยกย้ายไปยัง IronWood ใหม่ได้สำเร็จ เราได้เพิ่มการปรับปรุงเพิ่มเติมให้กับกระเป๋าเงิน zcash"},{"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 a239ca930..1bab34712 100644
--- a/assets/new-ui/changelog/text/changelog_tl.json
+++ b/assets/new-ui/changelog/text/changelog_tl.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"I-secure ang iyong XMR gamit ang suporta sa hardware wallet!"},{"title":"BAGONG WalletConnect UI","description":"ang pagkonekta sa Web3 dApps ay ginawang mas ligtas at mas madali"},{"title":"Mga pagpapabuti ng UI","description":"Nagdagdag ng ilang sariwang elemento ng UI para lang sa iyo"},{"title":"I-sync ang mga pagpapahusay","description":"Na-optimize na pag-sync para sa Bitcoin at Litecoin"},{"title":"Mga pag-aayos ng bug","description":"Nilapit ang higit pang mga bug"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_tr.json b/assets/new-ui/changelog/text/changelog_tr.json
index 103b373d4..9e2f8c917 100644
--- a/assets/new-ui/changelog/text/changelog_tr.json
+++ b/assets/new-ui/changelog/text/changelog_tr.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"XMR'nizi donanım cüzdanı desteğiyle güvence altına alın!"},{"title":"YENİ WalletConnect Kullanıcı Arayüzü","description":"Web3 dApp'lerine bağlanmak artık daha güvenli ve daha kolay"},{"title":"Kullanıcı arayüzü iyileştirmeleri","description":"Size özel bazı yeni kullanıcı arayüzü öğeleri eklendi"},{"title":"Senkronizasyon geliştirmeleri","description":"Bitcoin ve Litecoin için optimize edilmiş senkronizasyon"},{"title":"Hata düzeltmeleri","description":"Daha fazla hata giderildi"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_uk.json b/assets/new-ui/changelog/text/changelog_uk.json
index cb2a87037..ea4cf30a1 100644
--- a/assets/new-ui/changelog/text/changelog_uk.json
+++ b/assets/new-ui/changelog/text/changelog_uk.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Захистіть свій XMR за допомогою підтримки апаратного гаманця!"},{"title":"НОВИЙ інтерфейс WalletConnect","description":"підключення до Web3 dApps стало безпечнішим і простішим"},{"title":"Покращення інтерфейсу користувача","description":"Додано кілька свіжих елементів інтерфейсу спеціально для вас"},{"title":"Покращення синхронізації","description":"Оптимізована синхронізація для Bitcoin і Litecoin"},{"title":"Виправлення помилок","description":"Роздавив більше помилок"}]
\ No newline at end of file
+[{"title":"Покращення Zcash","description":"Після успішного переходу на новий IronWood ми додали додаткові покращення до гаманця zcash"},{"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 bf31ecf67..f0050e886 100644
--- a/assets/new-ui/changelog/text/changelog_ur.json
+++ b/assets/new-ui/changelog/text/changelog_ur.json
@@ -1 +1 @@
-[{"title":"مونیرو + ٹریزور","description":"ہارڈویئر والیٹ سپورٹ کے ساتھ اپنے XMR کو محفوظ بنائیں!"},{"title":"نیا WalletConnect UI","description":"Web3 dApps سے جڑنا محفوظ اور آسان بنا دیا ہے۔"},{"title":"UI میں بہتری","description":"صرف آپ کے لیے کچھ تازہ UI عناصر شامل کیے گئے۔"},{"title":"مطابقت پذیری میں اضافہ","description":"Bitcoin اور Litecoin کے لیے آپٹمائزڈ سنک"},{"title":"بگ کی اصلاحات","description":"مزید کیڑے کو کچل دیا۔"}]
\ No newline at end of file
+[{"title":"Zcash میں بہتری","description":"نئے IronWood میں کامیاب منتقلی کے بعد، ہم نے zcash wallet میں مزید بہتری شامل کی۔"},{"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 89c33da12..5bbd9e52f 100644
--- a/assets/new-ui/changelog/text/changelog_vi.json
+++ b/assets/new-ui/changelog/text/changelog_vi.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Bảo vệ XMR của bạn với sự hỗ trợ của ví phần cứng!"},{"title":"Giao diện người dùng WalletConnect MỚI","description":"kết nối với Web3 dApps trở nên an toàn và dễ dàng hơn"},{"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":"Cải tiến đồng bộ hóa","description":"Đồng bộ hóa được tối ưu hóa cho Bitcoin và Litecoin"},{"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 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
diff --git a/assets/new-ui/changelog/text/changelog_yo.json b/assets/new-ui/changelog/text/changelog_yo.json
index 6a5eded02..1a8d9ac53 100644
--- a/assets/new-ui/changelog/text/changelog_yo.json
+++ b/assets/new-ui/changelog/text/changelog_yo.json
@@ -1 +1 @@
-[{"title":"MONERO + TREZOR","description":"Ṣe aabo XMR rẹ pẹlu atilẹyin apamọwọ ohun elo!"},{"title":"Tuntun WalletConnect UI","description":"sisopọ si Web3 dApps jẹ ailewu ati rọrun"},{"title":"UI awọn ilọsiwaju","description":"Ṣafikun diẹ ninu awọn eroja UI tuntun kan fun ọ"},{"title":"Awọn imudara imuṣiṣẹpọ","description":"Iṣapeye amuṣiṣẹpọ fun Bitcoin ati Litecoin"},{"title":"Awọn atunṣe kokoro","description":"Squashed diẹ idun"}]
\ No newline at end of file
+[{"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
diff --git a/assets/new-ui/changelog/text/changelog_zh-cn.json b/assets/new-ui/changelog/text/changelog_zh-cn.json
index 59019db77..c33d6e328 100644
--- a/assets/new-ui/changelog/text/changelog_zh-cn.json
+++ b/assets/new-ui/changelog/text/changelog_zh-cn.json
@@ -1 +1 @@
-[{"title":"门罗+特雷佐","description":"通过硬件钱包支持保护您的 XMR!"},{"title":"新的 WalletConnect 用户界面","description":"连接到 Web3 dApp 变得更安全、更轻松"},{"title":"用户界面改进","description":"为您添加了一些新鲜的 UI 元素"},{"title":"同步增强功能","description":"优化比特币和莱特币的同步"},{"title":"错误修复","description":"消除了更多错误"}]
\ No newline at end of file
+[{"title":"Zcash 的改进","description":"成功迁移到新的 IronWood 后,我们对 zcash 钱包添加了更多改进"},{"title":"AnyPay 符合预期","description":"现在,从任何钱包粘贴或扫描地址都会正确地指示您从正确的钱包进行交换或发送,以及更多改进"},{"title":"用户界面改进","description":"为您添加了一些新鲜的 UI 元素"},{"title":"错误修复","description":"消除了更多错误"}]
\ No newline at end of file
diff --git a/build.yaml b/build.yaml
new file mode 100644
index 000000000..996b8d89f
--- /dev/null
+++ b/build.yaml
@@ -0,0 +1,8 @@
+targets:
+ $default:
+ sources:
+ exclude:
+ - "**/.secrets.g.dart"
+ - "integration_test/**"
+ - "test/**"
+ - "tool/**"
diff --git a/configure_cake_wallet.sh b/configure_cake_wallet.sh
index cf56bcead..f72272b66 100755
--- a/configure_cake_wallet.sh
+++ b/configure_cake_wallet.sh
@@ -35,6 +35,7 @@ fi
source ./app_env.sh cakewallet
./app_config.sh
+echo "flutter pub get may take a while, please wait..."
cd ../.. && flutter pub get
dart run tool/generate_localization.dart
./compile_graphics.sh
diff --git a/cw_bitcoin/build.yaml b/cw_bitcoin/build.yaml
new file mode 100644
index 000000000..81a9c96df
--- /dev/null
+++ b/cw_bitcoin/build.yaml
@@ -0,0 +1,5 @@
+targets:
+ $default:
+ sources:
+ exclude:
+ - "**/.secrets.g.dart"
diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart
index b8e53d11b..4f791aeb4 100644
--- a/cw_bitcoin/lib/bitcoin_wallet.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet.dart
@@ -14,6 +14,7 @@ import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
+import 'package:cw_bitcoin/locktime.dart';
import 'package:cw_bitcoin/hardware/bitcoin_hardware_wallet_service.dart';
import 'package:cw_bitcoin/lightning/lightning_wallet.dart';
import 'package:cw_bitcoin/hardware/bitcoin_ledger_service.dart';
@@ -31,6 +32,7 @@ import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/output_info.dart';
import 'package:cw_core/payjoin_session.dart';
import 'package:cw_core/pending_transaction.dart';
+import 'package:cw_core/sync_status.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/utils/print_verbose.dart';
@@ -447,8 +449,17 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
));
}
+ final locktime = antiFeeSnipingLocktime(
+ chainTip: await getCurrentChainTip(),
+ synced: syncStatus is SyncedSyncStatus,
+ );
+
return PSBTTransactionBuild(
- inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF, cwOutputs: cwOutputs)
+ inputs: psbtReadyInputs,
+ outputs: outputs,
+ enableRBF: enableRBF,
+ cwOutputs: cwOutputs,
+ locktime: locktime)
.psbt;
}
diff --git a/cw_bitcoin/lib/coin_selection.dart b/cw_bitcoin/lib/coin_selection.dart
new file mode 100644
index 000000000..4db86e1c2
--- /dev/null
+++ b/cw_bitcoin/lib/coin_selection.dart
@@ -0,0 +1,88 @@
+import 'dart:math';
+
+int effectiveValue(int value, int inputCost) => value - inputCost;
+
+class SelectedCoins {
+ final List indices;
+ final bool hasChange;
+ const SelectedCoins(this.indices, this.hasChange);
+}
+
+SelectedCoins? branchAndBound(List effValues, int target, int costOfChange,
+ {int maxTries = 100000}) {
+ final n = effValues.length;
+ final order = List.generate(n, (i) => i)
+ ..sort((a, b) => effValues[b].compareTo(effValues[a]));
+ final sorted = [for (final i in order) effValues[i]];
+ final suffix = List.filled(n + 1, 0);
+ for (var i = n - 1; i >= 0; i--) suffix[i] = suffix[i + 1] + sorted[i];
+ final upper = target + costOfChange;
+ List? best;
+ final picked = [];
+ var tries = 0;
+ void dfs(int i, int sum) {
+ if (best != null || tries++ >= maxTries) return;
+ if (sum > upper) return;
+ if (sum >= target) { best = List.of(picked); return; }
+ if (i >= n || sum + suffix[i] < target) return;
+ picked.add(order[i]); dfs(i + 1, sum + sorted[i]); picked.removeLast();
+ dfs(i + 1, sum);
+ }
+ dfs(0, 0);
+ return best == null ? null : SelectedCoins(best!, false);
+}
+
+SelectedCoins? singleRandomDraw(List effValues, int target, int minChange, Random rng) {
+ final order = List.generate(effValues.length, (i) => i)..shuffle(rng);
+ final picked = []; var sum = 0;
+ for (final i in order) {
+ picked.add(i); sum += effValues[i];
+ if (sum >= target + minChange) return SelectedCoins(picked, true);
+ }
+ return null;
+}
+
+/// Branch-and-bound over effective values (value minus the cost of spending the
+/// input at the current fee rate). [inputCosts] is parallel to [values] so each
+/// input pays for its own script type's size. A match means the excess over
+/// [target] stays within [window], so the remainder can be absorbed into the fee
+/// instead of creating a change output. Returns null when no such subset exists.
+SelectedCoins? changelessMatch({
+ required List values,
+ required int target,
+ required List inputCosts,
+ required int window,
+ int maxTries = 100000,
+}) {
+ assert(values.length == inputCosts.length);
+ final keep = [];
+ final eff = [];
+ for (var i = 0; i < values.length; i++) {
+ final e = effectiveValue(values[i], inputCosts[i]);
+ if (e > 0) {
+ keep.add(i);
+ eff.add(e);
+ }
+ }
+ final match = branchAndBound(eff, target, window, maxTries: maxTries);
+ if (match == null) return null;
+ return SelectedCoins([for (final i in match.indices) keep[i]], false);
+}
+
+class InsufficientFundsException implements Exception { const InsufficientFundsException(); }
+
+SelectedCoins selectCoins({required List values, required int target,
+ required int inputCost, required int costOfChange, required int minChange, Random? rng}) {
+ final keep = []; final eff = [];
+ for (var i = 0; i < values.length; i++) {
+ final e = effectiveValue(values[i], inputCost);
+ if (e > 0) { keep.add(i); eff.add(e); }
+ }
+ SelectedCoins? map(SelectedCoins? s) =>
+ s == null ? null : SelectedCoins([for (final i in s.indices) keep[i]], s.hasChange);
+ final bnb = map(branchAndBound(eff, target, costOfChange));
+ if (bnb != null) return bnb;
+ final srd = map(singleRandomDraw(eff, target, minChange, rng ?? Random.secure()));
+ if (srd != null) return srd;
+ throw const InsufficientFundsException();
+}
diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart
index 44aa096c4..b3bc6e843 100644
--- a/cw_bitcoin/lib/electrum.dart
+++ b/cw_bitcoin/lib/electrum.dart
@@ -579,14 +579,29 @@ class ElectrumClient {
return [];
});
+ // Floor at 0 so unavailable/-1 estimates never become negative rates;
+ // cap at 2000 sat/vB per CW-1597.
+ static const int _maxFeeRate = 2000;
+
+ static int _sanitizeFeeRate(double feeRate) {
+ final rate = (stringDoubleToBitcoinAmount(feeRate.toString()) / 1000).round();
+ if (rate < 0) {
+ return 0;
+ }
+ if (rate > _maxFeeRate) {
+ return _maxFeeRate;
+ }
+ return rate;
+ }
+
Future> feeRates({BasedUtxoNetwork? network}) async {
try {
- final topDoubleString = await estimatefee(p: 1);
- final middleDoubleString = await estimatefee(p: 5);
- final bottomDoubleString = await estimatefee(p: 10);
- final top = (stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000).round();
- final middle = (stringDoubleToBitcoinAmount(middleDoubleString.toString()) / 1000).round();
- final bottom = (stringDoubleToBitcoinAmount(bottomDoubleString.toString()) / 1000).round();
+ final topDouble = await estimatefee(p: 1);
+ final middleDouble = await estimatefee(p: 5);
+ final bottomDouble = await estimatefee(p: 10);
+ final top = _sanitizeFeeRate(topDouble);
+ final middle = _sanitizeFeeRate(middleDouble);
+ final bottom = _sanitizeFeeRate(bottomDouble);
return [bottom, middle, top];
} catch (_) {
diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart
index 5d3af65f5..c82ac8ebd 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -1,14 +1,17 @@
import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
+import 'dart:math' show Random;
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/lightning/lightning_wallet.dart';
+import 'package:cw_bitcoin/locktime.dart';
import 'package:cw_core/hardware/hardware_wallet_service.dart';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart';
+import 'package:cw_bitcoin/coin_selection.dart';
import 'package:cw_bitcoin/litecoin_wallet.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
@@ -260,6 +263,29 @@ abstract class ElectrumWalletBase
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
inputsCount * 68 + outputsCounts * 34 + 10;
+ // vbytes an input of the given script type adds to a transaction. The generic
+ // estimate above assumes P2WPKH (68); legacy and taproot inputs differ enough
+ // to break changeless-match arithmetic if not accounted for.
+ static int estimatedInputSize(BitcoinAddressType type) {
+ if (type == P2pkhAddressType.p2pkh) return 148;
+ if (type == P2shAddressType.p2wpkhInP2sh) return 91;
+ if (type == SegwitAddresType.p2tr) return 58;
+ if (type == SegwitAddresType.p2wsh) return 105;
+ if (type == SilentPaymentsAddresType.p2sp) return 58; // spent via taproot
+ return 68;
+ }
+
+ // vbytes an output of the given script type adds to a transaction. Silent
+ // payment outputs are delivered as taproot.
+ static int estimatedOutputSize(BitcoinAddressType type) {
+ if (type == P2pkhAddressType.p2pkh) return 34;
+ if (type == P2shAddressType.p2wpkhInP2sh) return 32;
+ if (type == SegwitAddresType.p2tr) return 43;
+ if (type == SegwitAddresType.p2wsh) return 43;
+ if (type == SilentPaymentsAddresType.p2sp) return 43;
+ return 31;
+ }
+
// Parses the account index from a BIP-44/49/84/86 derivation path.
// e.g. "m/84'/0'/1'" → 1. Returns 0 for unrecognised formats.
static int _parseAccountIndex(String? derivationPath) {
@@ -448,6 +474,15 @@ abstract class ElectrumWalletBase
return currentChainTip ?? 0;
}
+ /// Anti-fee-sniping locktime (current tip, exact-tip), LE-encoded for
+ /// `BitcoinTransactionBuilder`.
+ Future> _antiFeeSnipingLocktime() async {
+ return locktimeToBytes(antiFeeSnipingLocktime(
+ chainTip: await getCurrentChainTip(),
+ synced: syncStatus is SyncedSyncStatus,
+ ));
+ }
+
@override
BitcoinWalletKeys get keys {
String? wif;
@@ -750,6 +785,9 @@ abstract class ElectrumWalletBase
}
}
+ static bool _isValidFeeRates(List feeRates) =>
+ feeRates.length == 3 && feeRates.every((rate) => rate > 0);
+
@action
Future updateFeeRates() async {
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
@@ -776,7 +814,7 @@ abstract class ElectrumWalletBase
}
final feeRates = await electrumClient.feeRates(network: network);
- if (feeRates != [0, 0, 0]) {
+ if (_isValidFeeRates(feeRates)) {
_feeRates = feeRates;
} else if (isTestnet) {
_feeRates = [1, 1, 1];
@@ -868,11 +906,23 @@ abstract class ElectrumWalletBase
bool _isBelowDust(BigInt amount) =>
amount <= networkDustAmount && network != BitcoinNetwork.testnet;
+ // Random draw priority per outpoint. Assigned lazily with a secure RNG and kept
+ // until the next createTransaction call, so the recursive estimate passes of one
+ // transaction build all see the same input order (reshuffling between passes made
+ // fee estimation unstable). Cleared per transaction so each send is a fresh draw.
+ final Random _coinSelectionRng = Random.secure();
+ final Map _coinSelectionOrder = {};
+
+ int _coinSelectionPriority(BitcoinUnspent utx) => _coinSelectionOrder.putIfAbsent(
+ '${utx.hash}:${utx.vout}', () => _coinSelectionRng.nextInt(1 << 32));
+
UtxoDetails _createUTXOS({
required bool sendAll,
required bool paysToSilentPayment,
int credentialsAmount = 0,
int? inputsCount,
+ int feeRate = 0,
+ int? outputsVBytes,
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
}) {
List utxos = [];
@@ -901,8 +951,52 @@ abstract class ElectrumWalletBase
}).toList();
final unconfirmedCoins = availableInputs.where((utx) => utx.confirmations == 0).toList();
- // sort the unconfirmed coins so that mweb coins are last:
- availableInputs.sort((a, b) => a.bitcoinAddressRecord.type == SegwitAddresType.mweb ? 1 : -1);
+ // Single Random Draw: order the pool by each coin's random priority so selection is
+ // non-deterministic, removing the predictable address/scan order (a fingerprint).
+ // The priority is stable across the repeated calls of one transaction build.
+ // MWEB coins are kept last afterwards.
+ availableInputs.sort((a, b) {
+ final byPriority = _coinSelectionPriority(a).compareTo(_coinSelectionPriority(b));
+ if (byPriority != 0) return byPriority;
+ return '${a.hash}:${a.vout}'.compareTo('${b.hash}:${b.vout}');
+ });
+ availableInputs = [
+ ...availableInputs.where((u) => u.bitcoinAddressRecord.type != SegwitAddresType.mweb),
+ ...availableInputs.where((u) => u.bitcoinAddressRecord.type == SegwitAddresType.mweb),
+ ];
+
+ // Branch-and-bound: prefer an input set whose excess over the amount plus its own fee
+ // stays below dust, so the caller drops the change output and the send is changeless.
+ // When no such set exists, the shuffled pool below acts as a single random draw.
+ final canTryChangeless = !sendAll &&
+ inputsCount == null &&
+ credentialsAmount > 0 &&
+ feeRate > 0 &&
+ outputsVBytes != null &&
+ outputsVBytes > 0 &&
+ !availableInputs.any((u) => u.bitcoinAddressRecord.type == SegwitAddresType.mweb);
+ if (canTryChangeless) {
+ final match = changelessMatch(
+ values: [for (final u in availableInputs) u.value],
+ // estimatedTransactionSize(0, 0) is the fixed tx overhead (version,
+ // counters, locktime); the outputs' own vbytes come pre-computed per type.
+ target: credentialsAmount + (estimatedTransactionSize(0, 0) + outputsVBytes!) * feeRate,
+ inputCosts: [
+ for (final u in availableInputs)
+ estimatedInputSize(u.bitcoinAddressRecord.type) * feeRate
+ ],
+ window: networkDustAmount.toInt(),
+ );
+ if (match != null) {
+ final chosen = match.indices.toSet();
+ availableInputs = [
+ for (final i in match.indices) availableInputs[i],
+ for (var i = 0; i < availableInputs.length; i++)
+ if (!chosen.contains(i)) availableInputs[i],
+ ];
+ inputsCount = match.indices.length;
+ }
+ }
for (int i = 0; i < availableInputs.length; i++) {
final utx = availableInputs[i];
@@ -1024,7 +1118,7 @@ abstract class ElectrumWalletBase
vinOutpoints: utxoDetails.vinOutpoints,
);
- if (fee == 0) {
+ if (fee <= 0) {
throw BitcoinTransactionNoFeeException();
}
@@ -1118,10 +1212,25 @@ abstract class ElectrumWalletBase
}
}
+ // Per-type output sizes for the changeless target. MWEB outputs follow a
+ // different size model entirely, so they disable the changeless path (null).
+ int? outputsVBytes = 0;
+ for (final out in outputs) {
+ final type =
+ out.isSilentPayment == true ? SilentPaymentsAddresType.p2sp : _getScriptType(out.address);
+ if (type == SegwitAddresType.mweb) {
+ outputsVBytes = null;
+ break;
+ }
+ outputsVBytes = outputsVBytes! + estimatedOutputSize(type);
+ }
+
final utxoDetails = _createUTXOS(
sendAll: false,
credentialsAmount: credentialsAmount.amount.toInt(),
inputsCount: inputsCount,
+ feeRate: feeRate,
+ outputsVBytes: outputsVBytes,
paysToSilentPayment: hasSilentPayment,
coinTypeToSpendFrom: coinTypeToSpendFrom,
);
@@ -1205,7 +1314,7 @@ abstract class ElectrumWalletBase
));
}
- if (fee == 0) {
+ if (fee <= 0) {
throw BitcoinTransactionNoFeeException();
}
@@ -1384,6 +1493,10 @@ abstract class ElectrumWalletBase
@override
Future createTransaction(Object credentials) async {
try {
+ // New transaction, new random draw: drop the previous input ordering so this
+ // build gets fresh priorities, then keep them fixed for all estimate passes.
+ _coinSelectionOrder.clear();
+
// start by updating unspent coins
await updateAllUnspents();
@@ -1513,6 +1626,8 @@ abstract class ElectrumWalletBase
});
}
+ final locktime = await _antiFeeSnipingLocktime();
+
BasedBitcoinTransacationBuilder txb;
if (network is BitcoinCashNetwork) {
txb = ForkedTransactionBuilder(
@@ -1537,6 +1652,7 @@ abstract class ElectrumWalletBase
inputOrdering: BitcoinOrdering.shuffle,
outputOrdering: BitcoinOrdering.shuffle,
enableRBF: !estimatedTx.spendsUnconfirmedTX,
+ locktime: locktime,
);
}
@@ -2204,11 +2320,13 @@ abstract class ElectrumWalletBase
}
}
- // If still not enough, add UTXOs until the fee is covered
+ // If still not enough, add UTXOs until the fee is covered, drawing them at
+ // random instead of in the predictable wallet scan order (address, then age).
if (remainingFee > BigInt.zero) {
final unusedUtxos = unspentCoins
.where((utxo) => utxo.isSending && !utxo.isFrozen && utxo.confirmations! > 0)
- .toList();
+ .toList()
+ ..shuffle(Random.secure());
for (final utxo in unusedUtxos) {
final address = RegexUtils.addressTypeFromStr(utxo.address, network);
@@ -2303,6 +2421,7 @@ abstract class ElectrumWalletBase
inputOrdering: BitcoinOrdering.shuffle,
outputOrdering: BitcoinOrdering.shuffle,
enableRBF: true,
+ locktime: await _antiFeeSnipingLocktime(),
);
final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) {
@@ -2513,16 +2632,16 @@ abstract class ElectrumWalletBase
Map historiesWithDetails,
BitcoinAddressType type,
) async {
-
final addressesByType =
- walletAddresses.allAddresses.where((addr) => addr.type == type).toList();
+ walletAddresses.allAddresses.where((addr) => addr.type == type).toList();
final receiveStandard = getAddressBranchByType(hidden: false, legacy: false, type: type);
- final changeStandard = getAddressBranchByType(hidden: true, legacy: false, type: type);
+ final changeStandard = getAddressBranchByType(hidden: true, legacy: false, type: type);
final receiveLegacy = getAddressBranchByType(hidden: false, legacy: true, type: type);
- final changeLegacy = getAddressBranchByType(hidden: true, legacy: true, type: type);
+ final changeLegacy = getAddressBranchByType(hidden: true, legacy: true, type: type);
- walletAddresses.hiddenAddresses.addAll([...changeStandard, ...changeLegacy].map((e) => e.address));
+ walletAddresses.hiddenAddresses
+ .addAll([...changeStandard, ...changeLegacy].map((e) => e.address));
await walletAddresses.saveAddressesInBox();
await Future.wait(addressesByType.map((addressRecord) async {
final history = await _fetchAddressHistory(addressRecord, await getCurrentChainTip());
@@ -2637,13 +2756,13 @@ abstract class ElectrumWalletBase
Future fetchTransactionsForAddressTypeBatch(
Map historiesWithDetails, BitcoinAddressType type) async {
-
final receiveStandard = getAddressBranchByType(hidden: false, legacy: false, type: type);
- final changeStandard = getAddressBranchByType(hidden: true, legacy: false, type: type);
+ final changeStandard = getAddressBranchByType(hidden: true, legacy: false, type: type);
final receiveLegacy = getAddressBranchByType(hidden: false, legacy: true, type: type);
- final changeLegacy = getAddressBranchByType(hidden: true, legacy: true, type: type);
+ final changeLegacy = getAddressBranchByType(hidden: true, legacy: true, type: type);
- walletAddresses.hiddenAddresses.addAll([...changeStandard, ...changeLegacy].map((e) => e.address));
+ walletAddresses.hiddenAddresses
+ .addAll([...changeStandard, ...changeLegacy].map((e) => e.address));
await walletAddresses.saveAddressesInBox();
await fetchTransactionsForAddressesBranchBatch(
@@ -2665,7 +2784,7 @@ abstract class ElectrumWalletBase
await fetchTransactionsForAddressesBranchBatch(
historiesWithDetails,
type,
- receiveLegacy,
+ receiveLegacy,
isHidden: false,
isLegacyDerivation: true,
);
@@ -2749,10 +2868,13 @@ abstract class ElectrumWalletBase
}
}
- List getAddressBranchByType({required bool hidden, required bool legacy, required BitcoinAddressType
- type}) => walletAddresses.allAddresses.where((addr) => addr.type == type && addr.isHidden == hidden && addr.isLegacyDerivation == legacy)
- .toList()
- ..sort((a, b) => a.index.compareTo(b.index));
+ List getAddressBranchByType(
+ {required bool hidden, required bool legacy, required BitcoinAddressType type}) =>
+ walletAddresses.allAddresses
+ .where((addr) =>
+ addr.type == type && addr.isHidden == hidden && addr.isLegacyDerivation == legacy)
+ .toList()
+ ..sort((a, b) => a.index.compareTo(b.index));
int _highestUsedIndex(List addresses) {
for (int i = addresses.length - 1; i >= 0; i--) {
diff --git a/cw_bitcoin/lib/locktime.dart b/cw_bitcoin/lib/locktime.dart
new file mode 100644
index 000000000..639e6e1d0
--- /dev/null
+++ b/cw_bitcoin/lib/locktime.dart
@@ -0,0 +1,20 @@
+import "dart:typed_data";
+
+/// Anti-fee-sniping locktime, set to the current chain tip (exact-tip).
+///
+/// Matches the exact-tip cluster (payjoin-cli, ldk-node, Bull Bitcoin) and Core's
+/// default for externally-constructed transactions, and takes Cake off its unique
+/// `nLockTime = 0` fingerprint. It intentionally skips the ~10% backdate
+/// Core/Electrum apply for delayed-broadcast privacy, which does not apply here.
+/// Returns 0 when not synced or the tip is unknown, to avoid emitting a stale
+/// height.
+int antiFeeSnipingLocktime({
+ required int chainTip,
+ required bool synced,
+}) {
+ if (!synced || chainTip <= 0) return 0;
+ return chainTip;
+}
+
+/// Little-endian 4-byte encoding for `BtcTransaction.locktime`.
+List locktimeToBytes(int locktime) => (ByteData(4)..setUint32(0, locktime, Endian.little)).buffer.asUint8List();
diff --git a/cw_bitcoin/lib/payjoin/manager.dart b/cw_bitcoin/lib/payjoin/manager.dart
index efa120f99..ba0d616ad 100644
--- a/cw_bitcoin/lib/payjoin/manager.dart
+++ b/cw_bitcoin/lib/payjoin/manager.dart
@@ -295,6 +295,9 @@ class PayjoinManager {
await _wallet.updateAllUnspents();
utxos = _wallet.getUtxoWithPrivateKeys(confirmedOnly: true);
}
+ // Candidates arrive in wallet scan order (address, then age), which is
+ // predictable; shuffle so the receiver's input choice can't mirror it.
+ utxos.shuffle(Random.secure());
mainToIsolateSendPort?.send({
'requestId': message['requestId'],
'result': utxos,
diff --git a/cw_bitcoin/lib/psbt/transaction_builder.dart b/cw_bitcoin/lib/psbt/transaction_builder.dart
index 7d2ead134..ab107bfeb 100644
--- a/cw_bitcoin/lib/psbt/transaction_builder.dart
+++ b/cw_bitcoin/lib/psbt/transaction_builder.dart
@@ -14,8 +14,10 @@ class PSBTTransactionBuild {
{required List inputs,
required List outputs,
required List cwOutputs,
- bool enableRBF = true}) {
+ bool enableRBF = true,
+ int locktime = 0}) {
psbt.setGlobalTxVersion(2);
+ psbt.setGlobalFallbackLocktime(locktime);
psbt.setGlobalInputCount(inputs.length);
psbt.setGlobalOutputCount(outputs.length);
diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock
deleted file mode 100644
index b35b2bf09..000000000
--- a/cw_bitcoin/pubspec.lock
+++ /dev/null
@@ -1,1326 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- _fe_analyzer_shared:
- dependency: transitive
- description:
- name: _fe_analyzer_shared
- sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e"
- url: "https://pub.dev"
- source: hosted
- version: "92.0.0"
- analyzer:
- dependency: transitive
- description:
- name: analyzer
- sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e"
- url: "https://pub.dev"
- source: hosted
- version: "9.0.0"
- args:
- dependency: transitive
- description:
- name: args
- sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- asn1lib:
- dependency: transitive
- description:
- name: asn1lib
- sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024"
- url: "https://pub.dev"
- source: hosted
- version: "1.6.5"
- async:
- dependency: transitive
- description:
- name: async
- sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
- url: "https://pub.dev"
- source: hosted
- version: "2.13.0"
- bbqrdart:
- dependency: "direct main"
- description:
- path: "."
- ref: e867e3d0156d0b29858100f30adc2625b9dae586
- resolved-ref: e867e3d0156d0b29858100f30adc2625b9dae586
- url: "https://github.com/mrcyjanek/bbqrdart"
- source: git
- version: "1.0.0"
- bech32:
- dependency: transitive
- description:
- path: "."
- ref: HEAD
- resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
- url: "https://github.com/cake-tech/bech32.git"
- source: git
- version: "0.2.2"
- bip32:
- dependency: transitive
- description:
- name: bip32
- sha256: "54787cd7a111e9d37394aabbf53d1fc5e2e0e0af2cd01c459147a97c0e3f8a97"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- bip39:
- dependency: transitive
- description:
- name: bip39
- sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc
- url: "https://pub.dev"
- source: hosted
- version: "1.0.6"
- bitbox:
- dependency: "direct main"
- description:
- path: "."
- ref: Add-Support-For-OP-Return-data
- resolved-ref: "57b78afb85bd2c30d3cdb9f7884f3878a62be442"
- url: "https://github.com/cake-tech/bitbox-flutter.git"
- source: git
- version: "1.0.1"
- bitbox_flutter:
- dependency: "direct main"
- description:
- path: "../scripts/bitbox_flutter"
- relative: true
- source: path
- version: "0.0.1"
- bitcoin_base:
- dependency: "direct overridden"
- description:
- path: "."
- ref: cake-update-v11
- resolved-ref: bda0e2904effa799ec835b4578cc3fc5d31caa78
- url: "https://github.com/cake-tech/bitcoin_base"
- source: git
- version: "4.7.0"
- blockchain_utils:
- dependency: "direct main"
- description:
- path: "."
- ref: cake-update-v2
- resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
- url: "https://github.com/cake-tech/blockchain_utils"
- source: git
- version: "3.3.0"
- bluez:
- dependency: transitive
- description:
- name: bluez
- sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545"
- url: "https://pub.dev"
- source: hosted
- version: "0.8.3"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- breez_sdk_spark_flutter:
- dependency: "direct main"
- description:
- path: "."
- ref: "v0.14.0"
- resolved-ref: e18b6437daaf0572de6aea2439c2ec4d22658bbb
- url: "https://github.com/breez/breez-sdk-spark-flutter"
- source: git
- version: "0.14.0"
- bs58check:
- dependency: transitive
- description:
- name: bs58check
- sha256: c4a164d42b25c2f6bc88a8beccb9fc7d01440f3c60ba23663a20a70faf484ea9
- url: "https://pub.dev"
- source: hosted
- version: "1.0.2"
- build:
- dependency: transitive
- description:
- name: build
- sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10
- url: "https://pub.dev"
- source: hosted
- version: "4.0.6"
- build_cli_annotations:
- dependency: transitive
- description:
- name: build_cli_annotations
- sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
- url: "https://pub.dev"
- source: hosted
- version: "2.1.0"
- build_config:
- dependency: transitive
- description:
- name: build_config
- sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- build_daemon:
- dependency: transitive
- description:
- name: build_daemon
- sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.4"
- build_runner:
- dependency: "direct dev"
- description:
- name: build_runner
- sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6"
- url: "https://pub.dev"
- source: hosted
- version: "2.15.0"
- built_collection:
- dependency: transitive
- description:
- name: built_collection
- sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
- url: "https://pub.dev"
- source: hosted
- version: "5.1.1"
- built_value:
- dependency: transitive
- description:
- name: built_value
- sha256: ba95c961bafcd8686d1cf63be864eb59447e795e124d98d6a27d91fcd13602fb
- url: "https://pub.dev"
- source: hosted
- version: "8.11.1"
- cake_backup:
- dependency: transitive
- description:
- path: "."
- ref: main
- resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
- url: "https://github.com/cake-tech/cake_backup.git"
- source: git
- version: "1.0.0+1"
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- checked_yaml:
- dependency: transitive
- description:
- name: checked_yaml
- sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
- url: "https://pub.dev"
- source: hosted
- version: "2.0.3"
- cli_util:
- dependency: transitive
- description:
- name: cli_util
- sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
- url: "https://pub.dev"
- source: hosted
- version: "0.4.2"
- clock:
- dependency: transitive
- description:
- name: clock
- sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- code_builder:
- dependency: transitive
- description:
- name: code_builder
- sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
- url: "https://pub.dev"
- source: hosted
- version: "4.10.1"
- collection:
- dependency: transitive
- description:
- name: collection
- sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
- url: "https://pub.dev"
- source: hosted
- version: "1.19.1"
- convert:
- dependency: transitive
- description:
- name: convert
- sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- crypto:
- dependency: transitive
- description:
- name: crypto
- sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.6"
- cryptography:
- dependency: "direct main"
- description:
- name: cryptography
- sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- cupertino_icons:
- dependency: transitive
- description:
- name: cupertino_icons
- sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
- url: "https://pub.dev"
- source: hosted
- version: "1.0.8"
- cw_core:
- dependency: "direct main"
- description:
- path: "../cw_core"
- relative: true
- source: path
- version: "0.0.1"
- cw_mweb:
- dependency: "direct main"
- description:
- path: "../cw_mweb"
- relative: true
- source: path
- version: "0.0.1"
- dart_style:
- dependency: transitive
- description:
- name: dart_style
- sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
- dart_varuint_bitcoin:
- dependency: transitive
- description:
- name: dart_varuint_bitcoin
- sha256: "4f0ccc9733fb54148b9d3688eea822b7aaabf5cc00025998f8c09a1d45b31b4b"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.3"
- dbus:
- dependency: transitive
- description:
- name: dbus
- sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.11"
- decimal:
- dependency: transitive
- description:
- name: decimal
- sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.3"
- encrypt:
- dependency: transitive
- description:
- name: encrypt
- sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.3"
- fake_async:
- dependency: transitive
- description:
- name: fake_async
- sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.3"
- ffi:
- dependency: "direct overridden"
- description:
- name: ffi
- sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.0"
- ffigen:
- dependency: transitive
- description:
- name: ffigen
- sha256: "3e12e80ccb6539bb3917217bb6f32709220efb737de0d0fa8736da0b7cb507da"
- url: "https://pub.dev"
- source: hosted
- version: "12.0.0"
- file:
- dependency: transitive
- description:
- name: file
- sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
- url: "https://pub.dev"
- source: hosted
- version: "7.0.1"
- fixnum:
- dependency: transitive
- description:
- name: fixnum
- sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_mobx:
- dependency: "direct main"
- description:
- name: flutter_mobx
- sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- flutter_rust_bridge:
- dependency: transitive
- description:
- name: flutter_rust_bridge
- sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e"
- url: "https://pub.dev"
- source: hosted
- version: "2.11.1"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_web_bluetooth:
- dependency: transitive
- description:
- name: flutter_web_bluetooth
- sha256: ad26a1b3fef95b86ea5f63793b9a0cdc1a33490f35d754e4e711046cae3ebbf8
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- flutter_web_plugins:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- freezed_annotation:
- dependency: transitive
- description:
- name: freezed_annotation
- sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- glob:
- dependency: transitive
- description:
- name: glob
- sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- google_identity_services_web:
- dependency: transitive
- description:
- name: google_identity_services_web
- sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.3+1"
- googleapis_auth:
- dependency: transitive
- description:
- name: googleapis_auth
- sha256: befd71383a955535060acde8792e7efc11d2fccd03dd1d3ec434e85b68775938
- url: "https://pub.dev"
- source: hosted
- version: "1.6.0"
- graphs:
- dependency: transitive
- description:
- name: graphs
- sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.2"
- grpc:
- dependency: "direct main"
- description:
- name: grpc
- sha256: "5b99b7a420937d4361ece68b798c9af8e04b5bc128a7859f2a4be87427694813"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.1"
- hex:
- dependency: transitive
- description:
- name: hex
- sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.0"
- hive:
- dependency: "direct dev"
- description:
- name: hive
- sha256: "5184b6ea455689754578267c31c3b0b329cccf20a5f2bfdab6941c29c3d3c09a"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- http:
- dependency: "direct main"
- description:
- name: http
- sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
- url: "https://pub.dev"
- source: hosted
- version: "1.5.0"
- http2:
- dependency: transitive
- description:
- name: http2
- sha256: "382d3aefc5bd6dc68c6b892d7664f29b5beb3251611ae946a98d35158a82bbfa"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.1"
- http_multi_server:
- dependency: transitive
- description:
- name: http_multi_server
- sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- http_parser:
- dependency: transitive
- description:
- name: http_parser
- sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
- url: "https://pub.dev"
- source: hosted
- version: "4.1.2"
- intl:
- dependency: "direct main"
- description:
- name: intl
- sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
- url: "https://pub.dev"
- source: hosted
- version: "0.19.0"
- io:
- dependency: transitive
- description:
- name: io
- sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- js:
- dependency: transitive
- description:
- name: js
- sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
- url: "https://pub.dev"
- source: hosted
- version: "0.6.7"
- json_annotation:
- dependency: transitive
- description:
- name: json_annotation
- sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
- url: "https://pub.dev"
- source: hosted
- version: "4.9.0"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
- url: "https://pub.dev"
- source: hosted
- version: "11.0.2"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.10"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- ledger_bitcoin:
- dependency: "direct main"
- description:
- path: "packages/ledger-bitcoin"
- ref: "75bba8632c529debf30ee2b1858530009fa6440b"
- resolved-ref: "75bba8632c529debf30ee2b1858530009fa6440b"
- url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
- source: git
- version: "0.0.3"
- ledger_flutter_plus:
- dependency: "direct main"
- description:
- name: ledger_flutter_plus
- sha256: "531da5daba5731d9eca2732881ef2f039b97bf8aa3564e7098dfa99a9b07a8e6"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.3"
- ledger_litecoin:
- dependency: "direct main"
- description:
- path: "packages/ledger-litecoin"
- ref: HEAD
- resolved-ref: e8ab1a98493dfdd2277edde07a66b8d378ca70f6
- url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
- source: git
- version: "0.0.2"
- ledger_usb_plus:
- dependency: transitive
- description:
- name: ledger_usb_plus
- sha256: "21cc5d976cf7edb3518bd2a0c4164139cbb0817d2e4f2054707fc4edfdf9ce87"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.4"
- logging:
- dependency: transitive
- description:
- name: logging
- sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- matcher:
- dependency: transitive
- description:
- name: matcher
- sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
- url: "https://pub.dev"
- source: hosted
- version: "0.12.19"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
- url: "https://pub.dev"
- source: hosted
- version: "0.13.0"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
- url: "https://pub.dev"
- source: hosted
- version: "1.17.0"
- mime:
- dependency: transitive
- description:
- name: mime
- sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- mobx:
- dependency: "direct main"
- description:
- name: mobx
- sha256: "25ea9a3ee69243d578fb6288721d8eeb18550d0391c32f896d377d994154bff2"
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- mobx_codegen:
- dependency: "direct dev"
- description:
- name: mobx_codegen
- sha256: "6529bcae074838004b58ad01fbe4966be182a176aacfb723686985986ebac19f"
- url: "https://pub.dev"
- source: hosted
- version: "2.7.7"
- mockito:
- dependency: transitive
- description:
- name: mockito
- sha256: eff30d002f0c8bf073b6f929df4483b543133fcafce056870163587b03f1d422
- url: "https://pub.dev"
- source: hosted
- version: "5.6.4"
- nested:
- dependency: transitive
- description:
- name: nested
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- on_chain:
- dependency: transitive
- description:
- path: "."
- ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- url: "https://github.com/cake-tech/on_chain.git"
- source: git
- version: "3.7.0"
- package_config:
- dependency: transitive
- description:
- name: package_config
- sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- path:
- dependency: transitive
- description:
- name: path
- sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
- url: "https://pub.dev"
- source: hosted
- version: "1.9.1"
- path_provider:
- dependency: "direct main"
- description:
- name: path_provider
- sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- path_provider_android:
- dependency: transitive
- description:
- name: path_provider_android
- sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
- url: "https://pub.dev"
- source: hosted
- version: "2.2.17"
- path_provider_foundation:
- dependency: transitive
- description:
- name: path_provider_foundation
- sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- path_provider_linux:
- dependency: transitive
- description:
- name: path_provider_linux
- sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
- url: "https://pub.dev"
- source: hosted
- version: "2.2.1"
- path_provider_platform_interface:
- dependency: transitive
- description:
- name: path_provider_platform_interface
- sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- path_provider_windows:
- dependency: transitive
- description:
- name: path_provider_windows
- sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- payjoin_flutter:
- dependency: "direct main"
- description:
- path: "."
- ref: b28c825b1d63381e8c2b25ef2ccabacbf833ce53
- resolved-ref: b28c825b1d63381e8c2b25ef2ccabacbf833ce53
- url: "https://github.com/konstantinullrich/payjoin-flutter"
- source: git
- version: "0.23.0"
- petitparser:
- dependency: transitive
- description:
- name: petitparser
- sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
- url: "https://pub.dev"
- source: hosted
- version: "6.0.2"
- platform:
- dependency: transitive
- description:
- name: platform
- sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.6"
- plugin_platform_interface:
- dependency: transitive
- description:
- name: plugin_platform_interface
- sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.8"
- pointycastle:
- dependency: "direct overridden"
- description:
- name: pointycastle
- sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
- url: "https://pub.dev"
- source: hosted
- version: "3.7.4"
- pool:
- dependency: transitive
- description:
- name: pool
- sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.1"
- protobuf:
- dependency: "direct overridden"
- description:
- name: protobuf
- sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- provider:
- dependency: transitive
- description:
- name: provider
- sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
- url: "https://pub.dev"
- source: hosted
- version: "6.1.5"
- pub_semver:
- dependency: transitive
- description:
- name: pub_semver
- sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- pubspec_parse:
- dependency: transitive
- description:
- name: pubspec_parse
- sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.0"
- quiver:
- dependency: transitive
- description:
- name: quiver
- sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- rational:
- dependency: transitive
- description:
- name: rational
- sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
- rxdart:
- dependency: "direct main"
- description:
- name: rxdart
- sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
- url: "https://pub.dev"
- source: hosted
- version: "0.28.0"
- shared_preferences:
- dependency: "direct main"
- description:
- name: shared_preferences
- sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.3"
- shared_preferences_android:
- dependency: transitive
- description:
- name: shared_preferences_android
- sha256: "5bcf0772a761b04f8c6bf814721713de6f3e5d9d89caf8d3fe031b02a342379e"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.11"
- shared_preferences_foundation:
- dependency: transitive
- description:
- name: shared_preferences_foundation
- sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4"
- shared_preferences_linux:
- dependency: transitive
- description:
- name: shared_preferences_linux
- sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shared_preferences_platform_interface:
- dependency: transitive
- description:
- name: shared_preferences_platform_interface
- sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shared_preferences_web:
- dependency: transitive
- description:
- name: shared_preferences_web
- sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
- url: "https://pub.dev"
- source: hosted
- version: "2.4.3"
- shared_preferences_windows:
- dependency: transitive
- description:
- name: shared_preferences_windows
- sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shelf:
- dependency: transitive
- description:
- name: shelf
- sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
- url: "https://pub.dev"
- source: hosted
- version: "1.4.2"
- shelf_web_socket:
- dependency: transitive
- description:
- name: shelf_web_socket
- sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.0"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- socks5_proxy:
- dependency: transitive
- description:
- path: "."
- ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- url: "https://github.com/LacticWhale/socks_dart"
- source: git
- version: "2.1.0"
- socks_socket:
- dependency: "direct main"
- description:
- path: "."
- ref: e6232c53c1595469931ababa878759a067c02e94
- resolved-ref: e6232c53c1595469931ababa878759a067c02e94
- url: "https://github.com/sneurlax/socks_socket"
- source: git
- version: "1.1.1"
- source_gen:
- dependency: transitive
- description:
- name: source_gen
- sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02
- url: "https://pub.dev"
- source: hosted
- version: "4.2.3"
- source_span:
- dependency: transitive
- description:
- name: source_span
- sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
- url: "https://pub.dev"
- source: hosted
- version: "1.10.1"
- sp_scanner:
- dependency: "direct main"
- description:
- path: "."
- ref: "sp_v4.0.1"
- resolved-ref: "40ed3ce8319744907bef3b25bc6e0af8428c8724"
- url: "https://github.com/cake-tech/sp_scanner"
- source: git
- version: "0.0.1"
- sprintf:
- dependency: transitive
- description:
- name: sprintf
- sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
- url: "https://pub.dev"
- source: hosted
- version: "7.0.0"
- sqflite:
- dependency: transitive
- description:
- name: sqflite
- sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- sqflite_android:
- dependency: transitive
- description:
- name: sqflite_android
- sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqflite_common:
- dependency: transitive
- description:
- name: sqflite_common
- sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4+6"
- sqflite_common_ffi:
- dependency: transitive
- description:
- name: sqflite_common_ffi
- sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.4+4"
- sqflite_darwin:
- dependency: transitive
- description:
- name: sqflite_darwin
- sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1+1"
- sqflite_platform_interface:
- dependency: transitive
- description:
- name: sqflite_platform_interface
- sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqlite3:
- dependency: transitive
- description:
- name: sqlite3
- sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
- url: "https://pub.dev"
- source: hosted
- version: "2.9.0"
- sqlite3_flutter_libs:
- dependency: transitive
- description:
- name: sqlite3_flutter_libs
- sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
- url: "https://pub.dev"
- source: hosted
- version: "0.5.40"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
- url: "https://pub.dev"
- source: hosted
- version: "1.12.1"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- stream_transform:
- dependency: transitive
- description:
- name: stream_transform
- sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
- url: "https://pub.dev"
- source: hosted
- version: "3.3.0+3"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.2"
- test_api:
- dependency: transitive
- description:
- name: test_api
- sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.10"
- torch_dart:
- dependency: transitive
- description:
- path: "../scripts/torch_dart"
- relative: true
- source: path
- version: "0.0.1"
- trezor_connect:
- dependency: "direct main"
- description:
- path: "."
- ref: d1242cea90f84b00200e7bcab914a5af750e23fb
- resolved-ref: d1242cea90f84b00200e7bcab914a5af750e23fb
- url: "https://github.com/cake-tech/trezor_connect"
- source: git
- version: "0.0.1"
- tuple:
- dependency: transitive
- description:
- name: tuple
- sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- universal_ble:
- dependency: transitive
- description:
- name: universal_ble
- sha256: "35d210e93a5938c6a6d1fd3c710cf4ac90b1bdd1b11c8eb2beeb32600672e6e6"
- url: "https://pub.dev"
- source: hosted
- version: "0.17.0"
- universal_platform:
- dependency: transitive
- description:
- name: universal_platform
- sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- unorm_dart:
- dependency: transitive
- description:
- name: unorm_dart
- sha256: "8e3870a1caa60bde8352f9597dd3535d8068613269444f8e35ea8925ec84c1f5"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.1+1"
- ur:
- dependency: "direct main"
- description:
- path: "."
- ref: "5738f70d0ec3d50977ac3dd01fed62939600238b"
- resolved-ref: "5738f70d0ec3d50977ac3dd01fed62939600238b"
- url: "https://github.com/bukata-sa/bc-ur-dart"
- source: git
- version: "0.1.0"
- url_launcher:
- dependency: transitive
- description:
- name: url_launcher
- sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8
- url: "https://pub.dev"
- source: hosted
- version: "6.3.2"
- url_launcher_android:
- dependency: transitive
- description:
- name: url_launcher_android
- sha256: "81777b08c498a292d93ff2feead633174c386291e35612f8da438d6e92c4447e"
- url: "https://pub.dev"
- source: hosted
- version: "6.3.20"
- url_launcher_ios:
- dependency: transitive
- description:
- name: url_launcher_ios
- sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7
- url: "https://pub.dev"
- source: hosted
- version: "6.3.4"
- url_launcher_linux:
- dependency: transitive
- description:
- name: url_launcher_linux
- sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
- url: "https://pub.dev"
- source: hosted
- version: "3.2.1"
- url_launcher_macos:
- dependency: transitive
- description:
- name: url_launcher_macos
- sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f
- url: "https://pub.dev"
- source: hosted
- version: "3.2.3"
- url_launcher_platform_interface:
- dependency: transitive
- description:
- name: url_launcher_platform_interface
- sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.2"
- url_launcher_web:
- dependency: transitive
- description:
- name: url_launcher_web
- sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- url_launcher_windows:
- dependency: transitive
- description:
- name: url_launcher_windows
- sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.4"
- uuid:
- dependency: transitive
- description:
- name: uuid
- sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
- url: "https://pub.dev"
- source: hosted
- version: "4.5.1"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
- url: "https://pub.dev"
- source: hosted
- version: "15.0.0"
- watcher:
- dependency: "direct overridden"
- description:
- name: watcher
- sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- web:
- dependency: transitive
- description:
- name: web
- sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web_socket:
- dependency: transitive
- description:
- name: web_socket
- sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.1"
- web_socket_channel:
- dependency: transitive
- description:
- name: web_socket_channel
- sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
- url: "https://pub.dev"
- source: hosted
- version: "3.0.3"
- xdg_directories:
- dependency: transitive
- description:
- name: xdg_directories
- sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- xml:
- dependency: transitive
- description:
- name: xml
- sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
- url: "https://pub.dev"
- source: hosted
- version: "6.5.0"
- yaml:
- dependency: transitive
- description:
- name: yaml
- sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
- yaml_edit:
- dependency: transitive
- description:
- name: yaml_edit
- sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5
- url: "https://pub.dev"
- source: hosted
- version: "2.2.2"
-sdks:
- dart: ">=3.9.0 <4.0.0"
- flutter: ">=3.29.0"
diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml
index 98e1ec46c..46a8992cc 100644
--- a/cw_bitcoin/pubspec.yaml
+++ b/cw_bitcoin/pubspec.yaml
@@ -29,7 +29,7 @@ dependencies:
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
- ref: cake-update-v2
+ ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
cw_mweb:
path: ../cw_mweb
grpc: 4.0.1
@@ -88,7 +88,7 @@ dependency_overrides:
bitcoin_base:
git:
url: https://github.com/cake-tech/bitcoin_base
- ref: cake-update-v11
+ ref: bda0e2904effa799ec835b4578cc3fc5d31caa78
pointycastle: 3.7.4
ffi: 2.1.0
intl: any
diff --git a/cw_bitcoin/pubspec_overrides.yaml b/cw_bitcoin/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_bitcoin/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_bitcoin/test/coin_selection_test.dart b/cw_bitcoin/test/coin_selection_test.dart
new file mode 100644
index 000000000..8708075d0
--- /dev/null
+++ b/cw_bitcoin/test/coin_selection_test.dart
@@ -0,0 +1,100 @@
+import 'dart:math';
+import "package:cw_bitcoin/coin_selection.dart";
+import "package:flutter_test/flutter_test.dart";
+void main() {
+ test('effectiveValue', () {
+ expect(effectiveValue(10000, 136), 9864);
+ expect(effectiveValue(100, 136), -36);
+ });
+ test('BnB finds changeless match in window', () {
+ final r = branchAndBound([200,100,90,80], 300, 50);
+ expect(r, isNotNull); expect(r!.hasChange, isFalse);
+ final vals=[200,100,90,80]; final sum=r.indices.map((i)=>vals[i]).reduce((a,b)=>a+b);
+ expect(sum>=300 && sum<=350, isTrue);
+ });
+ test('BnB null when no subset in window', () {
+ expect(branchAndBound([1000,900], 300, 5), isNull);
+ });
+ test('SRD with change', () {
+ final r = singleRandomDraw([500,500,500,500], 700, 50, Random(1));
+ expect(r, isNotNull); expect(r!.hasChange, isTrue);
+ });
+ test('SRD randomizes across seeds', () {
+ final a = (singleRandomDraw([100,101,102,103,104,105],150,10,Random(1))!.indices..sort());
+ final b = (singleRandomDraw([100,101,102,103,104,105],150,10,Random(9))!.indices..sort());
+ expect(a, isNot(equals(b)));
+ });
+ test('SRD null on insufficient funds', () {
+ expect(singleRandomDraw([100,100], 500, 10, Random(1)), isNull);
+ });
+ test('selectCoins prefers changeless BnB, else SRD', () {
+ expect(selectCoins(values:[200,100,90],target:300,inputCost:0,costOfChange:20,minChange:10).hasChange, isFalse);
+ expect(selectCoins(values:[500,500,500],target:700,inputCost:0,costOfChange:5,minChange:10,rng:Random(1)).hasChange, isTrue);
+ });
+ test('selectCoins drops non-positive effective values', () {
+ // coin of value 50 with inputCost 136 -> effective -86 -> dropped; only the 1000 usable
+ final r = selectCoins(values:[50,1000],target:500,inputCost:136,costOfChange:5,minChange:10,rng:Random(1));
+ expect(r.indices, equals([1]));
+ });
+ test('changelessMatch finds a set whose effective sum lands in the window', () {
+ // inputCost 100: values [50, 400, 300, 200] -> eff [dropped, 300, 200, 100]
+ // target 500, window 46: eff {300, 200} = 500, exact
+ final r = changelessMatch(
+ values: [50, 400, 300, 200], target: 500, inputCosts: [100, 100, 100, 100], window: 46);
+ expect(r, isNotNull);
+ expect(r!.hasChange, isFalse);
+ final effSum = r.indices.map((i) => [50, 400, 300, 200][i] - 100).reduce((a, b) => a + b);
+ expect(effSum >= 500 && effSum <= 546, isTrue);
+ expect(r.indices.contains(0), isFalse); // negative-eff coin never selected
+ });
+ test('changelessMatch returns null when no subset lands in the window', () {
+ expect(
+ changelessMatch(values: [10000, 9000], target: 500, inputCosts: [100, 100], window: 46),
+ isNull);
+ });
+ test('selectCoins throws when insufficient', () {
+ expect(() => selectCoins(values:[100,100],target:500,inputCost:0,costOfChange:5,minChange:10),
+ throwsA(isA()));
+ });
+ test('changeless pipeline: leftover absorbed into fee is non-negative and below dust', () {
+ // Mirrors the _createUTXOS / estimateTxForAmount arithmetic with the wallet's
+ // 68*inputs + 34*outputs + 10 vBytes model, at 10 sat/vB with 1 recipient output.
+ const feeRate = 10;
+ const amount = 50000;
+ final values = [60700, 30000, 21800, 9000, 5000];
+ const target = amount + (34 * 1 + 10) * feeRate;
+ final r = changelessMatch(
+ values: values,
+ target: target,
+ inputCosts: List.filled(values.length, 68 * feeRate),
+ window: 546);
+ expect(r, isNotNull);
+ final inAmount = r!.indices.map((i) => values[i]).reduce((a, b) => a + b);
+ final feeNoChange = (68 * r.indices.length + 34 * 1 + 10) * feeRate;
+ final leftover = inAmount - amount - feeNoChange;
+ expect(leftover >= 0, isTrue); // the caller never recurses for more inputs
+ expect(leftover <= 546, isTrue); // fee overpay is bounded by the dust limit
+ });
+ test('BnB terminates and returns null on large pools with no possible match', () {
+ // 300 even effective values, odd target, zero window: no subset can ever match,
+ // so the search must stop at maxTries instead of exploring 2^300 branches.
+ final values = List.generate(300, (i) => 1000000 + i * 2);
+ final r = changelessMatch(
+ values: values, target: 1500001, inputCosts: List.filled(300, 10), window: 0);
+ expect(r, isNull);
+ });
+ test('changelessMatch charges each input its own script-type cost', () {
+ // Legacy input (148 vB) vs segwit input (68 vB) at 10 sat/vB: same value, but
+ // the legacy coin's effective value is 800 lower. Target only reachable when
+ // the cheaper segwit coin is chosen: eff segwit = 10000-680 = 9320.
+ const feeRate = 10;
+ final r = changelessMatch(
+ values: [10000, 10000],
+ target: 9320,
+ inputCosts: [148 * feeRate, 68 * feeRate],
+ window: 0,
+ );
+ expect(r, isNotNull);
+ expect(r!.indices, equals([1]));
+ });
+}
diff --git a/cw_bitcoin/test/locktime_test.dart b/cw_bitcoin/test/locktime_test.dart
new file mode 100644
index 000000000..cd20e0205
--- /dev/null
+++ b/cw_bitcoin/test/locktime_test.dart
@@ -0,0 +1,32 @@
+import 'package:cw_bitcoin/locktime.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ group('antiFeeSnipingLocktime', () {
+ test('returns 0 when not synced', () {
+ expect(antiFeeSnipingLocktime(chainTip: 800000, synced: false), 0);
+ });
+
+ test('returns 0 when chainTip <= 0', () {
+ expect(antiFeeSnipingLocktime(chainTip: 0, synced: true), 0);
+ });
+
+ test('returns the current tip when synced', () {
+ expect(antiFeeSnipingLocktime(chainTip: 800000, synced: true), 800000);
+ });
+ });
+
+ group('locktimeToBytes', () {
+ test('encodes 0 as four zero bytes', () {
+ expect(locktimeToBytes(0), [0, 0, 0, 0]);
+ });
+
+ test('encodes a block height little-endian', () {
+ expect(locktimeToBytes(800000), [0x00, 0x35, 0x0C, 0x00]);
+ });
+
+ test('encodes max 32-bit value', () {
+ expect(locktimeToBytes(0xFFFFFFFF), [0xFF, 0xFF, 0xFF, 0xFF]);
+ });
+ });
+}
diff --git a/cw_bitcoin_cash/.gitignore b/cw_bitcoin_cash/.gitignore
index 96486fd93..32aee4b25 100644
--- a/cw_bitcoin_cash/.gitignore
+++ b/cw_bitcoin_cash/.gitignore
@@ -22,8 +22,6 @@ migrate_working_dir/
#.vscode/
# Flutter/Dart/Pub related
-# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
-/pubspec.lock
**/doc/api/
.dart_tool/
.packages
diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml
index ec6e6bebc..5d0c46d42 100644
--- a/cw_bitcoin_cash/pubspec.yaml
+++ b/cw_bitcoin_cash/pubspec.yaml
@@ -28,7 +28,7 @@ dependencies:
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
- ref: cake-update-v2
+ ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
dev_dependencies:
flutter_test:
@@ -43,7 +43,7 @@ dependency_overrides:
bitcoin_base:
git:
url: https://github.com/cake-tech/bitcoin_base
- ref: cake-update-v11
+ ref: bda0e2904effa799ec835b4578cc3fc5d31caa78
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
diff --git a/cw_bitcoin_cash/pubspec_overrides.yaml b/cw_bitcoin_cash/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_bitcoin_cash/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_core/build.yaml b/cw_core/build.yaml
new file mode 100644
index 000000000..81a9c96df
--- /dev/null
+++ b/cw_core/build.yaml
@@ -0,0 +1,5 @@
+targets:
+ $default:
+ sources:
+ exclude:
+ - "**/.secrets.g.dart"
diff --git a/cw_core/lib/amount/money.dart b/cw_core/lib/amount/money.dart
index 20857e092..de5483e47 100644
--- a/cw_core/lib/amount/money.dart
+++ b/cw_core/lib/amount/money.dart
@@ -202,10 +202,6 @@ class Money implements Comparable {
@override
int get hashCode => amount.hashCode ^ currency.hashCode;
- // Added this to reduce the hops we do to convert Money to double
- // for fiat conversion and display
- double toDouble() => amount / multiplierOf(currency.decimals);
-
@override
String toString() => formatFixed(amount, currency.decimals);
diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart
index b3f711bd7..4954cad27 100644
--- a/cw_core/lib/crypto_currency.dart
+++ b/cw_core/lib/crypto_currency.dart
@@ -1007,6 +1007,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen
'bitcoin': btc,
'bitcoincash': bch,
'polygon': maticpoly,
+ 'solana': sol,
'nano-gpt': nano,
'secret': scrt,
'stellar': xlm,
diff --git a/cw_core/lib/db/sqlite.dart b/cw_core/lib/db/sqlite.dart
index 43bef5f38..0deffab8e 100644
--- a/cw_core/lib/db/sqlite.dart
+++ b/cw_core/lib/db/sqlite.dart
@@ -63,7 +63,7 @@ Future _initDb({String? pathOverride}) async {
}
}
await db?.close();
- db = await openDatabase(dbFile.path, version: 9,
+ db = await openDatabase(dbFile.path, version: 10,
onUpgrade: (Database db, int oldVersion, int newVersion) async {
printV("migrating: $oldVersion, $newVersion");
if (oldVersion <= 1) {
@@ -147,6 +147,11 @@ CREATE TABLE IF NOT EXISTS BalanceCardStyleSettings (
definition: 'BOOLEAN DEFAULT FALSE',
);
}
+ if (oldVersion <= 9) {
+ await _createErc20TokenTable(db);
+ await _createSplTokenTable(db);
+ await _createTronTokenTable(db);
+ }
}, onCreate: (Database db, int version) async {
await db.execute('''
CREATE TABLE WalletInfo (
@@ -242,6 +247,9 @@ CREATE TABLE BalanceCardStyleSettings (
await _createBridgeTransferTable(db);
await _createNodeTable(db);
await _createTradeTable(db);
+ await _createErc20TokenTable(db);
+ await _createSplTokenTable(db);
+ await _createTronTokenTable(db);
});
}
@@ -370,6 +378,71 @@ ON BridgeTransfer(wallet_id);
''');
}
+Future _createErc20TokenTable(Database db) async {
+ await db.execute("""
+CREATE TABLE IF NOT EXISTS Erc20Token (
+ Erc20TokenId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ walletName TEXT NOT NULL,
+ chainId INTEGER NOT NULL,
+ name TEXT NOT NULL DEFAULT '',
+ symbol TEXT NOT NULL DEFAULT '',
+ contractAddress TEXT NOT NULL,
+ decimal INTEGER NOT NULL DEFAULT 0,
+ enabled INTEGER NOT NULL DEFAULT 1,
+ iconPath TEXT,
+ tag TEXT,
+ isPotentialScam INTEGER NOT NULL DEFAULT 0
+);
+""");
+ await db.execute("""
+CREATE UNIQUE INDEX IF NOT EXISTS idx_erc20token_wallet_chain_contract
+ON Erc20Token (walletName, chainId, contractAddress);
+""");
+}
+
+Future _createSplTokenTable(Database db) async {
+ await db.execute("""
+CREATE TABLE IF NOT EXISTS SPLToken (
+ SPLTokenId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ walletName TEXT NOT NULL,
+ name TEXT NOT NULL DEFAULT '',
+ symbol TEXT NOT NULL DEFAULT '',
+ mintAddress TEXT NOT NULL,
+ decimal INTEGER NOT NULL DEFAULT 0,
+ mint TEXT NOT NULL DEFAULT '',
+ enabled INTEGER NOT NULL DEFAULT 1,
+ iconPath TEXT,
+ tag TEXT,
+ isPotentialScam INTEGER NOT NULL DEFAULT 0
+);
+""");
+ await db.execute("""
+CREATE UNIQUE INDEX IF NOT EXISTS idx_spltoken_wallet_mint
+ON SPLToken (walletName, mintAddress);
+""");
+}
+
+Future _createTronTokenTable(Database db) async {
+ await db.execute("""
+CREATE TABLE IF NOT EXISTS TronToken (
+ TronTokenId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ walletName TEXT NOT NULL,
+ name TEXT NOT NULL DEFAULT '',
+ symbol TEXT NOT NULL DEFAULT '',
+ contractAddress TEXT NOT NULL,
+ decimal INTEGER NOT NULL DEFAULT 0,
+ enabled INTEGER NOT NULL DEFAULT 1,
+ iconPath TEXT,
+ tag TEXT,
+ isPotentialScam INTEGER NOT NULL DEFAULT 0
+);
+""");
+ await db.execute("""
+CREATE UNIQUE INDEX IF NOT EXISTS idx_trontoken_wallet_contract
+ON TronToken (walletName, contractAddress);
+""");
+}
+
Future _createNodeTable(Database db) async {
db.execute("""
CREATE TABLE Node (
diff --git a/cw_core/lib/erc20_token.dart b/cw_core/lib/erc20_token.dart
index d5fde7aa2..a0c14173c 100644
--- a/cw_core/lib/erc20_token.dart
+++ b/cw_core/lib/erc20_token.dart
@@ -1,32 +1,8 @@
-import 'package:cw_core/crypto_currency.dart';
-import 'package:cw_core/hive_type_ids.dart';
-import 'package:hive/hive.dart';
-
-part 'erc20_token.part.dart';
-
-// @HiveType(typeId: Erc20Token.typeId)
-class Erc20Token extends CryptoCurrency with HiveObjectMixin {
- // @HiveField(0)
- final String name;
- // @HiveField(1)
- final String symbol;
- // @HiveField(2)
- final String contractAddress;
- // @HiveField(3)
- final int decimal;
- // @HiveField(4, defaultValue: true)
- bool _enabled;
- // @HiveField(5)
- String? iconPath;
- // @HiveField(6)
- final String? tag;
- // @HiveField(7, defaultValue: false)
- bool isPotentialScam;
-
- bool get enabled => _enabled;
-
- set enabled(bool value) => _enabled = value;
+import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/db/sqlite.dart";
+import "package:sqflite/sqflite.dart";
+class Erc20Token extends CryptoCurrency {
Erc20Token({
required this.name,
required this.symbol,
@@ -36,6 +12,9 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
this.iconPath,
this.tag,
this.isPotentialScam = false,
+ this.id = 0,
+ this.walletName,
+ this.chainId,
}) : _enabled = enabled,
super(
name: symbol.toLowerCase(),
@@ -47,32 +26,161 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
isPotentialScam: isPotentialScam,
);
- Erc20Token.copyWith(Erc20Token other, {String? icon, String? tag, bool? enabled})
- : this.name = other.name,
- this.symbol = other.symbol,
- this.contractAddress = other.contractAddress,
- this.decimal = other.decimal,
- this._enabled = enabled ?? other.enabled,
- this.tag = tag ?? other.tag,
- this.iconPath = icon ?? other.iconPath,
- this.isPotentialScam = other.isPotentialScam,
+ Erc20Token.copyWith(
+ Erc20Token other, {
+ String? icon,
+ super.tag,
+ bool? enabled,
+ String? walletName,
+ int? chainId,
+ }) : name = other.name,
+ symbol = other.symbol,
+ contractAddress = other.contractAddress,
+ decimal = other.decimal,
+ _enabled = enabled ?? other.enabled,
+ tag = tag ?? other.tag,
+ iconPath = icon ?? other.iconPath,
+ isPotentialScam = other.isPotentialScam,
+ id = 0,
+ walletName = walletName ?? other.walletName,
+ chainId = chainId ?? other.chainId,
super(
name: other.name,
title: other.symbol.toUpperCase(),
fullName: other.name,
- tag: tag,
iconPath: icon,
decimals: other.decimal,
isPotentialScam: other.isPotentialScam,
);
- static const typeId = ERC20_TOKEN_TYPE_ID;
- static const boxName = 'Erc20Tokens';
- static const ethereumBoxName = 'EthereumErc20Tokens';
- static const polygonBoxName = 'PolygonErc20Tokens';
- static const baseBoxName = 'BaseErc20Tokens';
- static const arbitrumBoxName = 'ArbitrumErc20Tokens';
- static const bscBoxName = 'BscErc20Tokens';
+ Erc20Token.fromMap(Map map)
+ : this(
+ name: map["name"] as String? ?? "",
+ symbol: map["symbol"] as String? ?? "",
+ contractAddress: map["contractAddress"] as String? ?? "",
+ decimal: (map["decimal"] ?? 0) as int,
+ enabled: _getBoolFromDB(map["enabled"], defaultValue: true),
+ iconPath: map["iconPath"] as String?,
+ tag: map["tag"] as String?,
+ isPotentialScam: _getBoolFromDB(map["isPotentialScam"]),
+ id: (map[selfIdColumn] ?? 0) as int,
+ walletName: map["walletName"] as String?,
+ chainId: map["chainId"] as int?,
+ );
+
+ @override
+ final String name;
+
+ @override
+ final String symbol;
+
+ @override
+ String? iconPath;
+
+ @override
+ final String? tag;
+
+ @override
+ bool isPotentialScam;
+
+ @override
+ bool get enabled => _enabled;
+
+ @override
+ set enabled(bool value) => _enabled = value;
+
+ int id;
+ int? chainId;
+ bool _enabled;
+ final int decimal;
+ String? walletName;
+ final String contractAddress;
+
+ static bool _getBoolFromDB(value, {bool? defaultValue}) {
+ if (value is bool) {
+ return value;
+ } else if (value is int) {
+ return value == 1;
+ } else {
+ return defaultValue ?? false;
+ }
+ }
+
+ Map toMap() => {
+ selfIdColumn: id,
+ "walletName": walletName,
+ "chainId": chainId,
+ "name": name,
+ "symbol": symbol,
+ "contractAddress": contractAddress.toLowerCase(),
+ "decimal": decimal,
+ "enabled": _enabled ? 1 : 0,
+ "iconPath": iconPath,
+ "tag": tag,
+ "isPotentialScam": isPotentialScam ? 1 : 0,
+ };
+
+ static String get tableName => "Erc20Token";
+ static String get selfIdColumn => "${tableName}Id";
+
+ Future save() async {
+ if (walletName == null || chainId == null) {
+ throw StateError("Erc20Token.save() requires walletName and chainId to be set");
+ }
+
+ final json = toMap();
+ if (json[selfIdColumn] == 0) {
+ json[selfIdColumn] = null;
+ }
+ id = await db!.insert(tableName, json, conflictAlgorithm: ConflictAlgorithm.replace);
+ return id;
+ }
+
+ static Future> selectList(
+ String where,
+ List whereArgs, {
+ String? orderBy,
+ }) async {
+ orderBy ??= selfIdColumn;
+ final list = await db!.query(
+ tableName,
+ where: where.isNotEmpty ? where : "1 = 1",
+ whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
+ orderBy: orderBy,
+ );
+ return List.generate(list.length, (index) => Erc20Token.fromMap(list[index]));
+ }
+
+ static Future> getAllForWallet(String walletName, int chainId) =>
+ selectList("walletName = ? AND chainId = ?", [walletName, chainId]);
+
+ static Future getByContract(
+ String walletName,
+ int chainId,
+ String contractAddress,
+ ) async {
+ final list = await selectList(
+ "walletName = ? AND chainId = ? AND contractAddress = ?",
+ [walletName, chainId, contractAddress.toLowerCase()],
+ );
+ return list.isEmpty ? null : list.first;
+ }
+
+ static Future deleteForWallet(String walletName, int chainId, String contractAddress) =>
+ db!.delete(
+ tableName,
+ where: "walletName = ? AND chainId = ? AND contractAddress = ?",
+ whereArgs: [walletName, chainId, contractAddress.toLowerCase()],
+ );
+
+ static Future deleteAllForWallet(String walletName) =>
+ db!.delete(tableName, where: "walletName = ?", whereArgs: [walletName]);
+
+ static Future renameWallet(String oldName, String newName) async {
+ await db!.delete(tableName, where: "walletName = ?", whereArgs: [newName]);
+ await db!
+ .update(tableName, {"walletName": newName}, where: "walletName = ?", whereArgs: [oldName]);
+ }
@override
bool operator ==(Object other) => other is Erc20Token && other.contractAddress == contractAddress;
diff --git a/cw_core/lib/erc20_token_legacy.dart b/cw_core/lib/erc20_token_legacy.dart
new file mode 100644
index 000000000..c965899cd
--- /dev/null
+++ b/cw_core/lib/erc20_token_legacy.dart
@@ -0,0 +1,213 @@
+import "package:cw_core/cake_hive.dart";
+import "package:cw_core/db/sqlite.dart";
+import "package:cw_core/erc20_token.dart" as erc20_new;
+import "package:cw_core/hive_type_ids.dart";
+import "package:cw_core/utils/print_verbose.dart";
+import "package:cw_core/wallet_info.dart";
+import "package:cw_core/wallet_type.dart";
+import "package:hive/hive.dart";
+import "package:sqflite/sqflite.dart";
+
+part "erc20_token_legacy.part.dart";
+
+Future performErc20TokenHiveMigration() async {
+ try {
+ if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
+ CakeHive.registerAdapter(Erc20TokenAdapter());
+ }
+
+ final wallets = await WalletInfo.getAll();
+ await Erc20Token.migrateAllToSqlite(wallets);
+ } catch (e) {
+ printV("Error performing Erc20Token Hive migration: $e, continuing anyway");
+ }
+}
+
+// @HiveType(typeId: Erc20Token.typeId)
+class Erc20Token extends HiveObject {
+ Erc20Token({
+ required this.name,
+ required this.symbol,
+ required this.contractAddress,
+ required this.decimal,
+ bool enabled = true,
+ this.iconPath,
+ this.tag,
+ this.isPotentialScam = false,
+ }) : _enabled = enabled;
+ // @HiveField(0)
+ final String name;
+ // @HiveField(1)
+ final String symbol;
+ // @HiveField(2)
+ final String contractAddress;
+ // @HiveField(3)
+ final int decimal;
+ // @HiveField(4, defaultValue: true)
+ bool _enabled;
+ // @HiveField(5)
+ String? iconPath;
+ // @HiveField(6)
+ final String? tag;
+ // @HiveField(7, defaultValue: false)
+ bool isPotentialScam;
+
+ bool get enabled => _enabled;
+
+ set enabled(bool value) => _enabled = value;
+
+ static const typeId = ERC20_TOKEN_TYPE_ID;
+ static const boxName = "Erc20Tokens";
+ static const ethereumBoxName = "EthereumErc20Tokens";
+ static const polygonBoxName = "PolygonErc20Tokens";
+ static const baseBoxName = "BaseErc20Tokens";
+ static const arbitrumBoxName = "ArbitrumErc20Tokens";
+ static const bscBoxName = "BscErc20Tokens";
+
+ static const chainIdToBoxSuffix = {
+ 1: ethereumBoxName,
+ 137: polygonBoxName,
+ 8453: baseBoxName,
+ 42161: arbitrumBoxName,
+ 56: bscBoxName,
+ };
+
+ static const evmWalletTypes = [
+ WalletType.ethereum,
+ WalletType.polygon,
+ WalletType.base,
+ WalletType.arbitrum,
+ WalletType.bsc,
+ ];
+
+ static Future migrateAllToSqlite(List wallets) async {
+ await _migrateLegacyGlobalBox(wallets);
+
+ final sanitizedToRawNames = >{};
+ for (final wallet in wallets) {
+ if (!evmWalletTypes.contains(wallet.type)) {
+ continue;
+ }
+
+ sanitizedToRawNames
+ .putIfAbsent(wallet.name.replaceAll(" ", "_"), () => {})
+ .add(wallet.name);
+ }
+
+ for (final entry in sanitizedToRawNames.entries) {
+ for (final chainEntry in chainIdToBoxSuffix.entries) {
+ final tokenBoxName = "${entry.key}_${chainEntry.value}";
+ try {
+ if (!await CakeHive.boxExists(tokenBoxName)) {
+ continue;
+ }
+
+ final box = await CakeHive.openBox(tokenBoxName);
+
+ for (final group in _mergeByLowercaseContract(box)) {
+ for (final rawName in entry.value) {
+ await group.token.migrateToSqlite(walletName: rawName, chainId: chainEntry.key);
+ }
+ await box.deleteAll(group.sourceKeys);
+ }
+
+ await box.deleteFromDisk();
+ } catch (e) {
+ printV("Error migrating erc20 token box $tokenBoxName: $e, continuing anyway");
+ }
+ }
+ }
+ }
+
+ static Future _migrateLegacyGlobalBox(List wallets) async {
+ try {
+ if (!await CakeHive.boxExists(boxName)) {
+ return;
+ }
+
+ if (!wallets.any((wallet) => wallet.type == WalletType.ethereum)) {
+ return;
+ }
+
+ final box = await CakeHive.openBox(boxName);
+ final ethereumWallets =
+ wallets.where((wallet) => wallet.type == WalletType.ethereum).toList();
+
+ for (final group in _mergeByLowercaseContract(box)) {
+ for (final wallet in ethereumWallets) {
+ await group.token.migrateToSqlite(walletName: wallet.name, chainId: 1);
+ }
+ await box.deleteAll(group.sourceKeys);
+ }
+
+ await box.deleteFromDisk();
+ } catch (e) {
+ printV("Error migrating legacy global erc20 token box: $e, continuing anyway");
+ }
+ }
+
+ static List<_MergedTokenGroup> _mergeByLowercaseContract(Box box) {
+ final groups = {};
+
+ for (final key in box.keys) {
+ final token = box.get(key);
+ if (token == null) {
+ continue;
+ }
+
+ final lowerKey = token.contractAddress.toLowerCase();
+ final existing = groups[lowerKey];
+
+ if (existing == null) {
+ groups[lowerKey] = _MergedTokenGroup(token: token, sourceKeys: [key]);
+ continue;
+ }
+
+ groups[lowerKey] = _MergedTokenGroup(
+ token: Erc20Token(
+ name: token.name,
+ symbol: token.symbol,
+ contractAddress: lowerKey,
+ decimal: token.decimal,
+ enabled: token.enabled || existing.token.enabled,
+ iconPath:
+ (token.iconPath?.isNotEmpty ?? false) ? token.iconPath : existing.token.iconPath,
+ tag: token.tag ?? existing.token.tag,
+ isPotentialScam: token.isPotentialScam || existing.token.isPotentialScam,
+ ),
+ sourceKeys: [...existing.sourceKeys, key],
+ );
+ }
+
+ return groups.values.toList();
+ }
+
+ Future migrateToSqlite({required String walletName, required int chainId}) async {
+ final row = erc20_new.Erc20Token(
+ name: name,
+ symbol: symbol,
+ contractAddress: contractAddress,
+ decimal: decimal,
+ enabled: _enabled,
+ iconPath: iconPath,
+ tag: tag,
+ isPotentialScam: isPotentialScam,
+ walletName: walletName,
+ chainId: chainId,
+ ).toMap();
+ row[erc20_new.Erc20Token.selfIdColumn] = null;
+
+ await db!.insert(
+ erc20_new.Erc20Token.tableName,
+ row,
+ conflictAlgorithm: ConflictAlgorithm.replace,
+ );
+ }
+}
+
+class _MergedTokenGroup {
+ _MergedTokenGroup({required this.token, required this.sourceKeys});
+
+ final Erc20Token token;
+ final List sourceKeys;
+}
diff --git a/cw_core/lib/erc20_token.part.dart b/cw_core/lib/erc20_token_legacy.part.dart
similarity index 97%
rename from cw_core/lib/erc20_token.part.dart
rename to cw_core/lib/erc20_token_legacy.part.dart
index e19b4b522..9614c0c1a 100644
--- a/cw_core/lib/erc20_token.part.dart
+++ b/cw_core/lib/erc20_token_legacy.part.dart
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
-part of 'erc20_token.dart';
+part of "erc20_token_legacy.dart";
// **************************************************************************
// TypeAdapterGenerator
diff --git a/cw_core/lib/exceptions.dart b/cw_core/lib/exceptions.dart
index 8460569c5..cc0729ee5 100644
--- a/cw_core/lib/exceptions.dart
+++ b/cw_core/lib/exceptions.dart
@@ -70,3 +70,12 @@ class WalletDeprecationException implements Exception {
WalletDeprecationException({required this.seed, required this.curr});
}
+
+class WalletSwitchException implements Exception {
+ WalletSwitchException(this.message);
+
+ final String message;
+
+ @override
+ String toString() => message;
+}
diff --git a/cw_core/lib/format_fixed.dart b/cw_core/lib/format_fixed.dart
index aa0162812..4e02c48d5 100644
--- a/cw_core/lib/format_fixed.dart
+++ b/cw_core/lib/format_fixed.dart
@@ -4,31 +4,44 @@ String formatFixed(BigInt value, int? decimals, {int? fractionalDigits, bool tri
decimals ??= 0;
fractionalDigits ??= decimals;
- final multiplier = multiplierOf(decimals);
- var negative = value.isNegative;
- if (negative) value = -value;
+ final multiplier = getMultiplier(decimals);
+ // Make sure wei is a big number (convert as necessary)
+ final negative = value.isNegative;
+ if (negative) {
+ value = -value;
+ }
- var fraction = (value % multiplier).toString().padLeft(decimals, "0");
+ var fraction =
+ value.modPow(BigInt.one, BigInt.parse(multiplier)).toString().padLeft(decimals, "0");
- if (fractionalDigits < 0) fractionalDigits = 0;
- if (fractionalDigits > decimals) fractionalDigits = decimals;
+ if (fractionalDigits < 0) {
+ fractionalDigits = 0;
+ }
+ if (fractionalDigits > decimals) {
+ fractionalDigits = decimals;
+ }
fraction = fraction.substring(0, fractionalDigits);
if (trimZeros) {
fraction = removeTrailing("0", fraction);
}
- final whole = value ~/ multiplier;
+ final whole = value ~/ BigInt.parse(multiplier);
final valString = fraction.isEmpty ? "$whole" : "$whole.$fraction";
- if (negative) return "-$valString";
+ if (negative) {
+ return "-$valString";
+ }
return valString;
}
String removeTrailing(String pattern, String from) {
- if (pattern.isEmpty) return from;
+ if (pattern.isEmpty) {
+ return from;
+ }
+
var i = from.length;
while (i > 0 && from.startsWith(pattern, i - pattern.length)) {
i -= pattern.length;
diff --git a/cw_core/lib/parse_fixed.dart b/cw_core/lib/parse_fixed.dart
index dbbc24f7c..a5a6d7b82 100644
--- a/cw_core/lib/parse_fixed.dart
+++ b/cw_core/lib/parse_fixed.dart
@@ -37,40 +37,44 @@ BigInt parseFixed(String value, int decimals) {
}
final negative = value.startsWith("-");
- if (negative) value = value.substring(1);
+ if (negative) {
+ value = value.substring(1);
+ }
- if (value == ".") throw FormatException("missing value, value, $value");
+ if (value == ".") {
+ throw FormatException("missing value, value, $value");
+ }
- if (value.startsWith(".")) value = "0$value";
+ if (value.startsWith(".")) {
+ value = "0$value";
+ }
final comps = value.split(".");
if (comps.length > 2) {
throw FormatException("too many decimal points, value, $value");
}
- var whole = comps.isNotEmpty ? comps[0] : "0";
- var fraction = (comps.length == 2 ? comps[1] : "0").padRight(decimals, "0");
+ final whole = comps.isNotEmpty ? comps[0] : "0";
+ final fraction = (comps.length == 2 ? comps[1] : "0").padRight(decimals, "0");
if (fraction.length > multiplier.length - 1) {
throw FormatException(
- "fractional component(${fraction.length}) exceeds decimals(${decimals}), underflow, parseFixed");
+ "fractional component(${fraction.length}) exceeds decimals(${decimals}), underflow, parseFixed",
+ );
}
final wholeValue = BigInt.parse(whole);
final fractionValue = BigInt.parse(fraction);
- final multiplierValue = multiplierOf(decimals);
+ final multiplierValue = BigInt.parse(multiplier);
var wei = (wholeValue * multiplierValue) + fractionValue;
- if (negative) wei *= BigInt.from(-1);
+ if (negative) {
+ wei *= BigInt.from(-1);
+ }
return wei;
}
// Returns a string "1" followed by decimal "0"s
String getMultiplier(int decimals) => "1".padRight(decimals + 1, "0");
-
-final _multipliers = {};
-
-// this is more direct and faster than having it as string then parsing everytime to get the number
-BigInt multiplierOf(int decimals) => _multipliers[decimals] ??= BigInt.from(10).pow(decimals);
diff --git a/cw_core/lib/payment_uris.dart b/cw_core/lib/payment_uris.dart
index 4ca12bdc3..effeb13a8 100644
--- a/cw_core/lib/payment_uris.dart
+++ b/cw_core/lib/payment_uris.dart
@@ -283,8 +283,8 @@ class ERC681URI extends PaymentURI {
} else {
final valueParam = uri.queryParameters["value"];
if (valueParam != null) {
- final normalized = _normalizeToIntegerWei(valueParam);
- formatedAmount = formatFixed(BigInt.parse(normalized), 18);
+ final normalized = BigInt.tryParse(_normalizeToIntegerWei(valueParam));
+ formatedAmount = normalized != null ? formatFixed(normalized, 18) : "";
} else {
formatedAmount = uri.queryParameters["amount"] ?? "";
}
@@ -313,9 +313,7 @@ class ERC681URI extends PaymentURI {
final targetAddress = contractAddress ?? address;
uri += targetAddress;
- if (chainId != 1) {
- uri += "@$chainId";
- }
+ uri += "@$chainId";
if (contractAddress != null) {
uri += "/transfer";
@@ -364,14 +362,18 @@ class ERC681URI extends PaymentURI {
}
}
- static int _getChainID(String path) => int.parse(
+ static int _getChainID(String path) =>
+ int.tryParse(
RegExp(r"@\d*").firstMatch(path)?.group(0)?.replaceAll("@", "") ?? "1",
- );
+ ) ??
+ 1;
static (bool, String) _getTargetAddress(String path) {
- final targetAddress =
- RegExp(r"^(0x)?[0-9a-f]{40}", caseSensitive: false).firstMatch(path)!.group(0)!;
- return (path.contains("/"), targetAddress);
+ // I saw in the schema (thanks Konsti) that EIP-681 allows an optional "pay-" prefix before the target address, so adding a check for it here
+ final cleaned = path.startsWith("pay-") ? path.substring(4) : path;
+ final match = RegExp(r"^(0x)?[0-9a-f]{40}", caseSensitive: false).firstMatch(cleaned);
+ final targetAddress = match?.group(0) ?? cleaned.split("@").first.split("/").first;
+ return (cleaned.contains("/"), targetAddress);
}
/// Normalize an input amount into an integer wei string.
diff --git a/cw_core/lib/spl_token.dart b/cw_core/lib/spl_token.dart
index 500435319..5ac9330fb 100644
--- a/cw_core/lib/spl_token.dart
+++ b/cw_core/lib/spl_token.dart
@@ -1,41 +1,8 @@
-import 'package:cw_core/crypto_currency.dart';
-import 'package:cw_core/hive_type_ids.dart';
-import 'package:hive/hive.dart';
+import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/db/sqlite.dart";
+import "package:sqflite/sqflite.dart";
-part 'spl_token.part.dart';
-
-// @HiveType(typeId: SPLToken.typeId)
-class SPLToken extends CryptoCurrency with HiveObjectMixin {
- @override
- // @HiveField(0)
- final String name;
-
- // @HiveField(1)
- final String symbol;
-
- // @HiveField(2)
- final String mintAddress;
-
- // @HiveField(3)
- final int decimal;
-
- // @HiveField(4, defaultValue: true)
- bool _enabled;
-
- // @HiveField(5)
- final String mint;
-
- @override
- // @HiveField(6)
- final String? iconPath;
-
- @override
- // @HiveField(7)
- final String? tag;
-
- @override
- // @HiveField(8, defaultValue: false)
- bool isPotentialScam;
+class SPLToken extends CryptoCurrency {
SPLToken({
required this.name,
@@ -44,10 +11,12 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
required this.decimal,
required this.mint,
this.iconPath,
- this.tag = 'SOL',
+ this.tag = "SOL",
bool enabled = true,
this.isPotentialScam = false,
- Set groups = const {},
+ super.groups,
+ this.id = 0,
+ this.walletName,
}) : _enabled = enabled,
super(
name: mint.toLowerCase(),
@@ -57,7 +26,6 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
iconPath: iconPath,
decimals: decimal,
isPotentialScam: isPotentialScam,
- groups: groups,
);
factory SPLToken.fromMetadata({
@@ -67,8 +35,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
required String mintAddress,
String? iconPath,
bool isPotentialScam = false,
- }) {
- return SPLToken(
+ }) => SPLToken(
name: name,
symbol: symbol,
mintAddress: mintAddress,
@@ -77,15 +44,8 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
iconPath: iconPath,
isPotentialScam: isPotentialScam,
);
- }
- @override
- bool get enabled => _enabled;
-
- @override
- set enabled(bool value) => _enabled = value;
-
- SPLToken.copyWith(SPLToken other, {String? icon, String? tag, bool? enabled})
+ SPLToken.copyWith(SPLToken other, {String? icon, String? tag, bool? enabled, String? walletName})
: name = other.name,
symbol = other.symbol,
mintAddress = other.mintAddress,
@@ -95,6 +55,8 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
tag = tag ?? other.tag,
iconPath = icon ?? other.iconPath,
isPotentialScam = other.isPotentialScam,
+ id = 0,
+ walletName = walletName ?? other.walletName,
super(
title: other.symbol.toUpperCase(),
name: other.symbol.toLowerCase(),
@@ -106,8 +68,124 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
groups: other.groups,
);
- static const typeId = SPL_TOKEN_TYPE_ID;
- static const boxName = 'SPLTokens';
+ SPLToken.fromMap(Map map)
+ : this(
+ name: map["name"] as String? ?? "",
+ symbol: map["symbol"] as String? ?? "",
+ mintAddress: map["mintAddress"] as String? ?? "",
+ decimal: (map["decimal"] ?? 0) as int,
+ mint: map["mint"] as String? ?? "",
+ enabled: _getBoolFromDB(map["enabled"], defaultValue: true),
+ iconPath: map["iconPath"] as String?,
+ tag: map["tag"] as String?,
+ isPotentialScam: _getBoolFromDB(map["isPotentialScam"]),
+ id: (map[selfIdColumn] ?? 0) as int,
+ walletName: map["walletName"] as String?,
+ );
+ @override
+ final String name;
+
+ @override
+ final String symbol;
+
+ final String mintAddress;
+
+ final int decimal;
+
+ bool _enabled;
+
+ final String mint;
+
+ @override
+ final String? iconPath;
+
+ @override
+ final String? tag;
+
+ @override
+ bool isPotentialScam;
+
+ int id;
+ String? walletName;
+
+ @override
+ bool get enabled => _enabled;
+
+ @override
+ set enabled(bool value) => _enabled = value;
+
+ static bool _getBoolFromDB(value, {bool? defaultValue}) {
+ if (value is bool) {
+ return value;
+ } else if (value is int) {
+ return value == 1;
+ } else {
+ return defaultValue ?? false;
+ }
+ }
+
+ Map toMap() => {
+ selfIdColumn: id,
+ "walletName": walletName,
+ "name": name,
+ "symbol": symbol,
+ "mintAddress": mintAddress,
+ "decimal": decimal,
+ "mint": mint,
+ "enabled": _enabled ? 1 : 0,
+ "iconPath": iconPath,
+ "tag": tag,
+ "isPotentialScam": isPotentialScam ? 1 : 0,
+ };
+
+ static String get tableName => "SPLToken";
+ static String get selfIdColumn => "${tableName}Id";
+
+ Future save() async {
+ if (walletName == null) {
+ throw StateError("SPLToken.save() requires walletName to be set");
+ }
+
+ final json = toMap();
+ if (json[selfIdColumn] == 0) {
+ json[selfIdColumn] = null;
+ }
+ id = await db!.insert(tableName, json, conflictAlgorithm: ConflictAlgorithm.replace);
+ return id;
+ }
+
+ static Future> selectList(String where, List whereArgs,
+ {String? orderBy}) async {
+ orderBy ??= selfIdColumn;
+ final list = await db!.query(
+ tableName,
+ where: where.isNotEmpty ? where : "1 = 1",
+ whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
+ orderBy: orderBy,
+ );
+ return List.generate(list.length, (index) => SPLToken.fromMap(list[index]));
+ }
+
+ static Future> getAllForWallet(String walletName) async => selectList("walletName = ?", [walletName]);
+
+ static Future getByMint(String walletName, String mintAddress) async {
+ final list = await selectList("walletName = ? AND mintAddress = ?", [walletName, mintAddress]);
+ return list.isEmpty ? null : list.first;
+ }
+
+ static Future deleteForWallet(String walletName, String mintAddress) => db!.delete(
+ tableName,
+ where: "walletName = ? AND mintAddress = ?",
+ whereArgs: [walletName, mintAddress],
+ );
+
+ static Future deleteAllForWallet(String walletName) => db!.delete(tableName, where: "walletName = ?", whereArgs: [walletName]);
+
+ static Future renameWallet(String oldName, String newName) async {
+ await db!.delete(tableName, where: "walletName = ?", whereArgs: [newName]);
+ await db!
+ .update(tableName, {"walletName": newName}, where: "walletName = ?", whereArgs: [oldName]);
+ }
@override
bool operator ==(other) =>
diff --git a/cw_core/lib/spl_token_legacy.dart b/cw_core/lib/spl_token_legacy.dart
new file mode 100644
index 000000000..aea751915
--- /dev/null
+++ b/cw_core/lib/spl_token_legacy.dart
@@ -0,0 +1,134 @@
+import "package:cw_core/cake_hive.dart";
+import "package:cw_core/db/sqlite.dart";
+import "package:cw_core/hive_type_ids.dart";
+import "package:cw_core/spl_token.dart" as spl_new;
+import "package:cw_core/utils/print_verbose.dart";
+import "package:cw_core/wallet_info.dart";
+import "package:cw_core/wallet_type.dart";
+import "package:hive/hive.dart";
+import "package:sqflite/sqflite.dart";
+
+part "spl_token_legacy.part.dart";
+
+Future performSplTokenHiveMigration() async {
+ try {
+ if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
+ CakeHive.registerAdapter(SPLTokenAdapter());
+ }
+
+ final wallets = await WalletInfo.getAll();
+ await SPLToken.migrateAllToSqlite(wallets);
+ } catch (e) {
+ printV("Error performing SPLToken Hive migration: $e, continuing anyway");
+ }
+}
+
+// @HiveType(typeId: SPLToken.typeId)
+class SPLToken extends HiveObject {
+ SPLToken({
+ required this.name,
+ required this.symbol,
+ required this.mintAddress,
+ required this.decimal,
+ required this.mint,
+ this.iconPath,
+ this.tag = "SOL",
+ bool enabled = true,
+ this.isPotentialScam = false,
+ }) : _enabled = enabled;
+ // @HiveField(0)
+ final String name;
+
+ // @HiveField(1)
+ final String symbol;
+
+ // @HiveField(2)
+ final String mintAddress;
+
+ // @HiveField(3)
+ final int decimal;
+
+ // @HiveField(4, defaultValue: true)
+ bool _enabled;
+
+ // @HiveField(5)
+ final String mint;
+
+ // @HiveField(6)
+ final String? iconPath;
+
+ // @HiveField(7)
+ final String? tag;
+
+ // @HiveField(8, defaultValue: false)
+ bool isPotentialScam;
+
+ bool get enabled => _enabled;
+
+ set enabled(bool value) => _enabled = value;
+
+ static const typeId = SPL_TOKEN_TYPE_ID;
+ static const boxName = "SPLTokens";
+
+ static Future migrateAllToSqlite(List wallets) async {
+ final sanitizedToRawNames = >{};
+ for (final wallet in wallets) {
+ if (wallet.type != WalletType.solana) {
+ continue;
+ }
+
+ sanitizedToRawNames
+ .putIfAbsent(wallet.name.replaceAll(" ", "_"), () => {})
+ .add(wallet.name);
+ }
+
+ for (final entry in sanitizedToRawNames.entries) {
+ final tokenBoxName = "${entry.key}_$boxName";
+ try {
+ if (!await CakeHive.boxExists(tokenBoxName)) {
+ continue;
+ }
+
+ final box = await CakeHive.openBox(tokenBoxName);
+
+ for (final key in box.keys.toList()) {
+ final token = box.get(key);
+ if (token == null) {
+ continue;
+ }
+
+ for (final rawName in entry.value) {
+ await token.migrateToSqlite(walletName: rawName);
+ }
+ await box.delete(key);
+ }
+
+ await box.deleteFromDisk();
+ } catch (e) {
+ printV("Error migrating spl token box $tokenBoxName: $e, continuing anyway");
+ }
+ }
+ }
+
+ Future migrateToSqlite({required String walletName}) async {
+ final row = spl_new.SPLToken(
+ name: name,
+ symbol: symbol,
+ mintAddress: mintAddress,
+ decimal: decimal,
+ mint: mint,
+ enabled: _enabled,
+ iconPath: iconPath,
+ tag: tag,
+ isPotentialScam: isPotentialScam,
+ walletName: walletName,
+ ).toMap();
+ row[spl_new.SPLToken.selfIdColumn] = null;
+
+ await db!.insert(
+ spl_new.SPLToken.tableName,
+ row,
+ conflictAlgorithm: ConflictAlgorithm.replace,
+ );
+ }
+}
diff --git a/cw_core/lib/spl_token.part.dart b/cw_core/lib/spl_token_legacy.part.dart
similarity index 98%
rename from cw_core/lib/spl_token.part.dart
rename to cw_core/lib/spl_token_legacy.part.dart
index cede960c9..ca228a65e 100644
--- a/cw_core/lib/spl_token.part.dart
+++ b/cw_core/lib/spl_token_legacy.part.dart
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
-part of 'spl_token.dart';
+part of "spl_token_legacy.dart";
// **************************************************************************
// TypeAdapterGenerator
diff --git a/cw_core/lib/tron_token.dart b/cw_core/lib/tron_token.dart
index c4b27ed21..2e1b7ed1d 100644
--- a/cw_core/lib/tron_token.dart
+++ b/cw_core/lib/tron_token.dart
@@ -1,41 +1,8 @@
-// ignore_for_file: annotate_overrides, overridden_fields
-
-import 'package:cw_core/crypto_currency.dart';
-import 'package:cw_core/hive_type_ids.dart';
-import 'package:hive/hive.dart';
-
-part 'tron_token.part.dart';
-
-// @HiveType(typeId: TronToken.typeId)
-class TronToken extends CryptoCurrency with HiveObjectMixin {
- // @HiveField(0)
- final String name;
-
- // @HiveField(1)
- final String symbol;
-
- // @HiveField(2)
- final String contractAddress;
-
- // @HiveField(3)
- final int decimal;
-
- // @HiveField(4, defaultValue: true)
- bool _enabled;
-
- // @HiveField(5)
- final String? iconPath;
-
- // @HiveField(6)
- final String? tag;
-
- // @HiveField(7, defaultValue: false)
- final bool isPotentialScam;
-
- bool get enabled => _enabled;
-
- set enabled(bool value) => _enabled = value;
+import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/db/sqlite.dart";
+import "package:sqflite/sqflite.dart";
+class TronToken extends CryptoCurrency {
TronToken({
required this.name,
required this.symbol,
@@ -43,8 +10,10 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
required this.decimal,
bool enabled = true,
this.iconPath,
- this.tag = 'TRX',
+ this.tag = "TRX",
this.isPotentialScam = false,
+ this.id = 0,
+ this.walletName,
}) : _enabled = enabled,
super(
name: symbol.toLowerCase(),
@@ -55,9 +24,27 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
decimals: decimal,
isPotentialScam: isPotentialScam,
);
+ TronToken.fromMap(Map map)
+ : this(
+ name: map["name"] as String? ?? "",
+ symbol: map["symbol"] as String? ?? "",
+ contractAddress: map["contractAddress"] as String? ?? "",
+ decimal: (map["decimal"] ?? 0) as int,
+ enabled: _getBoolFromDB(map["enabled"], defaultValue: true),
+ iconPath: map["iconPath"] as String?,
+ tag: map["tag"] as String?,
+ isPotentialScam: _getBoolFromDB(map["isPotentialScam"]),
+ id: (map[selfIdColumn] ?? 0) as int,
+ walletName: map["walletName"] as String?,
+ );
- TronToken.copyWith(TronToken other, {String? icon, String? tag, bool? enabled})
- : name = other.name,
+ TronToken.copyWith(
+ TronToken other, {
+ String? icon,
+ String? tag,
+ bool? enabled,
+ String? walletName,
+ }) : name = other.name,
symbol = other.symbol,
contractAddress = other.contractAddress,
decimal = other.decimal,
@@ -65,6 +52,8 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
tag = tag ?? other.tag,
iconPath = icon ?? other.iconPath,
isPotentialScam = other.isPotentialScam,
+ id = 0,
+ walletName = walletName ?? other.walletName,
super(
name: other.name,
title: other.symbol.toUpperCase(),
@@ -74,9 +63,110 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
decimals: other.decimal,
isPotentialScam: other.isPotentialScam,
);
+ @override
+ final String name;
- static const typeId = TRON_TOKEN_TYPE_ID;
- static const boxName = 'TronTokens';
+ @override
+ final String symbol;
+
+ @override
+ final String? iconPath;
+
+ @override
+ final String? tag;
+
+ @override
+ final bool isPotentialScam;
+
+ @override
+ bool get enabled => _enabled;
+
+ @override
+ set enabled(bool value) => _enabled = value;
+
+ int id;
+ bool _enabled;
+ final int decimal;
+ String? walletName;
+ final String contractAddress;
+
+ static bool _getBoolFromDB(value, {bool? defaultValue}) {
+ if (value is bool) {
+ return value;
+ } else if (value is int) {
+ return value == 1;
+ } else {
+ return defaultValue ?? false;
+ }
+ }
+
+ Map toMap() => {
+ selfIdColumn: id,
+ "walletName": walletName,
+ "name": name,
+ "symbol": symbol,
+ "contractAddress": contractAddress,
+ "decimal": decimal,
+ "enabled": _enabled ? 1 : 0,
+ "iconPath": iconPath,
+ "tag": tag,
+ "isPotentialScam": isPotentialScam ? 1 : 0,
+ };
+
+ static String get tableName => "TronToken";
+ static String get selfIdColumn => "${tableName}Id";
+
+ Future save() async {
+ if (walletName == null) {
+ throw StateError("TronToken.save() requires walletName to be set");
+ }
+
+ final json = toMap();
+ if (json[selfIdColumn] == 0) {
+ json[selfIdColumn] = null;
+ }
+ id = await db!.insert(tableName, json, conflictAlgorithm: ConflictAlgorithm.replace);
+ return id;
+ }
+
+ static Future> selectList(
+ String where,
+ List whereArgs, {
+ String? orderBy,
+ }) async {
+ orderBy ??= selfIdColumn;
+ final list = await db!.query(
+ tableName,
+ where: where.isNotEmpty ? where : "1 = 1",
+ whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
+ orderBy: orderBy,
+ );
+ return List.generate(list.length, (index) => TronToken.fromMap(list[index]));
+ }
+
+ static Future> getAllForWallet(String walletName) =>
+ selectList("walletName = ?", [walletName]);
+
+ static Future getByContract(String walletName, String contractAddress) async {
+ final list =
+ await selectList("walletName = ? AND contractAddress = ?", [walletName, contractAddress]);
+ return list.isEmpty ? null : list.first;
+ }
+
+ static Future deleteForWallet(String walletName, String contractAddress) => db!.delete(
+ tableName,
+ where: "walletName = ? AND contractAddress = ?",
+ whereArgs: [walletName, contractAddress],
+ );
+
+ static Future deleteAllForWallet(String walletName) =>
+ db!.delete(tableName, where: "walletName = ?", whereArgs: [walletName]);
+
+ static Future renameWallet(String oldName, String newName) async {
+ await db!.delete(tableName, where: "walletName = ?", whereArgs: [newName]);
+ await db!
+ .update(tableName, {"walletName": newName}, where: "walletName = ?", whereArgs: [oldName]);
+ }
@override
bool operator ==(other) =>
diff --git a/cw_core/lib/tron_token_legacy.dart b/cw_core/lib/tron_token_legacy.dart
new file mode 100644
index 000000000..c7fd8c907
--- /dev/null
+++ b/cw_core/lib/tron_token_legacy.dart
@@ -0,0 +1,129 @@
+import "package:cw_core/cake_hive.dart";
+import "package:cw_core/db/sqlite.dart";
+import "package:cw_core/hive_type_ids.dart";
+import "package:cw_core/tron_token.dart" as tron_new;
+import "package:cw_core/utils/print_verbose.dart";
+import "package:cw_core/wallet_info.dart";
+import "package:cw_core/wallet_type.dart";
+import "package:hive/hive.dart";
+import "package:sqflite/sqflite.dart";
+
+part "tron_token_legacy.part.dart";
+
+Future performTronTokenHiveMigration() async {
+ try {
+ if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
+ CakeHive.registerAdapter(TronTokenAdapter());
+ }
+
+ final wallets = await WalletInfo.getAll();
+ await TronToken.migrateAllToSqlite(wallets);
+ } catch (e) {
+ printV("Error performing TronToken Hive migration: $e, continuing anyway");
+ }
+}
+
+// @HiveType(typeId: TronToken.typeId)
+class TronToken extends HiveObject {
+ TronToken({
+ required this.name,
+ required this.symbol,
+ required this.contractAddress,
+ required this.decimal,
+ bool enabled = true,
+ this.iconPath,
+ this.tag = "TRX",
+ this.isPotentialScam = false,
+ }) : _enabled = enabled;
+ // @HiveField(0)
+ final String name;
+
+ // @HiveField(1)
+ final String symbol;
+
+ // @HiveField(2)
+ final String contractAddress;
+
+ // @HiveField(3)
+ final int decimal;
+
+ // @HiveField(4, defaultValue: true)
+ bool _enabled;
+
+ // @HiveField(5)
+ final String? iconPath;
+
+ // @HiveField(6)
+ final String? tag;
+
+ // @HiveField(7, defaultValue: false)
+ final bool isPotentialScam;
+
+ bool get enabled => _enabled;
+
+ set enabled(bool value) => _enabled = value;
+
+ static const typeId = TRON_TOKEN_TYPE_ID;
+ static const boxName = "TronTokens";
+
+ static Future migrateAllToSqlite(List wallets) async {
+ final sanitizedToRawNames = >{};
+ for (final wallet in wallets) {
+ if (wallet.type != WalletType.tron) {
+ continue;
+ }
+
+ sanitizedToRawNames
+ .putIfAbsent(wallet.name.replaceAll(" ", "_"), () => {})
+ .add(wallet.name);
+ }
+
+ for (final entry in sanitizedToRawNames.entries) {
+ final tokenBoxName = "${entry.key}_$boxName";
+ try {
+ if (!await CakeHive.boxExists(tokenBoxName)) {
+ continue;
+ }
+
+ final box = await CakeHive.openBox(tokenBoxName);
+
+ for (final key in box.keys.toList()) {
+ final token = box.get(key);
+ if (token == null) {
+ continue;
+ }
+
+ for (final rawName in entry.value) {
+ await token.migrateToSqlite(walletName: rawName);
+ }
+ await box.delete(key);
+ }
+
+ await box.deleteFromDisk();
+ } catch (e) {
+ printV("Error migrating tron token box $tokenBoxName: $e, continuing anyway");
+ }
+ }
+ }
+
+ Future migrateToSqlite({required String walletName}) async {
+ final row = tron_new.TronToken(
+ name: name,
+ symbol: symbol,
+ contractAddress: contractAddress,
+ decimal: decimal,
+ enabled: _enabled,
+ iconPath: iconPath,
+ tag: tag,
+ isPotentialScam: isPotentialScam,
+ walletName: walletName,
+ ).toMap();
+ row[tron_new.TronToken.selfIdColumn] = null;
+
+ await db!.insert(
+ tron_new.TronToken.tableName,
+ row,
+ conflictAlgorithm: ConflictAlgorithm.replace,
+ );
+ }
+}
diff --git a/cw_core/lib/tron_token.part.dart b/cw_core/lib/tron_token_legacy.part.dart
similarity index 97%
rename from cw_core/lib/tron_token.part.dart
rename to cw_core/lib/tron_token_legacy.part.dart
index c84865349..0884d9184 100644
--- a/cw_core/lib/tron_token.part.dart
+++ b/cw_core/lib/tron_token_legacy.part.dart
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
-part of 'tron_token.dart';
+part of "tron_token_legacy.dart";
// **************************************************************************
// TypeAdapterGenerator
diff --git a/cw_core/lib/wallet_service.dart b/cw_core/lib/wallet_service.dart
index 8d19a9f8c..122193649 100644
--- a/cw_core/lib/wallet_service.dart
+++ b/cw_core/lib/wallet_service.dart
@@ -1,14 +1,16 @@
-import 'dart:convert';
-import 'dart:io';
+import "dart:convert";
+import "dart:io";
-import 'package:cw_core/pathForWallet.dart';
-import 'package:cw_core/utils/file.dart';
-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_type.dart';
-import 'package:path/path.dart' as p;
+import "package:cw_core/pathForWallet.dart";
+import "package:cw_core/spl_token.dart";
+import "package:cw_core/tron_token.dart";
+import "package:cw_core/utils/file.dart";
+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_type.dart";
+import "package:path/path.dart" as p;
abstract class WalletService {
@@ -29,11 +31,13 @@ abstract class WalletService remove(String wallet);
Future rename(String currentName, String password, String newName) async {
- if (currentName == newName) return;
+ if (currentName == newName) {
+ return;
+ }
final currentWalletInfo = await WalletInfo.get(currentName, getType());
if (currentWalletInfo == null) {
- throw Exception('Wallet not found');
+ throw Exception("Wallet not found");
}
await copyWalletFilesTo(fromName: currentName, toName: newName, type: getType());
@@ -43,6 +47,8 @@ abstract class WalletService _renameTokenRows(String currentName, String newName) async {
+ if (getType() == WalletType.solana) {
+ await SPLToken.renameWallet(currentName, newName);
+ }
+
+ if (getType() == WalletType.tron) {
+ await TronToken.renameWallet(currentName, newName);
+ }
+ }
+
Future restoreWalletFilesFromBackup(String name) async {
final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: getType());
final walletDirPath = await pathForWalletDir(name: name, type: getType());
@@ -77,14 +93,14 @@ abstract class WalletService=3.9.0 <4.0.0"
- flutter: ">=3.27.0"
diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml
index ea642d82e..38a4e9a41 100644
--- a/cw_core/pubspec.yaml
+++ b/cw_core/pubspec.yaml
@@ -42,7 +42,7 @@ dependencies:
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
- ref: cake-update-v2
+ ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
sqflite: ^2.4.1
sqflite_common_ffi: ^2.3.4+4
bech32:
diff --git a/cw_core/pubspec_overrides.yaml b/cw_core/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_core/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_core/test/payment_uris_test.dart b/cw_core/test/payment_uris_test.dart
index 88e5e4a45..a61bab1cf 100644
--- a/cw_core/test/payment_uris_test.dart
+++ b/cw_core/test/payment_uris_test.dart
@@ -78,13 +78,13 @@ void main() {
const recipient = "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6";
const contract = "0xdAC17F958D2ee523a2206206994597C13D831ec7";
- test("builds a plain native transfer on mainnet", () {
+ test("includes the mainnet chainId on a plain native transfer", () {
final uri = ERC681URI(chainId: 1, address: recipient, amount: "", contractAddress: null);
- expect(uri.toString(), "ethereum:$recipient");
+ expect(uri.toString(), "ethereum:$recipient@1");
});
- test("appends the chainId for non-mainnet native transfers", () {
+ test("appends the chainId for native transfers", () {
final uri = ERC681URI(chainId: 137, address: recipient, amount: "", contractAddress: null);
expect(uri.toString(), "ethereum:$recipient@137");
@@ -93,7 +93,22 @@ void main() {
test("emits the native amount in ERC-681 scientific notation", () {
final uri = ERC681URI(chainId: 1, address: recipient, amount: "1", contractAddress: null);
- expect(uri.toString(), "ethereum:$recipient?value=1.0e18");
+ expect(uri.toString(), "ethereum:$recipient@1?value=1.0e18");
+ });
+
+ test("includes the mainnet chainId in the transfer form", () {
+ final uri = ERC681URI(
+ chainId: 1,
+ address: recipient,
+ amount: "200.172148",
+ contractAddress: contract,
+ tokenDecimals: 6,
+ );
+
+ expect(
+ uri.toString(),
+ "ethereum:$contract@1/transfer?address=$recipient&amount=200.172148",
+ );
});
test("builds the transfer form for a token", () {
@@ -189,7 +204,7 @@ void main() {
rawTokenAmount: "1000000",
);
- expect(uri.toString(), "ethereum:$contract/transfer?address=$recipient&uint256=1000000");
+ expect(uri.toString(), "ethereum:$contract@1/transfer?address=$recipient&uint256=1000000");
});
test("parses a scientific notation value", () {
diff --git a/cw_core/test/token_sqlite_migration_test.dart b/cw_core/test/token_sqlite_migration_test.dart
new file mode 100644
index 000000000..c81c1618c
--- /dev/null
+++ b/cw_core/test/token_sqlite_migration_test.dart
@@ -0,0 +1,365 @@
+import "dart:io";
+
+import "package:cw_core/cake_hive.dart";
+import "package:cw_core/db/sqlite.dart";
+import "package:cw_core/erc20_token.dart" as erc20_sql;
+import "package:cw_core/erc20_token_legacy.dart" as erc20_legacy;
+import "package:cw_core/root_dir.dart";
+import "package:cw_core/spl_token.dart" as spl_sql;
+import "package:cw_core/spl_token_legacy.dart" as spl_legacy;
+import "package:cw_core/tron_token.dart" as tron_sql;
+import "package:cw_core/tron_token_legacy.dart" as tron_legacy;
+import "package:cw_core/wallet_type.dart";
+import "package:flutter_test/flutter_test.dart";
+import "package:path_provider_platform_interface/path_provider_platform_interface.dart";
+import "package:sqflite_common_ffi/sqflite_ffi.dart";
+
+// Faking the documents dir keeps getAppDir() off the platform channel, so the
+// test runs with a plain `flutter test` on any host and in CI.
+class _FakePathProviderPlatform extends PathProviderPlatform {
+ _FakePathProviderPlatform(this.root);
+
+ final String root;
+
+ @override
+ Future getApplicationDocumentsPath() async => root;
+
+ @override
+ Future getApplicationSupportPath() async => root;
+}
+
+Future main() async {
+ final dataRoot = Directory("./test/data/token_migration");
+
+ Future insertWalletInfoRow(String name, WalletType type) async {
+ await db!.insert("WalletInfo", {
+ "id": "${walletTypeToString(type).toLowerCase()}_$name",
+ "name": name,
+ "type": type.index,
+ "isRecovery": 0,
+ "restoreHeight": 0,
+ "timestamp": 0,
+ "dirPath": "",
+ "path": "",
+ "address": "",
+ "showIntroCakePayCard": 0,
+ "walletInfoDerivationInfoId": 0,
+ "isNonSeedWallet": 0,
+ "sortOrder": 0,
+ "receiveInfoboxDismissed": 0,
+ "showCombinedBalance": 1,
+ });
+ }
+
+ group(
+ "token sqlite migration",
+ () {
+ setUpAll(() async {
+ if (dataRoot.existsSync()) {
+ dataRoot.deleteSync(recursive: true);
+ }
+ dataRoot.createSync(recursive: true);
+
+ PathProviderPlatform.instance = _FakePathProviderPlatform(dataRoot.absolute.path);
+
+ // On linux getAppDir() appends /cake_wallet to the documents dir and picks the
+ // first existing candidate, so create it up front to keep CI on the faked path.
+ Directory("${dataRoot.path}/cake_wallet").createSync(recursive: true);
+
+ sqfliteFfiInit();
+ databaseFactory = databaseFactoryFfi;
+ await initDb();
+
+ // Everything must share the dir initDb resolved so boxExists finds the boxes
+ final appDir = await getAppDir();
+ CakeHive.init(appDir.path);
+
+ if (!CakeHive.isAdapterRegistered(erc20_legacy.Erc20Token.typeId)) {
+ CakeHive.registerAdapter(erc20_legacy.Erc20TokenAdapter());
+ }
+ if (!CakeHive.isAdapterRegistered(spl_legacy.SPLToken.typeId)) {
+ CakeHive.registerAdapter(spl_legacy.SPLTokenAdapter());
+ }
+ if (!CakeHive.isAdapterRegistered(tron_legacy.TronToken.typeId)) {
+ CakeHive.registerAdapter(tron_legacy.TronTokenAdapter());
+ }
+
+ // Two ethereum wallets whose names sanitize to the same box name, plus sol and tron
+ await insertWalletInfoRow("My Wallet", WalletType.ethereum);
+ await insertWalletInfoRow("My_Wallet", WalletType.ethereum);
+ await insertWalletInfoRow("sol wallet", WalletType.solana);
+ await insertWalletInfoRow("tron1", WalletType.tron);
+
+ // Legacy global box shared by every ethereum wallet in the pre per-wallet era
+ final globalBox = await CakeHive.openBox("Erc20Tokens");
+ await globalBox.put(
+ "0xGlobalTokenAAA",
+ erc20_legacy.Erc20Token(
+ name: "Global Legacy",
+ symbol: "GLB",
+ contractAddress: "0xGlobalTokenAAA",
+ decimal: 18,
+ enabled: true,
+ ),
+ );
+
+ // Per-wallet ethereum box with a duplicate contract in two casings and a disabled token
+ final ethBox =
+ await CakeHive.openBox("My_Wallet_EthereumErc20Tokens");
+ await ethBox.put(
+ "0xDupCASE01",
+ erc20_legacy.Erc20Token(
+ name: "Dup Token",
+ symbol: "DUP",
+ contractAddress: "0xDupCASE01",
+ decimal: 18,
+ enabled: false,
+ iconPath: "",
+ ),
+ );
+ await ethBox.put(
+ "0xdupcase01",
+ erc20_legacy.Erc20Token(
+ name: "Dup Token",
+ symbol: "DUP",
+ contractAddress: "0xdupcase01",
+ decimal: 18,
+ enabled: true,
+ iconPath: "assets/images/dup.png",
+ ),
+ );
+ await ethBox.put(
+ "0xkeepmedisabled",
+ erc20_legacy.Erc20Token(
+ name: "Keep Me",
+ symbol: "KEEP",
+ contractAddress: "0xkeepmedisabled",
+ decimal: 6,
+ enabled: false,
+ ),
+ );
+
+ // A polygon chain box for the same wallet name
+ final polyBox =
+ await CakeHive.openBox("My_Wallet_PolygonErc20Tokens");
+ await polyBox.put(
+ "0xpolytoken01",
+ erc20_legacy.Erc20Token(
+ name: "Poly Token",
+ symbol: "PLY",
+ contractAddress: "0xpolytoken01",
+ decimal: 18,
+ enabled: true,
+ tag: "POL",
+ ),
+ );
+
+ // SPL and Tron boxes, base58 keys must keep their exact casing
+ final splBox = await CakeHive.openBox("sol_wallet_SPLTokens");
+ await splBox.put(
+ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+ spl_legacy.SPLToken(
+ name: "USD Coin",
+ symbol: "USDC",
+ mintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+ decimal: 6,
+ mint: "usdc",
+ enabled: false,
+ ),
+ );
+
+ final tronBox = await CakeHive.openBox("tron1_TronTokens");
+ await tronBox.put(
+ "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
+ tron_legacy.TronToken(
+ name: "Tether USD",
+ symbol: "USDT",
+ contractAddress: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
+ decimal: 6,
+ enabled: true,
+ ),
+ );
+
+ await globalBox.close();
+ await ethBox.close();
+ await polyBox.close();
+ await splBox.close();
+ await tronBox.close();
+ });
+
+ tearDownAll(() async {
+ await db?.close();
+ db = null;
+ if (dataRoot.existsSync()) {
+ dataRoot.deleteSync(recursive: true);
+ }
+ });
+
+ test("migrates every token box into sqlite", () async {
+ await erc20_legacy.performErc20TokenHiveMigration();
+ await spl_legacy.performSplTokenHiveMigration();
+ await tron_legacy.performTronTokenHiveMigration();
+
+ // Both ethereum wallets share the sanitized box name, so each gets the rows
+ for (final walletName in ["My Wallet", "My_Wallet"]) {
+ final ethTokens = await erc20_sql.Erc20Token.getAllForWallet(walletName, 1);
+ final addresses = ethTokens.map((t) => t.contractAddress).toSet();
+
+ expect(
+ addresses,
+ {"0xglobaltokenaaa", "0xdupcase01", "0xkeepmedisabled"},
+ reason: "wallet $walletName should have the global, merged dup and disabled tokens",
+ );
+
+ final dup = ethTokens.firstWhere((t) => t.contractAddress == "0xdupcase01");
+ expect(dup.enabled, true, reason: "dup merge ORs the enabled flags");
+ expect(dup.iconPath, "assets/images/dup.png", reason: "dup merge prefers non-empty icon");
+
+ final keep = ethTokens.firstWhere((t) => t.contractAddress == "0xkeepmedisabled");
+ expect(keep.enabled, false, reason: "disabled toggle must survive the migration");
+
+ final polyTokens = await erc20_sql.Erc20Token.getAllForWallet(walletName, 137);
+ expect(polyTokens.map((t) => t.contractAddress), ["0xpolytoken01"]);
+ }
+
+ final splTokens = await spl_sql.SPLToken.getAllForWallet("sol wallet");
+ expect(splTokens.length, 1);
+ expect(
+ splTokens.first.mintAddress,
+ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+ reason: "mint address casing must be preserved",
+ );
+ expect(splTokens.first.enabled, false);
+
+ final tronTokens = await tron_sql.TronToken.getAllForWallet("tron1");
+ expect(tronTokens.length, 1);
+ expect(
+ tronTokens.first.contractAddress,
+ "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
+ reason: "tron contract address casing must be preserved",
+ );
+
+ // Drained boxes are removed from disk
+ expect(await CakeHive.boxExists("Erc20Tokens"), false);
+ expect(await CakeHive.boxExists("My_Wallet_EthereumErc20Tokens"), false);
+ expect(await CakeHive.boxExists("My_Wallet_PolygonErc20Tokens"), false);
+ expect(await CakeHive.boxExists("sol_wallet_SPLTokens"), false);
+ expect(await CakeHive.boxExists("tron1_TronTokens"), false);
+ });
+
+ test("re-running the migrations is a no-op", () async {
+ final before = (await erc20_sql.Erc20Token.selectList("", [])).length +
+ (await spl_sql.SPLToken.selectList("", [])).length +
+ (await tron_sql.TronToken.selectList("", [])).length;
+
+ await erc20_legacy.performErc20TokenHiveMigration();
+ await spl_legacy.performSplTokenHiveMigration();
+ await tron_legacy.performTronTokenHiveMigration();
+
+ final after = (await erc20_sql.Erc20Token.selectList("", [])).length +
+ (await spl_sql.SPLToken.selectList("", [])).length +
+ (await tron_sql.TronToken.selectList("", [])).length;
+
+ expect(after, before);
+ });
+
+ test("an interrupted migration re-drains over existing rows without duplicating", () async {
+ // Simulates a run that inserted rows into sqlite but died before the box was
+ // emptied: the box reappears holding a token that already has a row (USDC,
+ // re-enabled in the box copy) plus one the interrupted run never reached (BONK)
+ final box = await CakeHive.openBox("sol_wallet_SPLTokens");
+ await box.put(
+ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+ spl_legacy.SPLToken(
+ name: "USD Coin",
+ symbol: "USDC",
+ mintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+ decimal: 6,
+ mint: "usdc",
+ enabled: true,
+ ),
+ );
+ await box.put(
+ "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
+ spl_legacy.SPLToken(
+ name: "Bonk",
+ symbol: "BONK",
+ mintAddress: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
+ decimal: 5,
+ mint: "bonk",
+ enabled: true,
+ ),
+ );
+ await box.close();
+
+ await spl_legacy.performSplTokenHiveMigration();
+
+ final tokens = await spl_sql.SPLToken.getAllForWallet("sol wallet");
+ expect(tokens.length, 2, reason: "the re-drain must not duplicate the existing USDC row");
+
+ final usdc = tokens.firstWhere((t) => t.symbol == "USDC");
+ expect(usdc.enabled, true, reason: "the box copy wins over the stale row on re-drain");
+
+ expect(await CakeHive.boxExists("sol_wallet_SPLTokens"), false);
+ });
+
+ test("save without wallet context throws", () {
+ final token = erc20_sql.Erc20Token(
+ name: "No Context",
+ symbol: "NOC",
+ contractAddress: "0xnocontext",
+ decimal: 18,
+ );
+
+ expect(token.save, throwsStateError);
+ });
+
+ test("seeding preserves the enabled toggle without clobbering", () async {
+ // Same shape addInitialTokens uses: read existing, copyWith preserving enabled
+ final existing =
+ await erc20_sql.Erc20Token.getByContract("My Wallet", 1, "0xKEEPMEDISABLED");
+ expect(existing, isNotNull);
+ expect(existing!.enabled, false);
+
+ final refreshedDefault = erc20_sql.Erc20Token(
+ name: "Keep Me Renamed By Defaults",
+ symbol: "KEEP",
+ contractAddress: "0xkeepmedisabled",
+ decimal: 6,
+ enabled: true,
+ );
+ final toSave = erc20_sql.Erc20Token.copyWith(
+ refreshedDefault,
+ enabled: existing.enabled,
+ walletName: "My Wallet",
+ chainId: 1,
+ );
+ await toSave.save();
+
+ final reloaded =
+ await erc20_sql.Erc20Token.getByContract("My Wallet", 1, "0xkeepmedisabled");
+ expect(reloaded!.enabled, false, reason: "metadata refresh must not re-enable the token");
+ expect(reloaded.name, "Keep Me Renamed By Defaults");
+
+ final rowCount = (await erc20_sql.Erc20Token.getAllForWallet("My Wallet", 1)).length;
+ expect(rowCount, 3, reason: "upsert must replace, not duplicate");
+ });
+
+ test("rename moves rows and delete removes them", () async {
+ await erc20_sql.Erc20Token.renameWallet("My Wallet", "Renamed Wallet");
+
+ expect(await erc20_sql.Erc20Token.getAllForWallet("My Wallet", 1), isEmpty);
+ expect((await erc20_sql.Erc20Token.getAllForWallet("Renamed Wallet", 1)).length, 3);
+ expect((await erc20_sql.Erc20Token.getAllForWallet("Renamed Wallet", 137)).length, 1);
+
+ await erc20_sql.Erc20Token.deleteAllForWallet("My_Wallet");
+ expect(await erc20_sql.Erc20Token.getAllForWallet("My_Wallet", 1), isEmpty);
+ expect(await erc20_sql.Erc20Token.getAllForWallet("My_Wallet", 137), isEmpty);
+
+ // Rename into a name that has orphaned rows must not trip the unique index
+ await erc20_sql.Erc20Token.renameWallet("Renamed Wallet", "My_Wallet");
+ expect((await erc20_sql.Erc20Token.getAllForWallet("My_Wallet", 1)).length, 3);
+ });
+ },
+ );
+}
diff --git a/cw_custom_lints/lib/main.dart b/cw_custom_lints/lib/main.dart
index e57e22525..1bf70f6aa 100644
--- a/cw_custom_lints/lib/main.dart
+++ b/cw_custom_lints/lib/main.dart
@@ -3,6 +3,8 @@ import "package:analysis_server_plugin/registry.dart";
import "package:cw_custom_lints/http_force_proxy/http_force_proxy_rule.dart";
import "package:cw_custom_lints/modal_top_bar_semantics/modal_top_bar_semantics_rule.dart";
import "package:cw_custom_lints/modern_button_semantics/modern_button_semantics_rule.dart";
+import "package:cw_custom_lints/money_amount_to_string/money_amount_to_string_fix.dart";
+import "package:cw_custom_lints/money_amount_to_string/money_amount_to_string_rule.dart";
import "package:cw_custom_lints/print_verbose/print_verbose_fix.dart";
import "package:cw_custom_lints/print_verbose/print_verbose_rule.dart";
import "package:cw_custom_lints/restricted_imports/restricted_imports_rule.dart";
@@ -20,7 +22,13 @@ class CwCustomLintsPlugin extends Plugin {
registry.registerWarningRule(HttpForceProxyRule());
registry.registerWarningRule(ModernButtonSemanticsRule());
registry.registerWarningRule(ModalTopBarSemanticsRule());
+ registry.registerWarningRule(MoneyAmountToStringRule());
registry.registerFixForRule(PrintVerboseRule.code, ReplaceWithPrintV.new);
+ registry.registerFixForRule(MoneyAmountToStringRule.code, ReplaceWithMoneyToString.new);
+ registry.registerFixForRule(
+ MoneyAmountToStringRule.code,
+ ReplaceWithMoneyToStringInBaseUnit.new,
+ );
}
}
diff --git a/cw_custom_lints/lib/money_amount_to_string/money_amount_to_string_fix.dart b/cw_custom_lints/lib/money_amount_to_string/money_amount_to_string_fix.dart
new file mode 100644
index 000000000..3aad8152a
--- /dev/null
+++ b/cw_custom_lints/lib/money_amount_to_string/money_amount_to_string_fix.dart
@@ -0,0 +1,66 @@
+import "package:analysis_server_plugin/edit/dart/correction_producer.dart";
+import "package:analysis_server_plugin/edit/dart/dart_fix_kind_priority.dart";
+import "package:analyzer/dart/ast/ast.dart";
+import "package:analyzer_plugin/utilities/change_builder/change_builder_core.dart";
+import "package:analyzer_plugin/utilities/fixes/fixes.dart";
+import "package:analyzer_plugin/utilities/range_factory.dart";
+import "package:cw_custom_lints/money_amount_to_string/money_amount_to_string_rule.dart";
+
+abstract class _ReplaceMoneyAmountToString extends ResolvedCorrectionProducer {
+ _ReplaceMoneyAmountToString({required super.context});
+
+ String get replacement;
+
+ @override
+ CorrectionApplicability get applicability => CorrectionApplicability.singleLocation;
+
+ @override
+ Future compute(ChangeBuilder builder) async {
+ final invocation = node.thisOrAncestorOfType();
+ if (invocation == null) {
+ return;
+ }
+
+ final amount = moneyAmountReference(invocation.realTarget);
+ if (amount == null) {
+ return;
+ }
+
+ await builder.addDartFileEdit(
+ file,
+ (builder) => builder.addSimpleReplacement(range.startEnd(amount, invocation), replacement),
+ );
+ }
+}
+
+class ReplaceWithMoneyToString extends _ReplaceMoneyAmountToString {
+ ReplaceWithMoneyToString({required super.context});
+
+ static const _fixKind = FixKind(
+ "dart.fix.replaceWithMoneyToString",
+ DartFixKindPriority.standard,
+ "Replace with toString() for a decimal amount",
+ );
+
+ @override
+ FixKind get fixKind => _fixKind;
+
+ @override
+ String get replacement => "toString()";
+}
+
+class ReplaceWithMoneyToStringInBaseUnit extends _ReplaceMoneyAmountToString {
+ ReplaceWithMoneyToStringInBaseUnit({required super.context});
+
+ static const _fixKind = FixKind(
+ "dart.fix.replaceWithMoneyToStringInBaseUnit",
+ DartFixKindPriority.standard,
+ "Replace with toStringWithPrecision(useBaseUnit: true) for base units",
+ );
+
+ @override
+ FixKind get fixKind => _fixKind;
+
+ @override
+ String get replacement => "toStringWithPrecision(useBaseUnit: true)";
+}
diff --git a/cw_custom_lints/lib/money_amount_to_string/money_amount_to_string_rule.dart b/cw_custom_lints/lib/money_amount_to_string/money_amount_to_string_rule.dart
new file mode 100644
index 000000000..3a7e58917
--- /dev/null
+++ b/cw_custom_lints/lib/money_amount_to_string/money_amount_to_string_rule.dart
@@ -0,0 +1,85 @@
+import "package:analyzer/analysis_rule/analysis_rule.dart";
+import "package:analyzer/analysis_rule/rule_context.dart";
+import "package:analyzer/analysis_rule/rule_visitor_registry.dart";
+import "package:analyzer/dart/ast/ast.dart";
+import "package:analyzer/dart/ast/visitor.dart";
+import "package:analyzer/dart/element/element.dart";
+import "package:analyzer/error/error.dart";
+
+class MoneyAmountToStringRule extends AnalysisRule {
+ MoneyAmountToStringRule()
+ : super(
+ name: "no_money_amount_to_string",
+ description:
+ "Money.amount is the internal BigInt, so stringifying it drops the decimal point.",
+ );
+
+ static const LintCode code = LintCode(
+ "no_money_amount_to_string",
+ "This stringifies the internal BigInt of Money instead of the Money itself, so the decimal point is dropped and the amount reads far larger than it is.",
+ correctionMessage:
+ "Call toString() on the Money for a decimal amount, or toStringWithPrecision(useBaseUnit: true) for base units.",
+ severity: DiagnosticSeverity.WARNING,
+ );
+
+ @override
+ LintCode get diagnosticCode => code;
+
+ @override
+ void registerNodeProcessors(RuleVisitorRegistry registry, RuleContext context) =>
+ registry.addMethodInvocation(this, _Visitor(this));
+}
+
+
+SimpleIdentifier? moneyAmountReference(Expression? expression) {
+ final identifier = switch (expression) {
+ PrefixedIdentifier() => expression.identifier,
+ PropertyAccess() => expression.propertyName,
+ SimpleIdentifier() => expression,
+ _ => null,
+ };
+
+ if (identifier == null || identifier.name != "amount") {
+ return null;
+ }
+
+ return _isDeclaredByMoney(identifier.element) ? identifier : null;
+}
+
+bool _isDeclaredByMoney(Element? element) {
+ if (element == null) {
+ return false;
+ }
+
+ final enclosing = element.enclosingElement;
+ if (enclosing is! InterfaceElement || enclosing.name != "Money") {
+ return false;
+ }
+
+ final libraryUri = element.library?.uri;
+ if (libraryUri == null || libraryUri.scheme != "package") {
+ return false;
+ }
+
+ final segments = libraryUri.pathSegments;
+ return segments.isNotEmpty && segments.first == "cw_core";
+}
+
+class _Visitor extends SimpleAstVisitor {
+ _Visitor(this.rule);
+
+ final AnalysisRule rule;
+
+ @override
+ void visitMethodInvocation(MethodInvocation node) {
+ if (node.methodName.name != "toString" || node.argumentList.arguments.isNotEmpty) {
+ return;
+ }
+
+ if (moneyAmountReference(node.realTarget) == null) {
+ return;
+ }
+
+ rule.reportAtNode(node);
+ }
+}
diff --git a/cw_decred/.gitignore b/cw_decred/.gitignore
index d8452de53..13e32daec 100644
--- a/cw_decred/.gitignore
+++ b/cw_decred/.gitignore
@@ -22,8 +22,6 @@ migrate_working_dir/
#.vscode/
# Flutter/Dart/Pub related
-# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
-/pubspec.lock
**/doc/api/
.dart_tool/
.packages
diff --git a/cw_decred/pubspec.lock b/cw_decred/pubspec.lock
deleted file mode 100644
index 9a568daa7..000000000
--- a/cw_decred/pubspec.lock
+++ /dev/null
@@ -1,881 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- _fe_analyzer_shared:
- dependency: transitive
- description:
- name: _fe_analyzer_shared
- sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
- url: "https://pub.dev"
- source: hosted
- version: "93.0.0"
- analyzer:
- dependency: transitive
- description:
- name: analyzer
- sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
- url: "https://pub.dev"
- source: hosted
- version: "10.0.1"
- args:
- dependency: transitive
- description:
- name: args
- sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- asn1lib:
- dependency: transitive
- description:
- name: asn1lib
- sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.8"
- async:
- dependency: transitive
- description:
- name: async
- sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
- url: "https://pub.dev"
- source: hosted
- version: "2.13.0"
- bech32:
- dependency: transitive
- description:
- path: "."
- ref: HEAD
- resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
- url: "https://github.com/cake-tech/bech32.git"
- source: git
- version: "0.2.2"
- blockchain_utils:
- dependency: transitive
- description:
- path: "."
- ref: cake-update-v2
- resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
- url: "https://github.com/cake-tech/blockchain_utils"
- source: git
- version: "3.3.0"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- build:
- dependency: transitive
- description:
- name: build
- sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10
- url: "https://pub.dev"
- source: hosted
- version: "4.0.6"
- build_config:
- dependency: transitive
- description:
- name: build_config
- sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- build_daemon:
- dependency: transitive
- description:
- name: build_daemon
- sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
- build_runner:
- dependency: "direct dev"
- description:
- name: build_runner
- sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6"
- url: "https://pub.dev"
- source: hosted
- version: "2.15.0"
- built_collection:
- dependency: transitive
- description:
- name: built_collection
- sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
- url: "https://pub.dev"
- source: hosted
- version: "5.1.1"
- built_value:
- dependency: transitive
- description:
- name: built_value
- sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56"
- url: "https://pub.dev"
- source: hosted
- version: "8.12.6"
- cake_backup:
- dependency: transitive
- description:
- path: "."
- ref: main
- resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
- url: "https://github.com/cake-tech/cake_backup.git"
- source: git
- version: "1.0.0+1"
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- checked_yaml:
- dependency: transitive
- description:
- name: checked_yaml
- sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
- url: "https://pub.dev"
- source: hosted
- version: "2.0.3"
- cli_util:
- dependency: transitive
- description:
- name: cli_util
- sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
- url: "https://pub.dev"
- source: hosted
- version: "0.4.2"
- clock:
- dependency: transitive
- description:
- name: clock
- sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- collection:
- dependency: transitive
- description:
- name: collection
- sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
- url: "https://pub.dev"
- source: hosted
- version: "1.19.1"
- convert:
- dependency: transitive
- description:
- name: convert
- sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- crypto:
- dependency: transitive
- description:
- name: crypto
- sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.6"
- cryptography:
- dependency: transitive
- description:
- name: cryptography
- sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- cupertino_icons:
- dependency: transitive
- description:
- name: cupertino_icons
- sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
- url: "https://pub.dev"
- source: hosted
- version: "1.0.8"
- cw_core:
- dependency: "direct main"
- description:
- path: "../cw_core"
- relative: true
- source: path
- version: "0.0.1"
- dart_style:
- dependency: transitive
- description:
- name: dart_style
- sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.7"
- decimal:
- dependency: transitive
- description:
- name: decimal
- sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.3"
- encrypt:
- dependency: transitive
- description:
- name: encrypt
- sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.3"
- fake_async:
- dependency: transitive
- description:
- name: fake_async
- sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.3"
- ffi:
- dependency: transitive
- description:
- name: ffi
- sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- ffigen:
- dependency: "direct dev"
- description:
- name: ffigen
- sha256: b7803707faeec4ce3c1b0c2274906504b796e3b70ad573577e72333bd1c9b3ba
- url: "https://pub.dev"
- source: hosted
- version: "20.1.1"
- file:
- dependency: transitive
- description:
- name: file
- sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
- url: "https://pub.dev"
- source: hosted
- version: "7.0.1"
- fixnum:
- dependency: transitive
- description:
- name: fixnum
- sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_mobx:
- dependency: transitive
- description:
- name: flutter_mobx
- sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- glob:
- dependency: transitive
- description:
- name: glob
- sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- graphs:
- dependency: transitive
- description:
- name: graphs
- sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.2"
- hive:
- dependency: "direct dev"
- description:
- name: hive
- sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
- http:
- dependency: transitive
- description:
- name: http
- sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- http_multi_server:
- dependency: transitive
- description:
- name: http_multi_server
- sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- http_parser:
- dependency: transitive
- description:
- name: http_parser
- sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
- intl:
- dependency: transitive
- description:
- name: intl
- sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
- url: "https://pub.dev"
- source: hosted
- version: "0.19.0"
- io:
- dependency: transitive
- description:
- name: io
- sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- js:
- dependency: transitive
- description:
- name: js
- sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
- url: "https://pub.dev"
- source: hosted
- version: "0.6.7"
- json_annotation:
- dependency: transitive
- description:
- name: json_annotation
- sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
- url: "https://pub.dev"
- source: hosted
- version: "4.9.0"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
- url: "https://pub.dev"
- source: hosted
- version: "11.0.2"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.10"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- logging:
- dependency: transitive
- description:
- name: logging
- sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- matcher:
- dependency: transitive
- description:
- name: matcher
- sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
- url: "https://pub.dev"
- source: hosted
- version: "0.12.19"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
- url: "https://pub.dev"
- source: hosted
- version: "0.13.0"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
- url: "https://pub.dev"
- source: hosted
- version: "1.17.0"
- mime:
- dependency: transitive
- description:
- name: mime
- sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- mobx:
- dependency: transitive
- description:
- name: mobx
- sha256: "25ea9a3ee69243d578fb6288721d8eeb18550d0391c32f896d377d994154bff2"
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- mobx_codegen:
- dependency: "direct dev"
- description:
- name: mobx_codegen
- sha256: "6529bcae074838004b58ad01fbe4966be182a176aacfb723686985986ebac19f"
- url: "https://pub.dev"
- source: hosted
- version: "2.7.7"
- nested:
- dependency: transitive
- description:
- name: nested
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- on_chain:
- dependency: transitive
- description:
- path: "."
- ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- url: "https://github.com/cake-tech/on_chain.git"
- source: git
- version: "3.7.0"
- package_config:
- dependency: transitive
- description:
- name: package_config
- sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- path:
- dependency: transitive
- description:
- name: path
- sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
- url: "https://pub.dev"
- source: hosted
- version: "1.9.1"
- path_provider:
- dependency: transitive
- description:
- name: path_provider
- sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- path_provider_android:
- dependency: transitive
- description:
- name: path_provider_android
- sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.15"
- path_provider_foundation:
- dependency: transitive
- description:
- name: path_provider_foundation
- sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- path_provider_linux:
- dependency: transitive
- description:
- name: path_provider_linux
- sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
- url: "https://pub.dev"
- source: hosted
- version: "2.2.1"
- path_provider_platform_interface:
- dependency: transitive
- description:
- name: path_provider_platform_interface
- sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- path_provider_windows:
- dependency: transitive
- description:
- name: path_provider_windows
- sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- platform:
- dependency: transitive
- description:
- name: platform
- sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.6"
- plugin_platform_interface:
- dependency: transitive
- description:
- name: plugin_platform_interface
- sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.8"
- pointycastle:
- dependency: transitive
- description:
- name: pointycastle
- sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
- url: "https://pub.dev"
- source: hosted
- version: "3.9.1"
- pool:
- dependency: transitive
- description:
- name: pool
- sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.1"
- provider:
- dependency: transitive
- description:
- name: provider
- sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
- url: "https://pub.dev"
- source: hosted
- version: "6.1.2"
- pub_semver:
- dependency: transitive
- description:
- name: pub_semver
- sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- pubspec_parse:
- dependency: transitive
- description:
- name: pubspec_parse
- sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- quiver:
- dependency: transitive
- description:
- name: quiver
- sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- rational:
- dependency: transitive
- description:
- name: rational
- sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
- shelf:
- dependency: transitive
- description:
- name: shelf
- sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- shelf_web_socket:
- dependency: transitive
- description:
- name: shelf_web_socket
- sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- socks5_proxy:
- dependency: transitive
- description:
- path: "."
- ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- url: "https://github.com/LacticWhale/socks_dart"
- source: git
- version: "2.1.0"
- socks_socket:
- dependency: transitive
- description:
- path: "."
- ref: e6232c53c1595469931ababa878759a067c02e94
- resolved-ref: e6232c53c1595469931ababa878759a067c02e94
- url: "https://github.com/sneurlax/socks_socket"
- source: git
- version: "1.1.1"
- source_gen:
- dependency: transitive
- description:
- name: source_gen
- sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02
- url: "https://pub.dev"
- source: hosted
- version: "4.2.3"
- source_span:
- dependency: transitive
- description:
- name: source_span
- sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
- url: "https://pub.dev"
- source: hosted
- version: "1.10.1"
- sqflite:
- dependency: transitive
- description:
- name: sqflite
- sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- sqflite_android:
- dependency: transitive
- description:
- name: sqflite_android
- sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqflite_common:
- dependency: transitive
- description:
- name: sqflite_common
- sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4+6"
- sqflite_common_ffi:
- dependency: transitive
- description:
- name: sqflite_common_ffi
- sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.4+4"
- sqflite_darwin:
- dependency: transitive
- description:
- name: sqflite_darwin
- sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1+1"
- sqflite_platform_interface:
- dependency: transitive
- description:
- name: sqflite_platform_interface
- sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqlite3:
- dependency: transitive
- description:
- name: sqlite3
- sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
- url: "https://pub.dev"
- source: hosted
- version: "2.9.0"
- sqlite3_flutter_libs:
- dependency: transitive
- description:
- name: sqlite3_flutter_libs
- sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
- url: "https://pub.dev"
- source: hosted
- version: "0.5.40"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
- url: "https://pub.dev"
- source: hosted
- version: "1.12.1"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- stream_transform:
- dependency: transitive
- description:
- name: stream_transform
- sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
- url: "https://pub.dev"
- source: hosted
- version: "3.3.0+3"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.2"
- test_api:
- dependency: transitive
- description:
- name: test_api
- sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.10"
- torch_dart:
- dependency: transitive
- description:
- path: "../scripts/torch_dart"
- relative: true
- source: path
- version: "0.0.1"
- tuple:
- dependency: transitive
- description:
- name: tuple
- sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- unorm_dart:
- dependency: transitive
- description:
- name: unorm_dart
- sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
- url: "https://pub.dev"
- source: hosted
- version: "15.0.0"
- watcher:
- dependency: transitive
- description:
- name: watcher
- sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web:
- dependency: transitive
- description:
- name: web
- sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web_socket:
- dependency: transitive
- description:
- name: web_socket
- sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.6"
- web_socket_channel:
- dependency: transitive
- description:
- name: web_socket_channel
- sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- xdg_directories:
- dependency: transitive
- description:
- name: xdg_directories
- sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- yaml:
- dependency: transitive
- description:
- name: yaml
- sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
- yaml_edit:
- dependency: transitive
- description:
- name: yaml_edit
- sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5
- url: "https://pub.dev"
- source: hosted
- version: "2.2.2"
-sdks:
- dart: ">=3.10.0 <4.0.0"
- flutter: ">=3.24.0"
diff --git a/cw_decred/pubspec_overrides.yaml b/cw_decred/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_decred/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_dogecoin/.gitignore b/cw_dogecoin/.gitignore
index eb6c05cd3..b050f03cf 100644
--- a/cw_dogecoin/.gitignore
+++ b/cw_dogecoin/.gitignore
@@ -22,8 +22,6 @@ migrate_working_dir/
#.vscode/
# Flutter/Dart/Pub related
-# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
-/pubspec.lock
**/doc/api/
.dart_tool/
.flutter-plugins
diff --git a/cw_dogecoin/pubspec.yaml b/cw_dogecoin/pubspec.yaml
index 910d2b63e..a93ea377b 100644
--- a/cw_dogecoin/pubspec.yaml
+++ b/cw_dogecoin/pubspec.yaml
@@ -25,7 +25,7 @@ dependencies:
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
- ref: cake-update-v2
+ ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
dev_dependencies:
flutter_test:
@@ -40,7 +40,7 @@ dependency_overrides:
bitcoin_base:
git:
url: https://github.com/cake-tech/bitcoin_base
- ref: cake-update-v11
+ ref: bda0e2904effa799ec835b4578cc3fc5d31caa78
# For information on the generic Dart part of this file, see the
diff --git a/cw_dogecoin/pubspec_overrides.yaml b/cw_dogecoin/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_dogecoin/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_evm/.gitignore b/cw_evm/.gitignore
index 96486fd93..32aee4b25 100644
--- a/cw_evm/.gitignore
+++ b/cw_evm/.gitignore
@@ -22,8 +22,6 @@ migrate_working_dir/
#.vscode/
# Flutter/Dart/Pub related
-# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
-/pubspec.lock
**/doc/api/
.dart_tool/
.packages
diff --git a/cw_evm/build.yaml b/cw_evm/build.yaml
new file mode 100644
index 000000000..81a9c96df
--- /dev/null
+++ b/cw_evm/build.yaml
@@ -0,0 +1,5 @@
+targets:
+ $default:
+ sources:
+ exclude:
+ - "**/.secrets.g.dart"
diff --git a/cw_evm/lib/evm_chain_exceptions.dart b/cw_evm/lib/evm_chain_exceptions.dart
index 4e5f4df08..62dfb78b5 100644
--- a/cw_evm/lib/evm_chain_exceptions.dart
+++ b/cw_evm/lib/evm_chain_exceptions.dart
@@ -1,5 +1,11 @@
import 'package:cw_core/crypto_currency.dart';
+class EVMChainMnemonicIsIncorrectException implements Exception {
+ @override
+ String toString() =>
+ 'EVM mnemonic has incorrect format. Mnemonic should contain 12 or 24 words separated by space.';
+}
+
class EVMChainTransactionCreationException implements Exception {
final String exceptionMessage;
diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart
index f66c34319..c9e07c4a7 100644
--- a/cw_evm/lib/evm_chain_wallet.dart
+++ b/cw_evm/lib/evm_chain_wallet.dart
@@ -5,7 +5,6 @@ import 'dart:typed_data';
import 'package:bip32/bip32.dart' as bip32;
import 'package:bip39/bip39.dart' as bip39;
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/erc20_token.dart';
@@ -38,7 +37,6 @@ import 'package:cw_evm/hardware/evm_chain_bitbox_credentials.dart';
import 'package:cw_evm/hardware/evm_chain_ledger_credentials.dart';
import 'package:cw_evm/hardware/evm_chain_trezor_credentials.dart';
import 'package:hex/hex.dart';
-import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:web3dart/crypto.dart';
@@ -109,10 +107,6 @@ abstract class EVMChainWalletBase
this.walletInfo = walletInfo;
transactionHistory = setUpTransactionHistory(walletInfo, password, encryptionFileUtils);
- if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
- CakeHive.registerAdapter(Erc20TokenAdapter());
- }
-
sharedPrefs.complete(SharedPreferences.getInstance());
}
@@ -121,9 +115,7 @@ abstract class EVMChainWalletBase
final String _password;
final EncryptionFileUtils encryptionFileUtils;
- late final Box erc20TokensBox;
-
- late Box evmChainErc20TokensBox;
+ List _erc20Tokens = [];
late final Credentials _evmChainPrivateKey;
@@ -217,8 +209,8 @@ abstract class EVMChainWalletBase
// Automatically connect to node for the selected chain
await connectToNode(node: node);
- // Reload ERC20 tokens box for the new chain
- await initErc20TokensBox();
+ // Reload ERC20 tokens for the new chain
+ await initErc20Tokens();
// Reload transaction history from the new chain's file
await transactionHistory.init();
@@ -228,179 +220,52 @@ abstract class EVMChainWalletBase
await startSync();
}
- void addInitialTokens() {
+ Future addInitialTokens() async {
final initialErc20Tokens = EVMChainDefaultTokens.getDefaultTokensByChainId(selectedChainId);
for (final token in initialErc20Tokens) {
- if (!evmChainErc20TokensBox.containsKey(token.contractAddress)) {
- evmChainErc20TokensBox.put(token.contractAddress, token);
- } else {
- // update existing token
- final existingToken = evmChainErc20TokensBox.get(token.contractAddress);
- evmChainErc20TokensBox.put(
- token.contractAddress,
- Erc20Token.copyWith(token, enabled: existingToken!.enabled),
- );
- }
+ final existingToken = _findCachedToken(token.contractAddress);
+
+ final newToken = Erc20Token.copyWith(
+ token,
+ enabled: existingToken?.enabled ?? token.enabled,
+ walletName: walletInfo.name,
+ chainId: selectedChainId,
+ );
+
+ await newToken.save();
+ _upsertCachedToken(newToken);
}
}
List get getDefaultTokenContractAddresses =>
EVMChainDefaultTokens.getDefaultTokenAddresses(selectedChainId);
- Future initErc20TokensBox() async {
- // Migration for old WalletType.ethereum wallets:
- // Old wallets used a global erc20TokensBox (shared across all wallets).
- // New system uses wallet-specific, chain-specific boxes.
- // This checks if migration is needed and runs it once.
- if (walletInfo.type == WalletType.ethereum) {
- try {
- // Try to access erc20TokensBox - if it exists, migration already ran
- final _ = erc20TokensBox;
- // Migration done, proceed with normal chain-specific logic below
- } catch (_) {
- // erc20TokensBox doesn't exist yet, run migration from global box
- await _initEthereumErc20TokensBox();
- await _normalizeEvmChainErc20TokensBoxKeys();
- return;
- }
- }
+ Future initErc20Tokens() async {
+ _erc20Tokens = await Erc20Token.getAllForWallet(walletInfo.name, selectedChainId);
- final chainId = selectedChainId;
-
- final boxName = EVMChainUtils.getErc20TokensBoxName(walletInfo.name, chainId);
-
- // Close existing box if it's already open (for chain switching)
- try {
- if (evmChainErc20TokensBox.isOpen) {
- await evmChainErc20TokensBox.close();
- }
- } catch (_) {
- // Box might not be initialized yet, ignore
- }
-
- // Check if box is already open, if so use it, otherwise open it
- if (CakeHive.isBoxOpen(boxName)) {
- evmChainErc20TokensBox = CakeHive.box(boxName);
- } else {
- evmChainErc20TokensBox = await CakeHive.openBox(boxName);
- }
-
- await _normalizeEvmChainErc20TokensBoxKeys();
-
- addInitialTokens();
+ await addInitialTokens();
}
- /// Ethereum-specific initialization with backward compatibility
- Future _initEthereumErc20TokensBox() async {
- // Opens a box specific to this wallet
- evmChainErc20TokensBox = await CakeHive.openBox(
- "${walletInfo.name.replaceAll(" ", "_")}_${Erc20Token.ethereumBoxName}",
- );
+ Erc20Token? _findCachedToken(String contractAddress) {
+ final lowerAddress = contractAddress.toLowerCase();
- erc20TokensBox = await CakeHive.openBox(Erc20Token.boxName);
-
- if (erc20TokensBox.isEmpty) {
- if (evmChainErc20TokensBox.isEmpty) addInitialTokens();
- return;
+ for (final token in _erc20Tokens) {
+ if (token.contractAddress.toLowerCase() == lowerAddress) return token;
}
+ return null;
+ }
- final allValues = erc20TokensBox.values.toList();
+ void _upsertCachedToken(Erc20Token token) {
+ final lowerAddress = token.contractAddress.toLowerCase();
- // Clear and delete the old token box
- await erc20TokensBox.clear();
- await erc20TokensBox.deleteFromDisk();
-
- // Add all the previous tokens with configs to the new box
- await evmChainErc20TokensBox.addAll(allValues);
+ _erc20Tokens.removeWhere((t) => t.contractAddress.toLowerCase() == lowerAddress);
+ _erc20Tokens.add(token);
}
String getTransactionHistoryFileName() =>
EVMChainUtils.getTransactionHistoryFileName(selectedChainId);
- /// Ensures all ERC20 token entries use lowercase contract addresses as
- /// their Hive keys to avoid duplicates caused by case differences.
- Future _normalizeEvmChainErc20TokensBoxKeys() async {
- if (!evmChainErc20TokensBox.isOpen) return;
-
- final prefs = await sharedPrefs.future;
- final migrationKey = 'erc20_box_normalized_${walletInfo.name}_$selectedChainId';
-
- if (prefs.getBool(migrationKey) ?? false) return;
-
- final box = evmChainErc20TokensBox;
- final keys = box.keys.toList();
-
- if (keys.isEmpty) {
- await prefs.setBool(migrationKey, true);
- return;
- }
-
- final Map normalizedTokens = {};
- var needsRewrite = false;
-
- for (final key in keys) {
- final token = box.get(key);
-
- if (token == null) {
- needsRewrite = true;
- continue;
- }
-
- final lowerKey = key is String ? key.toLowerCase() : token.contractAddress.toLowerCase();
- if (key is int) needsRewrite = true;
-
- final Erc20Token normalizedToken =
- token.contractAddress == token.contractAddress.toLowerCase()
- ? token
- : Erc20Token(
- name: token.name,
- symbol: token.symbol,
- contractAddress: token.contractAddress.toLowerCase(),
- decimal: token.decimal,
- enabled: token.enabled,
- iconPath: token.iconPath,
- tag: token.tag,
- isPotentialScam: token.isPotentialScam,
- );
-
- if (!needsRewrite && (lowerKey != key || identical(normalizedToken, token) == false)) {
- needsRewrite = true;
- }
-
- final existing = normalizedTokens[lowerKey];
-
- if (existing == null) {
- normalizedTokens[lowerKey] = normalizedToken;
- continue;
- }
-
- final merged = Erc20Token(
- name: normalizedToken.name,
- symbol: normalizedToken.symbol,
- contractAddress: lowerKey,
- decimal: normalizedToken.decimal,
- enabled: normalizedToken.enabled || existing.enabled,
- iconPath: (normalizedToken.iconPath?.isNotEmpty ?? false)
- ? normalizedToken.iconPath
- : existing.iconPath,
- tag: normalizedToken.tag ?? existing.tag,
- isPotentialScam: normalizedToken.isPotentialScam || existing.isPotentialScam,
- );
-
- normalizedTokens[lowerKey] = merged;
- }
-
- if (needsRewrite) {
- await box.clear();
- for (final entry in normalizedTokens.entries) {
- await box.put(entry.key, entry.value);
- }
- }
-
- await prefs.setBool(migrationKey, true);
- }
-
Future checkIfScanProviderIsEnabled() async {
final key = EVMChainUtils.getScanProviderPreferenceKey(selectedChainId);
return (await sharedPrefs.future).getBool(key) ?? true;
@@ -451,6 +316,8 @@ abstract class EVMChainWalletBase
tag: token.tag ?? EVMChainUtils.getDefaultTokenTag(selectedChainId),
iconPath: iconPath,
isPotentialScam: token.isPotentialScam,
+ walletName: walletInfo.name,
+ chainId: selectedChainId,
);
}
@@ -499,7 +366,7 @@ abstract class EVMChainWalletBase
String idFor(String name, WalletType type) => '${walletTypeToString(type).toLowerCase()}_$name';
Future init() async {
- await initErc20TokensBox();
+ await initErc20Tokens();
await walletAddresses.init();
await transactionHistory.init();
@@ -669,8 +536,6 @@ abstract class EVMChainWalletBase
Future discoverTokensFromMoralis() async {
try {
- if (!evmChainErc20TokensBox.isOpen) return MoralisDiscoveryResult.empty;
-
final address = walletAddresses.address;
if (address.isEmpty) return MoralisDiscoveryResult.empty;
@@ -680,8 +545,7 @@ abstract class EVMChainWalletBase
if (walletTokens.isEmpty) return MoralisDiscoveryResult.empty;
final existingTokenAddresses = {
- for (final token in evmChainErc20TokensBox.values)
- token.contractAddress.toLowerCase(): token,
+ for (final token in _erc20Tokens) token.contractAddress.toLowerCase(): token,
};
final whitelistedTokenAddresses =
@@ -1419,32 +1283,21 @@ abstract class EVMChainWalletBase
}
Future _fetchErc20Balances() async {
- // Check if box is open before accessing it
- if (!evmChainErc20TokensBox.isOpen) {
- return;
- }
-
// First, clean up any tokens in balance map that don't belong to current chain
// This handles tokens from previous chains that might still be in the balance map
final tokensInBalance = balance.keys.whereType().toList();
- final tokensInBox = evmChainErc20TokensBox.values.toList();
- final boxTokenAddresses = tokensInBox.map((t) => t.contractAddress.toLowerCase()).toSet();
+ final tokens = _erc20Tokens.toList();
+ final cachedTokenAddresses = tokens.map((t) => t.contractAddress.toLowerCase()).toSet();
for (var token in tokensInBalance) {
- // Remove token if it's not in the current box or doesn't match current chain
- if (!boxTokenAddresses.contains(token.contractAddress.toLowerCase()) ||
+ // Remove token if it's not in the current token list or doesn't match current chain
+ if (!cachedTokenAddresses.contains(token.contractAddress.toLowerCase()) ||
!_isTokenMatchingChain(token)) {
balance.remove(token);
}
}
- // Get a snapshot of tokens from current box to avoid issues if box is closed during iteration
- final tokens = tokensInBox;
-
for (var token in tokens) {
- // Check if box is still open before operating on tokens
- if (!evmChainErc20TokensBox.isOpen) break;
-
if (!_isTokenMatchingChain(token)) {
printV('NOTEE!!!: Token ${token.title} is not matching the currency ${currency.title}');
try {
@@ -1532,15 +1385,7 @@ abstract class EVMChainWalletBase
@override
Future updateTransactionsHistory() async => await _updateTransactions();
- List get erc20Currencies {
- try {
- if (!evmChainErc20TokensBox.isOpen) return [];
-
- return evmChainErc20TokensBox.values.toList();
- } catch (_) {
- return [];
- }
- }
+ List get erc20Currencies => _erc20Tokens.toList();
Future addErc20Token(Erc20Token token) async {
final isSuspicious = isTokenPropertiesSuspicious(token);
@@ -1561,32 +1406,26 @@ abstract class EVMChainWalletBase
final newToken = createNewErc20TokenObject(token, iconPath);
if (newToken.enabled) {
- try {
- balance[newToken] = await _client.fetchERC20Balances(_evmChainPrivateKey.address, newToken);
+ balance[newToken] = await _client.fetchERC20Balances(_evmChainPrivateKey.address, newToken);
- await evmChainErc20TokensBox.put(newToken.contractAddress, newToken);
- } on Exception catch (_) {
- rethrow;
- }
+ await newToken.save();
} else {
- await evmChainErc20TokensBox.put(newToken.contractAddress, newToken);
+ await newToken.save();
balance.remove(newToken);
}
+
+ _upsertCachedToken(newToken);
}
Future deleteErc20Token(Erc20Token token, {bool shouldUpdateBalance = true}) async {
- // Check if box is open before trying to delete
- if (!evmChainErc20TokensBox.isOpen) {
- balance.remove(token);
- return;
+ try {
+ await Erc20Token.deleteForWallet(walletInfo.name, selectedChainId, token.contractAddress);
+ } catch (e) {
+ printV('Error deleting token: $e');
}
- try {
- await token.delete();
- } catch (e) {
- // Token might be from a closed box, just remove from balance
- printV('Error deleting token from box: $e');
- }
+ _erc20Tokens
+ .removeWhere((t) => t.contractAddress.toLowerCase() == token.contractAddress.toLowerCase());
balance.remove(token);
await removeTokenTransactionsInHistory(token);
diff --git a/cw_evm/lib/evm_chain_wallet_service.dart b/cw_evm/lib/evm_chain_wallet_service.dart
index 425bdceb8..ec52c5194 100644
--- a/cw_evm/lib/evm_chain_wallet_service.dart
+++ b/cw_evm/lib/evm_chain_wallet_service.dart
@@ -1,7 +1,8 @@
-import 'dart:io';
+import "dart:io";
import 'package:bip39/bip39.dart' as bip39;
import 'package:cw_core/encryption_file_utils.dart';
+import "package:cw_core/erc20_token.dart";
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart';
@@ -11,6 +12,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:path/path.dart' as p;
import 'package:cw_evm/clients/evm_chain_client.dart';
import 'package:cw_evm/evm_chain_client_factory.dart';
+import 'package:cw_evm/evm_chain_exceptions.dart';
import 'package:cw_evm/evm_chain_registry.dart';
import 'package:cw_evm/evm_chain_wallet.dart';
import 'package:cw_evm/evm_chain_wallet_creation_credentials.dart';
@@ -48,8 +50,8 @@ class EVMChainWalletService extends WalletService<
@override
WalletType getType() {
throw UnsupportedError(
- 'EVMChainWalletService is unified and does not have a single type. '
- 'Use walletInfo.type instead.',
+ "EVMChainWalletService is unified and does not have a single type. "
+ "Use walletInfo.type instead.",
);
}
@@ -59,7 +61,7 @@ class EVMChainWalletService extends WalletService<
Future saveBackup(String name, {WalletInfo? walletInfo}) async {
final info = walletInfo ?? await _findWalletByName(name);
if (info == null) {
- throw Exception('Wallet not found: $name');
+ throw Exception("Wallet not found: $name");
}
final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: info.type);
@@ -75,7 +77,7 @@ class EVMChainWalletService extends WalletService<
Future restoreWalletFilesFromBackup(String name) async {
final walletInfo = await _findWalletByName(name);
if (walletInfo == null) {
- throw Exception('Wallet not found: $name');
+ throw Exception("Wallet not found: $name");
}
final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: walletInfo.type);
@@ -96,7 +98,7 @@ class EVMChainWalletService extends WalletService<
// Get chainId from wallet type
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
if (chainConfig == null) {
- throw Exception('Chain config not found for wallet type: ${walletInfo.type}');
+ throw Exception("Chain config not found for wallet type: ${walletInfo.type}");
}
final initialChainId = chainConfig.chainId;
@@ -124,7 +126,7 @@ class EVMChainWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
}
@@ -133,7 +135,7 @@ class EVMChainWalletService extends WalletService<
Future openWallet(String name, String password) async {
final walletInfo = await _findWalletByName(name);
if (walletInfo == null) {
- throw Exception('Wallet not found');
+ throw Exception("Wallet not found");
}
try {
@@ -145,7 +147,7 @@ class EVMChainWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
await saveBackup(name);
return wallet;
@@ -160,7 +162,7 @@ class EVMChainWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
}
@@ -172,7 +174,7 @@ class EVMChainWalletService extends WalletService<
final currentWalletInfo = await _findWalletByName(currentName);
if (currentWalletInfo == null) {
- throw Exception('Wallet not found');
+ throw Exception("Wallet not found");
}
final type = currentWalletInfo.type;
@@ -184,6 +186,16 @@ class EVMChainWalletService extends WalletService<
currentWalletInfo.name = newName;
await currentWalletInfo.save();
+ final oldNameStillUsed = (await _findWalletByName(currentName)) != null;
+ if (oldNameStillUsed) {
+ for (final token in await Erc20Token.selectList("walletName = ?", [currentName])) {
+ final copiedToken = Erc20Token.copyWith(token, walletName: newName);
+ await copiedToken.save();
+ }
+ } else {
+ await Erc20Token.renameWallet(currentName, newName);
+ }
+
final oldDir = Directory(p.join(await pathForWalletTypeDir(type: type), currentName));
if (oldDir.existsSync()) {
try {
@@ -199,12 +211,16 @@ class EVMChainWalletService extends WalletService<
EVMChainRestoreWalletFromSeedCredentials credentials, {
bool? isTestnet,
}) async {
+ if (!bip39.validateMnemonic(credentials.mnemonic)) {
+ throw EVMChainMnemonicIsIncorrectException();
+ }
+
final walletInfo = credentials.walletInfo!;
// Get chainId from wallet type
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
if (chainConfig == null) {
- throw Exception('Chain config not found for wallet type: ${walletInfo.type}');
+ throw Exception("Chain config not found for wallet type: ${walletInfo.type}");
}
final initialChainId = chainConfig.chainId;
@@ -230,7 +246,7 @@ class EVMChainWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
}
@@ -245,7 +261,7 @@ class EVMChainWalletService extends WalletService<
// Get chainId from wallet type
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
if (chainConfig == null) {
- throw Exception('Chain config not found for wallet type: ${walletInfo.type}');
+ throw Exception("Chain config not found for wallet type: ${walletInfo.type}");
}
final initialChainId = chainConfig.chainId;
@@ -270,7 +286,7 @@ class EVMChainWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
}
@@ -284,7 +300,7 @@ class EVMChainWalletService extends WalletService<
// Get chainId from wallet type
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
if (chainConfig == null) {
- throw Exception('Chain config not found for wallet type: ${walletInfo.type}');
+ throw Exception("Chain config not found for wallet type: ${walletInfo.type}");
}
final initialChainId = chainConfig.chainId;
@@ -308,7 +324,7 @@ class EVMChainWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
}
@@ -327,11 +343,15 @@ class EVMChainWalletService extends WalletService<
Future remove(String wallet) async {
final walletInfo = await _findWalletByName(wallet);
if (walletInfo == null) {
- throw Exception('Wallet not found');
+ throw Exception("Wallet not found");
}
File(await pathForWalletDir(name: wallet, type: walletInfo.type)).delete(recursive: true);
await WalletInfo.delete(walletInfo);
+ final nameStillUsed = (await _findWalletByName(wallet)) != null;
+ if (!nameStillUsed) {
+ await Erc20Token.deleteAllForWallet(wallet);
+ }
}
EVMChainWallet _createWalletInstance({
@@ -349,7 +369,7 @@ class EVMChainWalletService extends WalletService<
final chainConfig = _registry.getChainConfigByWalletType(walletType);
if (chainConfig == null) {
- throw Exception('Chain config not found for wallet type: $walletType');
+ throw Exception("Chain config not found for wallet type: $walletType");
}
return EVMChainWallet(
diff --git a/cw_evm/lib/utils/evm_chain_utils.dart b/cw_evm/lib/utils/evm_chain_utils.dart
index 60355cabf..969ffc7b3 100644
--- a/cw_evm/lib/utils/evm_chain_utils.dart
+++ b/cw_evm/lib/utils/evm_chain_utils.dart
@@ -1,11 +1,9 @@
-import 'package:cw_core/erc20_token.dart';
-import 'package:cw_evm/evm_chain_transaction_priority.dart';
-import 'package:web3dart/web3dart.dart' show EtherAmount, EtherUnit;
+import "package:cw_evm/evm_chain_transaction_priority.dart";
+import "package:web3dart/web3dart.dart" show EtherAmount, EtherUnit;
/// Utility class for chain-specific EVM chain operations
class EVMChainUtils {
- static int getTotalPriorityFee(EVMChainTransactionPriority priority, int chainId) {
- return switch (chainId) {
+ static int getTotalPriorityFee(EVMChainTransactionPriority priority, int chainId) => switch (chainId) {
1 => _ethereumPriorityFee(priority),
137 => _polygonPriorityFee(priority),
8453 => _basePriorityFee(priority),
@@ -13,14 +11,11 @@ class EVMChainUtils {
42161 => 0, // Arbitrum doesn't use priority fees
_ => _ethereumPriorityFee(priority),
};
- }
- static bool hasPriorityFee(int chainId) {
- return switch (chainId) {
+ static bool hasPriorityFee(int chainId) => switch (chainId) {
42161 => false, // Arbitrum doesn't use priority fees
_ => true,
};
- }
static int computeBufferedMaxFeePerGasWei({
required int? gasBaseFee,
@@ -38,78 +33,53 @@ class EVMChainUtils {
return gasPrice + priorityFeeWei;
}
- static String getErc20TokensBoxName(String walletName, int chainId) {
- final sanitizedName = walletName.replaceAll(" ", "_");
-
- return switch (chainId) {
- 1 => "${sanitizedName}_${Erc20Token.ethereumBoxName}",
- 137 => "${sanitizedName}_${Erc20Token.polygonBoxName}",
- 8453 => "${sanitizedName}_${Erc20Token.baseBoxName}",
- 42161 => "${sanitizedName}_${Erc20Token.arbitrumBoxName}",
- 56 => "${sanitizedName}_${Erc20Token.bscBoxName}",
- _ => "${sanitizedName}_${Erc20Token.ethereumBoxName}",
+ static String getTransactionHistoryFileName(int chainId) => switch (chainId) {
+ 1 => "transactions.json", // Ethereum
+ 137 => "polygon_transactions.json",
+ 8453 => "base_transactions.json",
+ 42161 => "arbitrum_transactions.json",
+ 56 => "bsc_transactions.json",
+ _ => "transactions_$chainId.json", // Generic format for other chains
};
- }
-
- static String getTransactionHistoryFileName(int chainId) {
- return switch (chainId) {
- 1 => 'transactions.json', // Ethereum
- 137 => 'polygon_transactions.json',
- 8453 => 'base_transactions.json',
- 42161 => 'arbitrum_transactions.json',
- 56 => 'bsc_transactions.json',
- _ => 'transactions_$chainId.json', // Generic format for other chains
- };
- }
/// Get scan provider preference key for a wallet type
- static String getScanProviderPreferenceKey(int chainId) {
- return switch (chainId) {
- 1 => 'use_etherscan',
- 137 => 'use_polygonscan',
- 8453 => 'use_basescan',
- 42161 => 'use_arbiscan',
- 56 => 'use_bscscan',
- _ => 'use_etherscan',
+ static String getScanProviderPreferenceKey(int chainId) => switch (chainId) {
+ 1 => "use_etherscan",
+ 137 => "use_polygonscan",
+ 8453 => "use_basescan",
+ 42161 => "use_arbiscan",
+ 56 => "use_bscscan",
+ _ => "use_etherscan",
};
- }
- static String getDefaultTokenTag(int chainId) {
- return switch (chainId) {
- 1 => 'ETH',
- 137 => 'POL',
- 8453 => 'BASE',
- 42161 => 'ARB',
- 56 => 'BSC',
- _ => 'ETH',
+ static String getDefaultTokenTag(int chainId) => switch (chainId) {
+ 1 => "ETH",
+ 137 => "POL",
+ 8453 => "BASE",
+ 42161 => "ARB",
+ 56 => "BSC",
+ _ => "ETH",
};
- }
- static String getFeeCurrency(int chainId) {
- return switch (chainId) {
- 1 => 'ETH',
- 137 => 'POL',
- 8453 => 'ETH',
- 42161 => 'ETH',
- 56 => 'BNB',
- _ => 'ETH',
+ static String getFeeCurrency(int chainId) => switch (chainId) {
+ 1 => "ETH",
+ 137 => "POL",
+ 8453 => "ETH",
+ 42161 => "ETH",
+ 56 => "BNB",
+ _ => "ETH",
};
- }
- static String getDefaultTokenSymbol(int chainId) {
- return switch (chainId) {
- 1 => 'ETH',
- 137 => 'POL',
- 8453 => 'BASE',
- 42161 => 'ARBITRUM',
- 56 => 'BSC',
- _ => 'ETH',
+ static String getDefaultTokenSymbol(int chainId) => switch (chainId) {
+ 1 => "ETH",
+ 137 => "POL",
+ 8453 => "BASE",
+ 42161 => "ARBITRUM",
+ 56 => "BSC",
+ _ => "ETH",
};
- }
- static int _ethereumPriorityFee(EVMChainTransactionPriority priority) {
- return EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
- }
+ static int _ethereumPriorityFee(EVMChainTransactionPriority priority) => EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
// Polygon priority fee calculation (minimum 25 gwei + additional based on priority)
static int _polygonPriorityFee(EVMChainTransactionPriority priority) {
@@ -127,12 +97,10 @@ class EVMChainUtils {
return minPriorityFeeWei + additionalPriorityFee;
}
- static int _basePriorityFee(EVMChainTransactionPriority priority) {
- return switch (priority) {
+ static int _basePriorityFee(EVMChainTransactionPriority priority) => switch (priority) {
EVMChainTransactionPriority.fast => EtherAmount.fromInt(EtherUnit.mwei, 5).getInWei.toInt(),
EVMChainTransactionPriority.medium => EtherAmount.fromInt(EtherUnit.mwei, 3).getInWei.toInt(),
EVMChainTransactionPriority.slow => EtherAmount.fromInt(EtherUnit.mwei, 1).getInWei.toInt(),
_ => EtherAmount.fromInt(EtherUnit.mwei, 1).getInWei.toInt(),
};
- }
}
diff --git a/cw_evm/pubspec_overrides.yaml b/cw_evm/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_evm/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock
deleted file mode 100644
index 0cc1a9e19..000000000
--- a/cw_monero/pubspec.lock
+++ /dev/null
@@ -1,1052 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- _fe_analyzer_shared:
- dependency: transitive
- description:
- name: _fe_analyzer_shared
- sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e"
- url: "https://pub.dev"
- source: hosted
- version: "92.0.0"
- analyzer:
- dependency: transitive
- description:
- name: analyzer
- sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e"
- url: "https://pub.dev"
- source: hosted
- version: "9.0.0"
- args:
- dependency: transitive
- description:
- name: args
- sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- asn1lib:
- dependency: transitive
- description:
- name: asn1lib
- sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.8"
- async:
- dependency: transitive
- description:
- name: async
- sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
- url: "https://pub.dev"
- source: hosted
- version: "2.13.0"
- bech32:
- dependency: transitive
- description:
- path: "."
- ref: HEAD
- resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
- url: "https://github.com/cake-tech/bech32.git"
- source: git
- version: "0.2.2"
- bip32:
- dependency: "direct main"
- description:
- name: bip32
- sha256: "54787cd7a111e9d37394aabbf53d1fc5e2e0e0af2cd01c459147a97c0e3f8a97"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- bip39:
- dependency: "direct main"
- description:
- name: bip39
- sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc
- url: "https://pub.dev"
- source: hosted
- version: "1.0.6"
- blockchain_utils:
- dependency: transitive
- description:
- path: "."
- ref: cake-update-v2
- resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
- url: "https://github.com/cake-tech/blockchain_utils"
- source: git
- version: "3.3.0"
- bluez:
- dependency: transitive
- description:
- name: bluez
- sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545"
- url: "https://pub.dev"
- source: hosted
- version: "0.8.3"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- bs58check:
- dependency: transitive
- description:
- name: bs58check
- sha256: c4a164d42b25c2f6bc88a8beccb9fc7d01440f3c60ba23663a20a70faf484ea9
- url: "https://pub.dev"
- source: hosted
- version: "1.0.2"
- build:
- dependency: transitive
- description:
- name: build
- sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10
- url: "https://pub.dev"
- source: hosted
- version: "4.0.6"
- build_config:
- dependency: transitive
- description:
- name: build_config
- sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- build_daemon:
- dependency: transitive
- description:
- name: build_daemon
- sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
- build_runner:
- dependency: "direct dev"
- description:
- name: build_runner
- sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6"
- url: "https://pub.dev"
- source: hosted
- version: "2.15.0"
- built_collection:
- dependency: transitive
- description:
- name: built_collection
- sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
- url: "https://pub.dev"
- source: hosted
- version: "5.1.1"
- built_value:
- dependency: transitive
- description:
- name: built_value
- sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56"
- url: "https://pub.dev"
- source: hosted
- version: "8.12.6"
- cake_backup:
- dependency: transitive
- description:
- path: "."
- ref: main
- resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
- url: "https://github.com/cake-tech/cake_backup.git"
- source: git
- version: "1.0.0+1"
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- checked_yaml:
- dependency: transitive
- description:
- name: checked_yaml
- sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
- url: "https://pub.dev"
- source: hosted
- version: "2.0.3"
- clock:
- dependency: transitive
- description:
- name: clock
- sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- code_builder:
- dependency: transitive
- description:
- name: code_builder
- sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
- url: "https://pub.dev"
- source: hosted
- version: "4.10.1"
- collection:
- dependency: transitive
- description:
- name: collection
- sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
- url: "https://pub.dev"
- source: hosted
- version: "1.19.1"
- convert:
- dependency: transitive
- description:
- name: convert
- sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- crypto:
- dependency: transitive
- description:
- name: crypto
- sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.6"
- cryptography:
- dependency: transitive
- description:
- name: cryptography
- sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- cupertino_icons:
- dependency: transitive
- description:
- name: cupertino_icons
- sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
- url: "https://pub.dev"
- source: hosted
- version: "1.0.8"
- cw_core:
- dependency: "direct main"
- description:
- path: "../cw_core"
- relative: true
- source: path
- version: "0.0.1"
- dart_style:
- dependency: transitive
- description:
- name: dart_style
- sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
- dbus:
- dependency: transitive
- description:
- name: dbus
- sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.11"
- decimal:
- dependency: transitive
- description:
- name: decimal
- sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.3"
- encrypt:
- dependency: "direct main"
- description:
- name: encrypt
- sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.3"
- fake_async:
- dependency: transitive
- description:
- name: fake_async
- sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.3"
- fast_base58:
- dependency: transitive
- description:
- name: fast_base58
- sha256: "611f65633b734f27a850b51371b3eba993a5165650e12e8e7b02959f3768ba06"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.1"
- ffi:
- dependency: "direct main"
- description:
- name: ffi
- sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- file:
- dependency: transitive
- description:
- name: file
- sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
- url: "https://pub.dev"
- source: hosted
- version: "7.0.1"
- fixnum:
- dependency: transitive
- description:
- name: fixnum
- sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_mobx:
- dependency: "direct main"
- description:
- name: flutter_mobx
- sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_web_bluetooth:
- dependency: transitive
- description:
- name: flutter_web_bluetooth
- sha256: ad26a1b3fef95b86ea5f63793b9a0cdc1a33490f35d754e4e711046cae3ebbf8
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- glob:
- dependency: transitive
- description:
- name: glob
- sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- graphs:
- dependency: transitive
- description:
- name: graphs
- sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.2"
- hashlib:
- dependency: transitive
- description:
- name: hashlib
- sha256: e13e8237d93fb275cd1c55fc339bb90638994d1a4f140c7ee270173b51f3d169
- url: "https://pub.dev"
- source: hosted
- version: "1.21.1"
- hashlib_codecs:
- dependency: transitive
- description:
- name: hashlib_codecs
- sha256: "8cea9ccafcfeaa7324d2ae52c61c69f7ff71f4237507a018caab31b9e416e3b1"
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- hex:
- dependency: transitive
- description:
- name: hex
- sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.0"
- hive:
- dependency: "direct dev"
- description:
- name: hive
- sha256: "5184b6ea455689754578267c31c3b0b329cccf20a5f2bfdab6941c29c3d3c09a"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- http:
- dependency: "direct main"
- description:
- name: http
- sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- http_multi_server:
- dependency: transitive
- description:
- name: http_multi_server
- sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- http_parser:
- dependency: transitive
- description:
- name: http_parser
- sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
- intl:
- dependency: "direct main"
- description:
- name: intl
- sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
- url: "https://pub.dev"
- source: hosted
- version: "0.19.0"
- io:
- dependency: transitive
- description:
- name: io
- sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- js:
- dependency: transitive
- description:
- name: js
- sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
- url: "https://pub.dev"
- source: hosted
- version: "0.6.7"
- json_annotation:
- dependency: transitive
- description:
- name: json_annotation
- sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
- url: "https://pub.dev"
- source: hosted
- version: "4.9.0"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
- url: "https://pub.dev"
- source: hosted
- version: "11.0.2"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.10"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- ledger_flutter_plus:
- dependency: "direct main"
- description:
- name: ledger_flutter_plus
- sha256: "59c5a6062505c721c2ca909fa085c52cffe93de995174b8418b54a6acf52eb70"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.6"
- ledger_usb_plus:
- dependency: transitive
- description:
- name: ledger_usb_plus
- sha256: "911df2d1d55cdae612ff2c9db140cf71a9b28a67ba16adfdc4983cd9f02c531e"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.8"
- logging:
- dependency: transitive
- description:
- name: logging
- sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- matcher:
- dependency: transitive
- description:
- name: matcher
- sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
- url: "https://pub.dev"
- source: hosted
- version: "0.12.19"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
- url: "https://pub.dev"
- source: hosted
- version: "0.13.0"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
- url: "https://pub.dev"
- source: hosted
- version: "1.17.0"
- mime:
- dependency: transitive
- description:
- name: mime
- sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- mobx:
- dependency: "direct main"
- description:
- name: mobx
- sha256: "25ea9a3ee69243d578fb6288721d8eeb18550d0391c32f896d377d994154bff2"
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- mobx_codegen:
- dependency: "direct dev"
- description:
- name: mobx_codegen
- sha256: "6529bcae074838004b58ad01fbe4966be182a176aacfb723686985986ebac19f"
- url: "https://pub.dev"
- source: hosted
- version: "2.7.7"
- mockito:
- dependency: "direct dev"
- description:
- name: mockito
- sha256: eff30d002f0c8bf073b6f929df4483b543133fcafce056870163587b03f1d422
- url: "https://pub.dev"
- source: hosted
- version: "5.6.4"
- monero:
- dependency: "direct main"
- description:
- path: "impls/monero.dart"
- ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
- resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
- url: "https://github.com/mrcyjanek/monero_c.git"
- source: git
- version: "0.0.0"
- mutex:
- dependency: "direct main"
- description:
- name: mutex
- sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- nested:
- dependency: transitive
- description:
- name: nested
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- on_chain:
- dependency: transitive
- description:
- path: "."
- ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- url: "https://github.com/cake-tech/on_chain.git"
- source: git
- version: "3.7.0"
- package_config:
- dependency: transitive
- description:
- name: package_config
- sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- path:
- dependency: transitive
- description:
- name: path
- sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
- url: "https://pub.dev"
- source: hosted
- version: "1.9.1"
- path_provider:
- dependency: "direct main"
- description:
- name: path_provider
- sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- path_provider_android:
- dependency: transitive
- description:
- name: path_provider_android
- sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.15"
- path_provider_foundation:
- dependency: transitive
- description:
- name: path_provider_foundation
- sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- path_provider_linux:
- dependency: transitive
- description:
- name: path_provider_linux
- sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
- url: "https://pub.dev"
- source: hosted
- version: "2.2.1"
- path_provider_platform_interface:
- dependency: transitive
- description:
- name: path_provider_platform_interface
- sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- path_provider_windows:
- dependency: transitive
- description:
- name: path_provider_windows
- sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- petitparser:
- dependency: transitive
- description:
- name: petitparser
- sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
- url: "https://pub.dev"
- source: hosted
- version: "6.0.2"
- platform:
- dependency: transitive
- description:
- name: platform
- sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.6"
- plugin_platform_interface:
- dependency: transitive
- description:
- name: plugin_platform_interface
- sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.8"
- pointycastle:
- dependency: transitive
- description:
- name: pointycastle
- sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
- url: "https://pub.dev"
- source: hosted
- version: "3.9.1"
- polyseed:
- dependency: "direct main"
- description:
- name: polyseed
- sha256: ccc6ba0ed3976837e770a324a6295fbf3d7c0d05fc0fa1906e36479b07c2675b
- url: "https://pub.dev"
- source: hosted
- version: "0.0.7"
- pool:
- dependency: transitive
- description:
- name: pool
- sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.1"
- protobuf:
- dependency: transitive
- description:
- name: protobuf
- sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- provider:
- dependency: transitive
- description:
- name: provider
- sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
- url: "https://pub.dev"
- source: hosted
- version: "6.1.2"
- pub_semver:
- dependency: transitive
- description:
- name: pub_semver
- sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- pubspec_parse:
- dependency: transitive
- description:
- name: pubspec_parse
- sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- rational:
- dependency: transitive
- description:
- name: rational
- sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
- rxdart:
- dependency: transitive
- description:
- name: rxdart
- sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
- url: "https://pub.dev"
- source: hosted
- version: "0.28.0"
- shelf:
- dependency: transitive
- description:
- name: shelf
- sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- shelf_web_socket:
- dependency: transitive
- description:
- name: shelf_web_socket
- sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- socks5_proxy:
- dependency: transitive
- description:
- path: "."
- ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- url: "https://github.com/LacticWhale/socks_dart"
- source: git
- version: "2.1.0"
- socks_socket:
- dependency: transitive
- description:
- path: "."
- ref: e6232c53c1595469931ababa878759a067c02e94
- resolved-ref: e6232c53c1595469931ababa878759a067c02e94
- url: "https://github.com/sneurlax/socks_socket"
- source: git
- version: "1.1.1"
- source_gen:
- dependency: transitive
- description:
- name: source_gen
- sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02
- url: "https://pub.dev"
- source: hosted
- version: "4.2.3"
- source_span:
- dependency: transitive
- description:
- name: source_span
- sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
- url: "https://pub.dev"
- source: hosted
- version: "1.10.1"
- sqflite:
- dependency: transitive
- description:
- name: sqflite
- sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- sqflite_android:
- dependency: transitive
- description:
- name: sqflite_android
- sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqflite_common:
- dependency: transitive
- description:
- name: sqflite_common
- sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4+6"
- sqflite_common_ffi:
- dependency: "direct dev"
- description:
- name: sqflite_common_ffi
- sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.4+4"
- sqflite_darwin:
- dependency: transitive
- description:
- name: sqflite_darwin
- sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1+1"
- sqflite_platform_interface:
- dependency: transitive
- description:
- name: sqflite_platform_interface
- sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqlite3:
- dependency: transitive
- description:
- name: sqlite3
- sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
- url: "https://pub.dev"
- source: hosted
- version: "2.9.0"
- sqlite3_flutter_libs:
- dependency: transitive
- description:
- name: sqlite3_flutter_libs
- sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
- url: "https://pub.dev"
- source: hosted
- version: "0.5.40"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
- url: "https://pub.dev"
- source: hosted
- version: "1.12.1"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- stream_transform:
- dependency: transitive
- description:
- name: stream_transform
- sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
- url: "https://pub.dev"
- source: hosted
- version: "3.3.0+3"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.2"
- test_api:
- dependency: transitive
- description:
- name: test_api
- sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.10"
- torch_dart:
- dependency: transitive
- description:
- path: "../scripts/torch_dart"
- relative: true
- source: path
- version: "0.0.1"
- trezor_flutter:
- dependency: "direct main"
- description:
- path: trezor-flutter
- ref: "7a736320f6d53ad5c763734ab832d6bea560a327"
- resolved-ref: "7a736320f6d53ad5c763734ab832d6bea560a327"
- url: "https://github.com/cake-tech/trezor-flutter.git"
- source: git
- version: "0.1.0"
- trezor_usb_transport:
- dependency: transitive
- description:
- path: trezor_usb_transport
- ref: "7a736320f6d53ad5c763734ab832d6bea560a327"
- resolved-ref: "7a736320f6d53ad5c763734ab832d6bea560a327"
- url: "https://github.com/cake-tech/trezor-flutter.git"
- source: git
- version: "0.0.1"
- tuple:
- dependency: transitive
- description:
- name: tuple
- sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- universal_ble:
- dependency: transitive
- description:
- name: universal_ble
- sha256: "8325ca9f5cce2fba2b4efef74a4fcfe7144f303b409d6fc6ed16197b00a1a241"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.0"
- universal_platform:
- dependency: transitive
- description:
- name: universal_platform
- sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- unorm_dart:
- dependency: transitive
- description:
- name: unorm_dart
- sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
- url: "https://pub.dev"
- source: hosted
- version: "15.0.0"
- watcher:
- dependency: "direct overridden"
- description:
- name: watcher
- sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web:
- dependency: transitive
- description:
- name: web
- sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web_socket:
- dependency: transitive
- description:
- name: web_socket
- sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.6"
- web_socket_channel:
- dependency: transitive
- description:
- name: web_socket_channel
- sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- xdg_directories:
- dependency: transitive
- description:
- name: xdg_directories
- sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- xml:
- dependency: transitive
- description:
- name: xml
- sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
- url: "https://pub.dev"
- source: hosted
- version: "6.5.0"
- yaml:
- dependency: transitive
- description:
- name: yaml
- sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
-sdks:
- dart: ">=3.9.0 <4.0.0"
- flutter: ">=3.24.0"
diff --git a/cw_monero/pubspec_overrides.yaml b/cw_monero/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_monero/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_mweb/.gitignore b/cw_mweb/.gitignore
index 9d90768f5..0ec651641 100644
--- a/cw_mweb/.gitignore
+++ b/cw_mweb/.gitignore
@@ -22,8 +22,6 @@ migrate_working_dir/
#.vscode/
# Flutter/Dart/Pub related
-# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
-/pubspec.lock
**/doc/api/
.dart_tool/
.packages
diff --git a/cw_mweb/pubspec_overrides.yaml b/cw_mweb/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_mweb/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_nano/build.yaml b/cw_nano/build.yaml
new file mode 100644
index 000000000..81a9c96df
--- /dev/null
+++ b/cw_nano/build.yaml
@@ -0,0 +1,5 @@
+targets:
+ $default:
+ sources:
+ exclude:
+ - "**/.secrets.g.dart"
diff --git a/cw_nano/pubspec.lock b/cw_nano/pubspec.lock
deleted file mode 100644
index 509d74498..000000000
--- a/cw_nano/pubspec.lock
+++ /dev/null
@@ -1,991 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- _fe_analyzer_shared:
- dependency: transitive
- description:
- name: _fe_analyzer_shared
- sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
- url: "https://pub.dev"
- source: hosted
- version: "93.0.0"
- analyzer:
- dependency: transitive
- description:
- name: analyzer
- sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
- url: "https://pub.dev"
- source: hosted
- version: "10.0.1"
- args:
- dependency: transitive
- description:
- name: args
- sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- asn1lib:
- dependency: transitive
- description:
- name: asn1lib
- sha256: "1c296cd268f486cabcc3930e9b93a8133169305f18d722916e675959a88f6d2c"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.9"
- async:
- dependency: transitive
- description:
- name: async
- sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
- url: "https://pub.dev"
- source: hosted
- version: "2.13.0"
- bech32:
- dependency: transitive
- description:
- path: "."
- ref: HEAD
- resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
- url: "https://github.com/cake-tech/bech32.git"
- source: git
- version: "0.2.2"
- bip32:
- dependency: "direct main"
- description:
- name: bip32
- sha256: "54787cd7a111e9d37394aabbf53d1fc5e2e0e0af2cd01c459147a97c0e3f8a97"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- bip39:
- dependency: "direct main"
- description:
- name: bip39
- sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc
- url: "https://pub.dev"
- source: hosted
- version: "1.0.6"
- blockchain_utils:
- dependency: transitive
- description:
- path: "."
- ref: cake-update-v2
- resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
- url: "https://github.com/cake-tech/blockchain_utils"
- source: git
- version: "3.3.0"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- bs58check:
- dependency: transitive
- description:
- name: bs58check
- sha256: c4a164d42b25c2f6bc88a8beccb9fc7d01440f3c60ba23663a20a70faf484ea9
- url: "https://pub.dev"
- source: hosted
- version: "1.0.2"
- build:
- dependency: transitive
- description:
- name: build
- sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10
- url: "https://pub.dev"
- source: hosted
- version: "4.0.6"
- build_config:
- dependency: transitive
- description:
- name: build_config
- sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- build_daemon:
- dependency: transitive
- description:
- name: build_daemon
- sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.4"
- build_runner:
- dependency: "direct dev"
- description:
- name: build_runner
- sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6"
- url: "https://pub.dev"
- source: hosted
- version: "2.15.0"
- built_collection:
- dependency: transitive
- description:
- name: built_collection
- sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
- url: "https://pub.dev"
- source: hosted
- version: "5.1.1"
- built_value:
- dependency: transitive
- description:
- name: built_value
- sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
- url: "https://pub.dev"
- source: hosted
- version: "8.10.1"
- cake_backup:
- dependency: transitive
- description:
- path: "."
- ref: main
- resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
- url: "https://github.com/cake-tech/cake_backup.git"
- source: git
- version: "1.0.0+1"
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- checked_yaml:
- dependency: transitive
- description:
- name: checked_yaml
- sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
- url: "https://pub.dev"
- source: hosted
- version: "2.0.3"
- clock:
- dependency: transitive
- description:
- name: clock
- sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- collection:
- dependency: transitive
- description:
- name: collection
- sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
- url: "https://pub.dev"
- source: hosted
- version: "1.19.1"
- convert:
- dependency: transitive
- description:
- name: convert
- sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- crypto:
- dependency: transitive
- description:
- name: crypto
- sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.6"
- cryptography:
- dependency: transitive
- description:
- name: cryptography
- sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- cupertino_icons:
- dependency: transitive
- description:
- name: cupertino_icons
- sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
- url: "https://pub.dev"
- source: hosted
- version: "1.0.8"
- cw_core:
- dependency: "direct main"
- description:
- path: "../cw_core"
- relative: true
- source: path
- version: "0.0.1"
- dart_style:
- dependency: transitive
- description:
- name: dart_style
- sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.7"
- decimal:
- dependency: "direct main"
- description:
- name: decimal
- sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.3"
- ed25519_hd_key:
- dependency: "direct main"
- description:
- name: ed25519_hd_key
- sha256: "31e191ec97492873067e46dc9cc0c7d55170559c83a478400feffa0627acaccf"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- encrypt:
- dependency: transitive
- description:
- name: encrypt
- sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.3"
- fake_async:
- dependency: transitive
- description:
- name: fake_async
- sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.3"
- ffi:
- dependency: transitive
- description:
- name: ffi
- sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- file:
- dependency: transitive
- description:
- name: file
- sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
- url: "https://pub.dev"
- source: hosted
- version: "7.0.1"
- fixnum:
- dependency: transitive
- description:
- name: fixnum
- sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- fixnum_nanodart:
- dependency: transitive
- description:
- name: fixnum_nanodart
- sha256: "4b0132d11ecddc0d2ca64b6d7dee6726db432ed02cac1349d7532a08be5c54fc"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_mobx:
- dependency: transitive
- description:
- name: flutter_mobx
- sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_web_plugins:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- glob:
- dependency: transitive
- description:
- name: glob
- sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- graphs:
- dependency: transitive
- description:
- name: graphs
- sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.2"
- hex:
- dependency: "direct main"
- description:
- name: hex
- sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.0"
- hive:
- dependency: "direct dev"
- description:
- name: hive
- sha256: "5184b6ea455689754578267c31c3b0b329cccf20a5f2bfdab6941c29c3d3c09a"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- http:
- dependency: "direct main"
- description:
- name: http
- sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- http_multi_server:
- dependency: transitive
- description:
- name: http_multi_server
- sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- http_parser:
- dependency: transitive
- description:
- name: http_parser
- sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
- url: "https://pub.dev"
- source: hosted
- version: "4.1.2"
- intl:
- dependency: transitive
- description:
- name: intl
- sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
- url: "https://pub.dev"
- source: hosted
- version: "0.19.0"
- io:
- dependency: transitive
- description:
- name: io
- sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- js:
- dependency: transitive
- description:
- name: js
- sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
- url: "https://pub.dev"
- source: hosted
- version: "0.6.7"
- json_annotation:
- dependency: transitive
- description:
- name: json_annotation
- sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
- url: "https://pub.dev"
- source: hosted
- version: "4.9.0"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
- url: "https://pub.dev"
- source: hosted
- version: "11.0.2"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.10"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- libcrypto:
- dependency: "direct main"
- description:
- name: libcrypto
- sha256: "18a97db8d88147b0b60d2755f29b5e4944181c4c1a9f52bd1ecbea1b0a5aab03"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.2"
- logging:
- dependency: transitive
- description:
- name: logging
- sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- matcher:
- dependency: transitive
- description:
- name: matcher
- sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
- url: "https://pub.dev"
- source: hosted
- version: "0.12.19"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
- url: "https://pub.dev"
- source: hosted
- version: "0.13.0"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
- url: "https://pub.dev"
- source: hosted
- version: "1.17.0"
- mime:
- dependency: transitive
- description:
- name: mime
- sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- mobx:
- dependency: "direct main"
- description:
- name: mobx
- sha256: "25ea9a3ee69243d578fb6288721d8eeb18550d0391c32f896d377d994154bff2"
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- mobx_codegen:
- dependency: "direct dev"
- description:
- name: mobx_codegen
- sha256: "6529bcae074838004b58ad01fbe4966be182a176aacfb723686985986ebac19f"
- url: "https://pub.dev"
- source: hosted
- version: "2.7.7"
- nanodart:
- dependency: transitive
- description:
- name: nanodart
- sha256: "4b2f42d60307b54e8cf384d6193a567d07f8efd773858c0d5948246153c13282"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- nanoutil:
- dependency: "direct main"
- description:
- path: "."
- ref: c01a9c552917008d8fbc6b540db657031625b04f
- resolved-ref: c01a9c552917008d8fbc6b540db657031625b04f
- url: "https://github.com/perishllc/nanoutil.git"
- source: git
- version: "1.0.3"
- nested:
- dependency: transitive
- description:
- name: nested
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- on_chain:
- dependency: transitive
- description:
- path: "."
- ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- url: "https://github.com/cake-tech/on_chain.git"
- source: git
- version: "3.7.0"
- package_config:
- dependency: transitive
- description:
- name: package_config
- sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- path:
- dependency: transitive
- description:
- name: path
- sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
- url: "https://pub.dev"
- source: hosted
- version: "1.9.1"
- path_provider:
- dependency: transitive
- description:
- name: path_provider
- sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- path_provider_android:
- dependency: transitive
- description:
- name: path_provider_android
- sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
- url: "https://pub.dev"
- source: hosted
- version: "2.2.17"
- path_provider_foundation:
- dependency: transitive
- description:
- name: path_provider_foundation
- sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- path_provider_linux:
- dependency: transitive
- description:
- name: path_provider_linux
- sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
- url: "https://pub.dev"
- source: hosted
- version: "2.2.1"
- path_provider_platform_interface:
- dependency: transitive
- description:
- name: path_provider_platform_interface
- sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- path_provider_windows:
- dependency: transitive
- description:
- name: path_provider_windows
- sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- pinenacl:
- dependency: transitive
- description:
- name: pinenacl
- sha256: "57e907beaacbc3c024a098910b6240758e899674de07d6949a67b52fd984cbdf"
- url: "https://pub.dev"
- source: hosted
- version: "0.6.0"
- platform:
- dependency: transitive
- description:
- name: platform
- sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.6"
- plugin_platform_interface:
- dependency: transitive
- description:
- name: plugin_platform_interface
- sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.8"
- pointycastle:
- dependency: transitive
- description:
- name: pointycastle
- sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
- url: "https://pub.dev"
- source: hosted
- version: "3.9.1"
- pool:
- dependency: transitive
- description:
- name: pool
- sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.1"
- provider:
- dependency: transitive
- description:
- name: provider
- sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
- url: "https://pub.dev"
- source: hosted
- version: "6.1.5"
- pub_semver:
- dependency: transitive
- description:
- name: pub_semver
- sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- pubspec_parse:
- dependency: transitive
- description:
- name: pubspec_parse
- sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.0"
- rational:
- dependency: transitive
- description:
- name: rational
- sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
- shared_preferences:
- dependency: "direct main"
- description:
- name: shared_preferences
- sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.3"
- shared_preferences_android:
- dependency: transitive
- description:
- name: shared_preferences_android
- sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.10"
- shared_preferences_foundation:
- dependency: transitive
- description:
- name: shared_preferences_foundation
- sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4"
- shared_preferences_linux:
- dependency: transitive
- description:
- name: shared_preferences_linux
- sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shared_preferences_platform_interface:
- dependency: transitive
- description:
- name: shared_preferences_platform_interface
- sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shared_preferences_web:
- dependency: transitive
- description:
- name: shared_preferences_web
- sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
- url: "https://pub.dev"
- source: hosted
- version: "2.4.3"
- shared_preferences_windows:
- dependency: transitive
- description:
- name: shared_preferences_windows
- sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shelf:
- dependency: transitive
- description:
- name: shelf
- sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
- url: "https://pub.dev"
- source: hosted
- version: "1.4.2"
- shelf_web_socket:
- dependency: transitive
- description:
- name: shelf_web_socket
- sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.0"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- socks5_proxy:
- dependency: transitive
- description:
- path: "."
- ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- url: "https://github.com/LacticWhale/socks_dart"
- source: git
- version: "2.1.0"
- socks_socket:
- dependency: transitive
- description:
- path: "."
- ref: e6232c53c1595469931ababa878759a067c02e94
- resolved-ref: e6232c53c1595469931ababa878759a067c02e94
- url: "https://github.com/sneurlax/socks_socket"
- source: git
- version: "1.1.1"
- source_gen:
- dependency: transitive
- description:
- name: source_gen
- sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02
- url: "https://pub.dev"
- source: hosted
- version: "4.2.3"
- source_span:
- dependency: transitive
- description:
- name: source_span
- sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
- url: "https://pub.dev"
- source: hosted
- version: "1.10.1"
- sqflite:
- dependency: transitive
- description:
- name: sqflite
- sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- sqflite_android:
- dependency: transitive
- description:
- name: sqflite_android
- sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqflite_common:
- dependency: transitive
- description:
- name: sqflite_common
- sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4+6"
- sqflite_common_ffi:
- dependency: transitive
- description:
- name: sqflite_common_ffi
- sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.4+4"
- sqflite_darwin:
- dependency: transitive
- description:
- name: sqflite_darwin
- sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1+1"
- sqflite_platform_interface:
- dependency: transitive
- description:
- name: sqflite_platform_interface
- sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqlite3:
- dependency: transitive
- description:
- name: sqlite3
- sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
- url: "https://pub.dev"
- source: hosted
- version: "2.9.0"
- sqlite3_flutter_libs:
- dependency: transitive
- description:
- name: sqlite3_flutter_libs
- sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
- url: "https://pub.dev"
- source: hosted
- version: "0.5.40"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
- url: "https://pub.dev"
- source: hosted
- version: "1.12.1"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- stream_transform:
- dependency: transitive
- description:
- name: stream_transform
- sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
- url: "https://pub.dev"
- source: hosted
- version: "3.3.0+3"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.2"
- test_api:
- dependency: transitive
- description:
- name: test_api
- sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.10"
- torch_dart:
- dependency: transitive
- description:
- path: "../scripts/torch_dart"
- relative: true
- source: path
- version: "0.0.1"
- tuple:
- dependency: transitive
- description:
- name: tuple
- sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- unorm_dart:
- dependency: transitive
- description:
- name: unorm_dart
- sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
- url: "https://pub.dev"
- source: hosted
- version: "15.0.0"
- watcher:
- dependency: "direct overridden"
- description:
- name: watcher
- sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web:
- dependency: transitive
- description:
- name: web
- sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web_socket:
- dependency: transitive
- description:
- name: web_socket
- sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.1"
- web_socket_channel:
- dependency: transitive
- description:
- name: web_socket_channel
- sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
- url: "https://pub.dev"
- source: hosted
- version: "3.0.3"
- xdg_directories:
- dependency: transitive
- description:
- name: xdg_directories
- sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- yaml:
- dependency: transitive
- description:
- name: yaml
- sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
-sdks:
- dart: ">=3.10.0 <4.0.0"
- flutter: ">=3.27.0"
diff --git a/cw_nano/pubspec_overrides.yaml b/cw_nano/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_nano/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_shared_external/pubspec.lock b/cw_shared_external/pubspec.lock
deleted file mode 100644
index 203ecd5c3..000000000
--- a/cw_shared_external/pubspec.lock
+++ /dev/null
@@ -1,189 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- async:
- dependency: transitive
- description:
- name: async
- sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
- url: "https://pub.dev"
- source: hosted
- version: "2.11.0"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- clock:
- dependency: transitive
- description:
- name: clock
- sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- collection:
- dependency: transitive
- description:
- name: collection
- sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
- url: "https://pub.dev"
- source: hosted
- version: "1.18.0"
- fake_async:
- dependency: transitive
- description:
- name: fake_async
- sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.1"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
- url: "https://pub.dev"
- source: hosted
- version: "10.0.4"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.3"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.1"
- matcher:
- dependency: transitive
- description:
- name: matcher
- sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
- url: "https://pub.dev"
- source: hosted
- version: "0.12.16+1"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
- url: "https://pub.dev"
- source: hosted
- version: "0.8.0"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
- url: "https://pub.dev"
- source: hosted
- version: "1.12.0"
- path:
- dependency: transitive
- description:
- name: path
- sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
- url: "https://pub.dev"
- source: hosted
- version: "1.9.0"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.99"
- source_span:
- dependency: transitive
- description:
- name: source_span
- sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
- url: "https://pub.dev"
- source: hosted
- version: "1.10.0"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
- url: "https://pub.dev"
- source: hosted
- version: "1.11.1"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.0"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
- url: "https://pub.dev"
- source: hosted
- version: "1.2.1"
- test_api:
- dependency: transitive
- description:
- name: test_api
- sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.0"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
- url: "https://pub.dev"
- source: hosted
- version: "14.2.1"
-sdks:
- dart: ">=3.3.0 <4.0.0"
- flutter: ">=3.18.0-18.0.pre.54"
diff --git a/cw_shared_external/pubspec_overrides.yaml b/cw_shared_external/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_shared_external/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_solana/.gitignore b/cw_solana/.gitignore
index 96486fd93..32aee4b25 100644
--- a/cw_solana/.gitignore
+++ b/cw_solana/.gitignore
@@ -22,8 +22,6 @@ migrate_working_dir/
#.vscode/
# Flutter/Dart/Pub related
-# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
-/pubspec.lock
**/doc/api/
.dart_tool/
.packages
diff --git a/cw_solana/build.yaml b/cw_solana/build.yaml
new file mode 100644
index 000000000..81a9c96df
--- /dev/null
+++ b/cw_solana/build.yaml
@@ -0,0 +1,5 @@
+targets:
+ $default:
+ sources:
+ exclude:
+ - "**/.secrets.g.dart"
diff --git a/cw_solana/lib/solana_wallet.dart b/cw_solana/lib/solana_wallet.dart
index 31a1bc3d2..b41ee421c 100644
--- a/cw_solana/lib/solana_wallet.dart
+++ b/cw_solana/lib/solana_wallet.dart
@@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:convert';
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';
@@ -28,7 +27,6 @@ import 'package:cw_solana/solana_transaction_model.dart';
import 'package:cw_solana/solana_wallet_addresses.dart';
import 'package:cw_core/spl_token.dart';
import 'package:hex/hex.dart';
-import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:on_chain/solana/solana.dart' hide Store;
@@ -67,10 +65,6 @@ abstract class SolanaWalletBase
encryptionFileUtils: encryptionFileUtils,
);
- if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
- CakeHive.registerAdapter(SPLTokenAdapter());
- }
-
_sharedPrefs.complete(SharedPreferences.getInstance());
}
@@ -90,7 +84,7 @@ abstract class SolanaWalletBase
Future? _currentRefresh;
- late final Box splTokensBox;
+ List _splTokens = [];
@override
WalletAddresses walletAddresses;
@@ -133,9 +127,7 @@ abstract class SolanaWalletBase
);
Future init() async {
- final boxName = "${walletInfo.name.replaceAll(" ", "_")}_${SPLToken.boxName}";
-
- splTokensBox = await CakeHive.openBox(boxName);
+ _splTokens = await SPLToken.getAllForWallet(walletInfo.name);
await _checkForExistingScamTokens();
@@ -160,8 +152,6 @@ abstract class SolanaWalletBase
String get _scamCheckDoneKey => 'solana_scam_check_v2_done_${walletInfo.name}';
Future _checkForExistingScamTokens() async {
- if (!splTokensBox.isOpen) return;
-
final prefs = await _sharedPrefs.future;
if (prefs.getBool(_scamCheckDoneKey) == true) return;
@@ -169,7 +159,7 @@ abstract class SolanaWalletBase
final defaultSymbolsUpper =
DefaultSPLTokens().initialSPLTokens.map((t) => t.symbol.toUpperCase()).toSet();
- for (final token in splTokensBox.values) {
+ for (final token in _splTokens) {
final suspicious = isTokenPropertiesSuspicious(
token,
cachedDefaultMints: defaultMints,
@@ -421,7 +411,7 @@ abstract class SolanaWalletBase
}
Future updateSPLTokenTransactions({List? specificMints}) async {
- final allTokens = splTokensBox.values.where((t) => t.enabled).toList(growable: false);
+ final allTokens = _splTokens.where((t) => t.enabled).toList(growable: false);
// Filter to specific mints if provided
final tokens = specificMints != null
@@ -618,11 +608,11 @@ abstract class SolanaWalletBase
List? tokenMints,
}) async {
// Remove disabled tokens first to keep state clean
- for (var token in splTokensBox.values.where((t) => !t.enabled)) {
+ for (var token in _splTokens.where((t) => !t.enabled)) {
balance.remove(token);
}
- final enabledTokens = splTokensBox.values.where((t) => t.enabled).toList(growable: false);
+ final enabledTokens = _splTokens.where((t) => t.enabled).toList(growable: false);
if (enabledTokens.isEmpty) return;
final tokens = tokenMints == null || tokenMints.isEmpty
@@ -677,35 +667,48 @@ abstract class SolanaWalletBase
}
}
- List get splTokenCurrencies => splTokensBox.values.toList();
+ List get splTokenCurrencies => _splTokens.toList();
SPLToken? splTokenBySymbol(String symbol) {
- for (final token in splTokensBox.values) {
+ for (final token in _splTokens) {
if (token.symbol == symbol) return token;
}
return null;
}
- void addInitialTokens() {
+ SPLToken? _findCachedToken(String mintAddress) {
+ for (final token in _splTokens) {
+ if (token.mintAddress == mintAddress) return token;
+ }
+
+ return null;
+ }
+
+ void _upsertCachedToken(SPLToken token) {
+ _splTokens.removeWhere((t) => t.mintAddress == token.mintAddress);
+ _splTokens.add(token);
+ }
+
+ Future addInitialTokens() async {
final initialSPLTokens = DefaultSPLTokens().initialSPLTokens;
for (var token in initialSPLTokens) {
- if (!splTokensBox.containsKey(token.mintAddress)) {
- splTokensBox.put(token.mintAddress, token);
- } else {
- // update existing token
- final existingToken = splTokensBox.get(token.mintAddress);
- splTokensBox.put(
- token.mintAddress, SPLToken.copyWith(token, enabled: existingToken!.enabled));
- }
+ final existingToken = _findCachedToken(token.mintAddress);
+
+ final newToken = SPLToken.copyWith(
+ token,
+ enabled: existingToken?.enabled ?? token.enabled,
+ walletName: walletInfo.name,
+ );
+
+ await newToken.save();
+ _upsertCachedToken(newToken);
}
}
Future discoverTokensFromMoralis() async {
try {
- if (!splTokensBox.isOpen) return SolanaMoralisDiscoveryResult.empty;
-
final address = walletAddresses.address;
if (address.isEmpty) return SolanaMoralisDiscoveryResult.empty;
@@ -713,7 +716,7 @@ abstract class SolanaWalletBase
if (walletTokens.isEmpty) return SolanaMoralisDiscoveryResult.empty;
final existingMints = {
- for (final token in splTokensBox.values) token.mintAddress: token,
+ for (final token in _splTokens) token.mintAddress: token,
};
final defaultMints = DefaultSPLTokens().initialSPLTokens.map((t) => t.mintAddress).toSet();
@@ -849,7 +852,9 @@ abstract class SolanaWalletBase
final isSuspicious = isTokenPropertiesSuspicious(token);
token.isPotentialScam = token.isPotentialScam || isSuspicious;
- await splTokensBox.put(token.mintAddress, token);
+ token.walletName = walletInfo.name;
+ await token.save();
+ _upsertCachedToken(token);
if (token.enabled) {
final tokenBalance = await _client.getSplTokenBalance(token, solanaAddress) ??
@@ -869,13 +874,10 @@ abstract class SolanaWalletBase
sources.add(_nativeSource);
}
- if (splTokensBox.isOpen) {
- sources.addAll(splTokensBox.values
- .where((t) => t.symbol == token.symbol)
- .map((t) => t.mintAddress));
+ sources.addAll(_splTokens.where((t) => t.symbol == token.symbol).map((t) => t.mintAddress));
- await splTokensBox.delete(token.mintAddress);
- }
+ await SPLToken.deleteForWallet(walletInfo.name, token.mintAddress);
+ _splTokens.removeWhere((t) => t.mintAddress == token.mintAddress);
balance.remove(token);
await _removeTokenTransactionsInHistory(token);
diff --git a/cw_solana/lib/solana_wallet_service.dart b/cw_solana/lib/solana_wallet_service.dart
index 1ed55c411..a557507f5 100644
--- a/cw_solana/lib/solana_wallet_service.dart
+++ b/cw_solana/lib/solana_wallet_service.dart
@@ -4,6 +4,7 @@ import 'package:bip39/bip39.dart' as bip39;
import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/pathForWallet.dart';
+import 'package:cw_core/spl_token.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_base.dart';
@@ -40,7 +41,7 @@ class SolanaWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
}
@@ -68,7 +69,7 @@ class SolanaWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
saveBackup(name);
return wallet;
@@ -83,7 +84,7 @@ class SolanaWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
}
@@ -97,6 +98,11 @@ class SolanaWalletService extends WalletService<
throw Exception('Wallet not found');
}
await WalletInfo.delete(walletInfo);
+ final nameStillUsed = await WalletInfo.get(wallet, getType()) != null;
+ if (!nameStillUsed) {
+ await SPLToken.deleteAllForWallet(wallet);
+ }
+
final prefs = await SharedPreferences.getInstance();
for (final key in prefs.getKeys().where(
(k) => k.startsWith('solana_last_synced_signature_${wallet}_'))) {
@@ -116,7 +122,7 @@ class SolanaWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
@@ -139,7 +145,7 @@ class SolanaWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
diff --git a/cw_solana/pubspec.yaml b/cw_solana/pubspec.yaml
index 1d0572ddd..e1e00d35d 100644
--- a/cw_solana/pubspec.yaml
+++ b/cw_solana/pubspec.yaml
@@ -27,7 +27,7 @@ dependencies:
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
- ref: cake-update-v2
+ ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
dev_dependencies:
flutter_test:
diff --git a/cw_solana/pubspec_overrides.yaml b/cw_solana/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_solana/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_tron/.gitignore b/cw_tron/.gitignore
index 96486fd93..32aee4b25 100644
--- a/cw_tron/.gitignore
+++ b/cw_tron/.gitignore
@@ -22,8 +22,6 @@ migrate_working_dir/
#.vscode/
# Flutter/Dart/Pub related
-# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
-/pubspec.lock
**/doc/api/
.dart_tool/
.packages
diff --git a/cw_tron/build.yaml b/cw_tron/build.yaml
new file mode 100644
index 000000000..81a9c96df
--- /dev/null
+++ b/cw_tron/build.yaml
@@ -0,0 +1,5 @@
+targets:
+ $default:
+ sources:
+ exclude:
+ - "**/.secrets.g.dart"
diff --git a/cw_tron/lib/tron_wallet.dart b/cw_tron/lib/tron_wallet.dart
index 6da85fe15..32ff8c75c 100644
--- a/cw_tron/lib/tron_wallet.dart
+++ b/cw_tron/lib/tron_wallet.dart
@@ -5,7 +5,6 @@ import 'dart:developer';
import 'package:bip39/bip39.dart' as bip39;
import 'package:blockchain_utils/blockchain_utils.dart';
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';
@@ -29,7 +28,6 @@ import 'package:cw_tron/tron_transaction_credentials.dart';
import 'package:cw_tron/tron_transaction_history.dart';
import 'package:cw_tron/tron_transaction_info.dart';
import 'package:cw_tron/tron_wallet_addresses.dart';
-import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:on_chain/on_chain.dart';
@@ -62,10 +60,6 @@ abstract class TronWalletBase
this.walletInfo = walletInfo;
transactionHistory = TronTransactionHistory(
walletInfo: walletInfo, password: password, encryptionFileUtils: encryptionFileUtils);
-
- if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
- CakeHive.registerAdapter(TronTokenAdapter());
- }
}
final String? _mnemonic;
@@ -73,7 +67,7 @@ abstract class TronWalletBase
final String _password;
final EncryptionFileUtils encryptionFileUtils;
- late final Box tronTokensBox;
+ List _tronTokens = [];
late final TronPrivateKey _tronPrivateKey;
@@ -107,7 +101,7 @@ abstract class TronWalletBase
late ObservableMap balance;
Future init() async {
- await initTronTokensBox();
+ await initTronTokens();
await walletAddresses.init();
await transactionHistory.init();
@@ -179,25 +173,38 @@ abstract class TronWalletBase
);
}
- void addInitialTokens() {
+ Future addInitialTokens() async {
final initialTronTokens = DefaultTronTokens().initialTronTokens;
for (var token in initialTronTokens) {
- if (!tronTokensBox.containsKey(token.contractAddress)) {
- tronTokensBox.put(token.contractAddress, token);
- } else {
- // update existing token
- final existingToken = tronTokensBox.get(token.contractAddress);
- tronTokensBox.put(
- token.contractAddress, TronToken.copyWith(token, enabled: existingToken!.enabled));
- }
+ final existingToken = _findCachedToken(token.contractAddress);
+
+ final newToken = TronToken.copyWith(
+ token,
+ enabled: existingToken?.enabled ?? token.enabled,
+ walletName: walletInfo.name,
+ );
+
+ await newToken.save();
+ _upsertCachedToken(newToken);
}
}
- Future initTronTokensBox() async {
- final boxName = "${walletInfo.name.replaceAll(" ", "_")}_${TronToken.boxName}";
+ Future initTronTokens() async {
+ _tronTokens = await TronToken.getAllForWallet(walletInfo.name);
+ }
- tronTokensBox = await CakeHive.openBox(boxName);
+ TronToken? _findCachedToken(String contractAddress) {
+ for (final token in _tronTokens) {
+ if (token.contractAddress == contractAddress) return token;
+ }
+
+ return null;
+ }
+
+ void _upsertCachedToken(TronToken token) {
+ _tronTokens.removeWhere((t) => t.contractAddress == token.contractAddress);
+ _tronTokens.add(token);
}
String idFor(String name, WalletType type) => '${walletTypeToString(type).toLowerCase()}_$name';
@@ -516,7 +523,7 @@ abstract class TronWalletBase
}
Future _fetchTronTokenBalances() async {
- for (var token in tronTokensBox.values) {
+ for (var token in _tronTokens.toList()) {
try {
if (token.enabled) {
balance[token] = await _client.fetchTronTokenBalances(
@@ -551,7 +558,7 @@ abstract class TronWalletBase
}
}
- List get tronTokenCurrencies => tronTokensBox.values.toList();
+ List get tronTokenCurrencies => _tronTokens.toList();
Future addTronToken(TronToken token) async {
String? iconPath;
@@ -574,9 +581,11 @@ abstract class TronWalletBase
tag: token.tag ?? "TRX",
iconPath: iconPath,
isPotentialScam: token.isPotentialScam,
+ walletName: walletInfo.name,
);
- await tronTokensBox.put(newToken.contractAddress, newToken);
+ await newToken.save();
+ _upsertCachedToken(newToken);
if (newToken.enabled) {
balance[newToken] = await _client
@@ -587,9 +596,8 @@ abstract class TronWalletBase
}
Future deleteTronToken(TronToken token) async {
- if (tronTokensBox.isOpen) {
- await tronTokensBox.delete(token.contractAddress);
- }
+ await TronToken.deleteForWallet(walletInfo.name, token.contractAddress);
+ _tronTokens.removeWhere((t) => t.contractAddress == token.contractAddress);
balance.remove(token);
await _removeTokenTransactionsInHistory(token);
diff --git a/cw_tron/lib/tron_wallet_service.dart b/cw_tron/lib/tron_wallet_service.dart
index 9b81a9a57..5c2e30a82 100644
--- a/cw_tron/lib/tron_wallet_service.dart
+++ b/cw_tron/lib/tron_wallet_service.dart
@@ -6,6 +6,7 @@ import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart';
+import 'package:cw_core/tron_token.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_service.dart';
@@ -45,7 +46,7 @@ class TronWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
@@ -67,7 +68,7 @@ class TronWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
saveBackup(name);
return wallet;
@@ -82,7 +83,7 @@ class TronWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
}
@@ -102,7 +103,7 @@ class TronWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
@@ -127,7 +128,7 @@ class TronWalletService extends WalletService<
);
await wallet.init();
- wallet.addInitialTokens();
+ await wallet.addInitialTokens();
await wallet.save();
return wallet;
@@ -145,6 +146,10 @@ class TronWalletService extends WalletService<
throw Exception('Wallet not found');
}
await WalletInfo.delete(walletInfo);
+ final nameStillUsed = await WalletInfo.get(wallet, getType()) != null;
+ if (!nameStillUsed) {
+ await TronToken.deleteAllForWallet(wallet);
+ }
}
@override
diff --git a/cw_tron/pubspec.yaml b/cw_tron/pubspec.yaml
index 8e742aae2..c765ea78e 100644
--- a/cw_tron/pubspec.yaml
+++ b/cw_tron/pubspec.yaml
@@ -22,7 +22,7 @@ dependencies:
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
- ref: cake-update-v2
+ ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
mobx: ^2.3.0+1
bip39: ^1.0.6
hive: ^2.2.3
diff --git a/cw_tron/pubspec_overrides.yaml b/cw_tron/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_tron/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_wownero/pubspec.lock b/cw_wownero/pubspec.lock
deleted file mode 100644
index 4b622b350..000000000
--- a/cw_wownero/pubspec.lock
+++ /dev/null
@@ -1,890 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- _fe_analyzer_shared:
- dependency: transitive
- description:
- name: _fe_analyzer_shared
- sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
- url: "https://pub.dev"
- source: hosted
- version: "93.0.0"
- analyzer:
- dependency: transitive
- description:
- name: analyzer
- sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
- url: "https://pub.dev"
- source: hosted
- version: "10.0.1"
- args:
- dependency: transitive
- description:
- name: args
- sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- asn1lib:
- dependency: transitive
- description:
- name: asn1lib
- sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.8"
- async:
- dependency: transitive
- description:
- name: async
- sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
- url: "https://pub.dev"
- source: hosted
- version: "2.13.0"
- bech32:
- dependency: transitive
- description:
- path: "."
- ref: HEAD
- resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
- url: "https://github.com/cake-tech/bech32.git"
- source: git
- version: "0.2.2"
- blockchain_utils:
- dependency: transitive
- description:
- path: "."
- ref: cake-update-v2
- resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
- url: "https://github.com/cake-tech/blockchain_utils"
- source: git
- version: "3.3.0"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- build:
- dependency: transitive
- description:
- name: build
- sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10
- url: "https://pub.dev"
- source: hosted
- version: "4.0.6"
- build_config:
- dependency: transitive
- description:
- name: build_config
- sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- build_daemon:
- dependency: transitive
- description:
- name: build_daemon
- sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
- build_runner:
- dependency: "direct dev"
- description:
- name: build_runner
- sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6"
- url: "https://pub.dev"
- source: hosted
- version: "2.15.0"
- built_collection:
- dependency: transitive
- description:
- name: built_collection
- sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
- url: "https://pub.dev"
- source: hosted
- version: "5.1.1"
- built_value:
- dependency: transitive
- description:
- name: built_value
- sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56"
- url: "https://pub.dev"
- source: hosted
- version: "8.12.6"
- cake_backup:
- dependency: transitive
- description:
- path: "."
- ref: main
- resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
- url: "https://github.com/cake-tech/cake_backup.git"
- source: git
- version: "1.0.0+1"
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- checked_yaml:
- dependency: transitive
- description:
- name: checked_yaml
- sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
- url: "https://pub.dev"
- source: hosted
- version: "2.0.3"
- clock:
- dependency: transitive
- description:
- name: clock
- sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- collection:
- dependency: transitive
- description:
- name: collection
- sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
- url: "https://pub.dev"
- source: hosted
- version: "1.19.1"
- convert:
- dependency: transitive
- description:
- name: convert
- sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- crypto:
- dependency: transitive
- description:
- name: crypto
- sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.6"
- cryptography:
- dependency: transitive
- description:
- name: cryptography
- sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- cupertino_icons:
- dependency: transitive
- description:
- name: cupertino_icons
- sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
- url: "https://pub.dev"
- source: hosted
- version: "1.0.8"
- cw_core:
- dependency: "direct main"
- description:
- path: "../cw_core"
- relative: true
- source: path
- version: "0.0.1"
- dart_style:
- dependency: transitive
- description:
- name: dart_style
- sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.7"
- decimal:
- dependency: transitive
- description:
- name: decimal
- sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.3"
- encrypt:
- dependency: "direct main"
- description:
- name: encrypt
- sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.3"
- fake_async:
- dependency: transitive
- description:
- name: fake_async
- sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.3"
- ffi:
- dependency: "direct main"
- description:
- name: ffi
- sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- file:
- dependency: transitive
- description:
- name: file
- sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
- url: "https://pub.dev"
- source: hosted
- version: "7.0.1"
- fixnum:
- dependency: transitive
- description:
- name: fixnum
- sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_mobx:
- dependency: "direct main"
- description:
- name: flutter_mobx
- sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- glob:
- dependency: transitive
- description:
- name: glob
- sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- graphs:
- dependency: transitive
- description:
- name: graphs
- sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.2"
- hashlib:
- dependency: transitive
- description:
- name: hashlib
- sha256: e13e8237d93fb275cd1c55fc339bb90638994d1a4f140c7ee270173b51f3d169
- url: "https://pub.dev"
- source: hosted
- version: "1.21.1"
- hashlib_codecs:
- dependency: transitive
- description:
- name: hashlib_codecs
- sha256: "8cea9ccafcfeaa7324d2ae52c61c69f7ff71f4237507a018caab31b9e416e3b1"
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- hive:
- dependency: "direct dev"
- description:
- name: hive
- sha256: "5184b6ea455689754578267c31c3b0b329cccf20a5f2bfdab6941c29c3d3c09a"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- http:
- dependency: "direct main"
- description:
- name: http
- sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- http_multi_server:
- dependency: transitive
- description:
- name: http_multi_server
- sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- http_parser:
- dependency: transitive
- description:
- name: http_parser
- sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
- intl:
- dependency: "direct main"
- description:
- name: intl
- sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
- url: "https://pub.dev"
- source: hosted
- version: "0.19.0"
- io:
- dependency: transitive
- description:
- name: io
- sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- js:
- dependency: transitive
- description:
- name: js
- sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
- url: "https://pub.dev"
- source: hosted
- version: "0.6.7"
- json_annotation:
- dependency: transitive
- description:
- name: json_annotation
- sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
- url: "https://pub.dev"
- source: hosted
- version: "4.9.0"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
- url: "https://pub.dev"
- source: hosted
- version: "11.0.2"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.10"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- logging:
- dependency: transitive
- description:
- name: logging
- sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- matcher:
- dependency: transitive
- description:
- name: matcher
- sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
- url: "https://pub.dev"
- source: hosted
- version: "0.12.19"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
- url: "https://pub.dev"
- source: hosted
- version: "0.13.0"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
- url: "https://pub.dev"
- source: hosted
- version: "1.17.0"
- mime:
- dependency: transitive
- description:
- name: mime
- sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- mobx:
- dependency: "direct main"
- description:
- name: mobx
- sha256: "25ea9a3ee69243d578fb6288721d8eeb18550d0391c32f896d377d994154bff2"
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- mobx_codegen:
- dependency: "direct dev"
- description:
- name: mobx_codegen
- sha256: "6529bcae074838004b58ad01fbe4966be182a176aacfb723686985986ebac19f"
- url: "https://pub.dev"
- source: hosted
- version: "2.7.7"
- monero:
- dependency: "direct main"
- description:
- path: "impls/monero.dart"
- ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
- resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
- url: "https://github.com/mrcyjanek/monero_c.git"
- source: git
- version: "0.0.0"
- mutex:
- dependency: "direct main"
- description:
- name: mutex
- sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- nested:
- dependency: transitive
- description:
- name: nested
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- on_chain:
- dependency: transitive
- description:
- path: "."
- ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- url: "https://github.com/cake-tech/on_chain.git"
- source: git
- version: "3.7.0"
- package_config:
- dependency: transitive
- description:
- name: package_config
- sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- path:
- dependency: transitive
- description:
- name: path
- sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
- url: "https://pub.dev"
- source: hosted
- version: "1.9.1"
- path_provider:
- dependency: "direct main"
- description:
- name: path_provider
- sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- path_provider_android:
- dependency: transitive
- description:
- name: path_provider_android
- sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.15"
- path_provider_foundation:
- dependency: transitive
- description:
- name: path_provider_foundation
- sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- path_provider_linux:
- dependency: transitive
- description:
- name: path_provider_linux
- sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
- url: "https://pub.dev"
- source: hosted
- version: "2.2.1"
- path_provider_platform_interface:
- dependency: transitive
- description:
- name: path_provider_platform_interface
- sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- path_provider_windows:
- dependency: transitive
- description:
- name: path_provider_windows
- sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- platform:
- dependency: transitive
- description:
- name: platform
- sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.6"
- plugin_platform_interface:
- dependency: transitive
- description:
- name: plugin_platform_interface
- sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.8"
- pointycastle:
- dependency: transitive
- description:
- name: pointycastle
- sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
- url: "https://pub.dev"
- source: hosted
- version: "3.9.1"
- polyseed:
- dependency: "direct main"
- description:
- name: polyseed
- sha256: ccc6ba0ed3976837e770a324a6295fbf3d7c0d05fc0fa1906e36479b07c2675b
- url: "https://pub.dev"
- source: hosted
- version: "0.0.7"
- pool:
- dependency: transitive
- description:
- name: pool
- sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.1"
- provider:
- dependency: transitive
- description:
- name: provider
- sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
- url: "https://pub.dev"
- source: hosted
- version: "6.1.2"
- pub_semver:
- dependency: transitive
- description:
- name: pub_semver
- sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- pubspec_parse:
- dependency: transitive
- description:
- name: pubspec_parse
- sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- rational:
- dependency: transitive
- description:
- name: rational
- sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
- shelf:
- dependency: transitive
- description:
- name: shelf
- sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- shelf_web_socket:
- dependency: transitive
- description:
- name: shelf_web_socket
- sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- socks5_proxy:
- dependency: transitive
- description:
- path: "."
- ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- url: "https://github.com/LacticWhale/socks_dart"
- source: git
- version: "2.1.0"
- socks_socket:
- dependency: transitive
- description:
- path: "."
- ref: e6232c53c1595469931ababa878759a067c02e94
- resolved-ref: e6232c53c1595469931ababa878759a067c02e94
- url: "https://github.com/sneurlax/socks_socket"
- source: git
- version: "1.1.1"
- source_gen:
- dependency: transitive
- description:
- name: source_gen
- sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02
- url: "https://pub.dev"
- source: hosted
- version: "4.2.3"
- source_span:
- dependency: transitive
- description:
- name: source_span
- sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
- url: "https://pub.dev"
- source: hosted
- version: "1.10.1"
- sqflite:
- dependency: transitive
- description:
- name: sqflite
- sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- sqflite_android:
- dependency: transitive
- description:
- name: sqflite_android
- sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqflite_common:
- dependency: transitive
- description:
- name: sqflite_common
- sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4+6"
- sqflite_common_ffi:
- dependency: transitive
- description:
- name: sqflite_common_ffi
- sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.4+4"
- sqflite_darwin:
- dependency: transitive
- description:
- name: sqflite_darwin
- sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1+1"
- sqflite_platform_interface:
- dependency: transitive
- description:
- name: sqflite_platform_interface
- sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqlite3:
- dependency: transitive
- description:
- name: sqlite3
- sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
- url: "https://pub.dev"
- source: hosted
- version: "2.9.0"
- sqlite3_flutter_libs:
- dependency: transitive
- description:
- name: sqlite3_flutter_libs
- sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
- url: "https://pub.dev"
- source: hosted
- version: "0.5.40"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
- url: "https://pub.dev"
- source: hosted
- version: "1.12.1"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- stream_transform:
- dependency: transitive
- description:
- name: stream_transform
- sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
- url: "https://pub.dev"
- source: hosted
- version: "3.3.0+3"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.2"
- test_api:
- dependency: transitive
- description:
- name: test_api
- sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.10"
- torch_dart:
- dependency: transitive
- description:
- path: "../scripts/torch_dart"
- relative: true
- source: path
- version: "0.0.1"
- tuple:
- dependency: transitive
- description:
- name: tuple
- sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- unorm_dart:
- dependency: transitive
- description:
- name: unorm_dart
- sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
- url: "https://pub.dev"
- source: hosted
- version: "15.0.0"
- watcher:
- dependency: "direct overridden"
- description:
- name: watcher
- sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web:
- dependency: transitive
- description:
- name: web
- sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web_socket:
- dependency: transitive
- description:
- name: web_socket
- sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.6"
- web_socket_channel:
- dependency: transitive
- description:
- name: web_socket_channel
- sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- xdg_directories:
- dependency: transitive
- description:
- name: xdg_directories
- sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- yaml:
- dependency: transitive
- description:
- name: yaml
- sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
-sdks:
- dart: ">=3.10.0 <4.0.0"
- flutter: ">=3.24.0"
diff --git a/cw_wownero/pubspec_overrides.yaml b/cw_wownero/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_wownero/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_zano/pubspec.lock b/cw_zano/pubspec.lock
deleted file mode 100644
index c4602f532..000000000
--- a/cw_zano/pubspec.lock
+++ /dev/null
@@ -1,887 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- _fe_analyzer_shared:
- dependency: transitive
- description:
- name: _fe_analyzer_shared
- sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
- url: "https://pub.dev"
- source: hosted
- version: "93.0.0"
- analyzer:
- dependency: transitive
- description:
- name: analyzer
- sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
- url: "https://pub.dev"
- source: hosted
- version: "10.0.1"
- args:
- dependency: transitive
- description:
- name: args
- sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- asn1lib:
- dependency: transitive
- description:
- name: asn1lib
- sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.8"
- async:
- dependency: transitive
- description:
- name: async
- sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
- url: "https://pub.dev"
- source: hosted
- version: "2.13.0"
- bech32:
- dependency: transitive
- description:
- path: "."
- ref: HEAD
- resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
- url: "https://github.com/cake-tech/bech32.git"
- source: git
- version: "0.2.2"
- blockchain_utils:
- dependency: transitive
- description:
- path: "."
- ref: cake-update-v2
- resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
- url: "https://github.com/cake-tech/blockchain_utils"
- source: git
- version: "3.3.0"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- build:
- dependency: transitive
- description:
- name: build
- sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10
- url: "https://pub.dev"
- source: hosted
- version: "4.0.6"
- build_config:
- dependency: transitive
- description:
- name: build_config
- sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- build_daemon:
- dependency: transitive
- description:
- name: build_daemon
- sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
- build_runner:
- dependency: "direct dev"
- description:
- name: build_runner
- sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6"
- url: "https://pub.dev"
- source: hosted
- version: "2.15.0"
- built_collection:
- dependency: transitive
- description:
- name: built_collection
- sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
- url: "https://pub.dev"
- source: hosted
- version: "5.1.1"
- built_value:
- dependency: transitive
- description:
- name: built_value
- sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56"
- url: "https://pub.dev"
- source: hosted
- version: "8.12.6"
- cake_backup:
- dependency: transitive
- description:
- path: "."
- ref: main
- resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
- url: "https://github.com/cake-tech/cake_backup.git"
- source: git
- version: "1.0.0+1"
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- checked_yaml:
- dependency: transitive
- description:
- name: checked_yaml
- sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
- url: "https://pub.dev"
- source: hosted
- version: "2.0.3"
- clock:
- dependency: transitive
- description:
- name: clock
- sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- collection:
- dependency: transitive
- description:
- name: collection
- sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
- url: "https://pub.dev"
- source: hosted
- version: "1.19.1"
- convert:
- dependency: transitive
- description:
- name: convert
- sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- crypto:
- dependency: transitive
- description:
- name: crypto
- sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.6"
- cryptography:
- dependency: transitive
- description:
- name: cryptography
- sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- cupertino_icons:
- dependency: transitive
- description:
- name: cupertino_icons
- sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
- url: "https://pub.dev"
- source: hosted
- version: "1.0.8"
- cw_core:
- dependency: "direct main"
- description:
- path: "../cw_core"
- relative: true
- source: path
- version: "0.0.1"
- dart_style:
- dependency: transitive
- description:
- name: dart_style
- sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.7"
- decimal:
- dependency: "direct main"
- description:
- name: decimal
- sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.3"
- encrypt:
- dependency: transitive
- description:
- name: encrypt
- sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.3"
- fake_async:
- dependency: transitive
- description:
- name: fake_async
- sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.3"
- ffi:
- dependency: "direct main"
- description:
- name: ffi
- sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- file:
- dependency: transitive
- description:
- name: file
- sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
- url: "https://pub.dev"
- source: hosted
- version: "7.0.1"
- fixnum:
- dependency: transitive
- description:
- name: fixnum
- sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_mobx:
- dependency: "direct main"
- description:
- name: flutter_mobx
- sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_web_plugins:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- fluttertoast:
- dependency: "direct main"
- description:
- name: fluttertoast
- sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1"
- url: "https://pub.dev"
- source: hosted
- version: "8.2.12"
- glob:
- dependency: transitive
- description:
- name: glob
- sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- graphs:
- dependency: transitive
- description:
- name: graphs
- sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.2"
- hive:
- dependency: "direct dev"
- description:
- name: hive
- sha256: "5184b6ea455689754578267c31c3b0b329cccf20a5f2bfdab6941c29c3d3c09a"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- http:
- dependency: "direct main"
- description:
- name: http
- sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- http_multi_server:
- dependency: transitive
- description:
- name: http_multi_server
- sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- http_parser:
- dependency: transitive
- description:
- name: http_parser
- sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
- intl:
- dependency: "direct main"
- description:
- name: intl
- sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
- url: "https://pub.dev"
- source: hosted
- version: "0.19.0"
- io:
- dependency: transitive
- description:
- name: io
- sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- js:
- dependency: transitive
- description:
- name: js
- sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
- url: "https://pub.dev"
- source: hosted
- version: "0.6.7"
- json_annotation:
- dependency: transitive
- description:
- name: json_annotation
- sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
- url: "https://pub.dev"
- source: hosted
- version: "4.9.0"
- json_bigint:
- dependency: "direct main"
- description:
- name: json_bigint
- sha256: "9e613e731847ab2154d67160682adf104cbd9863741ec2f7abfcf6e77c70592f"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
- url: "https://pub.dev"
- source: hosted
- version: "11.0.2"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.10"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- logging:
- dependency: transitive
- description:
- name: logging
- sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- matcher:
- dependency: transitive
- description:
- name: matcher
- sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
- url: "https://pub.dev"
- source: hosted
- version: "0.12.19"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
- url: "https://pub.dev"
- source: hosted
- version: "0.13.0"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
- url: "https://pub.dev"
- source: hosted
- version: "1.17.0"
- mime:
- dependency: transitive
- description:
- name: mime
- sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- mobx:
- dependency: "direct main"
- description:
- name: mobx
- sha256: "25ea9a3ee69243d578fb6288721d8eeb18550d0391c32f896d377d994154bff2"
- url: "https://pub.dev"
- source: hosted
- version: "2.6.0"
- mobx_codegen:
- dependency: "direct dev"
- description:
- name: mobx_codegen
- sha256: "6529bcae074838004b58ad01fbe4966be182a176aacfb723686985986ebac19f"
- url: "https://pub.dev"
- source: hosted
- version: "2.7.7"
- monero:
- dependency: "direct main"
- description:
- path: "impls/monero.dart"
- ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
- resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
- url: "https://github.com/mrcyjanek/monero_c.git"
- source: git
- version: "0.0.0"
- nested:
- dependency: transitive
- description:
- name: nested
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- on_chain:
- dependency: transitive
- description:
- path: "."
- ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
- url: "https://github.com/cake-tech/on_chain.git"
- source: git
- version: "3.7.0"
- package_config:
- dependency: transitive
- description:
- name: package_config
- sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- path:
- dependency: transitive
- description:
- name: path
- sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
- url: "https://pub.dev"
- source: hosted
- version: "1.9.1"
- path_provider:
- dependency: "direct main"
- description:
- name: path_provider
- sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- path_provider_android:
- dependency: transitive
- description:
- name: path_provider_android
- sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.15"
- path_provider_foundation:
- dependency: transitive
- description:
- name: path_provider_foundation
- sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- path_provider_linux:
- dependency: transitive
- description:
- name: path_provider_linux
- sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
- url: "https://pub.dev"
- source: hosted
- version: "2.2.1"
- path_provider_platform_interface:
- dependency: transitive
- description:
- name: path_provider_platform_interface
- sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- path_provider_windows:
- dependency: transitive
- description:
- name: path_provider_windows
- sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- petitparser:
- dependency: transitive
- description:
- name: petitparser
- sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
- url: "https://pub.dev"
- source: hosted
- version: "6.0.2"
- platform:
- dependency: transitive
- description:
- name: platform
- sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.6"
- plugin_platform_interface:
- dependency: transitive
- description:
- name: plugin_platform_interface
- sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.8"
- pointycastle:
- dependency: transitive
- description:
- name: pointycastle
- sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
- url: "https://pub.dev"
- source: hosted
- version: "3.9.1"
- pool:
- dependency: transitive
- description:
- name: pool
- sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.1"
- provider:
- dependency: transitive
- description:
- name: provider
- sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
- url: "https://pub.dev"
- source: hosted
- version: "6.1.2"
- pub_semver:
- dependency: transitive
- description:
- name: pub_semver
- sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- pubspec_parse:
- dependency: transitive
- description:
- name: pubspec_parse
- sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- rational:
- dependency: transitive
- description:
- name: rational
- sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
- shelf:
- dependency: transitive
- description:
- name: shelf
- sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- shelf_web_socket:
- dependency: transitive
- description:
- name: shelf_web_socket
- sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- socks5_proxy:
- dependency: transitive
- description:
- path: "."
- ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
- url: "https://github.com/LacticWhale/socks_dart"
- source: git
- version: "2.1.0"
- socks_socket:
- dependency: transitive
- description:
- path: "."
- ref: e6232c53c1595469931ababa878759a067c02e94
- resolved-ref: e6232c53c1595469931ababa878759a067c02e94
- url: "https://github.com/sneurlax/socks_socket"
- source: git
- version: "1.1.1"
- source_gen:
- dependency: transitive
- description:
- name: source_gen
- sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02
- url: "https://pub.dev"
- source: hosted
- version: "4.2.3"
- source_span:
- dependency: transitive
- description:
- name: source_span
- sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
- url: "https://pub.dev"
- source: hosted
- version: "1.10.1"
- sqflite:
- dependency: transitive
- description:
- name: sqflite
- sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- sqflite_android:
- dependency: transitive
- description:
- name: sqflite_android
- sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqflite_common:
- dependency: transitive
- description:
- name: sqflite_common
- sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4+6"
- sqflite_common_ffi:
- dependency: transitive
- description:
- name: sqflite_common_ffi
- sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.4+4"
- sqflite_darwin:
- dependency: transitive
- description:
- name: sqflite_darwin
- sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1+1"
- sqflite_platform_interface:
- dependency: transitive
- description:
- name: sqflite_platform_interface
- sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqlite3:
- dependency: transitive
- description:
- name: sqlite3
- sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
- url: "https://pub.dev"
- source: hosted
- version: "2.9.0"
- sqlite3_flutter_libs:
- dependency: transitive
- description:
- name: sqlite3_flutter_libs
- sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
- url: "https://pub.dev"
- source: hosted
- version: "0.5.40"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
- url: "https://pub.dev"
- source: hosted
- version: "1.12.1"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- stream_transform:
- dependency: transitive
- description:
- name: stream_transform
- sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
- url: "https://pub.dev"
- source: hosted
- version: "3.3.0+3"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.2"
- test_api:
- dependency: transitive
- description:
- name: test_api
- sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.10"
- torch_dart:
- dependency: transitive
- description:
- path: "../scripts/torch_dart"
- relative: true
- source: path
- version: "0.0.1"
- tuple:
- dependency: transitive
- description:
- name: tuple
- sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- unorm_dart:
- dependency: transitive
- description:
- name: unorm_dart
- sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
- url: "https://pub.dev"
- source: hosted
- version: "15.0.0"
- watcher:
- dependency: "direct overridden"
- description:
- name: watcher
- sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web:
- dependency: transitive
- description:
- name: web
- sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web_socket:
- dependency: transitive
- description:
- name: web_socket
- sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.6"
- web_socket_channel:
- dependency: transitive
- description:
- name: web_socket_channel
- sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- xdg_directories:
- dependency: transitive
- description:
- name: xdg_directories
- sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- yaml:
- dependency: transitive
- description:
- name: yaml
- sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
-sdks:
- dart: ">=3.10.0 <4.0.0"
- flutter: ">=3.24.0"
diff --git a/cw_zano/pubspec_overrides.yaml b/cw_zano/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_zano/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/cw_zcash/.gitignore b/cw_zcash/.gitignore
index 3cceda557..3a8579040 100644
--- a/cw_zcash/.gitignore
+++ b/cw_zcash/.gitignore
@@ -1,7 +1,3 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
-
-# Avoid committing pubspec.lock for library packages; see
-# https://dart.dev/guides/libraries/private-files#pubspeclock.
-pubspec.lock
diff --git a/cw_zcash/pubspec_overrides.yaml b/cw_zcash/pubspec_overrides.yaml
new file mode 120000
index 000000000..d957432d3
--- /dev/null
+++ b/cw_zcash/pubspec_overrides.yaml
@@ -0,0 +1 @@
+../pubspec_overrides.yaml
\ No newline at end of file
diff --git a/ios/Podfile b/ios/Podfile
index 60e07e6b4..2a847a6a0 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
-platform :ios, '13.0'
+platform :ios, '13.1'
source 'https://github.com/CocoaPods/Specs.git'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index b7e67acbf..f10f7d8ef 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -1,15 +1,9 @@
PODS:
- bitbox_flutter (0.0.1):
- Flutter
- - breez_sdk_spark_flutter (0.14.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):
@@ -67,8 +61,6 @@ 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):
@@ -79,13 +71,9 @@ 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):
@@ -93,10 +81,6 @@ 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)
@@ -107,8 +91,6 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- - sp_scanner (0.0.1):
- - Flutter
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
@@ -153,11 +135,8 @@ 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`)
@@ -169,24 +148,18 @@ 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`)
@@ -209,14 +182,8 @@ 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:
@@ -239,8 +206,6 @@ 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:
@@ -251,30 +216,20 @@ 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:
@@ -292,7 +247,6 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
bitbox_flutter: 9505732798041c413152669751beeaecc5fe400f
- breez_sdk_spark_flutter: ed3b6709b8ce9b40309d8728640eade5b19e8a0d
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6
@@ -323,8 +277,6 @@ 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
@@ -336,11 +288,11 @@ SPEC CHECKSUMS:
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
torch_dart: f4620705d10f05492fab047f2fa1c3a600e7d17d
uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152
- universal_ble: a322ebabee64f0ec27a313e89a5dd6967f37a60f
+ universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
YttriumWrapper: 31e937fe9fbe0f1314d2ca6be9ce9b379a059966
-PODFILE CHECKSUM: b08d7f4c8d9c64f5648599a30caea878b0f7616a
+PODFILE CHECKSUM: 18601c2df1b9c6704d6a786e4e6777ae88178c28
COCOAPODS: 1.16.2
diff --git a/ios/Runner/InfoBase.plist b/ios/Runner/InfoBase.plist
index ff0f43b61..a29c3d58f 100644
--- a/ios/Runner/InfoBase.plist
+++ b/ios/Runner/InfoBase.plist
@@ -199,7 +199,9 @@
solana-wallet
CFBundleURLSchemes
+ solana
solana-wallet
+ solana_wallet
diff --git a/lib/core/address_validator.dart b/lib/core/address_validator.dart
index e5905bb82..1c4c6d372 100644
--- a/lib/core/address_validator.dart
+++ b/lib/core/address_validator.dart
@@ -177,13 +177,7 @@ class AddressValidator extends TextValidator {
if (ZcashNetworkType.isDevNetwork(network)) {
return null;
}
- pattern = '(?:'
- 't1[0-9A-Za-z]{33}'
- '|t3[0-9A-Za-z]{33}'
- '|zs[a-z0-9]{76}'
- '|zxviews[a-z0-9]{278}'
- '|u1[a-z0-9]{1,300}'
- ')';
+ pattern = "(?:$zcashAddressPattern|zxviews[a-z0-9]{278})";
case CryptoCurrency.dcr:
pattern = '(D|T|S)[ksecS]([0-9a-zA-Z])+';
case CryptoCurrency.rvn:
@@ -355,6 +349,8 @@ class AddressValidator extends TextValidator {
static String get silentPaymentAddressPatternMainnet => 'sp1[0-9a-zA-Z]{113}';
static String get silentPaymentAddressPatternTestnet => '(tsp|sprt)1[0-9a-zA-Z]{113}';
static String get mWebAddressPattern => MwebAddress.regex.pattern;
+ static String get zcashAddressPattern =>
+ "t1[0-9A-Za-z]{33}|t3[0-9A-Za-z]{33}|zs[a-z0-9]{76}|u1[a-z0-9]{1,300}";
static const String bolt11InvoiceMatcher = r'^(lightning:)?(lnbc|lntb|lnbs|lnbcrt)[a-z0-9]+$';
static const String bolt12OfferMatcher = r'^(lightning:)?(lno1)[a-z0-9]+$';
@@ -401,13 +397,7 @@ class AddressValidator extends TextValidator {
case CryptoCurrency.zano:
pattern = '([1-9A-HJ-NP-Za-km-z]{90,200})|(@[\w\d.-]+)';
case CryptoCurrency.zec:
- pattern = '(?:'
- 't1[0-9A-Za-z]{33}'
- '|t3[0-9A-Za-z]{33}'
- '|zs[a-z0-9]{76}'
- '|zxviews[a-z0-9]{278}'
- '|u1[a-z0-9]{1,300}'
- ')';
+ pattern = "(?:$zcashAddressPattern|zxviews[a-z0-9]{278})";
default:
if (type.tag == CryptoCurrency.eth.title) {
pattern = '0x[0-9a-zA-Z]+';
diff --git a/lib/core/anypay/anypay_models.dart b/lib/core/anypay/anypay_models.dart
new file mode 100644
index 000000000..70f334f9b
--- /dev/null
+++ b/lib/core/anypay/anypay_models.dart
@@ -0,0 +1,174 @@
+import "package:cake_wallet/core/universal_address_detector.dart";
+import "package:cake_wallet/utils/payment_request.dart";
+import "package:cw_core/amount/money.dart";
+import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/wallet_info.dart";
+import "package:cw_core/wallet_type.dart";
+
+sealed class ChainBinding {
+ const ChainBinding();
+}
+
+class ExplicitEvmChain extends ChainBinding {
+ const ExplicitEvmChain(this.chainId);
+
+ final int chainId;
+}
+
+class ChainlessEvm extends ChainBinding {
+ const ChainlessEvm();
+}
+
+class NoEvmBinding extends ChainBinding {
+ const NoEvmBinding();
+}
+
+class AnyPayRequest {
+ AnyPayRequest({
+ required this.rawInput,
+ required this.paymentRequest,
+ required this.detection,
+ required this.chainBinding,
+ });
+
+ final String rawInput;
+ final PaymentRequest paymentRequest;
+ final AddressDetectionResult detection;
+ final ChainBinding chainBinding;
+
+ String get address => paymentRequest.address;
+
+ String get amount => paymentRequest.amount;
+
+ String? get contractAddress => paymentRequest.contractAddress;
+
+ bool get hasContract => contractAddress != null && contractAddress!.isNotEmpty;
+
+ bool get isLightning => detection.detectedCurrency == CryptoCurrency.btcln;
+}
+
+class WalletSnapshot {
+ WalletSnapshot({
+ required this.type,
+ required this.currentWalletIsEvm,
+ required this.currentChainId,
+ required this.wallets,
+ required this.supportedEvmChains,
+ required this.hasEvmProxy,
+ required this.hasSolanaProxy,
+ required this.hasTronProxy,
+ });
+
+ final WalletType type;
+ final bool currentWalletIsEvm;
+ final int? currentChainId;
+ final List wallets;
+ final Map supportedEvmChains;
+ final bool hasEvmProxy;
+ final bool hasSolanaProxy;
+ final bool hasTronProxy;
+
+ List walletsOfType(WalletType walletType) =>
+ wallets.where((wallet) => wallet.type == walletType).toList();
+}
+
+sealed class AnyPayResolution {
+ const AnyPayResolution();
+}
+
+class NoTokenRequested extends AnyPayResolution {
+ const NoTokenRequested();
+}
+
+class TokenResolved extends AnyPayResolution {
+ const TokenResolved({required this.token, this.chainId, this.amountOverride});
+
+ final CryptoCurrency token;
+ final int? chainId;
+ final String? amountOverride;
+}
+
+class TokenUnknown extends AnyPayResolution {
+ const TokenUnknown(this.contract);
+
+ final String contract;
+}
+
+sealed class AnyPayDecision {
+ const AnyPayDecision();
+}
+
+class AnyPayApplyToCurrentWallet extends AnyPayDecision {
+ const AnyPayApplyToCurrentWallet({
+ this.token,
+ this.amountOverride,
+ this.fallbackCurrency,
+ });
+
+ final CryptoCurrency? token;
+ final String? amountOverride;
+ final CryptoCurrency? fallbackCurrency;
+}
+
+class AnyPayEvmNetworkChoice extends AnyPayDecision {
+ const AnyPayEvmNetworkChoice();
+}
+
+class AnyPayCrossChainPayment extends AnyPayDecision {
+ const AnyPayCrossChainPayment({
+ required this.targetWalletType,
+ required this.wallets,
+ this.targetChainId,
+ this.token,
+ this.amountOverride,
+ this.canSwap = true,
+ });
+
+ final WalletType targetWalletType;
+ final int? targetChainId;
+ final List wallets;
+ final CryptoCurrency? token;
+ final String? amountOverride;
+ final bool canSwap;
+
+ bool get hasCompatibleWallet => wallets.isNotEmpty;
+}
+
+class AnyPayUnsupportedNetwork extends AnyPayDecision {
+ const AnyPayUnsupportedNetwork(this.chainId);
+
+ final int chainId;
+}
+
+class AnyPayUnsupportedToken extends AnyPayDecision {
+ const AnyPayUnsupportedToken(this.contract);
+
+ final String contract;
+}
+
+class AnyPayEmptyInput extends AnyPayDecision {
+ const AnyPayEmptyInput();
+}
+
+class AnyPayEvaluation {
+ AnyPayEvaluation({required this.request, required this.decision});
+
+ final AnyPayRequest request;
+ final AnyPayDecision decision;
+}
+
+class AnyPaySwapIntent {
+ AnyPaySwapIntent({
+ required this.request,
+ required this.receiveCurrency,
+ required this.targetWalletType,
+ this.receiveAmount,
+ });
+
+ final AnyPayRequest request;
+ final CryptoCurrency receiveCurrency;
+ final WalletType targetWalletType;
+ final Money? receiveAmount;
+
+ String get recipientAddress => request.address;
+}
diff --git a/lib/core/anypay/anypay_parser.dart b/lib/core/anypay/anypay_parser.dart
new file mode 100644
index 000000000..04afeb026
--- /dev/null
+++ b/lib/core/anypay/anypay_parser.dart
@@ -0,0 +1,71 @@
+import "package:cake_wallet/core/anypay/anypay_models.dart";
+import "package:cake_wallet/core/universal_address_detector.dart";
+import "package:cake_wallet/utils/payment_request.dart";
+import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/currency_for_wallet_type.dart";
+import "package:cw_core/payment_uris.dart";
+
+class AnyPayParser {
+ static AnyPayRequest fromRaw(String input) {
+ final paymentRequest = PaymentRequest.fromString(input);
+
+ return AnyPayRequest(
+ rawInput: input,
+ paymentRequest: paymentRequest,
+ detection: UniversalAddressDetector.detectAddress(input),
+ chainBinding: _bindingFor(paymentRequest),
+ );
+ }
+
+ static AnyPayRequest fromPaymentRequest(PaymentRequest request) {
+ final raw = _reconstructRawInput(request);
+
+ return AnyPayRequest(
+ rawInput: raw,
+ paymentRequest: request,
+ detection: UniversalAddressDetector.detectAddress(raw),
+ chainBinding: _bindingFor(request),
+ );
+ }
+
+ static String _reconstructRawInput(PaymentRequest request) {
+ final scheme = request.scheme.toLowerCase();
+
+ if (scheme.isEmpty || scheme == "lightning") {
+ return request.address;
+ }
+
+ if (scheme == "ethereum") {
+ return ERC681URI(
+ address: request.address,
+ amount: request.amount,
+ contractAddress: request.contractAddress,
+ chainId: request.chainId ?? 1,
+ rawTokenAmount: request.rawTokenAmount,
+ ).toString();
+ }
+
+ final amount = request.amount.isNotEmpty ? "?amount=${request.amount}" : "";
+ return "${request.scheme}:${request.address}$amount";
+ }
+
+ static ChainBinding _bindingFor(PaymentRequest request) {
+ final scheme = request.scheme.toLowerCase();
+
+ if (scheme == "ethereum") {
+ final chainId = request.chainId;
+ return chainId != null ? ExplicitEvmChain(chainId) : const ChainlessEvm();
+ }
+
+ if (scheme.isNotEmpty) {
+ try {
+ final chainId = getChainIdByCryptoCurrency(CryptoCurrency.fromString(scheme));
+ if (chainId != null) {
+ return ExplicitEvmChain(chainId);
+ }
+ } catch (_) {}
+ }
+
+ return const NoEvmBinding();
+ }
+}
diff --git a/lib/core/anypay/anypay_resolver.dart b/lib/core/anypay/anypay_resolver.dart
new file mode 100644
index 000000000..18a0400ce
--- /dev/null
+++ b/lib/core/anypay/anypay_resolver.dart
@@ -0,0 +1,109 @@
+import "package:cake_wallet/core/anypay/anypay_models.dart";
+import "package:cake_wallet/core/anypay/anypay_router.dart";
+import "package:cake_wallet/reactions/wallet_connect.dart";
+import "package:cake_wallet/utils/token_utilities.dart";
+import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/wallet_type.dart";
+
+class AnyPayResolver {
+ AnyPayResolver({AnyPayTokenLookup? tokenLookup})
+ : _tokenLookup = tokenLookup ?? const TokenUtilitiesLookup();
+
+ final AnyPayTokenLookup _tokenLookup;
+
+ Future resolve(AnyPayRequest request, WalletSnapshot snapshot) async {
+ if (!request.hasContract) {
+ return const NoTokenRequested();
+ }
+
+ final contract = request.contractAddress!;
+ final detectedType = request.detection.detectedWalletType;
+
+ if (detectedType != null && isEVMCompatibleChain(detectedType)) {
+ return _resolveEvm(request, snapshot, contract);
+ }
+
+ final token = await _tokenLookup.findTokenByAddress(
+ walletType: detectedType ?? snapshot.type,
+ address: contract,
+ );
+
+ if (token == null) {
+ return TokenUnknown(contract);
+ }
+
+ return TokenResolved(
+ token: token,
+ amountOverride: request.paymentRequest.resolveTokenAmount(token),
+ );
+ }
+
+ Future _resolveEvm(
+ AnyPayRequest request,
+ WalletSnapshot snapshot,
+ String contract,
+ ) async {
+ final requestedChainId = AnyPayRouter.requestedEvmChainId(request, snapshot) ?? 1;
+
+ final lookupType = snapshot.supportedEvmChains[requestedChainId];
+ if (lookupType != null) {
+ final token =
+ await _tokenLookup.findTokenByAddress(walletType: lookupType, address: contract);
+ if (token != null) {
+ return TokenResolved(
+ token: token,
+ chainId: requestedChainId,
+ amountOverride: request.paymentRequest.resolveTokenAmount(token),
+ );
+ }
+ }
+
+ // The QRs from our old app versions omit the chainId on mainnet, so a contract the target
+ // network does not know may still belong to another EVM network.
+ if (request.chainBinding is ChainlessEvm) {
+ final reboundChainId = await _tokenLookup.findEvmChainIdForContract(
+ contract,
+ excludingChainId: requestedChainId,
+ );
+ final reboundType =
+ reboundChainId != null ? snapshot.supportedEvmChains[reboundChainId] : null;
+ if (reboundType != null) {
+ final token =
+ await _tokenLookup.findTokenByAddress(walletType: reboundType, address: contract);
+ if (token != null) {
+ return TokenResolved(
+ token: token,
+ chainId: reboundChainId,
+ amountOverride: request.paymentRequest.resolveTokenAmount(token),
+ );
+ }
+ }
+ }
+
+ return TokenUnknown(contract);
+ }
+}
+
+abstract class AnyPayTokenLookup {
+ Future findTokenByAddress({
+ required WalletType walletType,
+ required String address,
+ });
+
+ Future findEvmChainIdForContract(String contractAddress, {int? excludingChainId});
+}
+
+class TokenUtilitiesLookup implements AnyPayTokenLookup {
+ const TokenUtilitiesLookup();
+
+ @override
+ Future findTokenByAddress({
+ required WalletType walletType,
+ required String address,
+ }) =>
+ TokenUtilities.findTokenByAddress(walletType: walletType, address: address);
+
+ @override
+ Future findEvmChainIdForContract(String contractAddress, {int? excludingChainId}) =>
+ TokenUtilities.findEvmChainIdForContract(contractAddress, excludingChainId: excludingChainId);
+}
diff --git a/lib/core/anypay/anypay_router.dart b/lib/core/anypay/anypay_router.dart
new file mode 100644
index 000000000..cf2487698
--- /dev/null
+++ b/lib/core/anypay/anypay_router.dart
@@ -0,0 +1,141 @@
+import "package:cake_wallet/core/address_validator.dart";
+import "package:cake_wallet/core/anypay/anypay_models.dart";
+import "package:cake_wallet/reactions/wallet_connect.dart";
+import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/wallet_type.dart";
+
+class AnyPayRouter {
+ static final List _swapIncompatibleAddressPatterns = [
+ RegExp("^(?:${AddressValidator.silentPaymentAddressPatternMainnet})\$"),
+ RegExp("^(?:${AddressValidator.silentPaymentAddressPatternTestnet})\$"),
+ RegExp("^(?:${AddressValidator.mWebAddressPattern})\$"),
+ ];
+
+ static bool _isSwapIncompatibleAddress(String address) =>
+ _swapIncompatibleAddressPatterns.any((pattern) => pattern.hasMatch(address));
+
+ static AnyPayDecision route(
+ AnyPayRequest request,
+ WalletSnapshot snapshot,
+ AnyPayResolution resolution,
+ ) {
+ if (request.rawInput.trim().isEmpty) {
+ return const AnyPayEmptyInput();
+ }
+
+ final detection = request.detection;
+ final detectedType = detection.detectedWalletType;
+
+ if (!detection.isValid || detectedType == null) {
+ return const AnyPayApplyToCurrentWallet();
+ }
+
+ if (detectedType == WalletType.solana && !snapshot.hasSolanaProxy) {
+ return const AnyPayApplyToCurrentWallet();
+ }
+
+ if (detectedType == WalletType.tron && !snapshot.hasTronProxy) {
+ return const AnyPayApplyToCurrentWallet();
+ }
+
+ if (isEVMCompatibleChain(detectedType)) {
+ if (!snapshot.hasEvmProxy) {
+ return const AnyPayApplyToCurrentWallet();
+ }
+
+ return _routeEvm(request, snapshot, resolution);
+ }
+
+ if (resolution is TokenUnknown) {
+ return AnyPayUnsupportedToken(resolution.contract);
+ }
+
+ if (detectedType == snapshot.type) {
+ return AnyPayApplyToCurrentWallet(
+ token: resolution is TokenResolved ? resolution.token : null,
+ amountOverride: resolution is TokenResolved ? resolution.amountOverride : null,
+ fallbackCurrency: _nativeRequestCurrency(request),
+ );
+ }
+
+ return AnyPayCrossChainPayment(
+ targetWalletType: detectedType,
+ wallets: snapshot.walletsOfType(detectedType),
+ token: resolution is TokenResolved ? resolution.token : null,
+ amountOverride: resolution is TokenResolved ? resolution.amountOverride : null,
+ canSwap: !_isSwapIncompatibleAddress(request.address),
+ );
+ }
+
+ static AnyPayDecision _routeEvm(
+ AnyPayRequest request,
+ WalletSnapshot snapshot,
+ AnyPayResolution resolution,
+ ) {
+ final requestedChainId = requestedEvmChainId(request, snapshot);
+
+ if (requestedChainId == null) {
+ if (snapshot.currentWalletIsEvm) {
+ return const AnyPayApplyToCurrentWallet();
+ }
+
+ return const AnyPayEvmNetworkChoice();
+ }
+
+ if (!snapshot.supportedEvmChains.containsKey(requestedChainId)) {
+ return AnyPayUnsupportedNetwork(requestedChainId);
+ }
+
+ if (resolution is TokenUnknown) {
+ return AnyPayUnsupportedToken(resolution.contract);
+ }
+
+ int targetChainId = requestedChainId;
+ if (resolution is TokenResolved && resolution.chainId != null) {
+ targetChainId = resolution.chainId!;
+ }
+
+ final token = resolution is TokenResolved ? resolution.token : null;
+ final amountOverride = resolution is TokenResolved ? resolution.amountOverride : null;
+
+ if (snapshot.currentWalletIsEvm && snapshot.currentChainId == targetChainId) {
+ return AnyPayApplyToCurrentWallet(
+ token: token,
+ amountOverride: amountOverride,
+ fallbackCurrency: _nativeRequestCurrency(request),
+ );
+ }
+
+ final targetWalletType = snapshot.supportedEvmChains[targetChainId]!;
+
+ return AnyPayCrossChainPayment(
+ targetWalletType: targetWalletType,
+ targetChainId: targetChainId,
+ wallets: snapshot.walletsOfType(targetWalletType),
+ token: token,
+ amountOverride: amountOverride,
+ );
+ }
+
+ static CryptoCurrency? _nativeRequestCurrency(AnyPayRequest request) {
+ if (request.paymentRequest.scheme.isEmpty || request.hasContract || request.amount.isEmpty) {
+ return null;
+ }
+ return request.detection.detectedCurrency;
+ }
+
+ static int? requestedEvmChainId(AnyPayRequest request, WalletSnapshot snapshot) {
+ final binding = request.chainBinding;
+
+ if (binding is ExplicitEvmChain) {
+ return binding.chainId;
+ }
+
+ if (binding is ChainlessEvm) {
+ // the eip 681 spec says we should use the current chain id if there is no chainId in the incoming request
+ return snapshot.currentWalletIsEvm ? snapshot.currentChainId ?? 1 : 1;
+ }
+
+ return null;
+ }
+}
diff --git a/lib/core/anypay/anypay_service.dart b/lib/core/anypay/anypay_service.dart
new file mode 100644
index 000000000..80b558f0c
--- /dev/null
+++ b/lib/core/anypay/anypay_service.dart
@@ -0,0 +1,140 @@
+import "package:cake_wallet/core/anypay/anypay_models.dart";
+import "package:cake_wallet/core/anypay/anypay_parser.dart";
+import "package:cake_wallet/core/anypay/anypay_resolver.dart";
+import "package:cake_wallet/core/anypay/anypay_router.dart";
+import "package:cake_wallet/evm/evm.dart";
+import "package:cake_wallet/new-ui/services/wallet_switch_service.dart";
+import "package:cake_wallet/reactions/wallet_connect.dart";
+import "package:cake_wallet/solana/solana.dart";
+import "package:cake_wallet/store/app_store.dart";
+import "package:cake_wallet/tron/tron.dart";
+import "package:cake_wallet/utils/payment_request.dart";
+import "package:cw_core/amount/money.dart";
+import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/currency_for_wallet_type.dart";
+import "package:cw_core/utils/print_verbose.dart";
+import "package:cw_core/wallet_info.dart";
+import "package:cw_core/wallet_type.dart";
+
+class AnyPayService {
+ AnyPayService({
+ required this.appStore,
+ required this.walletSwitchService,
+ AnyPayResolver? resolver,
+ }) : resolver = resolver ?? AnyPayResolver();
+
+ final AppStore appStore;
+ final WalletSwitchService walletSwitchService;
+ final AnyPayResolver resolver;
+
+ Future evaluateRawInput(String input) => _evaluate(AnyPayParser.fromRaw(input));
+
+ Future evaluatePaymentRequest(PaymentRequest request) =>
+ _evaluate(AnyPayParser.fromPaymentRequest(request));
+
+ Future evaluateForEvmChain(AnyPayRequest request, int chainId) => _evaluate(
+ AnyPayRequest(
+ rawInput: request.rawInput,
+ paymentRequest: request.paymentRequest,
+ detection: request.detection,
+ chainBinding: ExplicitEvmChain(chainId),
+ ),
+ );
+
+ Future _evaluate(AnyPayRequest request) async {
+ try {
+ final snapshot = await _buildWalletSnapshot();
+ final resolution = await resolver.resolve(request, snapshot);
+
+ return AnyPayEvaluation(
+ request: request,
+ decision: AnyPayRouter.route(request, snapshot, resolution),
+ );
+ } catch (e) {
+ printV("anypay evaluation failed: $e");
+ return AnyPayEvaluation(
+ request: request,
+ decision: const AnyPayApplyToCurrentWallet(),
+ );
+ }
+ }
+
+ Future _buildWalletSnapshot() async {
+ final wallet = appStore.wallet!;
+ final currentWalletIsEvm = isEVMCompatibleChain(wallet.type);
+
+ final supportedEvmChains = {};
+ if (evm != null) {
+ for (final chain in evm!.getAllChains()) {
+ final walletType = evm!.getWalletTypeByChainId(chain.chainId);
+ if (walletType != null) {
+ supportedEvmChains[chain.chainId] = walletType;
+ }
+ }
+ }
+
+ return WalletSnapshot(
+ type: wallet.type,
+ currentWalletIsEvm: currentWalletIsEvm,
+ currentChainId: currentWalletIsEvm && evm != null
+ ? evm!.getSelectedChainId(wallet) ?? evm!.getChainIdByWalletType(wallet.type)
+ : null,
+ wallets: await WalletInfo.getAll(),
+ supportedEvmChains: supportedEvmChains,
+ hasEvmProxy: evm != null,
+ hasSolanaProxy: solana != null,
+ hasTronProxy: tron != null,
+ );
+ }
+
+ AnyPaySwapIntent buildSwapIntent(
+ AnyPayRequest request, {
+ required WalletType targetWalletType,
+ int? targetChainId,
+ CryptoCurrency? token,
+ }) {
+ final receiveCurrency = token ??
+ (targetChainId != null
+ ? walletTypeToCryptoCurrency(targetWalletType, chainId: targetChainId)
+ : request.detection.detectedCurrency ?? walletTypeToCryptoCurrency(targetWalletType));
+
+ final amountValue = token != null
+ ? request.paymentRequest.resolveTokenAmount(token)
+ : (request.amount.isNotEmpty ? request.amount : null);
+
+ return AnyPaySwapIntent(
+ request: request,
+ receiveCurrency: receiveCurrency,
+ targetWalletType: targetWalletType,
+ receiveAmount: amountValue != null ? Money.tryParse(amountValue, receiveCurrency) : null,
+ );
+ }
+
+ Future switchWalletForPayment(WalletInfo walletInfo, {int? chainId}) async {
+ try {
+ await walletSwitchService.switchToWallet(walletInfo);
+ } catch (e) {
+ printV("wallet switch failed: $e");
+ return false;
+ }
+
+ final wallet = appStore.wallet!;
+ if (chainId != null && evm != null && isEVMCompatibleChain(wallet.type)) {
+ try {
+ final node = appStore.settingsStore.getCurrentNode(wallet.type, chainId: chainId);
+ await evm!.selectChain(wallet, chainId, node: node);
+ } catch (e, s) {
+ printV("switchWalletForPayment chain select failed: $e\n$s");
+ return false;
+ }
+ }
+
+ try {
+ await wallet.updateBalance();
+ } catch (e) {
+ printV("balance refresh after wallet switch failed: $e");
+ }
+
+ return true;
+ }
+}
diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart
index f195f2ac8..e85622af5 100644
--- a/lib/core/backup_service.dart
+++ b/lib/core/backup_service.dart
@@ -18,6 +18,9 @@ import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/encrypt.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/secret_store_key.dart';
+import 'package:cw_core/erc20_token_legacy.dart' show performErc20TokenHiveMigration;
+import 'package:cw_core/spl_token_legacy.dart' show performSplTokenHiveMigration;
+import 'package:cw_core/tron_token_legacy.dart' show performTronTokenHiveMigration;
import 'package:cw_core/wallet_info.dart';
import 'package:cake_wallet/exchange/trade_legacy.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
@@ -113,6 +116,10 @@ class $BackupService {
Future verifyWallets() async {
await performHiveMigration(); // for backups made before sqlite migration
await performTradeHiveMigration(_secureStorage);
+ await performErc20TokenHiveMigration();
+ await performSplTokenHiveMigration();
+ await performTronTokenHiveMigration();
+
correctWallets = (await WalletInfo.getAll())
.where((info) => availableWalletTypes.contains(info.type))
.toList();
diff --git a/lib/core/sync_status_title.dart b/lib/core/sync_status_title.dart
index b013bab17..d2988d07b 100644
--- a/lib/core/sync_status_title.dart
+++ b/lib/core/sync_status_title.dart
@@ -42,7 +42,7 @@ String syncStatusTitle(SyncStatus syncStatus, SyncStatusDisplayMode syncStatusDi
}
if (syncStatus is SyncedSyncStatus) {
- return "";
+ return S.current.sync_synced;
}
if (syncStatus is FailedSyncStatus) {
diff --git a/lib/core/universal_address_detector.dart b/lib/core/universal_address_detector.dart
index 1a88e6ec7..74b632cbb 100644
--- a/lib/core/universal_address_detector.dart
+++ b/lib/core/universal_address_detector.dart
@@ -238,6 +238,12 @@ class UniversalAddressDetector {
currency: CryptoCurrency.doge,
),
+ // Zcash (transparent, Sapling shielded, unified)
+ _DetectionPattern(
+ pattern: RegExp("^(?:${AddressValidator.zcashAddressPattern})\$"),
+ currency: CryptoCurrency.zec,
+ ),
+
// Solana (Base58 format)
_DetectionPattern(
pattern: RegExp(r'^[1-9A-HJ-NP-Za-km-z]{43,44}$'),
diff --git a/lib/di.dart b/lib/di.dart
index 173b119f5..ebb0063b5 100644
--- a/lib/di.dart
+++ b/lib/di.dart
@@ -7,6 +7,7 @@ import 'package:cake_wallet/anypay/anypay_api.dart';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:cake_wallet/core/address_resolver/address_resolver_service.dart';
+import 'package:cake_wallet/core/anypay/anypay_service.dart';
import 'package:cake_wallet/core/address_resolver/yat/yat_service.dart';
import 'package:cake_wallet/core/address_resolver/yat/yat_store.dart';
import 'package:cake_wallet/entities/bitcoin_amount_display_mode.dart';
@@ -62,6 +63,7 @@ import 'package:cake_wallet/new-ui/pages/coin_control_page.dart';
import 'package:cake_wallet/new-ui/pages/addresses_page.dart';
import 'package:cake_wallet/new-ui/pages/home_page.dart';
import 'package:cake_wallet/new-ui/pages/send_page.dart';
+import "package:cake_wallet/new-ui/services/wallet_switch_service.dart";
import 'package:cake_wallet/new-ui/pages/lightning_username_page.dart';
import 'package:cake_wallet/new-ui/pages/receive_page.dart';
import 'package:cake_wallet/new-ui/viewmodels/lightning_username/lightning_username_bloc.dart';
@@ -171,7 +173,6 @@ import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
import 'package:cake_wallet/src/screens/ur/animated_ur_page.dart';
import 'package:cake_wallet/new-ui/pages/bridge/bridge_detail_page.dart';
-import 'package:cake_wallet/new-ui/pages/bridge/bridge_history_page.dart';
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
@@ -195,7 +196,6 @@ import 'package:cake_wallet/store/dashboard/trade_filter_store.dart';
import 'package:cake_wallet/store/bridge_transfers_store.dart';
import 'package:cake_wallet/store/dashboard/trades_store.dart';
import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
-import 'package:cake_wallet/store/node_list_store.dart';
import 'package:cake_wallet/store/seed_settings_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/store/templates/exchange_template_store.dart';
@@ -252,7 +252,6 @@ import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_cr
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
-import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
import 'package:cake_wallet/view_model/order_details_view_model.dart';
import 'package:cake_wallet/view_model/payjoin_details_view_model.dart';
import 'package:cake_wallet/view_model/payment/payment_view_model.dart';
@@ -928,7 +927,8 @@ Future setup({
authService: getIt.get(),
params: params,
contactListViewModel: getIt.get(),
- paymentViewModel: getIt.get(),
+ anyPayService: getIt.get(),
+ linkViewModel: getIt.get(),
walletSwitcherViewModel: getIt.get(),
);
});
@@ -1293,6 +1293,16 @@ Future setup({
appStore: getIt.get(),
));
+ getIt.registerFactory(() => WalletSwitchService(
+ walletLoadingService: getIt.get(),
+ appStore: getIt.get(),
+ ));
+
+ getIt.registerFactory(() => AnyPayService(
+ appStore: getIt.get(),
+ walletSwitchService: getIt.get(),
+ ));
+
getIt.registerFactory(() => WalletSwitcherViewModel(
appStore: getIt.get(),
walletLoadingService: getIt.get(),
diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart
index 3934b6330..ae94b47e1 100644
--- a/lib/entities/default_settings_migration.dart
+++ b/lib/entities/default_settings_migration.dart
@@ -27,7 +27,6 @@ import 'package:cw_core/wallet_type.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:hive/hive.dart';
import 'package:shared_preferences/shared_preferences.dart';
-import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/erc20_token.dart';
const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
@@ -1270,22 +1269,22 @@ Future _addXautTokenToExistingEthereumWallets() async {
final ethereumWallets =
allWallets.where((wallet) => wallet.type == WalletType.ethereum).toList();
+ const ethereumChainId = 1;
for (final walletInfo in ethereumWallets) {
- final sanitizedName = walletInfo.name.replaceAll(' ', '_');
- final boxName = '${sanitizedName}_${Erc20Token.ethereumBoxName}';
+ final existingToken = await Erc20Token.getByContract(
+ walletInfo.name,
+ ethereumChainId,
+ xautToken.contractAddress,
+ );
- Box tokenBox;
- if (CakeHive.isBoxOpen(boxName)) {
- tokenBox = CakeHive.box(boxName);
- } else {
- tokenBox = await CakeHive.openBox(boxName);
- }
+ if (existingToken != null) continue;
- final xautAddress = xautToken.contractAddress;
- if (!tokenBox.containsKey(xautAddress)) {
- await tokenBox.put(xautAddress, xautToken);
- }
+ await Erc20Token.copyWith(
+ xautToken,
+ walletName: walletInfo.name,
+ chainId: ethereumChainId,
+ ).save();
}
} catch (e) {
printV('Error in XAUT migration: $e');
@@ -1309,20 +1308,11 @@ Future _addXaut0TokenToExistingSolanaWallets() async {
final solanaWallets = allWallets.where((wallet) => wallet.type == WalletType.solana).toList();
for (final walletInfo in solanaWallets) {
- final sanitizedName = walletInfo.name.replaceAll(' ', '_');
- final boxName = '${sanitizedName}_${SPLToken.boxName}';
+ final existingToken = await SPLToken.getByMint(walletInfo.name, xaut0Token.mintAddress);
- Box tokenBox;
- if (CakeHive.isBoxOpen(boxName)) {
- tokenBox = CakeHive.box(boxName);
- } else {
- tokenBox = await CakeHive.openBox(boxName);
- }
+ if (existingToken != null) continue;
- final xaut0Address = xaut0Token.mintAddress;
- if (!tokenBox.containsKey(xaut0Address)) {
- await tokenBox.put(xaut0Address, xaut0Token);
- }
+ await SPLToken.copyWith(xaut0Token, walletName: walletInfo.name).save();
}
} catch (e) {
printV('Error in XAUT0 migration: $e');
@@ -1346,20 +1336,13 @@ Future _addTbbTokenToExistingSolanaWallets() async {
final solanaWallets = allWallets.where((wallet) => wallet.type == WalletType.solana).toList();
for (final walletInfo in solanaWallets) {
- final sanitizedName = walletInfo.name.replaceAll(" ", "_");
- final boxName = "${sanitizedName}_${SPLToken.boxName}";
+ final existingToken = await SPLToken.getByMint(walletInfo.name, tbbToken.mintAddress);
- Box tokenBox;
- if (CakeHive.isBoxOpen(boxName)) {
- tokenBox = CakeHive.box(boxName);
- } else {
- tokenBox = await CakeHive.openBox(boxName);
+ if (existingToken != null) {
+ continue;
}
- final tbbAddress = tbbToken.mintAddress;
- if (!tokenBox.containsKey(tbbAddress)) {
- await tokenBox.put(tbbAddress, tbbToken);
- }
+ await SPLToken.copyWith(tbbToken, walletName: walletInfo.name).save();
}
} catch (e) {
printV("Error in TBB migration: $e");
diff --git a/lib/exchange/provider/near_Intents_exchange_provider.dart b/lib/exchange/provider/near_Intents_exchange_provider.dart
index cbf0999e4..7b1c2ef1d 100644
--- a/lib/exchange/provider/near_Intents_exchange_provider.dart
+++ b/lib/exchange/provider/near_Intents_exchange_provider.dart
@@ -534,6 +534,13 @@ class NearIntentsExchangeProvider extends ExchangeProvider {
final symbol = currency.title.toUpperCase();
final blockchain = _normalizeTagToNearBlockchain(currency.tag);
+// Use the native Bitcoin asset routed through Omni Bridge.
+ if (currency == CryptoCurrency.btc) {
+ return supported.firstWhereOrNull(
+ (t) => t.assetId == '1cs_v1:btc:native:coin',
+ );
+ }
+
// Native asset (no contract)
final native = supported.firstWhereOrNull((t) =>
t.symbol.toUpperCase() == symbol &&
@@ -572,7 +579,7 @@ class NearIntentsExchangeProvider extends ExchangeProvider {
String _buildDeadline() {
return DateTime.now()
.toUtc()
- .add(const Duration(hours: 2))
+ .add(const Duration(hours: 1))
.toIso8601String()
.replaceFirst(RegExp(r'\.\d+Z$'), 'Z');
}
diff --git a/lib/main.dart b/lib/main.dart
index 2f248858e..02229c80a 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -43,7 +43,7 @@ import 'package:cake_wallet/zcash/zcash.dart';
import 'package:cw_core/address_info.dart';
import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/db/sqlite.dart';
-import 'package:cw_core/erc20_token.dart';
+import 'package:cw_core/erc20_token_legacy.dart' show performErc20TokenHiveMigration;
import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/key.dart';
import 'package:cw_core/mweb_utxo.dart';
@@ -51,8 +51,8 @@ import 'package:cw_core/node.dart';
import 'package:cw_core/node_legacy.dart' show performNodeHiveMigration;
import 'package:cw_core/payjoin_session.dart';
import 'package:cw_core/root_dir.dart';
-import 'package:cw_core/spl_token.dart';
-import 'package:cw_core/tron_token.dart';
+import 'package:cw_core/spl_token_legacy.dart' show performSplTokenHiveMigration;
+import 'package:cw_core/tron_token_legacy.dart' show performTronTokenHiveMigration;
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/proxy_logger/memory_proxy_logger.dart';
@@ -265,18 +265,10 @@ Future initializeAppConfigs({bool loadWallet = true}) async {
CakeHive.registerAdapter(PayjoinSessionAdapter());
}
- if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
- CakeHive.registerAdapter(Erc20TokenAdapter());
- }
-
- if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
- CakeHive.registerAdapter(SPLTokenAdapter());
- }
-
- if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
- CakeHive.registerAdapter(TronTokenAdapter());
- }
await performHiveMigration();
+ await performErc20TokenHiveMigration();
+ await performSplTokenHiveMigration();
+ await performTronTokenHiveMigration();
final secureStorage = secureStorageShared;
final transactionDescriptionsBoxKey =
diff --git a/lib/new-ui/pages/send_page.dart b/lib/new-ui/pages/send_page.dart
index 1500e2ca6..0b0c51d03 100644
--- a/lib/new-ui/pages/send_page.dart
+++ b/lib/new-ui/pages/send_page.dart
@@ -1,11 +1,13 @@
-import "package:cake_wallet/core/address_resolver/address_resolver_service.dart";
+import "dart:async";
+
import "package:cake_wallet/core/address_resolver/parsed_address.dart";
import "package:cake_wallet/core/address_validator.dart";
+import "package:cake_wallet/core/anypay/anypay_models.dart";
+import "package:cake_wallet/core/anypay/anypay_parser.dart";
+import "package:cake_wallet/core/anypay/anypay_service.dart";
import "package:cake_wallet/core/auth_service.dart";
import "package:cake_wallet/core/execution_state.dart";
import "package:cake_wallet/core/open_crypto_pay/open_cryptopay_service.dart";
-import "package:cake_wallet/core/universal_address_detector.dart";
-import "package:cake_wallet/di.dart";
import "package:cake_wallet/entities/contact_record.dart";
import "package:cake_wallet/entities/priority_for_wallet_type.dart";
import "package:cake_wallet/evm/evm.dart";
@@ -14,14 +16,10 @@ import "package:cake_wallet/main.dart";
import "package:cake_wallet/monero/monero.dart";
import "package:cake_wallet/new-ui/modal_navigator.dart";
import "package:cake_wallet/new-ui/pages/coin_control_page.dart";
-import "package:cake_wallet/new-ui/pages/swap_page.dart";
import "package:cake_wallet/new-ui/widgets/animated_dropdown.dart";
-import "package:cake_wallet/new-ui/widgets/anypay/evm_address_detected_sheet.dart";
+import "package:cake_wallet/new-ui/widgets/anypay/anypay_flow.dart";
import "package:cake_wallet/new-ui/widgets/anypay/recipient_network_row.dart";
import "package:cake_wallet/new-ui/widgets/anypay/select_recipient_network_sheet.dart";
-import "package:cake_wallet/new-ui/widgets/anypay/send_to_network_page.dart";
-import "package:cake_wallet/new-ui/widgets/anypay/swap_from_network_page.dart";
-import "package:cake_wallet/new-ui/widgets/anypay/switch_network_wallet_page.dart";
import "package:cake_wallet/new-ui/widgets/currency_picker/currency_picker_args.dart";
import "package:cake_wallet/new-ui/widgets/currency_picker/currency_picker_sheet.dart";
import "package:cake_wallet/new-ui/widgets/currency_picker/fiat_currency_picker_sheet.dart";
@@ -40,22 +38,17 @@ import "package:cake_wallet/new-ui/widgets/send_page/send_amount_input.dart";
import "package:cake_wallet/new-ui/widgets/send_page/send_confirm_sheet.dart";
import "package:cake_wallet/new-ui/widgets/send_page/send_memo_input.dart";
import "package:cake_wallet/new-ui/widgets/send_page/send_syncing_indicator.dart";
-import "package:cake_wallet/new-ui/widgets/swap_page/swap_from_send_args.dart";
import "package:cake_wallet/reactions/wallet_connect.dart";
import "package:cake_wallet/routes.dart" show Routes;
import "package:cake_wallet/src/screens/connect_device/connect_device_page.dart";
import "package:cake_wallet/src/widgets/alert_with_one_action.dart";
-import "package:cake_wallet/src/widgets/bottom_sheet/info_bottom_sheet_widget.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/src/widgets/new_list_row/list_item_regular_row_widget.dart";
import "package:cake_wallet/src/widgets/standard_checkbox.dart";
-import "package:cake_wallet/store/app_store.dart";
import "package:cake_wallet/utils/payment_request.dart";
import "package:cake_wallet/utils/show_pop_up.dart";
-import "package:cake_wallet/utils/token_utilities.dart";
import "package:cake_wallet/view_model/contact_list/contact_list_view_model.dart";
-import "package:cake_wallet/view_model/exchange/exchange_view_model.dart";
-import "package:cake_wallet/view_model/payment/payment_view_model.dart";
+import "package:cake_wallet/view_model/link_view_model.dart";
import "package:cake_wallet/view_model/send/output.dart";
import "package:cake_wallet/view_model/send/send_view_model.dart";
import "package:cake_wallet/view_model/send/send_view_model_state.dart";
@@ -64,12 +57,11 @@ import "package:cw_core/amount/amount_sanitizer.dart";
import "package:cw_core/amount/money.dart";
import "package:cw_core/crypto_currency.dart";
import "package:cw_core/currency_for_wallet_type.dart";
+import "package:cw_core/erc20_token.dart";
import "package:cw_core/lnurl.dart";
-import "package:cw_core/payment_uris.dart";
import "package:cw_core/transaction_priority.dart";
import "package:cw_core/unspent_coin_type.dart";
import "package:cw_core/utils/print_verbose.dart";
-import "package:cw_core/wallet_info.dart";
import "package:cw_core/wallet_type.dart";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
@@ -168,12 +160,14 @@ class SendPageModes {
class SendPageParams {
SendPageParams({
this.initialPaymentRequest,
+ this.initialRawInput,
SendPageModes? mode,
this.unspentCoinType = UnspentCoinType.any,
this.initialCurrency,
}) : mode = mode ?? SendPageModes.normal;
final PaymentRequest? initialPaymentRequest;
+ final String? initialRawInput;
final SendPageModes mode;
final CryptoCurrency? initialCurrency;
final UnspentCoinType unspentCoinType;
@@ -182,13 +176,15 @@ class SendPageParams {
class NewSendPage extends StatefulWidget {
NewSendPage({
required this.sendViewModel,
- required this.paymentViewModel,
+ required this.anyPayService,
+ required this.linkViewModel,
required this.walletSwitcherViewModel,
required this.contactListViewModel,
required this.authService,
required SendPageParams params,
super.key,
}) : initialPaymentRequest = params.initialPaymentRequest,
+ initialRawInput = params.initialRawInput,
mode = params.mode {
if (params.initialCurrency != null) {
sendViewModel.selectedCryptoCurrency = params.initialCurrency!;
@@ -196,11 +192,13 @@ class NewSendPage extends StatefulWidget {
}
final SendViewModel sendViewModel;
- final PaymentViewModel paymentViewModel;
+ final AnyPayService anyPayService;
+ final LinkViewModel linkViewModel;
final WalletSwitcherViewModel walletSwitcherViewModel;
final ContactListViewModel contactListViewModel;
final AuthService authService;
final PaymentRequest? initialPaymentRequest;
+ final String? initialRawInput;
final SendPageModes mode;
@override
@@ -215,8 +213,14 @@ class _NewSendPageState extends State {
final _memoControllers = [];
final _formKey = GlobalKey();
final _addressFocusNode = FocusNode();
- BuildContext? loadingBottomSheetContext;
- BuildContext? dialogContext;
+ final _disposers = [];
+ StreamSubscription? _deepLinkSubscription;
+ late final AnyPayFlow _anyPayFlow = AnyPayFlow(
+ anyPayService: widget.anyPayService,
+ sendViewModel: widget.sendViewModel,
+ authService: widget.authService,
+ walletSwitcherViewModel: widget.walletSwitcherViewModel,
+ );
ContactRecord? newContactAddress;
bool _justHandledPasteButton = false;
@@ -226,85 +230,64 @@ class _NewSendPageState extends State {
super.initState();
_addInputControllers();
- reaction((_) => widget.sendViewModel.outputs[_selectedOutput].sendAll, (all) {
- if (all) {
- widget.sendViewModel.outputs[_selectedOutput].isFiatEntry = false;
- _amountControllers[_selectedOutput].text = S.current.all;
- }
- });
-
- reaction((_) => widget.sendViewModel.outputs[_selectedOutput].address, (address) {
- if (_addressControllers[_selectedOutput].text != address) {
- _addressControllers[_selectedOutput].text = address;
- }
- });
-
- reaction((_) => widget.sendViewModel.outputs[_selectedOutput].memo, (memo) {
- if (memo != _memoControllers[_selectedOutput].text) {
- _memoControllers[_selectedOutput].text = memo;
- }
- });
-
- if (widget.initialPaymentRequest != null) {
- if (_isInitialRequestTypeSameAsCurrentWallet()) {
- _addressControllers[0].text = widget.initialPaymentRequest!.address;
- // _memoControllers[0].text = widget.initialPaymentRequest!.note;
- _applyNote(widget.initialPaymentRequest!.note, 0);
- final contractAddress = widget.initialPaymentRequest!.contractAddress;
- if (contractAddress != null && contractAddress.isNotEmpty) {
- WidgetsBinding.instance.addPostFrameCallback((_) async {
- if (!mounted) {
- return;
- }
- final token = await TokenUtilities.findTokenByAddress(
- walletType: widget.sendViewModel.wallet.type,
- address: contractAddress,
- );
- if (!mounted) {
- return;
- }
-
- if (token == null) {
- _showUnsupportedTokenAlert();
- return;
- }
- await widget.sendViewModel.fetchTokenForContractAddress(contractAddress);
- if (!mounted) {
- return;
- }
- _amountControllers[0].text =
- widget.initialPaymentRequest!.resolveTokenAmount(token) ?? "";
- });
- } else {
- _amountControllers[0].text = widget.initialPaymentRequest!.amount;
+ _disposers.add(
+ reaction((_) => widget.sendViewModel.outputs[_selectedOutput].sendAll, (all) {
+ if (all) {
+ widget.sendViewModel.outputs[_selectedOutput].isFiatEntry = false;
+ _amountControllers[_selectedOutput].text = S.current.all;
}
- } else {
- WidgetsBinding.instance.addPostFrameCallback(
- (timeStamp) {
- if (mounted) {
- final paymentRequest = widget.initialPaymentRequest!;
- final scheme = paymentRequest.scheme.toLowerCase();
- final String uri;
- if (scheme.isEmpty || scheme == "lightning") {
- uri = paymentRequest.address;
- } else if (scheme == "ethereum") {
- uri = ERC681URI(
- address: paymentRequest.address,
- amount: paymentRequest.amount,
- contractAddress: paymentRequest.contractAddress,
- chainId: paymentRequest.chainId ?? _currentEvmChainIdOrMainnet(),
- rawTokenAmount: paymentRequest.rawTokenAmount,
- ).toString();
- } else {
- final amount =
- paymentRequest.amount.isNotEmpty ? "?amount=${paymentRequest.amount}" : "";
- uri = "${paymentRequest.scheme}:${paymentRequest.address}$amount";
- }
- _handlePaymentFlow(uri, paymentRequest);
- }
- },
+ }),
+ );
+
+ _disposers.add(
+ reaction((_) => widget.sendViewModel.outputs[_selectedOutput].address, (address) {
+ if (_addressControllers[_selectedOutput].text != address) {
+ _addressControllers[_selectedOutput].text = address;
+ }
+ }),
+ );
+
+ _disposers.add(
+ reaction((_) => widget.sendViewModel.outputs[_selectedOutput].memo, (memo) {
+ if (memo != _memoControllers[_selectedOutput].text) {
+ _memoControllers[_selectedOutput].text = memo;
+ }
+ }),
+ );
+
+ if (widget.initialRawInput != null || widget.initialPaymentRequest != null) {
+ WidgetsBinding.instance.addPostFrameCallback((_) async {
+ if (!mounted) {
+ return;
+ }
+ await _runAnyPayFlow(
+ rawInput: widget.initialRawInput,
+ paymentRequest: widget.initialPaymentRequest,
);
- }
+ });
+ }
+
+ if (widget.mode == SendPageModes.normal) {
+ _deepLinkSubscription = widget.linkViewModel.incomingPaymentLinks.listen((link) async {
+ if (!mounted) {
+ return;
+ }
+
+ final state = widget.sendViewModel.state;
+ if (_anyPayFlow.isSwitchingWallet ||
+ state is IsExecutingState ||
+ state is TransactionCommitting) {
+ printV("dropping incoming payment link while the send flow is busy");
+ return;
+ }
+
+ final route = ModalRoute.of(context);
+ if (route != null && !route.isCurrent) {
+ Navigator.of(context).popUntil((r) => r == route);
+ }
+
+ await _runAnyPayFlow(rawInput: link.toString());
+ });
}
_addressFocusNode.addListener(() async {
@@ -315,6 +298,25 @@ class _NewSendPageState extends State {
});
}
+ @override
+ void dispose() {
+ _deepLinkSubscription?.cancel();
+ for (final disposer in _disposers) {
+ disposer();
+ }
+ for (final controller in _amountControllers) {
+ controller.dispose();
+ }
+ for (final controller in _addressControllers) {
+ controller.dispose();
+ }
+ for (final controller in _memoControllers) {
+ controller.dispose();
+ }
+ _addressFocusNode.dispose();
+ super.dispose();
+ }
+
Future _resolveAddressForOutput(Output output) async {
final result = await widget.sendViewModel.resolveAddressForOutput(output);
if (result == null || !mounted) {
@@ -343,6 +345,9 @@ class _NewSendPageState extends State {
Widget build(BuildContext context) => Observer(
builder: (_) {
final output = widget.sendViewModel.outputs[_selectedOutput];
+ final recipientChain = widget.sendViewModel.isEVMWallet
+ ? evm!.getChainInfoByChainId(_currentEvmChainIdOrMainnet())
+ : null;
return SafeArea(
bottom: false,
child: KeyboardHideOverlay(
@@ -468,11 +473,7 @@ class _NewSendPageState extends State {
output.resetParsedAddress();
await _resolveAddressForOutput(output);
- // Process the payment through the new flow
- await _handlePaymentFlow(
- uri.toString(),
- PaymentRequest.fromString(uri.toString()),
- );
+ await _runAnyPayFlow(rawInput: uri.toString());
},
onEditingComplete: _addressFocusNode.unfocus,
onPushAddressBookButton: (_) {
@@ -494,16 +495,7 @@ class _NewSendPageState extends State {
? output.extractedAddress
: output.address;
- await _handlePaymentFlow(
- address,
- PaymentRequest(
- address,
- _amountControllers[_selectedOutput].text,
- _memoControllers[_selectedOutput].text,
- "",
- null,
- ),
- );
+ await _runAnyPayPaste(address);
} finally {
_justHandledPasteButton = false;
}
@@ -514,10 +506,17 @@ class _NewSendPageState extends State {
widget.sendViewModel.selectedCryptoCurrency,
),
if (widget.sendViewModel.isEVMWallet &&
- _hasEvmRecipient(output))
+ _hasEvmRecipient(output) &&
+ recipientChain != null)
RecipientNetworkSelector(
- wallet: widget.sendViewModel.wallet,
- onTap: _presentRecipientNetworkPicker,
+ networkName: recipientChain.name,
+ networkIconPath: symbolIconPathForWalletType(
+ widget.sendViewModel.wallet.type,
+ ) ??
+ "",
+ onTap: () => _presentRecipientNetworkPicker(
+ recipientChain,
+ ),
),
],
),
@@ -1048,504 +1047,124 @@ class _NewSendPageState extends State {
}
Future _handleManualNetworkSelection(ChainInfo target) async {
- final address = _addressControllers[_selectedOutput].text.trim();
- final amount = _amountControllers[_selectedOutput].text;
+ final output = widget.sendViewModel.outputs[_selectedOutput];
+ final address = output.isParsedAddress
+ ? output.extractedAddress
+ : _addressControllers[_selectedOutput].text.trim();
final note = _memoControllers[_selectedOutput].text;
- final paymentRequest = PaymentRequest(address, amount, note, "", null);
- await _handleEvmNetworkFlow(target, paymentRequest);
- }
+ final isTokenSelected = widget.sendViewModel.selectedCryptoCurrency is Erc20Token;
+ final amount = isTokenSelected ? "" : _amountControllers[_selectedOutput].text;
+ final request =
+ AnyPayParser.fromPaymentRequest(PaymentRequest(address, amount, note, "", null));
- bool _isInitialRequestTypeSameAsCurrentWallet() {
- final req = widget.initialPaymentRequest;
- if (req == null) {
- return false;
- }
-
- final currentType = widget.sendViewModel.wallet.type;
- if (evm != null && isEVMCompatibleChain(currentType)) {
- final targetChainId = _evmTargetChainId(req);
- if (targetChainId != null) {
- return targetChainId == _currentEvmChainIdOrMainnet();
- }
- }
- return widget.sendViewModel.walletCurrencyName == req.scheme.toLowerCase();
- }
-
- int? _evmTargetChainId(PaymentRequest req) {
- final scheme = req.scheme.toLowerCase();
- if (scheme == "ethereum") {
- if (req.chainId != null) {
- return req.chainId;
- }
-
- return _currentEvmChainIdOrMainnet();
- }
- try {
- return getChainIdByCryptoCurrency(CryptoCurrency.fromString(scheme));
- } catch (_) {
- return null;
+ final evaluation = await widget.anyPayService.evaluateForEvmChain(request, target.chainId);
+ if (!mounted) {
+ return;
}
+ await _handleEvaluation(evaluation, fallbackCurrency: target.currency);
}
int _currentEvmChainIdOrMainnet() {
final wallet = widget.sendViewModel.wallet;
- if (evm != null && isEVMCompatibleChain(wallet.type)) {
+ if (isEVMCompatibleChain(wallet.type)) {
return evm!.getSelectedChainId(wallet) ?? evm!.getChainIdByWalletType(wallet.type);
}
return 1;
}
- Future _handlePaymentFlow(String uri, PaymentRequest paymentRequest) async {
- final isEip681 = uri.toLowerCase().startsWith("ethereum:");
- if (!isEip681 && (uri.contains("@") || paymentRequest.address.contains("@"))) {
+ Future _handleIfOpenCryptoPay(String input) async {
+ if (!OpenCryptoPayService.isOpenCryptoPayQR(input) ||
+ widget.sendViewModel.selectedCryptoCurrency == CryptoCurrency.btcln) {
+ return false;
+ }
+
+ if (_selectedOutput != 0) {
+ setState(() => _selectedOutput = 0);
+ }
+
+ final request = await widget.sendViewModel.getOpenCryptoPayRequest(input);
+ if (request != null && mounted) {
+ _applyPaymentRequest(request);
+ }
+ return true;
+ }
+
+ Future _runAnyPayFlow({String? rawInput, PaymentRequest? paymentRequest}) async {
+ assert(rawInput != null || paymentRequest != null);
+
+ final evaluation = rawInput != null
+ ? await widget.anyPayService.evaluateRawInput(rawInput)
+ : await widget.anyPayService.evaluatePaymentRequest(paymentRequest!);
+
+ if (!mounted) {
return;
}
- if (OpenCryptoPayService.isOpenCryptoPayQR(uri) &&
- widget.sendViewModel.selectedCryptoCurrency != CryptoCurrency.btcln) {
- final request = await widget.sendViewModel.getOpenCryptoPayRequest(uri);
- if (request == null) {
- return;
- }
- _applyPaymentRequest(request);
+ if (await _handleIfOpenCryptoPay(evaluation.request.rawInput)) {
+ return;
+ }
+
+ await _handleEvaluation(evaluation);
+ }
+
+ Future _runAnyPayPaste(String pasted) async {
+ if (await _handleIfOpenCryptoPay(pasted)) {
+ return;
+ }
+
+ final parsed = PaymentRequest.fromString(pasted);
+ final parsedAmount = parsed.amount == "0" ? "" : parsed.amount;
+ final merged = parsed.copyWith(
+ amount: parsedAmount.isNotEmpty ? parsedAmount : _amountControllers[_selectedOutput].text,
+ note: parsed.note.isNotEmpty ? parsed.note : _memoControllers[_selectedOutput].text,
+ );
+
+ await _runAnyPayFlow(paymentRequest: merged);
+ }
+
+ Future _handleEvaluation(
+ AnyPayEvaluation evaluation, {
+ CryptoCurrency? fallbackCurrency,
+ }) async {
+ final evaluationResult = await _anyPayFlow.handleEvaluation(
+ context,
+ evaluation,
+ fallbackCurrency: fallbackCurrency,
+ );
+ if (evaluationResult == null || !mounted) {
return;
}
try {
- final result = await widget.paymentViewModel.processAddress(uri);
-
- if (paymentRequest.contractAddress != null) {
- await widget.sendViewModel.fetchTokenForContractAddress(paymentRequest.contractAddress!);
- }
-
- // This automatically switches to lightning mode if you are in a bitcoin wallet
- if (result.addressDetectionResult?.detectedCurrency == CryptoCurrency.btcln) {
- widget.sendViewModel.selectedCryptoCurrency = CryptoCurrency.btcln;
- widget.sendViewModel.coinTypeToSpendFrom = UnspentCoinType.lightning;
- }
-
- switch (result.type) {
- case PaymentFlowType.singleWallet:
- case PaymentFlowType.multipleWallets:
- case PaymentFlowType.noWallets:
- await _showPaymentConfirmation(
- widget.paymentViewModel,
- widget.walletSwitcherViewModel,
- paymentRequest,
- result,
- );
- break;
- case PaymentFlowType.evmNetworkSelection:
- if (result.chainId != null && evm!.getChainInfoByChainId(result.chainId!) == null) {
- _showUnsupportedNetworkAlert(result.chainId!);
- return;
- }
-
- final targetChainId =
- paymentRequest.scheme.isNotEmpty ? _evmTargetChainId(paymentRequest) : null;
- final targetChain =
- targetChainId != null ? evm!.getChainInfoByChainId(targetChainId) : null;
- final currentChainId = isEVMCompatibleChain(widget.sendViewModel.wallet.type)
- ? _currentEvmChainIdOrMainnet()
- : null;
- final isCrossChain = targetChain != null && targetChain.chainId != currentChainId;
-
- if (isCrossChain) {
- await _handleEvmNetworkFlow(targetChain, paymentRequest);
- } else if (widget.sendViewModel.isEVMWallet) {
- _applyPaymentRequest(paymentRequest);
- } else {
- await _showEvmNetworkPicker(paymentRequest, result.walletType);
- }
- break;
- case PaymentFlowType.solanaTokenSelection:
- case PaymentFlowType.tronTokenSelection:
- await _showPaymentConfirmation(
- widget.paymentViewModel,
- widget.walletSwitcherViewModel,
- paymentRequest,
- result,
- );
- break;
- case PaymentFlowType.currentWalletCompatible:
- case PaymentFlowType.error:
- case PaymentFlowType.incompatible:
- _applyPaymentRequest(paymentRequest);
- break;
- }
+ await _applyIntent(
+ evaluationResult.request,
+ token: evaluationResult.token,
+ fallbackCurrency: evaluationResult.fallbackCurrency,
+ amountOverride: evaluationResult.amountOverride,
+ );
} catch (e) {
printV("Payment flow error: $e");
- _applyPaymentRequest(paymentRequest);
+ _applyPaymentRequest(evaluationResult.request.paymentRequest);
}
}
- void _showUnsupportedNetworkAlert(int chainId) {
- if (!mounted) {
- return;
- }
-
- showPopUp(
- context: context,
- builder: (context) => AlertWithOneAction(
- alertTitle: S.of(context).error,
- alertContent: S.of(context).unsupported_network_requested(chainId.toString()),
- buttonText: S.of(context).ok,
- buttonAction: () => Navigator.of(context).pop(),
- ),
- );
- }
-
- Future _showPaymentConfirmation(
- PaymentViewModel paymentViewModel,
- WalletSwitcherViewModel walletSwitcherViewModel,
- PaymentRequest paymentRequest,
- PaymentFlowResult result,
- ) async {
- if (!mounted || result.walletType == null) {
- return;
- }
-
- final destinationType = result.walletType!;
- final isEvmTarget = isEVMCompatibleChain(destinationType);
- final destinationChainId = result.chainId;
- final destinationNetworkName = networkDisplayName(destinationType, destinationChainId);
- final destinationNetworkIcon = symbolIconPathForWalletType(destinationType) ?? "";
-
- final currentType = widget.sendViewModel.wallet.type;
- final currentChainId =
- isEVMCompatibleChain(currentType) && evm != null ? _currentEvmChainIdOrMainnet() : null;
- final currentNetworkName = networkDisplayName(currentType, currentChainId);
- final currentNetworkIcon = symbolIconPathForWalletType(currentType) ?? "";
-
- final hasSingleWallet =
- result.type == PaymentFlowType.singleWallet || result.wallets.length == 1;
- final hasMultipleWallets =
- result.type == PaymentFlowType.multipleWallets || result.wallets.length > 1;
- final hasWallet = hasSingleWallet || hasMultipleWallets || result.wallet != null;
-
- final decisionTitle = isEvmTarget
- ? S.of(context).send_to_network(destinationNetworkName)
- : S.of(context).network_address_detected(destinationNetworkName);
- final swapConfirmTitle = isEvmTarget
- ? S.of(context).swap_from_network(currentNetworkName)
- : S.of(context).network_address_detected(destinationNetworkName);
- final swapConfirmPrimary = isEvmTarget
- ? S.of(context).continue_to_swap
- : S.of(context).swap_from_network(currentNetworkName);
-
- if (hasWallet) {
- await Navigator.of(context).push(
- CupertinoPageRoute(
- builder: (pageContext) => SendToNetworkPage(
- title: decisionTitle,
- destinationNetworkName: destinationNetworkName,
- destinationIconPath: destinationNetworkIcon,
- currentNetworkName: currentNetworkName,
- onSwitchWallet: () => _onSwitchWalletSelected(
- pageContext,
- result,
- paymentRequest,
- destinationNetworkName,
- destinationNetworkIcon,
- hasMultipleWallets,
- ),
- onSwap: () => _onSwapSelected(pageContext, result, paymentRequest),
- ),
- ),
- );
- } else {
- await Navigator.of(context).push(
- CupertinoPageRoute(
- builder: (pageContext) => SwapFromNetworkPage(
- title: swapConfirmTitle,
- primaryButtonText: swapConfirmPrimary,
- primaryHasSwapIcon: !isEvmTarget,
- destinationNetworkName: destinationNetworkName,
- destinationNetworkIconPath: destinationNetworkIcon,
- currentNetworkName: currentNetworkName,
- currentNetworkIconPath: currentNetworkIcon,
- onProceed: () => _onSwapSelected(pageContext, result, paymentRequest),
- ),
- ),
- );
- }
- }
-
- Future _onSwapSelected(
- BuildContext pageContext,
- PaymentFlowResult result,
- PaymentRequest paymentRequest,
- ) async {
- await _handleSwapFlow(result, pageContext, paymentRequest);
- }
-
- Future _onSwitchWalletSelected(
- BuildContext pageContext,
- PaymentFlowResult result,
- PaymentRequest paymentRequest,
- String destName,
- String destIcon,
- bool hasMultipleWallets,
- ) async {
- WalletInfo? destinationWalletInfo;
- if (hasMultipleWallets) {
- destinationWalletInfo = await SwitchNetworkWalletPage.push(
- context: pageContext,
- networkName: destName,
- targetIconPath: destIcon,
- wallets: result.wallets,
- );
- if (destinationWalletInfo == null) {
- return;
- }
- } else {
- destinationWalletInfo =
- result.wallet ?? (result.wallets.isNotEmpty ? result.wallets.first : null);
- }
-
- if (destinationWalletInfo == null) {
- return;
- }
-
- // We may have awaited the wallet picker above, so make sure the decision page
- // is still around before we reach into its navigator.
- if (!pageContext.mounted) {
- return;
- }
- if (Navigator.of(pageContext).canPop()) {
- Navigator.of(pageContext).pop();
- }
- if (!mounted) {
- return;
- }
- await _completeWalletSwitch(destinationWalletInfo, result, paymentRequest);
- }
-
- Future _applyPaymentSelectingCurrency(
- PaymentRequest paymentRequest,
+ Future _applyIntent(
+ AnyPayRequest request, {
+ CryptoCurrency? token,
CryptoCurrency? fallbackCurrency,
- ) async {
- String? amountOverride;
- final contract = paymentRequest.contractAddress;
- if (contract != null && contract.isNotEmpty) {
- final token = await TokenUtilities.findTokenByAddress(
- walletType: widget.sendViewModel.wallet.type,
- address: contract,
- );
- if (!mounted) {
- return;
- }
-
- if (token == null) {
- _showUnsupportedTokenAlert();
- return;
- }
- await widget.sendViewModel.fetchTokenForContractAddress(contract);
- amountOverride = paymentRequest.resolveTokenAmount(token);
- } else if (fallbackCurrency != null) {
- widget.sendViewModel.setSelectedCryptoCurrency(fallbackCurrency.title);
- }
- if (!mounted) {
- return;
- }
- _applyPaymentRequest(paymentRequest, amountOverride: amountOverride);
- }
-
- Future _completeWalletSwitch(
- WalletInfo wallet,
- PaymentFlowResult result,
- PaymentRequest paymentRequest,
- ) async {
- widget.walletSwitcherViewModel.selectWallet(wallet);
- final success = await widget.walletSwitcherViewModel.switchToSelectedWallet();
- if (!success) {
- _showNetworkSwitchFailedAlert();
- return;
- }
- if (!mounted) {
- return;
+ String? amountOverride,
+ }) async {
+ final currency = token ?? fallbackCurrency;
+ if (currency != null) {
+ widget.sendViewModel.applyAnyPayCurrency(currency);
}
- bool completedFlow = false;
- WidgetsBinding.instance.addPostFrameCallback((_) {
- if (!mounted || completedFlow) {
- return;
- }
- showModalBottomSheet(
- context: context,
- isDismissible: false,
- builder: (BuildContext sheetContext) {
- if (completedFlow) {
- WidgetsBinding.instance.addPostFrameCallback((_) {
- if (Navigator.canPop(sheetContext)) {
- Navigator.of(sheetContext).pop();
- }
- });
- return const SizedBox.shrink();
- }
- loadingBottomSheetContext = sheetContext;
- return LoadingBottomSheet(titleText: S.of(sheetContext).loading_your_wallet);
- },
- );
- });
-
- bool chainSwitchFailed = false;
- try {
- if (evm != null &&
- isEVMCompatibleChain(widget.sendViewModel.wallet.type) &&
- result.chainId != null) {
- final appStore = getIt.get();
- final node = appStore.settingsStore
- .getCurrentNode(widget.sendViewModel.wallet.type, chainId: result.chainId);
- await evm!.selectChain(widget.sendViewModel.wallet, result.chainId!, node: node);
- }
- } catch (e, s) {
- chainSwitchFailed = true;
- printV("completeWalletSwitch failed: $e\n$s");
+ if (token == null && fallbackCurrency != null && request.amount.isEmpty) {
+ widget.sendViewModel.outputs[_selectedOutput].setCryptoAmount("");
+ _amountControllers[_selectedOutput].clear();
}
- if (!chainSwitchFailed) {
- try {
- await widget.sendViewModel.wallet.updateBalance();
- } catch (e) {
- printV("balance refresh after network switch failed: $e");
- }
- }
-
- completedFlow = true;
- if (loadingBottomSheetContext != null &&
- loadingBottomSheetContext!.mounted &&
- Navigator.canPop(loadingBottomSheetContext!)) {
- Navigator.of(loadingBottomSheetContext!).pop();
- }
- loadingBottomSheetContext = null;
-
- if (!mounted) {
- return;
- }
-
- if (chainSwitchFailed) {
- _showNetworkSwitchFailedAlert();
- return;
- }
-
- await _applyPaymentSelectingCurrency(
- paymentRequest,
- result.addressDetectionResult?.detectedCurrency,
- );
- }
-
- void _showNetworkSwitchFailedAlert() {
- if (!mounted) {
- return;
- }
-
- showPopUp(
- context: context,
- builder: (context) => AlertWithOneAction(
- alertTitle: S.of(context).error,
- alertContent: S.of(context).network_switch_failed,
- buttonText: S.of(context).ok,
- buttonAction: () => Navigator.of(context).pop(),
- ),
- );
- }
-
- void _showUnsupportedTokenAlert() {
- if (!mounted) {
- return;
- }
-
- showPopUp