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( - context: context, - builder: (context) => AlertWithOneAction( - alertTitle: S.of(context).error, - alertContent: S.of(context).unsupported_token_requested, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop(), - ), - ); - } - - Future _showEvmNetworkPicker( - PaymentRequest paymentRequest, - WalletType? fixedNetwork, - ) async { - if (!mounted || evm == null || fixedNetwork == null || !isEVMCompatibleChain(fixedNetwork)) { - return; - } - - final chains = evm!.getAllChains(); - final networks = chains.map((chain) { - final walletType = evm!.getWalletTypeByChainId(chain.chainId) ?? fixedNetwork; - return RecipientNetworkItem( - chainId: chain.chainId, - name: chain.name, - iconPath: getCryptoCurrencyIconForWalletListItem(walletType, chainId: chain.chainId), - chainBadgeIconPath: symbolIconPathForWalletType(walletType), - ); - }).toList(); - - final selectedChainId = - await EvmAddressDetectedSheet.show(context: context, networks: networks); - if (!mounted || selectedChainId == null) { - return; - } - - final target = chains.firstWhere( - (chain) => chain.chainId == selectedChainId, - orElse: () => chains.first, - ); - await _handleEvmNetworkFlow(target, paymentRequest); - } - - Future _handleEvmNetworkFlow(ChainInfo target, PaymentRequest paymentRequest) async { - if (evm == null || !mounted) { - return; - } - - final targetType = evm!.getWalletTypeByChainId(target.chainId); - if (targetType == null) { - _showUnsupportedNetworkAlert(target.chainId); - return; - } - - final detection = AddressDetectionResult( - address: paymentRequest.address, - detectedWalletType: targetType, - detectedCurrency: target.currency, - chainId: target.chainId, - amount: paymentRequest.amount, - note: paymentRequest.note, - scheme: "", - isValid: true, - ); - widget.paymentViewModel.applyManualEvmSelection(detection); - - final currentType = widget.sendViewModel.wallet.type; - final currentChainId = isEVMCompatibleChain(currentType) ? _currentEvmChainIdOrMainnet() : null; - if (currentChainId != null && target.chainId == currentChainId) { - await _applyPaymentSelectingCurrency(paymentRequest, target.currency); - return; - } - - final compatibleWallets = await widget.paymentViewModel.getWalletsByType(targetType); - if (!mounted) { - return; - } - - final result = PaymentFlowResult.evmNetworkSelection( - detection, - compatibleWallets: compatibleWallets, - wallet: compatibleWallets.isNotEmpty ? compatibleWallets.first : null, - ); - - await _showPaymentConfirmation( - widget.paymentViewModel, - widget.walletSwitcherViewModel, - paymentRequest, - result, - ); + _applyPaymentRequest(request.paymentRequest, amountOverride: amountOverride); } void _applyPaymentRequest(PaymentRequest paymentRequest, {String? amountOverride}) { @@ -1570,81 +1189,6 @@ class _NewSendPageState extends State { _applyNote(paymentRequest.note, _selectedOutput); } - Future _handleSwapFlow( - PaymentFlowResult result, - BuildContext presentContext, - PaymentRequest paymentRequest, - ) async { - if (!mounted) { - return; - } - - final destWalletType = result.walletType; - if (destWalletType == null) { - return; - } - - CryptoCurrency? resolvedToken; - final contract = paymentRequest.contractAddress; - if (contract != null && contract.isNotEmpty) { - resolvedToken = await TokenUtilities.findTokenByAddress( - walletType: destWalletType, - address: contract, - ); - } - if (!mounted || !presentContext.mounted) { - return; - } - - if (contract != null && contract.isNotEmpty && resolvedToken == null) { - _showUnsupportedTokenAlert(); - return; - } - - final receiveCurrency = resolvedToken ?? - result.detectedCurrency ?? - walletTypeToCryptoCurrency(destWalletType, chainId: result.chainId); - - final receiveAmountValue = resolvedToken != null - ? paymentRequest.resolveTokenAmount(resolvedToken) - : (paymentRequest.amount.isNotEmpty ? paymentRequest.amount : null); - final receiveAmount = - receiveAmountValue != null ? Money.tryParse(receiveAmountValue, receiveCurrency) : null; - - final isFiatDisabled = widget.sendViewModel.isFiatDisabled; - final depositBalanceByAsset = { - for (final r in widget.sendViewModel.balanceViewModel.formattedBalances) - r.asset: CurrencyPickerBalance( - amount: "${r.availableBalance} ${r.asset.title}", - fiat: isFiatDisabled ? null : "${r.fiatAvailableBalanceRaw} ${r.fiatCurrency?.symbol}", - fiatValue: isFiatDisabled ? null : double.tryParse(r.fiatAvailableBalanceRaw), - ), - }; - - final page = NewSwapPage( - getIt.get(), - widget.authService, - getIt.get(), - null, - walletSwitcherViewModel: widget.walletSwitcherViewModel, - fromSend: SwapFromSendArgs( - recipientAddress: result.addressDetectionResult?.address ?? "", - receiveCurrency: receiveCurrency, - targetWalletType: destWalletType, - depositBalanceByAsset: depositBalanceByAsset, - receiveAmount: receiveAmount, - ), - ); - await Navigator.of(presentContext).push( - CupertinoPageRoute( - builder: (context) => Material( - color: Theme.of(context).colorScheme.surface, - child: SafeArea(bottom: false, child: page), - ), - ), - ); - } - void showErrorValidationAlert(BuildContext context) { int emptyAddressIndex = -1; for (int i = 0; i < widget.sendViewModel.outputs.length; i++) { diff --git a/lib/new-ui/pages/swap_page.dart b/lib/new-ui/pages/swap_page.dart index d17447801..b59ef80e0 100644 --- a/lib/new-ui/pages/swap_page.dart +++ b/lib/new-ui/pages/swap_page.dart @@ -7,6 +7,7 @@ import "package:cake_wallet/exchange/exchange_trade_state.dart"; import "package:cake_wallet/exchange/provider/chainflip_exchange_provider.dart"; import "package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart"; import "package:cake_wallet/generated/i18n.dart"; +import "package:cake_wallet/new-ui/widgets/currency_picker/currency_picker_args.dart"; import "package:cake_wallet/new-ui/widgets/keyboard_hide_overlay.dart"; import "package:cake_wallet/new-ui/widgets/modern_button.dart"; import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart"; @@ -27,6 +28,7 @@ import "package:cake_wallet/src/widgets/primary_button.dart"; import "package:cake_wallet/utils/debounce.dart"; import "package:cake_wallet/utils/payment_request.dart"; import "package:cake_wallet/utils/show_pop_up.dart"; +import "package:cake_wallet/view_model/dashboard/balance_view_model.dart"; import "package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart"; import "package:cake_wallet/view_model/exchange/exchange_view_model.dart"; import "package:cake_wallet/view_model/wallet_switcher_view_model.dart"; @@ -51,6 +53,7 @@ class NewSwapPage extends StatefulWidget { required this.walletSwitcherViewModel, CryptoCurrency? initialCurrency, this.fromSend, + this.balanceViewModel, }) { depositWalletName = exchangeViewModel.depositCurrency == CryptoCurrency.xmr ? exchangeViewModel.wallet.name @@ -69,6 +72,7 @@ class NewSwapPage extends StatefulWidget { final AddressResolverService adrResService; final PaymentRequest? initialPaymentRequest; final SwapFromSendArgs? fromSend; + final BalanceViewModel? balanceViewModel; late final String? depositWalletName; late final String? receiveWalletName; @@ -93,6 +97,25 @@ class _NewSwapPageState extends State { .contains(widget.exchangeViewModel.depositCurrency) && !(widget.exchangeViewModel.status is SyncedSyncStatus); + Map? _depositBalanceByAsset() { + final balanceViewModel = widget.balanceViewModel; + if (balanceViewModel == null) { + return null; + } + + return { + for (final r in balanceViewModel.formattedBalances) + r.asset: CurrencyPickerBalance( + amount: "${r.availableBalance} ${r.asset.title}", + fiat: balanceViewModel.isFiatDisabled + ? null + : "${r.fiatAvailableBalanceRaw} ${r.fiatCurrency?.symbol}", + fiatValue: + balanceViewModel.isFiatDisabled ? null : double.tryParse(r.fiatAvailableBalanceRaw), + ), + }; + } + @override void initState() { super.initState(); @@ -258,8 +281,8 @@ class _NewSwapPageState extends State { (bool isReceiveAmountEditable) {}, )); - _disposers - .add(reaction((_) => widget.exchangeViewModel.tradeState, (ExchangeTradeState state) { + _disposers.add( + reaction((_) => widget.exchangeViewModel.tradeState, (ExchangeTradeState state) async { if (state is TradeIsCreatedFailure) { WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { @@ -298,11 +321,15 @@ class _NewSwapPageState extends State { exchangeTradeViewModel: vm, receiveAmount: receiveAmount, ); - showMaterialModalBottomSheet( - context: context, - builder: (context) => page, - backgroundColor: Colors.transparent, - ); + try { + await showMaterialModalBottomSheet( + context: context, + builder: (context) => page, + backgroundColor: Colors.transparent, + ); + } finally { + widget.exchangeViewModel.tradeStarted = false; + } } })); @@ -629,7 +656,8 @@ class _NewSwapPageState extends State { walletName: fromSend != null ? widget.exchangeViewModel.wallet.name : null, - balanceByAsset: fromSend?.depositBalanceByAsset, + balanceByAsset: + fromSend != null ? _depositBalanceByAsset() : null, useSingleNetworkLayout: fromSend != null, filteredNetwork: fromSend != null ? widget.exchangeViewModel.wallet.type diff --git a/lib/new-ui/services/wallet_switch_service.dart b/lib/new-ui/services/wallet_switch_service.dart new file mode 100644 index 000000000..9c77635c5 --- /dev/null +++ b/lib/new-ui/services/wallet_switch_service.dart @@ -0,0 +1,29 @@ +import "package:cake_wallet/core/wallet_loading_service.dart"; +import "package:cake_wallet/store/app_store.dart"; +import "package:cw_core/exceptions.dart"; +import "package:cw_core/wallet_info.dart"; + +class WalletSwitchService { + WalletSwitchService({ + required WalletLoadingService walletLoadingService, + required AppStore appStore, + }) : _walletLoadingService = walletLoadingService, + _appStore = appStore; + + final AppStore _appStore; + final WalletLoadingService _walletLoadingService; + + Future switchToWallet(WalletInfo walletInfo) async { + final wallet = await _walletLoadingService.load(walletInfo.type, walletInfo.name); + + // load() recovers from a corrupted wallet by opening any other wallet it can, + // so the one it returns may not be the one that was requested. + if (wallet.name != walletInfo.name || wallet.type != walletInfo.type) { + throw WalletSwitchException( + "wallet switch loaded ${wallet.name} instead of ${walletInfo.name}", + ); + } + + await _appStore.changeCurrentWallet(wallet); + } +} diff --git a/lib/new-ui/widgets/anypay/anypay_flow.dart b/lib/new-ui/widgets/anypay/anypay_flow.dart new file mode 100644 index 000000000..0a6077b2f --- /dev/null +++ b/lib/new-ui/widgets/anypay/anypay_flow.dart @@ -0,0 +1,391 @@ +import "package:cake_wallet/core/address_resolver/address_resolver_service.dart"; +import "package:cake_wallet/core/anypay/anypay_models.dart"; +import "package:cake_wallet/core/anypay/anypay_service.dart"; +import "package:cake_wallet/core/auth_service.dart"; +import "package:cake_wallet/di.dart"; +import "package:cake_wallet/evm/evm.dart"; +import "package:cake_wallet/generated/i18n.dart"; +import "package:cake_wallet/new-ui/pages/swap_page.dart"; +import "package:cake_wallet/new-ui/widgets/anypay/evm_address_detected_sheet.dart"; +import "package:cake_wallet/new-ui/widgets/anypay/network_decision_page.dart"; +import "package:cake_wallet/new-ui/widgets/anypay/select_recipient_network_sheet.dart"; +import "package:cake_wallet/new-ui/widgets/anypay/switch_network_wallet_page.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/src/widgets/alert_with_one_action.dart"; +import "package:cake_wallet/src/widgets/bottom_sheet/info_bottom_sheet_widget.dart"; +import "package:cake_wallet/utils/show_pop_up.dart"; +import "package:cake_wallet/view_model/exchange/exchange_view_model.dart"; +import "package:cake_wallet/view_model/send/send_view_model.dart"; +import "package:cake_wallet/view_model/wallet_switcher_view_model.dart"; +import "package:cw_core/crypto_currency.dart"; +import "package:cw_core/currency_for_wallet_type.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:flutter/cupertino.dart"; +import "package:flutter/material.dart"; + +class AnyPayFormFill { + const AnyPayFormFill({ + required this.request, + this.token, + this.fallbackCurrency, + this.amountOverride, + }); + + final AnyPayRequest request; + final CryptoCurrency? token; + final CryptoCurrency? fallbackCurrency; + final String? amountOverride; +} + +class AnyPayFlow { + AnyPayFlow({ + required this.anyPayService, + required this.sendViewModel, + required this.authService, + required this.walletSwitcherViewModel, + }); + + final AnyPayService anyPayService; + final SendViewModel sendViewModel; + final AuthService authService; + final WalletSwitcherViewModel walletSwitcherViewModel; + + bool _isSwitchingWallet = false; + + bool get isSwitchingWallet => _isSwitchingWallet; + + Future handleEvaluation( + BuildContext context, + AnyPayEvaluation evaluation, { + CryptoCurrency? fallbackCurrency, + }) async { + final request = evaluation.request; + + if (!request.rawInput.toLowerCase().startsWith("ethereum:") && + (request.rawInput.contains("@") || request.address.contains("@"))) { + return null; + } + + try { + return await _handleDecision(context, evaluation, fallbackCurrency); + } catch (e) { + printV("Payment flow error: $e"); + return AnyPayFormFill(request: request); + } + } + + Future _handleDecision( + BuildContext context, + AnyPayEvaluation evaluation, + CryptoCurrency? fallbackCurrency, + ) async { + final request = evaluation.request; + + switch (evaluation.decision) { + case final AnyPayApplyToCurrentWallet decision: + if (request.isLightning) { + _enterLightningMode(); + } + return AnyPayFormFill( + request: request, + token: decision.token, + fallbackCurrency: fallbackCurrency ?? decision.fallbackCurrency, + amountOverride: decision.amountOverride, + ); + case AnyPayEvmNetworkChoice(): + return _pickEvmNetwork(context, request); + case final AnyPayCrossChainPayment decision: + return _handleCrossChain(context, request, decision, fallbackCurrency); + case final AnyPayUnsupportedNetwork decision: + _showError( + context, + S.of(context).unsupported_network_requested(decision.chainId.toString()), + ); + return null; + case AnyPayUnsupportedToken(): + _showError(context, S.of(context).unsupported_token_requested); + return null; + case AnyPayEmptyInput(): + return null; + } + } + + Future _pickEvmNetwork(BuildContext context, AnyPayRequest request) async { + final chains = evm!.getAllChains(); + final networks = chains.map((chain) { + final walletType = evm!.getWalletTypeByChainId(chain.chainId) ?? sendViewModel.wallet.type; + return RecipientNetworkItem( + chainId: chain.chainId, + name: chain.name, + iconPath: getCryptoCurrencyIconForWalletListItem(walletType, chainId: chain.chainId), + chainBadgeIconPath: symbolIconPathForWalletType(walletType), + ); + }).toList(); + + final selectedChainId = + await EvmAddressDetectedSheet.show(context: context, networks: networks); + if (!context.mounted || selectedChainId == null) { + return null; + } + + final target = chains.firstWhere( + (chain) => chain.chainId == selectedChainId, + orElse: () => chains.first, + ); + + final evaluation = await anyPayService.evaluateForEvmChain(request, target.chainId); + if (!context.mounted) { + return null; + } + return handleEvaluation(context, evaluation, fallbackCurrency: target.currency); + } + + Future _handleCrossChain( + BuildContext context, + AnyPayRequest request, + AnyPayCrossChainPayment decision, + CryptoCurrency? fallbackCurrency, + ) async { + final destinationType = decision.targetWalletType; + final isEvmTarget = isEVMCompatibleChain(destinationType); + final destinationNetworkName = networkDisplayName(destinationType, decision.targetChainId); + final destinationNetworkIcon = symbolIconPathForWalletType(destinationType) ?? ""; + + if (!decision.canSwap && !decision.hasCompatibleWallet) { + _showError( + context, + S.of(context).swap_unavailable_needs_network_wallet(destinationNetworkName), + ); + return null; + } + + final currentType = sendViewModel.wallet.type; + final currentChainId = isEVMCompatibleChain(currentType) ? _currentEvmChainId() : null; + final currentNetworkName = networkDisplayName(currentType, currentChainId); + final currentNetworkIcon = symbolIconPathForWalletType(currentType) ?? ""; + + if (!decision.hasCompatibleWallet) { + 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); + + await Navigator.of(context).push( + CupertinoPageRoute( + builder: (pageContext) => NetworkDecisionPage( + title: swapConfirmTitle, + description: S.of(context).swap_from_network_description( + destinationNetworkName, + currentNetworkName, + ), + destinationIconPath: destinationNetworkIcon, + currentIconPath: currentNetworkIcon, + primaryText: swapConfirmPrimary, + primaryIconPath: isEvmTarget ? null : "assets/new-ui/swap_arrows.svg", + onPrimary: () => _openSwap(pageContext, request, decision), + secondaryText: S.of(context).cancel, + ), + ), + ); + return null; + } + + final decisionTitle = isEvmTarget + ? S.of(context).send_to_network(destinationNetworkName) + : S.of(context).network_address_detected(destinationNetworkName); + + final selectedWallet = await Navigator.of(context).push( + CupertinoPageRoute( + builder: (pageContext) => NetworkDecisionPage( + title: decisionTitle, + description: decision.canSwap + ? S.of(context).send_to_network_description( + destinationNetworkName, + currentNetworkName, + ) + : S.of(context).swap_unavailable_switch_to_network(destinationNetworkName), + destinationIconPath: destinationNetworkIcon, + primaryText: S.of(context).switch_to_x_wallet(destinationNetworkName), + primaryIconPath: "assets/new-ui/wallet_filled.svg", + onPrimary: () => _pickDestinationWallet(pageContext, decision, destinationNetworkName), + secondaryText: decision.canSwap + ? S.of(context).swap_from_network(currentNetworkName) + : S.of(context).cancel, + secondaryIconPath: decision.canSwap ? "assets/new-ui/swap_arrows.svg" : null, + onSecondary: decision.canSwap ? () => _openSwap(pageContext, request, decision) : null, + ), + ), + ); + + if (selectedWallet == null || !context.mounted) { + return null; + } + + return _switchWallet(context, selectedWallet, request, decision, fallbackCurrency); + } + + Future _pickDestinationWallet( + BuildContext pageContext, + AnyPayCrossChainPayment decision, + String networkName, + ) async { + WalletInfo? destinationWalletInfo; + if (decision.wallets.length > 1) { + destinationWalletInfo = await SwitchNetworkWalletPage.push( + context: pageContext, + networkName: networkName, + targetIconPath: symbolIconPathForWalletType(decision.targetWalletType) ?? "", + wallets: decision.wallets, + ); + } else { + destinationWalletInfo = decision.wallets.first; + } + + if (destinationWalletInfo == null || !pageContext.mounted) { + return; + } + + Navigator.of(pageContext).pop(destinationWalletInfo); + } + + Future _switchWallet( + BuildContext context, + WalletInfo walletInfo, + AnyPayRequest request, + AnyPayCrossChainPayment decision, + CryptoCurrency? fallbackCurrency, + ) async { + if (request.isLightning) { + _enterLightningMode(); + } + + _isSwitchingWallet = true; + BuildContext? loadingSheetContext; + bool completedFlow = false; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!context.mounted || completedFlow) { + return; + } + showModalBottomSheet( + context: context, + isDismissible: false, + builder: (sheetContext) { + if (completedFlow) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (Navigator.canPop(sheetContext)) { + Navigator.of(sheetContext).pop(); + } + }); + return const SizedBox.shrink(); + } + loadingSheetContext = sheetContext; + return LoadingBottomSheet(titleText: S.of(sheetContext).loading_your_wallet); + }, + ); + }); + + bool success = false; + try { + success = await anyPayService.switchWalletForPayment( + walletInfo, + chainId: decision.targetChainId, + ); + } finally { + _isSwitchingWallet = false; + completedFlow = true; + if (loadingSheetContext != null && + loadingSheetContext!.mounted && + Navigator.canPop(loadingSheetContext!)) { + Navigator.of(loadingSheetContext!).pop(); + } + loadingSheetContext = null; + } + + if (!context.mounted) { + return null; + } + + if (!success) { + _showError(context, S.of(context).network_switch_failed); + return null; + } + + return AnyPayFormFill( + request: request, + token: decision.token, + fallbackCurrency: fallbackCurrency ?? request.detection.detectedCurrency, + amountOverride: decision.amountOverride, + ); + } + + Future _openSwap( + BuildContext presentContext, + AnyPayRequest request, + AnyPayCrossChainPayment decision, + ) async { + if (!presentContext.mounted) { + return; + } + + if (request.hasContract && decision.token == null) { + _showError(presentContext, S.of(presentContext).unsupported_token_requested); + return; + } + + final intent = anyPayService.buildSwapIntent( + request, + targetWalletType: decision.targetWalletType, + targetChainId: decision.targetChainId, + token: decision.token, + ); + + final page = NewSwapPage( + getIt.get(), + authService, + getIt.get(), + null, + walletSwitcherViewModel: walletSwitcherViewModel, + fromSend: SwapFromSendArgs.fromIntent(intent), + balanceViewModel: sendViewModel.balanceViewModel, + ); + await Navigator.of(presentContext).push( + CupertinoPageRoute( + builder: (context) => Material( + color: Theme.of(context).colorScheme.surface, + child: SafeArea(bottom: false, child: page), + ), + ), + ); + } + + void _showError(BuildContext context, String message) { + if (!context.mounted) { + return; + } + + showPopUp( + context: context, + builder: (context) => AlertWithOneAction( + alertTitle: S.of(context).error, + alertContent: message, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop(), + ), + ); + } + + void _enterLightningMode() { + sendViewModel.selectedCryptoCurrency = CryptoCurrency.btcln; + sendViewModel.coinTypeToSpendFrom = UnspentCoinType.lightning; + } + + int _currentEvmChainId() { + final wallet = sendViewModel.wallet; + return evm!.getSelectedChainId(wallet) ?? evm!.getChainIdByWalletType(wallet.type); + } +} diff --git a/lib/new-ui/widgets/anypay/swap_from_network_page.dart b/lib/new-ui/widgets/anypay/network_decision_page.dart similarity index 51% rename from lib/new-ui/widgets/anypay/swap_from_network_page.dart rename to lib/new-ui/widgets/anypay/network_decision_page.dart index 24e41731d..527f9c290 100644 --- a/lib/new-ui/widgets/anypay/swap_from_network_page.dart +++ b/lib/new-ui/widgets/anypay/network_decision_page.dart @@ -5,31 +5,37 @@ import "package:cake_wallet/src/widgets/cake_image_widget.dart"; import "package:cw_core/currency_for_wallet_type.dart"; import "package:flutter/material.dart"; -class SwapFromNetworkPage extends StatelessWidget { - const SwapFromNetworkPage({ +class NetworkDecisionPage extends StatelessWidget { + const NetworkDecisionPage({ required this.title, - required this.primaryButtonText, - required this.destinationNetworkName, - required this.destinationNetworkIconPath, - required this.currentNetworkName, - required this.currentNetworkIconPath, - required this.onProceed, + required this.description, + required this.destinationIconPath, + required this.primaryText, + required this.onPrimary, + required this.secondaryText, + this.currentIconPath, + this.primaryIconPath, + this.secondaryIconPath, + this.onSecondary, super.key, - this.primaryHasSwapIcon = false, }); final String title; - final String primaryButtonText; - final bool primaryHasSwapIcon; - final String destinationNetworkName; - final String destinationNetworkIconPath; - final String currentNetworkName; - final String currentNetworkIconPath; - final VoidCallback onProceed; + final String description; + final String destinationIconPath; + final String? currentIconPath; + final String primaryText; + final VoidCallback onPrimary; + final String? primaryIconPath; + final String secondaryText; + final String? secondaryIconPath; + final VoidCallback? onSecondary; @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; + final primaryIcon = primaryIconPath; + final secondaryIcon = secondaryIconPath; return Material( color: colors.surface, child: SafeArea( @@ -40,9 +46,6 @@ class SwapFromNetworkPage extends StatelessWidget { leadingIcon: const Icon(Icons.arrow_back_ios_new), leadingSemanticLabel: S.of(context).seed_alert_back, onLeadingPressed: () => Navigator.of(context).maybePop(), - trailingIcon: const Icon(Icons.close), - trailingSemanticLabel: S.of(context).close, - onTrailingPressed: () => Navigator.of(context).maybePop(), ), Expanded( child: Center( @@ -51,30 +54,11 @@ class SwapFromNetworkPage extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - Row( - mainAxisSize: MainAxisSize.min, - spacing: 12, - children: [ - CakeImageWidget( - imageUrl: currentNetworkIconPath, - width: 50, - height: 50, - fit: BoxFit.contain, - color: isMonochromeSymbolIcon(currentNetworkIconPath) - ? colors.primary - : null, - ), - Icon(Icons.arrow_forward, color: colors.primary, size: 28), - CakeImageWidget( - imageUrl: destinationNetworkIconPath, - width: 50, - height: 50, - fit: BoxFit.contain, - color: isMonochromeSymbolIcon(destinationNetworkIconPath) - ? colors.primary - : null, - ), - ], + ExcludeSemantics( + child: _DecisionHeader( + destinationIconPath: destinationIconPath, + currentIconPath: currentIconPath, + ), ), const SizedBox(height: 24), Text( @@ -88,10 +72,7 @@ class SwapFromNetworkPage extends StatelessWidget { ), const SizedBox(height: 16), Text( - S.of(context).swap_from_network_description( - destinationNetworkName, - currentNetworkName, - ), + description, textAlign: TextAlign.center, style: Theme.of(context) .textTheme @@ -109,23 +90,31 @@ class SwapFromNetworkPage extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ NewPrimaryButton( - onPressed: onProceed, - image: primaryHasSwapIcon + onPressed: onPrimary, + image: primaryIcon != null ? CakeImageWidget( - imageUrl: "assets/new-ui/swap_arrows.svg", + imageUrl: primaryIcon, width: 24, height: 24, colorFilter: ColorFilter.mode(colors.onPrimary, BlendMode.srcIn), ) : null, - text: primaryButtonText, + text: primaryText, color: colors.primary, textColor: colors.onPrimary, ), const SizedBox(height: 12), NewPrimaryButton( - onPressed: () => Navigator.of(context).maybePop(), - text: S.of(context).cancel, + onPressed: onSecondary ?? () => Navigator.of(context).maybePop(), + image: secondaryIcon != null + ? CakeImageWidget( + imageUrl: secondaryIcon, + width: 24, + height: 24, + colorFilter: ColorFilter.mode(colors.primary, BlendMode.srcIn), + ) + : null, + text: secondaryText, color: colors.surfaceContainer, textColor: colors.primary, ), @@ -138,3 +127,48 @@ class SwapFromNetworkPage extends StatelessWidget { ); } } + +class _DecisionHeader extends StatelessWidget { + const _DecisionHeader({required this.destinationIconPath, this.currentIconPath}); + + final String destinationIconPath; + final String? currentIconPath; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + final current = currentIconPath; + + if (current == null) { + return CakeImageWidget( + imageUrl: destinationIconPath, + width: 75, + height: 75, + fit: BoxFit.contain, + color: isMonochromeSymbolIcon(destinationIconPath) ? colors.primary : null, + ); + } + + return Row( + mainAxisSize: MainAxisSize.min, + spacing: 12, + children: [ + CakeImageWidget( + imageUrl: current, + width: 50, + height: 50, + fit: BoxFit.contain, + color: isMonochromeSymbolIcon(current) ? colors.primary : null, + ), + Icon(Icons.arrow_forward, color: colors.primary, size: 28), + CakeImageWidget( + imageUrl: destinationIconPath, + width: 50, + height: 50, + fit: BoxFit.contain, + color: isMonochromeSymbolIcon(destinationIconPath) ? colors.primary : null, + ), + ], + ); + } +} diff --git a/lib/new-ui/widgets/anypay/recipient_network_row.dart b/lib/new-ui/widgets/anypay/recipient_network_row.dart index 3d978fa1e..9df29541c 100644 --- a/lib/new-ui/widgets/anypay/recipient_network_row.dart +++ b/lib/new-ui/widgets/anypay/recipient_network_row.dart @@ -1,46 +1,14 @@ -import "package:cake_wallet/evm/evm.dart"; import "package:cake_wallet/generated/i18n.dart"; import "package:cake_wallet/src/widgets/cake_image_widget.dart"; import "package:cw_core/currency_for_wallet_type.dart"; -import "package:cw_core/utils/print_verbose.dart"; -import "package:cw_core/wallet_base.dart"; import "package:flutter/material.dart"; class RecipientNetworkSelector extends StatelessWidget { const RecipientNetworkSelector({ - super.key, - required this.wallet, - required this.onTap, - }); - - final WalletBase wallet; - final void Function(ChainInfo currentChain) onTap; - - @override - Widget build(BuildContext context) { - if (evm == null) return const SizedBox.shrink(); - - final currentChainId = - evm!.getSelectedChainId(wallet) ?? evm!.getChainIdByWalletType(wallet.type); - final currentChain = evm!.getChainInfoByChainId(currentChainId); - if (currentChain == null) { - printV("RecipientNetworkSelector: no chain info for chainId $currentChainId"); - return const SizedBox.shrink(); - } - - return _RecipientNetworkRow( - networkName: currentChain.name, - networkIconPath: symbolIconPathForWalletType(wallet.type) ?? "", - onTap: () => onTap(currentChain), - ); - } -} - -class _RecipientNetworkRow extends StatelessWidget { - const _RecipientNetworkRow({ required this.networkName, required this.networkIconPath, required this.onTap, + super.key, }); final String networkName; @@ -50,50 +18,56 @@ class _RecipientNetworkRow extends StatelessWidget { @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; - return GestureDetector( - onTap: onTap, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - S.of(context).network_prefix_on, - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith(color: colors.onSurfaceVariant, letterSpacing: -0.07), - ), - const SizedBox(width: 12), - CakeImageWidget( - imageUrl: networkIconPath, - width: 16, - height: 16, - fit: BoxFit.cover, - color: isMonochromeSymbolIcon(networkIconPath) ? colors.primary : null, - ), - const SizedBox(width: 8), - Text( - networkName, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w400, - letterSpacing: -0.07, - color: colors.primary, + return Semantics( + button: true, + label: "${S.of(context).network_prefix_on} $networkName", + child: GestureDetector( + onTap: onTap, + child: ExcludeSemantics( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + S.of(context).network_prefix_on, + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(color: colors.onSurfaceVariant, letterSpacing: -0.07), + ), + const SizedBox(width: 12), + CakeImageWidget( + imageUrl: networkIconPath, + width: 16, + height: 16, + fit: BoxFit.cover, + color: isMonochromeSymbolIcon(networkIconPath) ? colors.primary : null, + ), + const SizedBox(width: 8), + Text( + networkName, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w400, + letterSpacing: -0.07, + color: colors.primary, + ), + ), + const SizedBox(width: 8), + Container( + width: 28, + height: 28, + decoration: BoxDecoration( + color: colors.surfaceContainer, + shape: BoxShape.circle, ), + child: Icon( + Icons.keyboard_arrow_down, + size: 18, + color: colors.onSurfaceVariant, + ), + ), + ], ), - const SizedBox(width: 8), - Container( - width: 28, - height: 28, - decoration: BoxDecoration( - color: colors.surfaceContainer, - shape: BoxShape.circle, - ), - child: Icon( - Icons.keyboard_arrow_down, - size: 18, - color: colors.onSurfaceVariant, - ), - ), - ], + ), ), ); } diff --git a/lib/new-ui/widgets/anypay/send_to_network_page.dart b/lib/new-ui/widgets/anypay/send_to_network_page.dart deleted file mode 100644 index f25cd6d14..000000000 --- a/lib/new-ui/widgets/anypay/send_to_network_page.dart +++ /dev/null @@ -1,122 +0,0 @@ -import "package:cake_wallet/generated/i18n.dart"; -import "package:cake_wallet/new-ui/widgets/new_primary_button.dart"; -import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart"; -import "package:cake_wallet/src/widgets/cake_image_widget.dart"; -import "package:cw_core/currency_for_wallet_type.dart"; -import "package:flutter/material.dart"; - -class SendToNetworkPage extends StatelessWidget { - const SendToNetworkPage({ - required this.title, - required this.destinationNetworkName, - required this.destinationIconPath, - required this.currentNetworkName, - required this.onSwitchWallet, - required this.onSwap, - super.key, - }); - - final String title; - final String destinationNetworkName; - final String destinationIconPath; - final String currentNetworkName; - final VoidCallback onSwitchWallet; - final VoidCallback onSwap; - - @override - Widget build(BuildContext context) { - final colors = Theme.of(context).colorScheme; - return Material( - color: colors.surface, - child: SafeArea( - child: Column( - children: [ - ModalTopBar( - title: "", - leadingIcon: const Icon(Icons.arrow_back_ios_new), - leadingSemanticLabel: S.of(context).seed_alert_back, - onLeadingPressed: () => Navigator.of(context).maybePop(), - trailingIcon: const Icon(Icons.close), - trailingSemanticLabel: S.of(context).close, - onTrailingPressed: () => Navigator.of(context).maybePop(), - ), - Expanded( - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - CakeImageWidget( - imageUrl: destinationIconPath, - width: 75, - height: 75, - fit: BoxFit.contain, - color: isMonochromeSymbolIcon(destinationIconPath) ? colors.primary : null, - ), - const SizedBox(height: 24), - Text( - title, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleLarge?.copyWith( - fontSize: 20, - fontWeight: FontWeight.w500, - letterSpacing: -0.1, - ), - ), - const SizedBox(height: 16), - Text( - S.of(context).send_to_network_description( - destinationNetworkName, - currentNetworkName, - ), - textAlign: TextAlign.center, - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith(color: colors.onSurfaceVariant, letterSpacing: -0.07), - ), - ], - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - NewPrimaryButton( - onPressed: onSwitchWallet, - image: CakeImageWidget( - imageUrl: "assets/new-ui/wallet_filled.svg", - width: 24, - height: 24, - colorFilter: ColorFilter.mode(colors.onPrimary, BlendMode.srcIn), - ), - text: S.of(context).switch_to_x_wallet(destinationNetworkName), - color: colors.primary, - textColor: colors.onPrimary, - ), - const SizedBox(height: 12), - NewPrimaryButton( - onPressed: onSwap, - image: CakeImageWidget( - imageUrl: "assets/new-ui/swap_arrows.svg", - width: 24, - height: 24, - colorFilter: ColorFilter.mode(colors.primary, BlendMode.srcIn), - ), - text: S.of(context).swap_from_network(currentNetworkName), - color: colors.surfaceContainer, - textColor: colors.primary, - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/new-ui/widgets/changelog_modal.dart b/lib/new-ui/widgets/changelog_modal.dart index 1778b7cdc..7197aabb2 100644 --- a/lib/new-ui/widgets/changelog_modal.dart +++ b/lib/new-ui/widgets/changelog_modal.dart @@ -181,23 +181,28 @@ class ChangelogItemWidget extends StatelessWidget { width: 36, colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn), ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 4, - children: [ - if (item.title.isNotEmpty) - Text( - item.title, - style: TextStyle(fontWeight: FontWeight.w500), - ), - if (item.description.isNotEmpty) - Text(item.description, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 4, + children: [ + if (item.title.isNotEmpty) + Text( + item.title, + style: TextStyle(fontWeight: FontWeight.w500), + ), + if (item.description.isNotEmpty) + Text( + item.description, style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant, - )) - ], + ), + ) + ], + ), ) ], ); } } + diff --git a/lib/new-ui/widgets/coins_page/action_row/coin_action_row.dart b/lib/new-ui/widgets/coins_page/action_row/coin_action_row.dart index c88d2195f..f085a2d38 100644 --- a/lib/new-ui/widgets/coins_page/action_row/coin_action_row.dart +++ b/lib/new-ui/widgets/coins_page/action_row/coin_action_row.dart @@ -162,7 +162,8 @@ class CoinActionRow extends StatelessWidget { if (code == null || code.isEmpty) return; - late final PaymentRequest req; + PaymentRequest? req; + String? rawInput; var unspentCoinType = UnspentCoinType.any; if (SendViewModelBase.isNonZeroAmountLightningInvoice(code)) { unspentCoinType = UnspentCoinType.lightning; @@ -172,8 +173,6 @@ class CoinActionRow extends StatelessWidget { unspentCoinType = UnspentCoinType.lightning; final amount = (await LNURL.getPayRequestAmount(code))?.toString() ?? "0"; req = PaymentRequest(code, amount, "", "", ""); - } else if (OpenCryptoPayService.isOpenCryptoPayQR(code)) { - req = PaymentRequest(code, "", "", "", ""); } else if (Uri.tryParse(code)?.scheme == "wc") { if (!isWalletConnectCompatibleChain(walletType)) { showPopUp( @@ -190,19 +189,19 @@ class CoinActionRow extends StatelessWidget { Navigator.of(context) .pushNamed(Routes.walletConnectConnectionsListing, arguments: Uri.parse(code)); return; - } else if (["http", "https", "tcp"].contains(Uri.tryParse(code)?.scheme)) { + } else if (!OpenCryptoPayService.isOpenCryptoPayQR(code) && + ["http", "https", "tcp"].contains(Uri.tryParse(code)?.scheme)) { Navigator.of(context).pushNamed(Routes.newNode, arguments: {"editingNode": Node.fromUri(Uri.parse(code), walletType)}); return; } else { - final uri = Uri.tryParse(code); - if (uri == null) return; - req = PaymentRequest.fromUri(uri); + rawInput = code; } final sendPage = getIt.get( param1: SendPageParams( initialPaymentRequest: req, + initialRawInput: rawInput, unspentCoinType: unspentCoinType, ), ); diff --git a/lib/new-ui/widgets/coins_page/top_bar_widget/chain_icon.dart b/lib/new-ui/widgets/coins_page/top_bar_widget/chain_icon.dart index 3fe2ebd76..ec3607a25 100644 --- a/lib/new-ui/widgets/coins_page/top_bar_widget/chain_icon.dart +++ b/lib/new-ui/widgets/coins_page/top_bar_widget/chain_icon.dart @@ -10,18 +10,20 @@ class ChainIcon extends StatelessWidget { {super.key, required this.iconPath, required this.dashboardViewModel, - required this.isSyncHeavy}); + required this.isSyncHeavy, + required this.showSyncedMessage}); final String iconPath; final bool isSyncHeavy; final DashboardViewModel dashboardViewModel; + final bool showSyncedMessage; @override Widget build(BuildContext context) { return Observer( builder: (_) { final progress = dashboardViewModel.status.progress(); - final done = !isSyncHeavy || progress >= 1; + final done = !showSyncedMessage && (!isSyncHeavy || progress >= 1); return Stack( children: [ @@ -30,10 +32,10 @@ class ChainIcon extends StatelessWidget { opacity: done ? 0 : 1, // Faded out means "nothing to report", so it must leave the tree too. child: ExcludeSemantics( - excluding: done, + excluding: done || showSyncedMessage, child: CircularProgressIndicator( value: progress, - color: Color(0xFFFFB84E), + color: showSyncedMessage ? Color(0xFFFF12A439) : Color(0xFFFFB84E), strokeWidth: 2, semanticsLabel: S.of(context).synchronizing, semanticsValue: "${(progress * 100).round()}%", diff --git a/lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart b/lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart index 97ba02326..f38f72b0d 100644 --- a/lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart +++ b/lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart @@ -1,21 +1,26 @@ import 'package:cake_wallet/core/sync_status_title.dart'; import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/pulsing_dot.dart'; import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart'; import 'package:cake_wallet/src/widgets/cake_image_widget.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cw_core/sync_status.dart'; +import "package:flutter/cupertino.dart"; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; class SyncBar extends StatelessWidget { - SyncBar({super.key, required this.dashboardViewModel, required this.isSyncHeavy}); + SyncBar({ + super.key, + required this.dashboardViewModel, + required this.isSyncHeavy, + required this.showSyncedMessage, + }); final DashboardViewModel dashboardViewModel; final bool isSyncHeavy; + final bool showSyncedMessage; static const failStatuses = [ FailedSyncStatus, @@ -37,9 +42,10 @@ class SyncBar extends StatelessWidget { ConnectedSyncStatus, ]; + static const syncedColor = Color(0xFF12A439); + @override - Widget build(BuildContext context) { - return Observer( + Widget build(BuildContext context) => Observer( builder: (_) { final status = dashboardViewModel.status; final Widget? icon = _getIcon(context, status.runtimeType); @@ -106,7 +112,6 @@ class SyncBar extends StatelessWidget { ); }, ); - } void _openNodeManagement(BuildContext context) => CupertinoScaffold.showCupertinoModalBottomSheet( @@ -130,8 +135,9 @@ class SyncBar extends StatelessWidget { width: 20, height: 20, ), - if (_showDot()) PulsingDot(), - ], + if (_showDot()) const CupertinoActivityIndicator(radius: 8), + if(_showLightSyncCheck()) const Icon(Icons.check, color: syncedColor, size: 18), + ], ); final label = _joinLabels([ @@ -144,6 +150,9 @@ class SyncBar extends StatelessWidget { return Semantics(label: label, child: ExcludeSemantics(child: row)); } + bool get _isShowingSyncedMessage => + showSyncedMessage && dashboardViewModel.status.runtimeType == SyncedSyncStatus; + String _statusSemanticsLabel(BuildContext context, SyncStatus status) { final isFailure = failStatuses.contains(status.runtimeType); @@ -166,7 +175,7 @@ class SyncBar extends StatelessWidget { } Border? _getBorder(BuildContext context, Type status) { - if (progressStatuses.contains(status)) { + if (progressStatuses.contains(status) || _isShowingSyncedMessage) { return Border.all(color: Theme.of(context).colorScheme.surfaceContainerHigh, width: 1); } @@ -174,19 +183,26 @@ class SyncBar extends StatelessWidget { } TextStyle? _getTextStyle(BuildContext context, Type status) { + final Color color; if (failStatuses.contains(status)) { - return TextStyle( - fontSize: 12, fontWeight: FontWeight.w400, color: Theme.of(context).colorScheme.error); + color = Theme.of(context).colorScheme.error; + } else if (status == SyncedSyncStatus) { + color = syncedColor; } else { - return TextStyle( - fontSize: 12, - fontWeight: FontWeight.w400, - color: Theme.of(context).colorScheme.onSurfaceVariant); + color = Theme.of(context).colorScheme.onSurfaceVariant; } + + return TextStyle( + fontSize: 12, fontWeight: FontWeight.w400, color: color); } Widget? _getIcon(BuildContext context, Type status) { - if (status == LostConnectionSyncStatus || status == FailedSyncStatus) { + + if(status == SyncedSyncStatus) { + return Icon(Icons.check, color: syncedColor, size: 12); + } + + if (status == LostConnectionSyncStatus) { return CakeImageWidget( imageUrl: "assets/new-ui/offline.svg", colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.error, BlendMode.srcIn), @@ -228,11 +244,14 @@ class SyncBar extends StatelessWidget { } bool _showFullBar() { - if (dashboardViewModel.status.runtimeType == SyncedSyncStatus) return false; + if (dashboardViewModel.status.runtimeType == SyncedSyncStatus) + return isSyncHeavy && _isShowingSyncedMessage; return isSyncHeavy || failStatuses.contains(dashboardViewModel.status.runtimeType); } - bool _showDot() { - return !isSyncHeavy && progressStatuses.contains(dashboardViewModel.status.runtimeType); - } + bool _showDot() => + !isSyncHeavy && progressStatuses.contains(dashboardViewModel.status.runtimeType); + + bool _showLightSyncCheck() => + !isSyncHeavy && _isShowingSyncedMessage; } diff --git a/lib/new-ui/widgets/coins_page/top_bar_widget/top_bar.dart b/lib/new-ui/widgets/coins_page/top_bar_widget/top_bar.dart index 71627f9d9..21035c258 100644 --- a/lib/new-ui/widgets/coins_page/top_bar_widget/top_bar.dart +++ b/lib/new-ui/widgets/coins_page/top_bar_widget/top_bar.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:cake_wallet/generated/i18n.dart'; @@ -6,11 +7,13 @@ import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/lightning_s import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart'; import 'package:cake_wallet/new-ui/widgets/modern_button.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; +import 'package:cw_core/sync_status.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:mobx/mobx.dart'; -class TopBar extends StatelessWidget { +class TopBar extends StatefulWidget { const TopBar({ super.key, required this.lightningMode, @@ -25,33 +28,76 @@ class TopBar extends StatelessWidget { final DashboardViewModel dashboardViewModel; @override - Widget build(BuildContext context) { - return Padding( + State createState() => _TopBarState(); +} + +class _TopBarState extends State { + static const syncedMessageDuration = Duration(seconds: 3); + + bool showSyncedMessage = false; + Timer? syncedMessageTimer; + late final ReactionDisposer? _statusReactionDisposer; + + @override + void initState() { + super.initState(); + + _statusReactionDisposer = reaction( + (_) => widget.dashboardViewModel.status.runtimeType, + (status) { + syncedMessageTimer?.cancel(); + + if (status == SyncedSyncStatus) { + if(mounted) { + setState(() => showSyncedMessage = true); + } + syncedMessageTimer = + Timer(syncedMessageDuration, () => setState(() => showSyncedMessage = false)); + } else { + if(mounted) { + setState(() => showSyncedMessage = false); + } + } + }, + ); + } + + @override + void dispose() { + syncedMessageTimer?.cancel(); + _statusReactionDisposer?.reaction.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) => Padding( padding: EdgeInsets.only( bottom: 10, left: 18, right: 18, top: 10 + _additionalTopPadding(context)), child: Observer( builder: (_) => Row( spacing: 12, children: [ - (dashboardViewModel.hasLightning) + (widget.dashboardViewModel.hasLightning) ? LightningSwitcher( - lightningMode: lightningMode, - onLightningSwitchPress: onLightningSwitchPress, + lightningMode: widget.lightningMode, + onLightningSwitchPress: widget.onLightningSwitchPress, ) : ChainIcon( - iconPath: dashboardViewModel.wallet.currency.flatIconPath ?? "", - dashboardViewModel: dashboardViewModel, - isSyncHeavy: dashboardViewModel.isSyncHeavy), + iconPath: widget.dashboardViewModel.wallet.currency.flatIconPath ?? "", + dashboardViewModel: widget.dashboardViewModel, + isSyncHeavy: widget.dashboardViewModel.isSyncHeavy, + showSyncedMessage: showSyncedMessage), SyncBar( - dashboardViewModel: dashboardViewModel, - isSyncHeavy: dashboardViewModel.isSyncHeavy, + dashboardViewModel: widget.dashboardViewModel, + isSyncHeavy: widget.dashboardViewModel.isSyncHeavy, + showSyncedMessage: showSyncedMessage, ), ModernButton.svg( iconColor: Theme.of(context).colorScheme.primary, size: 36, onPressed: () { HapticFeedback.mediumImpact(); - onSettingsButtonPress(); + widget.onSettingsButtonPress(); }, svgPath: "assets/new-ui/top-settings.svg", semanticLabel: S.of(context).settings_title, @@ -60,7 +106,6 @@ class TopBar extends StatelessWidget { ), ), ); - } //FIXME remove after this gets fixed flutter-side double _additionalTopPadding(BuildContext context) { diff --git a/lib/new-ui/widgets/swap_page/anypay_swap_footer.dart b/lib/new-ui/widgets/swap_page/anypay_swap_footer.dart index f0d03e652..57d78ba09 100644 --- a/lib/new-ui/widgets/swap_page/anypay_swap_footer.dart +++ b/lib/new-ui/widgets/swap_page/anypay_swap_footer.dart @@ -18,6 +18,22 @@ class AnyPaySwapFooter extends StatelessWidget { final textTheme = Theme.of(context).textTheme; return Observer( builder: (_) { + if (exchangeViewModel.noProviderForPair) { + return Container( + alignment: Alignment.center, + height: 48, + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + border: Border.all(color: colors.error), + ), + child: Text( + S.of(context).no_providers_available, + style: textTheme.bodyMedium?.copyWith(color: colors.error, letterSpacing: -0.07), + ), + ); + } + if (exchangeViewModel.depositAmount.isEmpty) { return const SizedBox.shrink(); } diff --git a/lib/new-ui/widgets/swap_page/swap_amount_box.dart b/lib/new-ui/widgets/swap_page/swap_amount_box.dart index 9f7debf02..784dbd4ef 100644 --- a/lib/new-ui/widgets/swap_page/swap_amount_box.dart +++ b/lib/new-ui/widgets/swap_page/swap_amount_box.dart @@ -8,6 +8,7 @@ import "package:cake_wallet/new-ui/widgets/send_page/fiat_amount_bar.dart"; import "package:cake_wallet/new-ui/widgets/send_page/send_memo_input.dart"; import "package:cake_wallet/new-ui/widgets/swap_page/refund_address_modal.dart"; import "package:cake_wallet/new-ui/widgets/swap_page/swap_address_selection_modal.dart"; +import "package:cake_wallet/new-ui/widgets/swap_page/swap_source_selector.dart"; import "package:cake_wallet/src/widgets/cake_image_widget.dart"; import "package:cake_wallet/utils/decimal_input_formatter.dart"; import "package:cake_wallet/utils/permission_handler.dart"; @@ -82,10 +83,14 @@ class SwapAmountBoxState extends State { final fiatAmountController = TextEditingController(); final amountFocusNode = FocusNode(); final memoController = TextEditingController(); + final _amountFieldKey = GlobalKey>(); mobx.ReactionDisposer? _memoReactionDisposer; @override void initState() { + amountController + .addListener(() => _amountFieldKey.currentState?.didChange(amountController.text)); + if (widget.isReceiverCard) { memoController.text = widget.exchangeViewModel.receiveAddressExtraId; @@ -145,95 +150,13 @@ class SwapAmountBoxState extends State { final colors = Theme.of(context).colorScheme; if (widget.sourceSelectorMode) { - final available = _sourceBalance()?.amount.split(" ").first ?? "—"; - return Column( - spacing: 12, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GestureDetector( - onTap: _presentCurrencyPicker, - child: Container( - height: 52, - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - color: colors.surfaceContainer, - borderRadius: BorderRadius.circular(18), - ), - child: Row( - children: [ - CakeImageWidget( - imageUrl: widget.currency.iconPath ?? "", - width: 24, - height: 24, - ), - const SizedBox(width: 8), - Text( - currencyToShow, - style: Theme.of(context).textTheme.bodyLarge?.copyWith(letterSpacing: -0.08), - ), - if (chainIconPath != null && chainIconPath.isNotEmpty) ...[ - const SizedBox(width: 4), - CakeImageWidget( - imageUrl: chainIconPath, - width: 12, - height: 12, - colorFilter: ColorFilter.mode(colors.onSurfaceVariant, BlendMode.srcIn), - ), - ], - const Spacer(), - CakeImageWidget( - imageUrl: "assets/new-ui/chooser.svg", - width: 12, - height: 12, - colorFilter: ColorFilter.mode(colors.onSurfaceVariant, BlendMode.srcIn), - ), - ], - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - CakeImageWidget( - imageUrl: "assets/new-ui/wallet_filled.svg", - width: 16, - height: 16, - colorFilter: ColorFilter.mode(colors.onSurfaceVariant, BlendMode.srcIn), - ), - const SizedBox(width: 4), - Flexible( - child: Text( - widget.walletName ?? "", - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - fontWeight: FontWeight.w500, - letterSpacing: -0.06, - color: colors.onSurfaceVariant, - ), - ), - ), - ], - ), - ), - const SizedBox(width: 8), - Text( - "${S.of(context).avl}: $available", - style: Theme.of(context).textTheme.bodySmall?.copyWith( - fontWeight: FontWeight.w500, - letterSpacing: -0.06, - color: colors.primary, - ), - ), - ], - ), - ), - ], + return SwapSourceSelector( + currencyIconPath: widget.currency.iconPath ?? "", + currencyLabel: currencyToShow, + chainIconPath: chainIconPath, + walletName: widget.walletName, + availableBalance: _sourceBalance()?.amount.split(" ").first ?? "—", + onTap: _presentCurrencyPicker, ); } @@ -260,139 +183,168 @@ class SwapAmountBoxState extends State { child: Column( spacing: 12, children: [ - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: amountFocusNode.requestFocus, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - spacing: 4, + FormField( + key: _amountFieldKey, + initialValue: amountController.text, + validator: _fiatInputMode ? null : widget.currencyValueValidator, + builder: (state) => Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: amountFocusNode.requestFocus, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, spacing: 4, - crossAxisAlignment: CrossAxisAlignment.center, children: [ - Flexible( - child: IntrinsicWidth( - child: Observer( - builder: (_) { - final showFetching = !widget.isReceiverCard && - widget.exchangeViewModel.isFixedRateMode && - widget.exchangeViewModel.receiveAmount.isNotEmpty && - widget.exchangeViewModel.depositAmount.isEmpty; - return TextFormField( - keyboardType: TextInputType.numberWithOptions( - signed: false, - decimal: !widget.useBaseUnit, + Expanded( + child: Row( + spacing: 4, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flexible( + child: IntrinsicWidth( + child: Observer( + builder: (_) { + final showFetching = !widget.isReceiverCard && + widget.exchangeViewModel.isFixedRateMode && + widget.exchangeViewModel.receiveAmount.isNotEmpty && + widget.exchangeViewModel.depositAmount.isEmpty; + return TextField( + keyboardType: TextInputType.numberWithOptions( + signed: false, + decimal: !widget.useBaseUnit, + ), + onChanged: state.didChange, + controller: _fiatInputMode + ? fiatAmountController + : amountController, + focusNode: amountFocusNode, + style: TextStyle( + fontSize: 28, + color: Theme.of(context).colorScheme.onSurface, + fontWeight: FontWeight.w400, + ), + decoration: InputDecoration( + contentPadding: EdgeInsets.zero, + isDense: true, + hintText: showFetching ? S.of(context).fetching : "0", + fillColor: Colors.transparent, + hoverColor: Colors.transparent, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + inputFormatters: [ + DecimalInputFormatter( + maxDecimals: widget.useBaseUnit + ? 0 + : widget.currency.decimals, + ), + ], + ); + }, ), - validator: - _fiatInputMode ? null : widget.currencyValueValidator, - controller: - _fiatInputMode ? fiatAmountController : amountController, - focusNode: amountFocusNode, - style: TextStyle( - fontSize: 28, - color: Theme.of(context).colorScheme.onSurface, - fontWeight: FontWeight.w400, - ), - decoration: InputDecoration( - contentPadding: EdgeInsets.zero, - isDense: true, - hintText: showFetching ? S.of(context).fetching : "0", - fillColor: Colors.transparent, - hoverColor: Colors.transparent, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - ), - inputFormatters: [ - DecimalInputFormatter( - maxDecimals: - widget.useBaseUnit ? 0 : widget.currency.decimals, + ), + ), + if (_fiatInputMode) + Center( + child: Text( + widget.exchangeViewModel.fiat.title, + style: TextStyle( + fontSize: 16, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), - ], - ); - }, - ), + ), + ), + ], ), ), - if (_fiatInputMode) - Center( - child: Text( - widget.exchangeViewModel.fiat.title, - style: TextStyle( - fontSize: 16, - color: Theme.of(context).colorScheme.onSurfaceVariant, + GestureDetector( + onTap: _presentCurrencyPicker, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(999999), + ), + child: Padding( + padding: + const EdgeInsets.only(top: 4, bottom: 4, left: 4, right: 4), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CakeImageWidget( + imageUrl: widget.currency.iconPath ?? "", + width: 28, + height: 28, + ), + const SizedBox(width: 10), + Text( + currencyToShow, + textAlign: TextAlign.center, + ), + if (chainIconPath != null && chainIconPath.isNotEmpty) ...[ + const SizedBox(width: 4), + CakeImageWidget( + imageUrl: chainIconPath, + width: 12, + height: 12, + colorFilter: ColorFilter.mode( + Theme.of(context).colorScheme.onSurfaceVariant, + BlendMode.srcIn, + ), + ), + const SizedBox(width: 6), + ] else + const SizedBox(width: 10), + Container( + width: 16, + height: 16, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(9999999999), + color: Theme.of(context).colorScheme.surfaceContainerHigh, + ), + child: Padding( + padding: const EdgeInsets.all(4), + child: RotatedBox( + quarterTurns: 2, + child: CakeImageWidget( + imageUrl: "assets/new-ui/dropdown_arrow.svg", + width: 4, + height: 4, + colorFilter: ColorFilter.mode( + Theme.of(context).colorScheme.primary, + BlendMode.srcIn, + ), + ), + ), + ), + ), + const SizedBox(width: 4), + ], ), ), ), + ), ], ), ), - GestureDetector( - onTap: _presentCurrencyPicker, - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: BorderRadius.circular(999999), - ), - child: Padding( - padding: const EdgeInsets.only(top: 4, bottom: 4, left: 4, right: 4), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CakeImageWidget( - imageUrl: widget.currency.iconPath ?? "", - width: 28, - height: 28, - ), - const SizedBox(width: 10), - Text( - currencyToShow, - textAlign: TextAlign.center, - ), - if (chainIconPath != null && chainIconPath.isNotEmpty) ...[ - const SizedBox(width: 4), - CakeImageWidget( - imageUrl: chainIconPath, - width: 12, - height: 12, - colorFilter: ColorFilter.mode( - Theme.of(context).colorScheme.onSurfaceVariant, - BlendMode.srcIn, - ), - ), - const SizedBox(width: 6), - ] else - const SizedBox(width: 10), - Container( - width: 16, - height: 16, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(9999999999), - color: Theme.of(context).colorScheme.surfaceContainerHigh, - ), - child: Padding( - padding: const EdgeInsets.all(4), - child: RotatedBox( - quarterTurns: 2, - child: CakeImageWidget( - imageUrl: "assets/new-ui/dropdown_arrow.svg", - width: 4, - height: 4, - colorFilter: ColorFilter.mode( - Theme.of(context).colorScheme.primary, - BlendMode.srcIn, - ), - ), - ), - ), - ), - const SizedBox(width: 4), - ], + if (state.hasError) + Padding( + padding: const EdgeInsets.only(top: 6), + child: Semantics( + container: true, + liveRegion: true, + label: "${S.of(context).amount}${state.errorText!}", + excludeSemantics: true, + child: Text( + state.errorText!, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.error, + ), ), ), ), - ), ], ), ), diff --git a/lib/new-ui/widgets/swap_page/swap_from_send_args.dart b/lib/new-ui/widgets/swap_page/swap_from_send_args.dart index fc939aceb..41f38995a 100644 --- a/lib/new-ui/widgets/swap_page/swap_from_send_args.dart +++ b/lib/new-ui/widgets/swap_page/swap_from_send_args.dart @@ -1,4 +1,4 @@ -import "package:cake_wallet/new-ui/widgets/currency_picker/currency_picker_args.dart"; +import "package:cake_wallet/core/anypay/anypay_models.dart"; import "package:cw_core/amount/money.dart"; import "package:cw_core/crypto_currency.dart"; import "package:cw_core/wallet_type.dart"; @@ -8,13 +8,18 @@ class SwapFromSendArgs { required this.recipientAddress, required this.receiveCurrency, required this.targetWalletType, - this.depositBalanceByAsset, this.receiveAmount, }); + factory SwapFromSendArgs.fromIntent(AnyPaySwapIntent intent) => SwapFromSendArgs( + recipientAddress: intent.recipientAddress, + receiveCurrency: intent.receiveCurrency, + targetWalletType: intent.targetWalletType, + receiveAmount: intent.receiveAmount, + ); + final String recipientAddress; final CryptoCurrency receiveCurrency; final WalletType targetWalletType; - final Map? depositBalanceByAsset; final Money? receiveAmount; } diff --git a/lib/new-ui/widgets/swap_page/swap_source_selector.dart b/lib/new-ui/widgets/swap_page/swap_source_selector.dart new file mode 100644 index 000000000..b5f9667eb --- /dev/null +++ b/lib/new-ui/widgets/swap_page/swap_source_selector.dart @@ -0,0 +1,118 @@ +import "package:cake_wallet/generated/i18n.dart"; +import "package:cake_wallet/src/widgets/cake_image_widget.dart"; +import "package:flutter/material.dart"; + +class SwapSourceSelector extends StatelessWidget { + const SwapSourceSelector({ + required this.currencyIconPath, + required this.currencyLabel, + required this.availableBalance, + required this.onTap, + this.chainIconPath, + this.walletName, + super.key, + }); + + final String currencyIconPath; + final String currencyLabel; + final String availableBalance; + final VoidCallback onTap; + final String? chainIconPath; + final String? walletName; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + final chainIcon = chainIconPath; + + return Column( + spacing: 12, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + onTap: onTap, + child: Container( + height: 52, + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: BoxDecoration( + color: colors.surfaceContainer, + borderRadius: BorderRadius.circular(18), + ), + child: Row( + children: [ + CakeImageWidget( + imageUrl: currencyIconPath, + width: 24, + height: 24, + ), + const SizedBox(width: 8), + Text( + currencyLabel, + style: Theme.of(context).textTheme.bodyLarge?.copyWith(letterSpacing: -0.08), + ), + if (chainIcon != null && chainIcon.isNotEmpty) ...[ + const SizedBox(width: 4), + CakeImageWidget( + imageUrl: chainIcon, + width: 12, + height: 12, + colorFilter: ColorFilter.mode(colors.onSurfaceVariant, BlendMode.srcIn), + ), + ], + const Spacer(), + CakeImageWidget( + imageUrl: "assets/new-ui/chooser.svg", + width: 12, + height: 12, + colorFilter: ColorFilter.mode(colors.onSurfaceVariant, BlendMode.srcIn), + ), + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + CakeImageWidget( + imageUrl: "assets/new-ui/wallet_filled.svg", + width: 16, + height: 16, + colorFilter: ColorFilter.mode(colors.onSurfaceVariant, BlendMode.srcIn), + ), + const SizedBox(width: 4), + Flexible( + child: Text( + walletName ?? "", + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + fontWeight: FontWeight.w500, + letterSpacing: -0.06, + color: colors.onSurfaceVariant, + ), + ), + ), + ], + ), + ), + const SizedBox(width: 8), + Text( + S.of(context).available_balance_short(availableBalance), + style: Theme.of(context).textTheme.bodySmall?.copyWith( + fontWeight: FontWeight.w500, + letterSpacing: -0.06, + color: colors.primary, + ), + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/reactions/check_connection.dart b/lib/reactions/check_connection.dart index 8cee07276..1103d0c25 100644 --- a/lib/reactions/check_connection.dart +++ b/lib/reactions/check_connection.dart @@ -28,20 +28,24 @@ void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore try { final connectivityResult = await (Connectivity().checkConnectivity()); + int? chainId; + if (isEVMCompatibleChain(wallet.type)) { + chainId = evm!.getSelectedChainId(wallet); + } + + final node = settingsStore.getCurrentNode(wallet.type, chainId: chainId); + if (connectivityResult.contains(ConnectivityResult.none)) { - wallet.syncStatus = FailedSyncStatus(); - return; + // Still try node even when OS says no network - it might be a LAN node. + if (!await node.requestNode()) { + wallet.syncStatus = FailedSyncStatus(); + return; + } } if (wallet.type != WalletType.bitcoin && (wallet.syncStatus is LostConnectionSyncStatus || wallet.syncStatus is FailedSyncStatus)) { - int? chainId; - if (isEVMCompatibleChain(wallet.type)) { - chainId = evm!.getSelectedChainId(wallet); - } - - final node = settingsStore.getCurrentNode(wallet.type, chainId: chainId); final alive = await node.requestNode(); if (alive) { diff --git a/lib/router.dart b/lib/router.dart index 39a28a42f..2b01b079f 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -149,7 +149,6 @@ import 'package:cake_wallet/view_model/hardware_wallet/hardware_wallet_view_mode import 'package:cake_wallet/view_model/hardware_wallet/trezor_connect_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; -import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart'; @@ -445,6 +444,7 @@ Route createRoute(RouteSettings settings) { case Routes.send: final args = settings.arguments as Map?; final initialPaymentRequest = args?['paymentRequest'] as PaymentRequest?; + final initialRawInput = args?["rawLink"] as String?; final coinTypeToSpendFrom = args?['coinTypeToSpendFrom'] as UnspentCoinType?; return handleRouteWithPlatformAwareness( @@ -452,6 +452,7 @@ Route createRoute(RouteSettings settings) { child: getIt.get( param1: SendPageParams( initialPaymentRequest: initialPaymentRequest, + initialRawInput: initialRawInput, unspentCoinType: coinTypeToSpendFrom ?? UnspentCoinType.any), ), ), @@ -473,7 +474,7 @@ Route createRoute(RouteSettings settings) { case Routes.newReceivePage: if (FeatureFlag.hasNewUi) { return handleRouteWithPlatformAwareness( - (context) => Material(child: getIt.get(param1: false, param2: null)), + (context) => Material(child: getIt.get(param1: false, param2: null)), settings: settings, ); } @@ -835,9 +836,7 @@ Route createRoute(RouteSettings settings) { final useTestnet = args['useTestnet'] as bool; final toggleTestnet = args['toggleTestnet'] as Function(bool? val); final zcashNetwork = args['zcashNetwork'] as int? ?? ZcashNetworkType.mainnet; - final setZcashNetwork = - args['setZcashNetwork'] as void Function(int network)? ?? (_) {}; - final restoredWallet = args['restoredWallet'] as RestoredWallet?; + final setZcashNetwork = args['setZcashNetwork'] as void Function(int network)? ?? (_) {}; final viewModelParam = {'type': type, 'isPow': false}; diff --git a/lib/src/screens/connect_device/connect_device_page.dart b/lib/src/screens/connect_device/connect_device_page.dart index 123c0656c..4a049993a 100644 --- a/lib/src/screens/connect_device/connect_device_page.dart +++ b/lib/src/screens/connect_device/connect_device_page.dart @@ -120,6 +120,8 @@ class ConnectDevicePageBodyState extends State { } if (widget.hardwareWalletVM.hasBluetooth) { + widget.hardwareWalletVM.updateBleState(); + _longWaitTimer = Timer(const Duration(seconds: 10), () { if (widget.hardwareWalletVM.isBleEnabled && bleDevices.isEmpty) { setState(() => longWait = true); diff --git a/lib/utils/payment_request.dart b/lib/utils/payment_request.dart index d238f91a0..d4452bfc4 100644 --- a/lib/utils/payment_request.dart +++ b/lib/utils/payment_request.dart @@ -125,6 +125,31 @@ class PaymentRequest { ); } + PaymentRequest copyWith({ + String? address, + String? amount, + String? note, + String? scheme, + String? pjUri, + String? callbackUrl, + String? callbackMessage, + String? contractAddress, + int? chainId, + String? rawTokenAmount, + }) => + PaymentRequest( + address ?? this.address, + amount ?? this.amount, + note ?? this.note, + scheme ?? this.scheme, + pjUri ?? this.pjUri, + callbackUrl: callbackUrl ?? this.callbackUrl, + callbackMessage: callbackMessage ?? this.callbackMessage, + contractAddress: contractAddress ?? this.contractAddress, + chainId: chainId ?? this.chainId, + rawTokenAmount: rawTokenAmount ?? this.rawTokenAmount, + ); + final String address; final String amount; final String note; diff --git a/lib/utils/token_utilities.dart b/lib/utils/token_utilities.dart index 7fedd27a0..efb7b684d 100644 --- a/lib/utils/token_utilities.dart +++ b/lib/utils/token_utilities.dart @@ -8,6 +8,7 @@ import 'package:cw_core/currency_for_wallet_type.dart'; import 'package:cw_core/erc20_token.dart'; import 'package:cw_core/spl_token.dart'; import 'package:cw_core/tron_token.dart'; +import "package:cw_core/utils/print_verbose.dart"; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; @@ -25,10 +26,10 @@ class TokenUtilities { for (final wallet in evmWallets) { final chain = getTokenNameBasedOnWalletType(wallet.type); - final box = await _openEvmTokensBoxFor(wallet); + final tokens = await Erc20Token.getAllForWallet(wallet.name, _getDefaultChainId(wallet.type)); - for (final t in box.values.where((t) => t.enabled)) { - final key = '$chain|${t.contractAddress.toLowerCase()}'; + for (final t in tokens.where((t) => t.enabled)) { + final key = "$chain|${t.contractAddress.toLowerCase()}"; if (seen.add(key)) { unique.add(t); } @@ -46,15 +47,17 @@ class TokenUtilities { final tokens = []; for (final wallet in solWallets) { - final box = await _openSolTokensBoxFor(wallet); - tokens.addAll(box.values.where((t) => t.enabled)); + final walletTokens = await SPLToken.getAllForWallet(wallet.name); + tokens.addAll(walletTokens.where((t) => t.enabled)); } final seen = {}; final unique = []; for (final token in tokens) { final key = token.mintAddress.toLowerCase(); - if (seen.add(key)) unique.add(token); + if (seen.add(key)) { + unique.add(token); + } } return unique; } @@ -68,25 +71,31 @@ class TokenUtilities { final seen = {}; final unique = []; for (final wallet in tronWallets) { - final box = await _openTronTokensBoxFor(wallet); - for (final t in box.values.where((t) => t.enabled)) { + final walletTokens = await TronToken.getAllForWallet(wallet.name); + for (final t in walletTokens.where((t) => t.enabled)) { final key = t.contractAddress.toLowerCase(); - if (seen.add(key)) unique.add(t); + if (seen.add(key)) { + unique.add(t); + } } } return unique; } static List loadDefaultEvmTokensForSwap() { - if (evm == null) return []; + if (evm == null) { + return []; + } final tokens = []; final seen = {}; for (final chain in evm!.getAllChains()) { for (final token in evm!.getDefaultTokensByChainId(chain.chainId)) { - final key = '${chain.chainId}|${token.contractAddress.toLowerCase()}'; - if (seen.add(key)) tokens.add(token); + final key = "${chain.chainId}|${token.contractAddress.toLowerCase()}"; + if (seen.add(key)) { + tokens.add(token); + } } } @@ -108,7 +117,9 @@ class TokenUtilities { for (final t in [...defaultTokens, ...userTokens]) { final key = '${t.tag ?? 'ETH'}|${t.contractAddress.toLowerCase()}'; - if (seen.add(key)) result.add(t); + if (seen.add(key)) { + result.add(t); + } } return result; @@ -123,7 +134,9 @@ class TokenUtilities { for (final t in [...defaultTokens, ...userTokens]) { final key = t.mintAddress.toLowerCase(); - if (seen.add(key)) result.add(t); + if (seen.add(key)) { + result.add(t); + } } return result; @@ -138,7 +151,9 @@ class TokenUtilities { for (final t in [...defaultTokens, ...userTokens]) { final key = t.contractAddress.toLowerCase(); - if (seen.add(key)) result.add(t); + if (seen.add(key)) { + result.add(t); + } } return result; @@ -152,56 +167,69 @@ class TokenUtilities { required WalletType walletType, required String address, }) async { - if (address.isEmpty) return null; + if (address.isEmpty) { + return null; + } final lower = address.toLowerCase(); final tokens = await getAvailableTokensForNetwork(walletType); for (final t in tokens) { - if (t is Erc20Token && t.contractAddress.toLowerCase() == lower) return t; - if (t is SPLToken && t.mintAddress.toLowerCase() == lower) return t; - if (t is TronToken && t.contractAddress.toLowerCase() == lower) return t; + if (t is Erc20Token && t.contractAddress.toLowerCase() == lower) { + return t; + } + if (t is SPLToken && t.mintAddress.toLowerCase() == lower) { + return t; + } + if (t is TronToken && t.contractAddress.toLowerCase() == lower) { + return t; + } } return null; } - static Future> _openEvmTokensBoxFor(WalletInfo walletInfo) async { - final walletKey = walletInfo.name.replaceAll(' ', '_'); - final boxName = _getErc20TokensBoxName(walletKey, walletInfo.type); - - if (CakeHive.isBoxOpen(boxName)) { - return CakeHive.box(boxName); - } - return CakeHive.openBox(boxName); - } - - static String _getErc20TokensBoxName(String walletKey, WalletType walletType) { - return switch (walletType) { - WalletType.ethereum => '${walletKey}_${Erc20Token.ethereumBoxName}', - WalletType.polygon => '${walletKey}_${Erc20Token.polygonBoxName}', - WalletType.base => '${walletKey}_${Erc20Token.baseBoxName}', - WalletType.arbitrum => '${walletKey}_${Erc20Token.arbitrumBoxName}', - WalletType.bsc => '${walletKey}_${Erc20Token.bscBoxName}', - _ => '${walletKey}_${Erc20Token.ethereumBoxName}', + static int _getDefaultChainId(WalletType walletType) => switch (walletType) { + WalletType.ethereum => 1, + WalletType.polygon => 137, + WalletType.base => 8453, + WalletType.arbitrum => 42161, + WalletType.bsc => 56, + _ => 1, }; - } - static Future> _openSolTokensBoxFor(WalletInfo wallet) async { - final boxName = '${wallet.name.replaceAll(' ', '_')}_${SPLToken.boxName}'; - if (CakeHive.isBoxOpen(boxName)) { - return CakeHive.box(boxName); + static Future findEvmChainIdForContract( + String contractAddress, { + int? excludingChainId, + }) async { + if (evm == null || contractAddress.isEmpty) { + return null; } - return CakeHive.openBox(boxName); - } - static Future> _openTronTokensBoxFor(WalletInfo walletInfo) async { - final boxName = '${walletInfo.name.replaceAll(' ', '_')}_${TronToken.boxName}'; - if (CakeHive.isBoxOpen(boxName)) { - return CakeHive.box(boxName); + try { + for (final chain in evm!.getAllChains()) { + if (chain.chainId == excludingChainId) { + continue; + } + + final walletType = evm!.getWalletTypeByChainId(chain.chainId); + if (walletType == null) { + continue; + } + + final token = await findTokenByAddress(walletType: walletType, address: contractAddress); + if (token != null) { + return chain.chainId; + } + } + } catch (e) { + printV("findEvmChainIdForContract failed: $e"); } - return CakeHive.openBox(boxName); + + return null; } static Erc20Token? findErc20Token(CryptoCurrency currency, WalletBase wallet) { - if (currency is Erc20Token) return currency; + if (currency is Erc20Token) { + return currency; + } // More of a fallback for us for (final balanceCurrency in wallet.balance.keys) { @@ -214,10 +242,14 @@ class TokenUtilities { } static Erc20Token? findErc20TokenForSwap(CryptoCurrency currency) { - if (currency is Erc20Token) return currency; + if (currency is Erc20Token) { + return currency; + } for (final token in loadDefaultEvmTokensForSwap()) { - if (_matchesCurrency(token, currency)) return token; + if (_matchesCurrency(token, currency)) { + return token; + } } return null; } @@ -244,19 +276,19 @@ class TokenUtilities { final title = currency.title.toLowerCase(); final tag = currency.tag?.toLowerCase(); - return title == 'eth' || - title == 'ethereum' || - title == 'matic' || - title == 'polygon' || - title == 'base' || - title == 'arbitrum' || - title == 'bnb' || - title == 'bsc' || - title == 'avax' || - title == 'avalanche' || - tag == 'polygon' || - tag == 'bsc' || - tag == 'avalanche'; + return title == "eth" || + title == "ethereum" || + title == "matic" || + title == "polygon" || + title == "base" || + title == "arbitrum" || + title == "bnb" || + title == "bsc" || + title == "avax" || + title == "avalanche" || + tag == "polygon" || + tag == "bsc" || + tag == "avalanche"; } static int getChainId(CryptoCurrency currency) { @@ -266,37 +298,37 @@ class TokenUtilities { // Only check EVM registry for currencies that might be EVM-related final isPotentialEVM = isNativeToken(currency) || (tag != null && - (tag == 'ETH' || tag == 'POL' || tag == 'BASE' || tag == 'ARB' || tag == 'BSC')); + (tag == "ETH" || tag == "POL" || tag == "BASE" || tag == "ARB" || tag == "BSC")); if (isPotentialEVM) { // Try by tag first if available (e.g., 'POL', 'BASE', 'ARB') if (tag != null) { final chainId = evm?.getChainIdByTag(tag); - if (chainId != null) return chainId; + if (chainId != null) { + return chainId; + } } // Try by title (case-insensitive) final titleChainId = evm?.getChainIdByTitle(title); - if (titleChainId != null) return titleChainId; + if (titleChainId != null) { + return titleChainId; + } } // Fallback to hardcoded values for chains not in registry yet - // Avalanche C-Chain - if (title == 'avalanche' || title == 'avax' || tag == 'AVALANCHE') { + if (title == "avalanche" || title == "avax" || tag == "AVALANCHE") { return 43114; } - // Optimism - if (title == 'optimism' || title == 'op' || tag == 'OPTIMISM') { + if (title == "optimism" || title == "op" || tag == "OPTIMISM") { return 10; } - // Fantom Opera - if (title == 'fantom' || title == 'ftm' || tag == 'FANTOM') { + if (title == "fantom" || title == "ftm" || tag == "FANTOM") { return 250; } - // Default to Ethereum mainnet return 1; } @@ -363,7 +395,7 @@ class TokenUtilities { } for (final currency in CryptoCurrency.all) { - if (currency.tag?.toLowerCase() == 'sol') { + if (currency.tag?.toLowerCase() == "sol") { if (currency is SPLToken) { final mintAddress = currency.mintAddress.toLowerCase(); if (addedAddresses.add(mintAddress)) { @@ -374,10 +406,7 @@ class TokenUtilities { } } } - } - - // Handle Tron network - else if (network == WalletType.tron) { + } else if (network == WalletType.tron) { final userTronTokens = await loadAllUniqueTronTokens(); for (final token in userTronTokens) { final contractAddress = token.contractAddress.toLowerCase(); @@ -394,7 +423,7 @@ class TokenUtilities { } for (final currency in CryptoCurrency.all) { - if (currency.tag?.toLowerCase() == 'trx') { + if (currency.tag?.toLowerCase() == "trx") { if (currency is TronToken) { final contractAddress = currency.contractAddress.toLowerCase(); if (addedAddresses.add(contractAddress)) { @@ -410,31 +439,34 @@ class TokenUtilities { return allTokens; } - static bool _matchesCurrency(CryptoCurrency a, CryptoCurrency b) { - return a.title.toUpperCase() == b.title.toUpperCase() && - (a.tag?.toUpperCase() == b.tag?.toUpperCase()); - } + static bool _matchesCurrency(CryptoCurrency a, CryptoCurrency b) => + a.title.toUpperCase() == b.title.toUpperCase() && + (a.tag?.toUpperCase() == b.tag?.toUpperCase()); static Future> _getUserTokensForNetwork(CryptoCurrency baseCurrency) async { final walletType = cryptoCurrencyOrTokenToWalletType(baseCurrency); - if (walletType == null) return []; + if (walletType == null) { + return []; + } if (isEVMCompatibleChain(walletType)) { final tokens = await TokenUtilities.loadAllUniqueEvmTokens(); return tokens.where((token) { - if (baseCurrency.tag == null) return token.tag == baseCurrency.title; + if (baseCurrency.tag == null) { + return token.tag == baseCurrency.title; + } return token.tag?.toLowerCase() == baseCurrency.tag?.toLowerCase(); }).toList(); } if (walletType == WalletType.solana) { - return await loadAllUniqueSolTokens(); + return loadAllUniqueSolTokens(); } if (walletType == WalletType.tron) { - return await loadAllUniqueTronTokens(); + return loadAllUniqueTronTokens(); } return []; diff --git a/lib/view_model/dashboard/transaction_list_item.dart b/lib/view_model/dashboard/transaction_list_item.dart index 9a7dfa655..620dcd1e1 100644 --- a/lib/view_model/dashboard/transaction_list_item.dart +++ b/lib/view_model/dashboard/transaction_list_item.dart @@ -203,7 +203,7 @@ class TransactionListItem extends ActionListItem with Keyable { case WalletType.decred: case WalletType.zcash: amount = calculateFiatAmountRaw( - cryptoAmount: transaction.amount.toDouble(), + cryptoAmount: double.parse(transaction.amount.toString()), price: price, ).withLocalSeperator(_appStore.settingsStore.languageCode); case WalletType.ethereum: @@ -214,15 +214,15 @@ class TransactionListItem extends ActionListItem with Keyable { final asset = assetOfTransaction; final price = balanceViewModel.fiatConversionStore.prices[asset]; amount = calculateFiatAmountRaw( - cryptoAmount: transaction.amount.toDouble(), + cryptoAmount: double.parse(transaction.amount.toString()), price: price, ).withLocalSeperator(_appStore.settingsStore.languageCode); break; case WalletType.solana: - final asset = assetOfTransaction; + final asset = solana!.assetOfTransaction(balanceViewModel.wallet, transaction); final price = balanceViewModel.fiatConversionStore.prices[asset]; amount = calculateFiatAmountRaw( - cryptoAmount: transaction.amount.toDouble(), + cryptoAmount: double.parse(transaction.amount.toString()), price: price, ).withLocalSeperator(_appStore.settingsStore.languageCode); break; @@ -230,7 +230,7 @@ class TransactionListItem extends ActionListItem with Keyable { final asset = tron!.assetOfTransaction(balanceViewModel.wallet, transaction); final price = balanceViewModel.fiatConversionStore.prices[asset]; amount = calculateFiatAmountRaw( - cryptoAmount: transaction.amount.toDouble(), + cryptoAmount: double.parse(transaction.amount.toString()), price: price, ).withLocalSeperator(_appStore.settingsStore.languageCode); break; @@ -242,7 +242,7 @@ class TransactionListItem extends ActionListItem with Keyable { } final price = balanceViewModel.fiatConversionStore.prices[asset]; amount = calculateFiatAmountRaw( - cryptoAmount: transaction.amount.toDouble(), + cryptoAmount: double.parse(transaction.amount.toString()), price: price, ).withLocalSeperator(_appStore.settingsStore.languageCode); break; diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 595d70d47..5b6ee9e10 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -2,12 +2,10 @@ import 'dart:async'; import 'dart:collection'; import 'dart:convert'; import 'dart:developer'; -import 'dart:math' show min; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/bitcoin/bitcoin.dart'; -import 'package:cake_wallet/core/address_validator.dart'; import 'package:cake_wallet/core/amount_parsing_proxy.dart'; import 'package:cake_wallet/core/create_trade_result.dart'; import 'package:cake_wallet/core/fiat_conversion_service.dart'; @@ -415,6 +413,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with @observable bool tradeStarted = false; + @observable + bool noProviderForPair = false; + @observable bool isSendFromExternal = false; @@ -980,6 +981,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with bestRate = _sortedAvailableProviders.keys.first; bestRateProvider = _sortedAvailableProviders.values.first; } + noProviderForPair = _sortedAvailableProviders.isEmpty; } @action @@ -1603,24 +1605,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with } } - String? _addressTypeValidation(String refundAddress, String receiveAddress) { - final isRefundAddressSP = - RegExp(AddressValidator.silentPaymentAddressPatternMainnet).hasMatch(refundAddress); - if (isRefundAddressSP) return 'Silent Payment ${S.current.address_not_allowed_as_refund}'; - - final isReceiveAddressSP = - RegExp(AddressValidator.silentPaymentAddressPatternMainnet).hasMatch(receiveAddress); - if (isReceiveAddressSP) return 'Silent Payment ${S.current.address_not_allowed_as_receive}'; - - final isRefundAddressMWEB = RegExp(AddressValidator.mWebAddressPattern).hasMatch(refundAddress); - if (isRefundAddressMWEB) return 'MWEB ${S.current.address_not_allowed_as_refund}'; - - final isReceiveAddressMWEB = - RegExp(AddressValidator.mWebAddressPattern).hasMatch(receiveAddress); - if (isReceiveAddressMWEB) return 'MWEB ${S.current.address_not_allowed_as_receive}'; - return null; - } - void _defineIsReceiveAmountEditable() { /*if ((provider is ChangeNowExchangeProvider) &&(depositCurrency == CryptoCurrency.xmr) diff --git a/lib/view_model/hardware_wallet/ledger_view_model.dart b/lib/view_model/hardware_wallet/ledger_view_model.dart index f5efaa52e..113ce51ff 100644 --- a/lib/view_model/hardware_wallet/ledger_view_model.dart +++ b/lib/view_model/hardware_wallet/ledger_view_model.dart @@ -42,8 +42,6 @@ abstract class LedgerViewModelBase extends HardwareWalletViewModel with Store { } }); - updateBleState(); - if (!Platform.isIOS) { ledgerPlusUSB = sdk.LedgerInterface.usb(); } diff --git a/lib/view_model/hardware_wallet/trezor_connect_view_model.dart b/lib/view_model/hardware_wallet/trezor_connect_view_model.dart index 28116e3cb..4d65e4d53 100644 --- a/lib/view_model/hardware_wallet/trezor_connect_view_model.dart +++ b/lib/view_model/hardware_wallet/trezor_connect_view_model.dart @@ -39,7 +39,6 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S _initBLE(); } }); - updateBleState(); if (!Platform.isIOS) { trezorUSB = sdk.TrezorInterface.usb(); diff --git a/lib/view_model/link_view_model.dart b/lib/view_model/link_view_model.dart index f14718ec5..f7067c93d 100644 --- a/lib/view_model/link_view_model.dart +++ b/lib/view_model/link_view_model.dart @@ -25,6 +25,10 @@ class LinkViewModel { Uri? currentLink; bool readyToOpenPage = false; + final StreamController _incomingPaymentLinksController = StreamController.broadcast(); + + Stream get incomingPaymentLinks => _incomingPaymentLinksController.stream; + bool get _isValidPaymentUri => currentLink?.path.isNotEmpty ?? false; bool get isWalletConnectLink => currentLink?.authority == 'wc'; bool get isNanoGptLink => currentLink?.scheme == 'nano-gpt'; @@ -96,7 +100,10 @@ class LinkViewModel { } if (_isValidPaymentUri) { - return {"paymentRequest": PaymentRequest.fromUri(currentLink)}; + return { + "paymentRequest": PaymentRequest.fromUri(currentLink), + "rawLink": currentLink.toString(), + }; } return null; @@ -132,8 +139,20 @@ class LinkViewModel { return; } - // Prevent navigating to the same route again. + if (route == Routes.send && + !isQuickActionLink && + currentLink != null && + _incomingPaymentLinksController.hasListener) { + final link = currentLink!; + currentLink = null; + _incomingPaymentLinksController.add(link); + return; + } + + // Prevent navigating to the same route again and clear the link so a later auth + // event cannot refire it. if (appStore.currentRouteName == route) { + currentLink = null; return; } diff --git a/lib/view_model/restore/wallet_restore_from_qr_code.dart b/lib/view_model/restore/wallet_restore_from_qr_code.dart index 732729d6c..f1456b9b5 100644 --- a/lib/view_model/restore/wallet_restore_from_qr_code.dart +++ b/lib/view_model/restore/wallet_restore_from_qr_code.dart @@ -11,6 +11,7 @@ import 'package:cake_wallet/view_model/restore/restore_mode.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cw_core/currency_for_wallet_type.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:bip39/bip39.dart' as bip39; import 'package:flutter/cupertino.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:collection/collection.dart'; @@ -89,9 +90,7 @@ class WalletRestoreFromQRCode { try { return AddressResolverUtils.extractAddressByType( raw: rawString, - type: walletTypeToCryptoCurrency( - type, - ), + type: walletTypeToCryptoCurrency(type), requireSurroundingWhitespaces: false, ); } catch (_) { @@ -127,8 +126,8 @@ class WalletRestoreFromQRCode { final prefix = code.startsWith('xpub') ? 'xpub' : code.startsWith('zpub') - ? 'zpub' - : '????'; + ? 'zpub' + : '????'; if (walletType == null) { await _specifyWalletAssets(context, "Can't determine wallet type, please pick it manually"); walletType = @@ -140,8 +139,8 @@ class WalletRestoreFromQRCode { formattedUri = seedPhrase != null ? '$walletType:?seed=$seedPhrase' : code.startsWith(prefix) - ? '$walletType:?$prefix=$code' - : throw Exception('Failed to determine valid seed phrase'); + ? '$walletType:?$prefix=$code' + : throw Exception('Failed to determine valid seed phrase'); } else { final index = code.indexOf(':'); final query = code.substring(index + 1).replaceAll('?', '&'); @@ -202,9 +201,15 @@ class WalletRestoreFromQRCode { seedValue.split(' ').forEach((element) { if (!words.contains(element)) { throw Exception( - "Unexpected restore mode: mnemonic_seed is invalid or doesn't match wallet type"); + "Unexpected restore mode: mnemonic_seed is invalid or doesn't match wallet type", + ); } }); + if (isEVMCompatibleChain(type) && !bip39.validateMnemonic(seedValue)) { + throw Exception( + 'EVM mnemonic has an invalid checksum. Please check the seed phrase for typos.', + ); + } return WalletRestoreMode.seed; } @@ -268,12 +273,14 @@ class WalletRestoreFromQRCode { Future _specifyWalletAssets(BuildContext context, String error) async { await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.current.error, - alertContent: error, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.current.error, + alertContent: error, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop(), + ); + }, + ); } diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 5bcbe44b8..7d3381b73 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -126,9 +126,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor super(appStore: _appStore) { outputs.add(Output(wallet, _appStore, _fiatConversationStore, _outputCryptoCurrencyHandler)); - unspentCoinsListViewModel - .initialSetup(); - // .then((_) => unspentCoinsListViewModel.resetUnspentCoinsInfoSelections()); + unspentCoinsListViewModel.initialSetup(); + // .then((_) => unspentCoinsListViewModel.resetUnspentCoinsInfoSelections()); reaction((_) { if (isEVMCompatibleChain(wallet.type)) { @@ -1718,9 +1717,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor String? payjoinUri; @action - Future fetchTokenForContractAddress(String contractAddress) async { + Future fetchTokenForContractAddress(String contractAddress, + {WalletType? walletType}) async { final token = await TokenUtilities.findTokenByAddress( - walletType: wallet.type, + walletType: walletType ?? wallet.type, address: contractAddress, ); @@ -1729,6 +1729,11 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor } } + @action + void applyAnyPayCurrency(CryptoCurrency currency) { + selectedCryptoCurrency = currency; + } + String _decodeMethodSelector(String s) => (s.startsWith('0x') && s.length >= 10) ? s.substring(0, 10) : ''; } diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 7a45c054b..d9466e56e 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -160,6 +160,13 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) COMPONENT Runtime) endforeach(bundled_library) +install(CODE " + execute_process( + COMMAND \"${CMAKE_COMMAND}\" -E create_symlink + libsqlite3_flutter_libs_plugin.so + \"${INSTALL_BUNDLE_LIB_DIR}/libsqlite3.so\") +" COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/model_generator.sh b/model_generator.sh index 20de89b39..06df837fd 100755 --- a/model_generator.sh +++ b/model_generator.sh @@ -1,11 +1,14 @@ #!/bin/bash set -x -e +pids=() + for cwcoin in cw_{core,evm,monero,bitcoin,nano,bitcoin_cash,solana,tron,wownero,zano,decred,dogecoin,zcash} do if [[ "x$1" == "xasync" ]]; then - bash -c "cd $cwcoin; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .." & + env PUB_CACHE=$HOME/.cache/pub-cache-$cwcoin bash -c "cd $cwcoin; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .." & + pids+=($!) else cd $cwcoin; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. fi @@ -15,10 +18,20 @@ do if [[ "x$1" == "xasync" ]]; then bash -c "cd $cwcoin; flutter pub get; cd .." & + pids+=($!) else cd $cwcoin; flutter pub get; cd .. fi done +for pid in "${pids[@]}"; do + if ! wait "$pid"; then + ec=$? + echo "Error: Failed to generate models: $ec" + exit $ec + fi +done + flutter pub get dart run build_runner build --delete-conflicting-outputs +flutter pub get diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 000000000..f0277a2dc --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,3495 @@ +# 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" + adaptive_number: + dependency: "direct overridden" + description: + path: "." + ref: c3f06de08064acca1b04975abcd4c3977c0b5256 + resolved-ref: c3f06de08064acca1b04975abcd4c3977c0b5256 + url: "https://github.com/lemoony/adaptive_number_dart" + source: git + version: "1.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b + url: "https://pub.dev" + source: hosted + version: "10.0.1" + animate_do: + dependency: "direct main" + description: + path: "." + ref: "94ca5c43abd93901fcd97b47102b6e5d37ce67ca" + resolved-ref: "94ca5c43abd93901fcd97b47102b6e5d37ce67ca" + url: "https://github.com/Klerith/animate_do_package" + source: git + version: "2.1.0" + animated_reorderable_list: + dependency: "direct overridden" + description: + path: "." + ref: "4a6810d0a912018fb0b193337f46973a478fcc4b" + resolved-ref: "4a6810d0a912018fb0b193337f46973a478fcc4b" + url: "https://github.com/canopas/animated_reorderable_list" + source: git + version: "1.3.0" + another_flushbar: + dependency: "direct main" + description: + path: "." + ref: a334e8e2dfbe3d5e531b63f72164093aa399047b + resolved-ref: a334e8e2dfbe3d5e531b63f72164093aa399047b + url: "https://github.com/ideployed/another-flushbar" + source: git + version: "1.12.32" + ansicolor: + dependency: "direct overridden" + description: + path: "." + ref: "35e67e6eb2da5e6d726fadfa90ccf437981c1e65" + resolved-ref: "35e67e6eb2da5e6d726fadfa90ccf437981c1e65" + url: "https://github.com/google/ansicolor-dart" + source: git + version: "2.0.3" + archive: + dependency: "direct main" + description: + path: "." + ref: f01d6a340ffe24e0ef46fa682d1b6bcc7b7aef13 + resolved-ref: f01d6a340ffe24e0ef46fa682d1b6bcc7b7aef13 + url: "https://github.com/brendan-duncan/archive" + source: git + version: "4.0.9" + args: + dependency: "direct overridden" + description: + path: "pkgs/args" + ref: "61e677100b06d56a1b3731ab1178ebf9102ecb1f" + resolved-ref: "61e677100b06d56a1b3731ab1178ebf9102ecb1f" + url: "https://github.com/dart-lang/core" + source: git + version: "2.7.0" + asn1lib: + dependency: "direct overridden" + description: + path: "." + ref: "1616ff662cd84301e029d1fa936acb8192a2b165" + resolved-ref: "1616ff662cd84301e029d1fa936acb8192a2b165" + url: "https://github.com/wstrange/asn1lib" + source: git + version: "1.6.5" + async: + dependency: "direct overridden" + description: + path: "pkgs/async" + ref: "158d80dc6d17c7b967e655e27a859cbc1c6aa71d" + resolved-ref: "158d80dc6d17c7b967e655e27a859cbc1c6aa71d" + url: "https://github.com/dart-lang/core" + source: git + version: "2.13.1" + auto_size_text: + dependency: "direct main" + description: + path: "." + ref: "2178f0821132636bc4f0dea1bc4d40a889d8249b" + resolved-ref: "2178f0821132636bc4f0dea1bc4d40a889d8249b" + url: "https://github.com/leisim/auto_size_text" + source: git + version: "3.0.0" + awesome_dialog: + dependency: "direct overridden" + description: + path: "." + ref: c7923f15d1d22de5c9077fff0bab6f9cc6463540 + resolved-ref: c7923f15d1d22de5c9077fff0bab6f9cc6463540 + url: "https://github.com/marcos930807/awesomeDialogs" + source: git + version: "3.2.1" + base32: + dependency: "direct main" + description: + path: "." + ref: "6ed989354aee7865ee74f3f1802268dd81bb234d" + resolved-ref: "6ed989354aee7865ee74f3f1802268dd81bb234d" + url: "https://github.com/Daegalus/dart-base32" + source: git + version: "2.1.3" + base58check: + dependency: "direct overridden" + description: + path: "." + ref: "240913d11885ee80506ff6f51033ddf527106086" + resolved-ref: "240913d11885ee80506ff6f51033ddf527106086" + url: "https://github.com/dartcoin/base58check" + source: git + version: "2.0.0" + base_x: + dependency: "direct overridden" + description: + path: "." + ref: b434cc7890337af7c04004c681018a2f32689217 + resolved-ref: b434cc7890337af7c04004c681018a2f32689217 + url: "https://github.com/litaoh/base-x" + source: git + version: "2.0.1" + basic_utils: + dependency: "direct main" + description: + path: "." + ref: "6a5034927857a08f3bdf5a177529e361179f6dab" + resolved-ref: "6a5034927857a08f3bdf5a177529e361179f6dab" + url: "https://github.com/Ephenodrom/Dart-Basic-Utils" + source: git + version: "5.7.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: "direct overridden" + description: + path: "." + ref: "05755063b593aa6cca0a4820a318e0ce17de6192" + resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192" + url: "https://github.com/cake-tech/bech32.git" + source: git + version: "0.2.2" + bip32: + dependency: "direct overridden" + description: + path: "." + ref: b5c6a6e891b89f92529799b42af62b8a8af09eaf + resolved-ref: b5c6a6e891b89f92529799b42af62b8a8af09eaf + url: "https://github.com/dart-bitcoin/bip32-dart" + source: git + version: "2.0.0" + bip340: + dependency: "direct overridden" + description: + path: "." + ref: bbab1a01b6b6ab7c18f26294febb3bee38b24798 + resolved-ref: bbab1a01b6b6ab7c18f26294febb3bee38b24798 + url: "https://github.com/fiatjaf/dart-bip340" + source: git + version: "0.2.0" + bip39: + dependency: "direct overridden" + description: + path: "." + ref: "3633daa2026b98c523ae9a091322be2903f7a8ab" + resolved-ref: "3633daa2026b98c523ae9a091322be2903f7a8ab" + url: "https://github.com/anicdh/bip39" + source: git + version: "1.0.6" + bitbox: + dependency: "direct overridden" + description: + path: "." + ref: "57b78afb85bd2c30d3cdb9f7884f3878a62be442" + 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: "4e41f96f4838139895c65c3f49109d05af5d46aa" + resolved-ref: "4e41f96f4838139895c65c3f49109d05af5d46aa" + url: "https://github.com/cake-tech/bitcoin_base" + source: git + version: "4.7.0" + bloc: + dependency: "direct main" + description: + path: "packages/bloc" + ref: "60892540c1faec3fd01cc8c8fea378a59cf42e3d" + resolved-ref: "60892540c1faec3fd01cc8c8fea378a59cf42e3d" + url: "https://github.com/felangel/bloc" + source: git + version: "9.2.1" + bloc_concurrency: + dependency: "direct main" + description: + path: "packages/bloc_concurrency" + ref: "13dbe0ce078e7efaebb54b37489879daeb57459d" + resolved-ref: "13dbe0ce078e7efaebb54b37489879daeb57459d" + url: "https://github.com/felangel/bloc" + source: git + version: "0.3.0" + blockchain_utils: + dependency: "direct main" + description: + path: "." + ref: "59fdf29d72068e0522a96a8953ed7272833a9f57" + resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57" + url: "https://github.com/cake-tech/blockchain_utils" + source: git + version: "3.3.0" + bluez: + dependency: "direct overridden" + description: + path: "." + ref: f02727e93b61585ea6c5a6a18ebf84b7374a71d3 + resolved-ref: f02727e93b61585ea6c5a6a18ebf84b7374a71d3 + url: "https://github.com/canonical/bluez.dart" + source: git + version: "0.8.3" + boolean_selector: + dependency: "direct overridden" + description: + path: "pkgs/boolean_selector" + ref: b1312b18df67b0be3101ca15c03dfd8d7c9383bb + resolved-ref: b1312b18df67b0be3101ca15c03dfd8d7c9383bb + url: "https://github.com/dart-lang/tools" + source: git + version: "2.1.2" + borsh_annotation: + dependency: "direct overridden" + description: + path: "packages/borsh_annotation" + ref: ab60e9d4c7d7271037597154ad2a835812054ed6 + resolved-ref: ab60e9d4c7d7271037597154ad2a835812054ed6 + url: "https://github.com/espresso-cash/espresso-cash-public" + source: git + version: "0.3.2" + breez_sdk_spark_flutter: + dependency: "direct overridden" + description: + path: "." + ref: e18b6437daaf0572de6aea2439c2ec4d22658bbb + resolved-ref: e18b6437daaf0572de6aea2439c2ec4d22658bbb + url: "https://github.com/breez/breez-sdk-spark-flutter" + source: git + version: "0.14.0" + bs58: + dependency: "direct overridden" + description: + path: "." + ref: "637d7b4bef20ac4edb553ef20e40725c4a213736" + resolved-ref: "637d7b4bef20ac4edb553ef20e40725c4a213736" + url: "https://github.com/litaoh/base58" + source: git + version: "1.0.2" + bs58check: + dependency: "direct overridden" + description: + path: "." + ref: "1216b214e26332ccc4a3de4c9eac87de7fd47b5a" + resolved-ref: "1216b214e26332ccc4a3de4c9eac87de7fd47b5a" + url: "https://github.com/MrCyjaneK/bs58check" + source: git + version: "1.0.2" + bubble: + dependency: "direct overridden" + description: + path: "." + ref: "6a90afbbb8fee0dccfd7843248c74c1f8460e813" + resolved-ref: "6a90afbbb8fee0dccfd7843248c74c1f8460e813" + url: "https://github.com/vi-k/bubble" + source: git + version: "1.2.1" + buffer: + dependency: "direct overridden" + description: + path: "." + ref: "96be675b6f2bbca859a13da6c5f551ffd7eebc1c" + resolved-ref: "96be675b6f2bbca859a13da6c5f551ffd7eebc1c" + url: "https://github.com/isoos/buffer" + source: git + version: "1.2.3" + build: + dependency: "direct overridden" + description: + path: build + ref: "565856b394c26a0d4c8cda88b69b6dcfaa2acd1f" + resolved-ref: "565856b394c26a0d4c8cda88b69b6dcfaa2acd1f" + url: "https://github.com/dart-lang/build" + source: git + version: "4.0.7" + build_cli_annotations: + dependency: "direct overridden" + description: + path: build_cli_annotations + ref: d01ba0ba11a73b4e541ff65508ae55842a8f887f + resolved-ref: d01ba0ba11a73b4e541ff65508ae55842a8f887f + url: "https://github.com/kevmoo/build_cli" + source: git + version: "2.1.1" + build_config: + dependency: "direct overridden" + description: + path: build_config + ref: "7d6c879a01d80056b3eae52f7fab2237103a7fe7" + resolved-ref: "7d6c879a01d80056b3eae52f7fab2237103a7fe7" + url: "https://github.com/dart-lang/build" + source: git + version: "1.3.2" + build_daemon: + dependency: "direct overridden" + description: + path: build_daemon + ref: f20f2a24e0e1259f6ee53c6828d7c396d5b23bbf + resolved-ref: f20f2a24e0e1259f6ee53c6828d7c396d5b23bbf + url: "https://github.com/dart-lang/build" + source: git + version: "4.1.5" + build_runner: + dependency: "direct dev" + description: + path: build_runner + ref: "565856b394c26a0d4c8cda88b69b6dcfaa2acd1f" + resolved-ref: "565856b394c26a0d4c8cda88b69b6dcfaa2acd1f" + url: "https://github.com/dart-lang/build" + source: git + version: "2.15.1" + built_collection: + dependency: "direct overridden" + description: + path: "." + ref: "8153cc41299a28e4426b22959f87dca0f7f8cd19" + resolved-ref: "8153cc41299a28e4426b22959f87dca0f7f8cd19" + url: "https://github.com/google/built_collection.dart" + source: git + version: "5.1.1" + built_value: + dependency: "direct overridden" + description: + path: built_value + ref: b66790e815350e8c569bfe723d5263925df5a46d + resolved-ref: b66790e815350e8c569bfe723d5263925df5a46d + url: "https://github.com/google/built_value.dart" + source: git + version: "8.12.7" + cake_backup: + dependency: "direct main" + description: + path: "." + ref: "3aba867dcab6737f6707782f5db15d71f303db38" + resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38" + url: "https://github.com/cake-tech/cake_backup.git" + source: git + version: "1.0.0+1" + characters: + dependency: "direct overridden" + description: + path: "pkgs/characters" + ref: b59ecf4ceebe6153e1c0166b7c9a7fdd9458a89d + resolved-ref: b59ecf4ceebe6153e1c0166b7c9a7fdd9458a89d + url: "https://github.com/dart-lang/core" + source: git + version: "1.4.1" + checked_yaml: + dependency: "direct overridden" + description: + path: checked_yaml + ref: d30c2fdb0598d548c25705931531842957623fdd + resolved-ref: d30c2fdb0598d548c25705931531842957623fdd + url: "https://github.com/google/json_serializable.dart" + source: git + version: "2.0.4" + cli_config: + dependency: "direct overridden" + description: + path: "pkgs/cli_config" + ref: "378790dd8cdaecd8cb48283de445f7cf80419cc0" + resolved-ref: "378790dd8cdaecd8cb48283de445f7cf80419cc0" + url: "https://github.com/dart-lang/tools" + source: git + version: "0.2.0" + cli_util: + dependency: "direct overridden" + description: + path: "pkgs/cli_util" + ref: d7a7e2ebba2fdc25e78000a1af08508b60beb7fc + resolved-ref: d7a7e2ebba2fdc25e78000a1af08508b60beb7fc + url: "https://github.com/dart-lang/tools" + source: git + version: "0.4.2" + clock: + dependency: "direct overridden" + description: + path: "pkgs/clock" + ref: "04f7512ab6d7d554e33abd124a41e2aeec97dcbd" + resolved-ref: "04f7512ab6d7d554e33abd124a41e2aeec97dcbd" + url: "https://github.com/dart-lang/tools" + source: git + version: "1.1.2" + code_assets: + dependency: "direct overridden" + description: + path: "pkgs/code_assets" + ref: fca756b953bc94f109039dd553f0bc18de620338 + resolved-ref: fca756b953bc94f109039dd553f0bc18de620338 + url: "https://github.com/dart-lang/native" + source: git + version: "1.2.1" + code_builder: + dependency: "direct overridden" + description: + path: "pkgs/code_builder" + ref: "125b9a9a5556fa88ecec26f649e1cddb1623aa2f" + resolved-ref: "125b9a9a5556fa88ecec26f649e1cddb1623aa2f" + url: "https://github.com/dart-lang/tools" + source: git + version: "4.11.1" + collection: + dependency: "direct overridden" + description: + path: "pkgs/collection" + ref: dec28c1d477cd191e2af868579817b926b07d9f5 + resolved-ref: dec28c1d477cd191e2af868579817b926b07d9f5 + url: "https://github.com/dart-lang/core" + source: git + version: "1.19.1" + connectivity_plus: + dependency: "direct main" + description: + path: "packages/connectivity_plus/connectivity_plus" + ref: "9f03424b7916b195ec6a4bebe4cc1a310ba40d4a" + resolved-ref: "9f03424b7916b195ec6a4bebe4cc1a310ba40d4a" + url: "https://github.com/fluttercommunity/plus_plugins" + source: git + version: "6.1.5" + connectivity_plus_platform_interface: + dependency: "direct overridden" + description: + path: "packages/connectivity_plus/connectivity_plus_platform_interface" + ref: c46ab89942b2be24aedf79555f247c566d99777f + resolved-ref: c46ab89942b2be24aedf79555f247c566d99777f + url: "https://github.com/fluttercommunity/plus_plugins" + source: git + version: "2.1.0" + console: + dependency: "direct overridden" + description: + path: "." + ref: f391b6d289490e1735566c63fe539d1c3fc40818 + resolved-ref: f391b6d289490e1735566c63fe539d1c3fc40818 + url: "https://github.com/DirectMyFile/console.dart" + source: git + version: "4.1.0" + convert: + dependency: "direct overridden" + description: + path: "pkgs/convert" + ref: "16f396fcf87da1db940187db3564b3a490015678" + resolved-ref: "16f396fcf87da1db940187db3564b3a490015678" + url: "https://github.com/dart-lang/core" + source: git + version: "3.1.2" + coverage: + dependency: "direct overridden" + description: + path: "pkgs/coverage" + ref: "176ad7aea84d9fccc5c17795568ea2165a0414f9" + resolved-ref: "176ad7aea84d9fccc5c17795568ea2165a0414f9" + url: "https://github.com/dart-lang/tools" + source: git + version: "1.15.1" + cross_file: + dependency: "direct overridden" + description: + path: "packages/cross_file" + ref: b967797f07f1e4fc4fb264f5c8e5181b1385d9d9 + resolved-ref: b967797f07f1e4fc4fb264f5c8e5181b1385d9d9 + url: "https://github.com/flutter/packages" + source: git + version: "0.3.5+4" + crypto: + dependency: "direct main" + description: + path: "pkgs/crypto" + ref: e6c3810cdbbd6b483973f4685e950644114b495e + resolved-ref: e6c3810cdbbd6b483973f4685e950644114b495e + url: "https://github.com/dart-lang/core" + source: git + version: "3.0.7" + cryptography: + dependency: "direct main" + description: + path: cryptography + ref: "87f42fad6f7f120feb8e47854164016ceac3dfd0" + resolved-ref: "87f42fad6f7f120feb8e47854164016ceac3dfd0" + url: "https://github.com/dint-dev/cryptography" + source: git + version: "2.9.0" + csslib: + dependency: "direct overridden" + description: + path: "pkgs/csslib" + ref: "91a840b6bc02e5e4b57fb55a047267923b894c89" + resolved-ref: "91a840b6bc02e5e4b57fb55a047267923b894c89" + url: "https://github.com/dart-lang/tools" + source: git + version: "1.0.2" + cupertino_icons: + dependency: "direct main" + description: + path: "third_party/packages/cupertino_icons" + ref: f330175dbf168a7bf94a127c492e025b4cc0bfba + resolved-ref: f330175dbf168a7bf94a127c492e025b4cc0bfba + url: "https://github.com/flutter/packages" + source: git + version: "1.0.9" + cw_bitcoin: + dependency: "direct main" + description: + path: cw_bitcoin + relative: true + source: path + version: "0.0.1" + cw_bitcoin_cash: + dependency: "direct main" + description: + path: cw_bitcoin_cash + relative: true + source: path + version: "0.0.1" + cw_core: + dependency: "direct main" + description: + path: cw_core + relative: true + source: path + version: "0.0.1" + cw_decred: + dependency: "direct main" + description: + path: cw_decred + relative: true + source: path + version: "0.0.1" + cw_dogecoin: + dependency: "direct main" + description: + path: cw_dogecoin + relative: true + source: path + version: "0.0.1" + cw_evm: + dependency: "direct main" + description: + path: cw_evm + relative: true + source: path + version: "0.0.1" + cw_monero: + dependency: "direct main" + description: + path: cw_monero + relative: true + source: path + version: "0.0.1" + cw_mweb: + dependency: transitive + description: + path: cw_mweb + relative: true + source: path + version: "0.0.1" + cw_nano: + dependency: "direct main" + description: + path: cw_nano + relative: true + source: path + version: "0.0.1" + cw_solana: + dependency: "direct main" + description: + path: cw_solana + relative: true + source: path + version: "0.0.1" + cw_tron: + dependency: "direct main" + description: + path: cw_tron + relative: true + source: path + version: "0.0.1" + cw_wownero: + dependency: "direct main" + description: + path: cw_wownero + relative: true + source: path + version: "0.0.1" + cw_zano: + dependency: "direct main" + description: + path: cw_zano + relative: true + source: path + version: "0.0.1" + cw_zcash: + dependency: "direct main" + description: + path: cw_zcash + relative: true + source: path + version: "1.0.0" + dart_style: + dependency: "direct overridden" + description: + path: "." + ref: a0f21e86a7a0ba52f11f46e3ed2ad1144616b512 + resolved-ref: a0f21e86a7a0ba52f11f46e3ed2ad1144616b512 + url: "https://github.com/dart-lang/dart_style" + source: git + version: "3.1.7" + dart_varuint_bitcoin: + dependency: "direct overridden" + description: + path: "." + ref: "51f9656d5937659c9f034cb0910dd0144459f137" + resolved-ref: "51f9656d5937659c9f034cb0910dd0144459f137" + url: "https://github.com/dart-bitcoin-lib/dart-varuint-bitcoin" + source: git + version: "1.0.3" + data_table_2: + dependency: "direct overridden" + description: + path: "." + ref: "4db30aa145e4e831e5527708cf77d9ed4d8e9700" + resolved-ref: "4db30aa145e4e831e5527708cf77d9ed4d8e9700" + url: "https://github.com/maxim-saplin/data_table_2" + source: git + version: "2.7.2" + dbus: + dependency: "direct overridden" + description: + path: "." + ref: "2db8509d7f7081025e7246511e823287fdd09abc" + resolved-ref: "2db8509d7f7081025e7246511e823287fdd09abc" + url: "https://github.com/canonical/dbus.dart" + source: git + version: "0.7.12" + decimal: + dependency: "direct overridden" + description: + path: "." + ref: bc9771127e4c26f068fc9b016269f0ddabe9b475 + resolved-ref: bc9771127e4c26f068fc9b016269f0ddabe9b475 + url: "https://github.com/a14n/dart-decimal" + source: git + version: "2.3.3" + device_display_brightness: + dependency: "direct main" + description: + path: "." + ref: "4cac18c446ce686f3d75b1565badbd7da439bbd9" + resolved-ref: "4cac18c446ce686f3d75b1565badbd7da439bbd9" + url: "https://github.com/MrCyjaneK/device_display_brightness.git" + source: git + version: "0.0.6" + device_info_plus: + dependency: "direct main" + description: + path: "packages/device_info_plus/device_info_plus" + ref: "83f86a357da31c7e9c47ee668fe3142bafea9c91" + resolved-ref: "83f86a357da31c7e9c47ee668fe3142bafea9c91" + url: "https://github.com/fluttercommunity/plus_plugins" + source: git + version: "9.1.2" + device_info_plus_platform_interface: + dependency: "direct overridden" + description: + path: "packages/device_info_plus/device_info_plus_platform_interface" + ref: "1b37ba220c99b16693991042c3fcc69eae98864a" + resolved-ref: "1b37ba220c99b16693991042c3fcc69eae98864a" + url: "https://github.com/fluttercommunity/plus_plugins" + source: git + version: "7.0.3" + devicelocale: + dependency: "direct main" + description: + path: "." + ref: "3ed4bcc443a40da200af162f4b97d63d7b00d291" + resolved-ref: "3ed4bcc443a40da200af162f4b97d63d7b00d291" + url: "https://github.com/magnatronus/flutter-devicelocale" + source: git + version: "0.8.1" + dio: + dependency: "direct main" + description: + path: dio + ref: ef9dbb860c085a8e81ecd36d5bcf29d5672947e1 + resolved-ref: ef9dbb860c085a8e81ecd36d5bcf29d5672947e1 + url: "https://github.com/cfug/dio" + source: git + version: "5.11.0" + dio_web_adapter: + dependency: "direct overridden" + description: + path: "plugins/web_adapter" + ref: f72e83c8e832e81169f621b13c9e39aeaf9286b8 + resolved-ref: f72e83c8e832e81169f621b13c9e39aeaf9286b8 + url: "https://github.com/cfug/dio" + source: git + version: "2.2.1" + dnssec_proof: + dependency: "direct main" + description: + path: "." + ref: b48a9defddce036048bae02e2069ebcbd6824afc + resolved-ref: b48a9defddce036048bae02e2069ebcbd6824afc + url: "https://github.com/MrCyjaneK/dnssec_proof.git" + source: git + version: "0.0.1" + dotenv: + dependency: "direct overridden" + description: + path: "." + ref: "08216384e8a03b0aa55e0fcb81f4d03a52f7ea76" + resolved-ref: "08216384e8a03b0aa55e0fcb81f4d03a52f7ea76" + url: "https://github.com/mockturtl/dotenv" + source: git + version: "3.0.0" + dotted_border: + dependency: "direct main" + description: + path: "." + ref: a0168f4a4d410087afb378a06deb058cb92a9fb1 + resolved-ref: a0168f4a4d410087afb378a06deb058cb92a9fb1 + url: "https://github.com/ajilo297/Flutter-Dotted-Border" + source: git + version: "2.1.0" + easy_debounce: + dependency: "direct overridden" + description: + path: "." + ref: ed3f2aff0f080aa21cecd86e3a7c108340a9f17d + resolved-ref: ed3f2aff0f080aa21cecd86e3a7c108340a9f17d + url: "https://github.com/magnuswikhog/easy_debounce" + source: git + version: "2.0.3" + easy_stepper: + dependency: "direct overridden" + description: + path: "." + ref: cec4390aef9e5ff9fe064a44ed06b4f2c6dae1d2 + resolved-ref: cec4390aef9e5ff9fe064a44ed06b4f2c6dae1d2 + url: "https://github.com/ma7moud3osman/easy_stepper" + source: git + version: "0.8.5+1" + ed25519_edwards: + dependency: "direct overridden" + description: + path: "." + ref: "944daea677c4d7f3abea608f55b34aec93bb79fb" + resolved-ref: "944daea677c4d7f3abea608f55b34aec93bb79fb" + url: "https://github.com/Tougee/ed25519" + source: git + version: "0.3.1" + ed25519_hd_key: + dependency: "direct overridden" + description: + path: "." + ref: be3939527511af23dbfd97b5abde56215a5ce60d + resolved-ref: be3939527511af23dbfd97b5abde56215a5ce60d + url: "https://github.com/alepop/dart-ed25519-hd-key" + source: git + version: "2.3.0" + eip1559: + dependency: "direct overridden" + description: + path: "." + ref: d1888bf05e99cca1638e7fcc10d7f82d21857f9a + resolved-ref: d1888bf05e99cca1638e7fcc10d7f82d21857f9a + url: "https://github.com/xclud/dart_eip1559" + source: git + version: "0.6.2" + eip55: + dependency: "direct overridden" + description: + path: "." + ref: "1dd7172b6d8f7e21f11378a4bf3489a8d1ff890f" + resolved-ref: "1dd7172b6d8f7e21f11378a4bf3489a8d1ff890f" + url: "https://github.com/xclud/dart_eip55" + source: git + version: "1.0.2" + encrypt: + dependency: "direct main" + description: + path: "." + ref: "8581b81c060cde1c531e35a6eaa4b7324e9ab813" + resolved-ref: "8581b81c060cde1c531e35a6eaa4b7324e9ab813" + url: "https://github.com/leocavalcante/encrypt" + source: git + version: "5.0.2" + ens_dart: + dependency: "direct main" + description: + path: "." + ref: "9fa09b9db69b8645d5d50a844652aa570451d101" + resolved-ref: "9fa09b9db69b8645d5d50a844652aa570451d101" + url: "https://github.com/cake-tech/ens_dart.git" + source: git + version: "1.0.0" + equatable: + dependency: "direct main" + description: + path: "." + ref: f98a58960545ba72b51d0eacf746af393a0c6b24 + resolved-ref: f98a58960545ba72b51d0eacf746af393a0c6b24 + url: "https://github.com/felangel/equatable" + source: git + version: "2.1.0" + erc20: + dependency: "direct overridden" + description: + path: "." + ref: "759c4363d1dc9d6a3c2604ceb4261b5bcdfc68b1" + resolved-ref: "759c4363d1dc9d6a3c2604ceb4261b5bcdfc68b1" + url: "https://github.com/xclud/dart_erc20" + source: git + version: "1.0.1" + eth_sig_util: + dependency: "direct main" + description: + path: "." + ref: "6acd66a126f470b5541f089fdd1c079d35a59c9a" + resolved-ref: "6acd66a126f470b5541f089fdd1c079d35a59c9a" + url: "https://github.com/wakumo/eth-sig-util" + source: git + version: "0.0.9" + event: + dependency: "direct overridden" + description: + path: "." + ref: "93e1c474cf736481a0ef07c15a8c8bbdc5f21b60" + resolved-ref: "93e1c474cf736481a0ef07c15a8c8bbdc5f21b60" + url: "https://github.com/aryehof/dart-event" + source: git + version: "3.1.0" + fake_async: + dependency: "direct overridden" + description: + path: "pkgs/fake_async" + ref: "82417ab30b95ff471ded4bf6a3eea005ca97774f" + resolved-ref: "82417ab30b95ff471ded4bf6a3eea005ca97774f" + url: "https://github.com/dart-lang/test" + source: git + version: "1.3.3" + fast_base58: + dependency: "direct overridden" + description: + path: "." + ref: "46955c19e499ce5c15755f6f573479d5f5218a45" + resolved-ref: "46955c19e499ce5c15755f6f573479d5f5218a45" + url: "https://github.com/maoxs2/dart_fast_base58" + source: git + version: "0.2.2" + fast_scanner: + dependency: "direct main" + description: + path: "." + ref: "69b3276b090fa6ac01b4483ca3adca93a8e615be" + resolved-ref: "69b3276b090fa6ac01b4483ca3adca93a8e615be" + url: "https://github.com/MrCyjaneK/fast_scanner" + source: git + version: "5.1.1" + ffi: + dependency: "direct overridden" + description: + path: "pkgs/ffi" + ref: "6bd0935f29c7294ebb9aab21c06b47b513def933" + resolved-ref: "6bd0935f29c7294ebb9aab21c06b47b513def933" + url: "https://github.com/dart-lang/native" + source: git + version: "2.1.0" + ffigen: + dependency: "direct overridden" + description: + path: "pkgs/ffigen" + ref: c837526da8808501b53255caea0364eaa2c84afb + resolved-ref: c837526da8808501b53255caea0364eaa2c84afb + url: "https://github.com/dart-lang/native" + source: git + version: "12.0.0" + file: + dependency: "direct overridden" + description: + path: "pkgs/file" + ref: "3f7a46606496f826c2f60586ab71c2b7a9bfbf15" + resolved-ref: "3f7a46606496f826c2f60586ab71c2b7a9bfbf15" + url: "https://github.com/dart-lang/tools" + source: git + version: "7.0.1" + file_picker: + dependency: "direct main" + description: + path: "." + ref: c414574bc5ac349450f601e7f72c7b9f31b4d087 + resolved-ref: c414574bc5ac349450f601e7f72c7b9f31b4d087 + url: "https://github.com/cake-tech/flutter_file_picker.git" + source: git + version: "8.1.6" + file_selector_linux: + dependency: "direct overridden" + description: + path: "packages/file_selector/file_selector_linux" + ref: e67b6be3f57927f6831ec41afd3444adb31be3d3 + resolved-ref: e67b6be3f57927f6831ec41afd3444adb31be3d3 + url: "https://github.com/flutter/packages" + source: git + version: "0.9.4" + file_selector_macos: + dependency: "direct overridden" + description: + path: "packages/file_selector/file_selector_macos" + ref: e67b6be3f57927f6831ec41afd3444adb31be3d3 + resolved-ref: e67b6be3f57927f6831ec41afd3444adb31be3d3 + url: "https://github.com/flutter/packages" + source: git + version: "0.9.5" + file_selector_platform_interface: + dependency: "direct overridden" + description: + path: "packages/file_selector/file_selector_platform_interface" + ref: "29211e8b56107f477d4521dd30e8ad713007860e" + resolved-ref: "29211e8b56107f477d4521dd30e8ad713007860e" + url: "https://github.com/flutter/packages" + source: git + version: "2.7.0" + file_selector_windows: + dependency: "direct overridden" + description: + path: "packages/file_selector/file_selector_windows" + ref: "18b9cc5f2b0820cb6164f0150958ba76db75c61a" + resolved-ref: "18b9cc5f2b0820cb6164f0150958ba76db75c61a" + url: "https://github.com/flutter/packages" + source: git + version: "0.9.3+5" + fixed: + dependency: "direct overridden" + description: + path: "." + ref: "1bdd715b95d8ed9c7fdffa6735bdcf2bf5ff8e65" + resolved-ref: "1bdd715b95d8ed9c7fdffa6735bdcf2bf5ff8e65" + url: "https://github.com/onepub-dev/fixed" + source: git + version: "5.3.4" + fixnum: + dependency: "direct overridden" + description: + path: "pkgs/fixnum" + ref: "17d1b2cd13991f3cf844886db1c7ad18910a8908" + resolved-ref: "17d1b2cd13991f3cf844886db1c7ad18910a8908" + url: "https://github.com/dart-lang/core" + source: git + version: "1.1.1" + fixnum_nanodart: + dependency: "direct overridden" + description: + path: "." + ref: "332e879371f175b52f688383d6ff795609aece85" + resolved-ref: "332e879371f175b52f688383d6ff795609aece85" + url: "https://github.com/MrCyjaneK/fixnum_nanodart" + source: git + version: "1.0.0" + fl_chart: + dependency: "direct main" + description: + path: "." + ref: be14b9722b7f18310c869c930562b7871b0165ed + resolved-ref: be14b9722b7f18310c869c930562b7871b0165ed + url: "https://github.com/imaNNeo/fl_chart" + source: git + version: "0.70.2" + flat_buffers: + dependency: "direct overridden" + description: + path: dart + ref: "187240970746d00bbd26b0f5873ed54d2477f9f3" + resolved-ref: "187240970746d00bbd26b0f5873ed54d2477f9f3" + url: "https://github.com/google/flatbuffers" + source: git + version: "25.9.23" + flex_color_scheme: + dependency: "direct overridden" + description: + path: "." + ref: c0e810b1eba7cd2b2be1f5c6130b86672858db3d + resolved-ref: c0e810b1eba7cd2b2be1f5c6130b86672858db3d + url: "https://github.com/rydmike/flex_color_scheme" + source: git + version: "8.4.0" + flex_seed_scheme: + dependency: "direct overridden" + description: + path: "." + ref: aa7be701ad58dc8e61637373db2bef0f28d2606e + resolved-ref: aa7be701ad58dc8e61637373db2bef0f28d2606e + url: "https://github.com/rydmike/flex_seed_scheme" + source: git + version: "4.0.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + path: "packages/flutter_bloc" + ref: "59098d33f3eed63001d3170295d2bfa76fa84351" + resolved-ref: "59098d33f3eed63001d3170295d2bfa76fa84351" + url: "https://github.com/felangel/bloc" + source: git + version: "9.1.1" + flutter_daemon: + dependency: "direct main" + description: + path: "." + ref: c24ee99f2f3070ea02d8108bbdd7727d73f7e5f1 + resolved-ref: c24ee99f2f3070ea02d8108bbdd7727d73f7e5f1 + url: "https://github.com/MrCyjaneK/flutter_daemon" + source: git + version: "0.0.1" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_form_builder: + dependency: "direct overridden" + description: + path: "." + ref: c55646b1d7f995752dbf5a9bd63da7592d342ffb + resolved-ref: c55646b1d7f995752dbf5a9bd63da7592d342ffb + url: "https://github.com/flutter-form-builder-ecosystem/flutter_form_builder" + source: git + version: "10.3.0+2" + flutter_hooks: + dependency: "direct overridden" + description: + path: "packages/flutter_hooks" + ref: "9a2245f922bbd0ec397562fc7dc4b22b98c9199e" + resolved-ref: "9a2245f922bbd0ec397562fc7dc4b22b98c9199e" + url: "https://github.com/rrousselGit/flutter_hooks" + source: git + version: "0.21.3+1" + flutter_inappwebview: + dependency: "direct main" + description: + path: flutter_inappwebview + ref: f67ae1f34868c7660c16a2473f53a7a7bfb6f784 + resolved-ref: f67ae1f34868c7660c16a2473f53a7a7bfb6f784 + url: "https://github.com/pichillilorenzo/flutter_inappwebview" + source: git + version: "6.1.5" + flutter_inappwebview_android: + dependency: "direct overridden" + description: + path: flutter_inappwebview_android + ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + resolved-ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + url: "https://github.com/pichillilorenzo/flutter_inappwebview" + source: git + version: "1.1.3" + flutter_inappwebview_internal_annotations: + dependency: "direct overridden" + description: + path: "dev_packages/flutter_inappwebview_internal_annotations" + ref: "5be1ade739ab2a385e94a1bd5936c5a2000d52a9" + resolved-ref: "5be1ade739ab2a385e94a1bd5936c5a2000d52a9" + url: "https://github.com/pichillilorenzo/flutter_inappwebview" + source: git + version: "1.3.0" + flutter_inappwebview_ios: + dependency: "direct overridden" + description: + path: flutter_inappwebview_ios + ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + resolved-ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + url: "https://github.com/pichillilorenzo/flutter_inappwebview" + source: git + version: "1.1.2" + flutter_inappwebview_macos: + dependency: "direct overridden" + description: + path: flutter_inappwebview_macos + ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + resolved-ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + url: "https://github.com/pichillilorenzo/flutter_inappwebview" + source: git + version: "1.1.2" + flutter_inappwebview_platform_interface: + dependency: "direct overridden" + description: + path: flutter_inappwebview_platform_interface + ref: "60f1012e804f785421878ba1ee34403458e6baf2" + resolved-ref: "60f1012e804f785421878ba1ee34403458e6baf2" + url: "https://github.com/pichillilorenzo/flutter_inappwebview" + source: git + version: "1.3.0+1" + flutter_inappwebview_web: + dependency: "direct overridden" + description: + path: flutter_inappwebview_web + ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + resolved-ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + url: "https://github.com/pichillilorenzo/flutter_inappwebview" + source: git + version: "1.1.2" + flutter_inappwebview_windows: + dependency: "direct overridden" + description: + path: flutter_inappwebview_windows + ref: "952aa783912c9b0fd98d01e3c2c707d97512cd63" + resolved-ref: "952aa783912c9b0fd98d01e3c2c707d97512cd63" + url: "https://github.com/pichillilorenzo/flutter_inappwebview" + source: git + version: "0.6.0" + flutter_local_authentication: + dependency: "direct main" + description: + path: "." + ref: "75c8681ebef62398a87c8ae0cccb7cfddffa9734" + resolved-ref: "75c8681ebef62398a87c8ae0cccb7cfddffa9734" + url: "https://github.com/cake-tech/flutter_local_authentication" + source: git + version: "1.2.0" + flutter_local_notifications: + dependency: "direct main" + description: + path: flutter_local_notifications + ref: "6c7378ddb1ed7f885e1e80caa3df3bcfb0fe8707" + resolved-ref: "6c7378ddb1ed7f885e1e80caa3df3bcfb0fe8707" + url: "https://github.com/MaikuB/flutter_local_notifications" + source: git + version: "19.5.0" + flutter_local_notifications_linux: + dependency: "direct overridden" + description: + path: flutter_local_notifications_linux + ref: "314b432f98bcaef768468e5755317e10213a59bf" + resolved-ref: "314b432f98bcaef768468e5755317e10213a59bf" + url: "https://github.com/MaikuB/flutter_local_notifications" + source: git + version: "6.0.0" + flutter_local_notifications_platform_interface: + dependency: "direct overridden" + description: + path: flutter_local_notifications_platform_interface + ref: "816a1ddbf733bba3fb8d87ac3a9c2673ec15881b" + resolved-ref: "816a1ddbf733bba3fb8d87ac3a9c2673ec15881b" + url: "https://github.com/MaikuB/flutter_local_notifications" + source: git + version: "9.1.0" + flutter_local_notifications_windows: + dependency: "direct overridden" + description: + path: flutter_local_notifications_windows + ref: ecd66b1515d17e327a62ca4ff8e94f925e97d688 + resolved-ref: ecd66b1515d17e327a62ca4ff8e94f925e97d688 + url: "https://github.com/MaikuB/flutter_local_notifications" + source: git + version: "1.0.3" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_mailer: + dependency: "direct main" + description: + path: "." + ref: "9c4ed111a9151a2bbfb9afe2c18a37599c6f84f3" + resolved-ref: "9c4ed111a9151a2bbfb9afe2c18a37599c6f84f3" + url: "https://github.com/taljacobson/flutter_mailer" + source: git + version: "3.0.0" + flutter_mobx: + dependency: "direct main" + description: + path: flutter_mobx + ref: "0cadcd03551baaae57788b7288e1245e6408d5cf" + resolved-ref: "0cadcd03551baaae57788b7288e1245e6408d5cf" + url: "https://github.com/mobxjs/mobx.dart" + source: git + version: "2.3.0" + flutter_native_splash: + dependency: "direct overridden" + description: + path: "." + ref: "8c65117f0a4adc04f93deeb595a699a0d6dac559" + resolved-ref: "8c65117f0a4adc04f93deeb595a699a0d6dac559" + url: "https://github.com/jonbhanson/flutter_native_splash" + source: git + version: "2.4.6" + flutter_plugin_android_lifecycle: + dependency: "direct main" + description: + path: "packages/flutter_plugin_android_lifecycle" + ref: "4afc383a6db56cb969af5d8ad02a1a0220758b66" + resolved-ref: "4afc383a6db56cb969af5d8ad02a1a0220758b66" + url: "https://github.com/flutter/packages" + source: git + version: "2.0.23" + flutter_riverpod: + dependency: "direct overridden" + description: + path: "packages/flutter_riverpod" + ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + resolved-ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + url: "https://github.com/rrousselGit/riverpod" + source: git + version: "3.3.2" + flutter_rust_bridge: + dependency: "direct overridden" + description: + path: frb_dart + ref: f19087cd0cac019b82d52cfa5153ce81b1b6e902 + resolved-ref: f19087cd0cac019b82d52cfa5153ce81b1b6e902 + url: "https://github.com/fzyzcjy/flutter_rust_bridge" + source: git + version: "2.11.1" + flutter_secure_storage: + dependency: "direct main" + description: + path: flutter_secure_storage + ref: ca897a08677edb443b366352dd7412735e098e7b + resolved-ref: ca897a08677edb443b366352dd7412735e098e7b + url: "https://github.com/cake-tech/flutter_secure_storage.git" + source: git + version: "8.1.0" + flutter_secure_storage_linux: + dependency: "direct overridden" + description: + path: flutter_secure_storage_linux + ref: "1355e56cd48404fdbb0848979de72ee317b0c6c9" + resolved-ref: "1355e56cd48404fdbb0848979de72ee317b0c6c9" + url: "https://github.com/mogol/flutter_secure_storage" + source: git + version: "1.2.3" + flutter_secure_storage_macos: + dependency: "direct overridden" + description: + path: flutter_secure_storage_macos + ref: ca897a08677edb443b366352dd7412735e098e7b + resolved-ref: ca897a08677edb443b366352dd7412735e098e7b + url: "https://github.com/cake-tech/flutter_secure_storage.git" + source: git + version: "3.0.0" + flutter_secure_storage_platform_interface: + dependency: "direct overridden" + description: + path: flutter_secure_storage_platform_interface + ref: "3d5466cc3b93196bc9d8287f67f85a45ab6ebd3e" + resolved-ref: "3d5466cc3b93196bc9d8287f67f85a45ab6ebd3e" + url: "https://github.com/mogol/flutter_secure_storage" + source: git + version: "1.1.2" + flutter_secure_storage_web: + dependency: "direct overridden" + description: + path: flutter_secure_storage_web + ref: "62cb9ec42b78fca2a1e64d729423367735134c11" + resolved-ref: "62cb9ec42b78fca2a1e64d729423367735134c11" + url: "https://github.com/mogol/flutter_secure_storage" + source: git + version: "1.2.1" + flutter_secure_storage_windows: + dependency: "direct overridden" + description: + path: flutter_secure_storage_windows + ref: "908d3f3f5fb1ba90927ceebde8b253f413f833d7" + resolved-ref: "908d3f3f5fb1ba90927ceebde8b253f413f833d7" + url: "https://github.com/mogol/flutter_secure_storage" + source: git + version: "3.1.2" + flutter_shaders: + dependency: "direct overridden" + description: + path: "." + ref: e331377d58755fe914a2ce54b0f70ba34898dfdd + resolved-ref: e331377d58755fe914a2ce54b0f70ba34898dfdd + url: "https://github.com/jonahwilliams/flutter_shaders" + source: git + version: "0.1.3" + flutter_slidable: + dependency: "direct main" + description: + path: "." + ref: "7dbeb6667bf410d9a8401f0f8412e14669e7338f" + resolved-ref: "7dbeb6667bf410d9a8401f0f8412e14669e7338f" + url: "https://github.com/letsar/flutter_slidable" + source: git + version: "3.1.2" + flutter_spinkit: + dependency: "direct main" + description: + path: "." + ref: bf8508db798f1e31dea152b9b762f223d90d3449 + resolved-ref: bf8508db798f1e31dea152b9b762f223d90d3449 + url: "https://github.com/jogboms/flutter_spinkit" + source: git + version: "5.2.2" + flutter_svg: + dependency: "direct main" + description: + path: "third_party/packages/flutter_svg" + ref: ddc9430a0080bea73c5511732f396acde1f48fe0 + resolved-ref: ddc9430a0080bea73c5511732f396acde1f48fe0 + url: "https://github.com/flutter/packages" + source: git + version: "2.3.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_bluetooth: + dependency: "direct overridden" + description: + path: "." + ref: "82d12cda1b65efc1d96b53b27b8b5451e34c96ef" + resolved-ref: "82d12cda1b65efc1d96b53b27b8b5451e34c96ef" + url: "https://github.com/jeroen1602/flutter_web_bluetooth" + source: git + version: "1.1.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + path: "." + ref: e875d071da02fe6f3090794d1ac623093c3b7074 + resolved-ref: e875d071da02fe6f3090794d1ac623093c3b7074 + url: "https://github.com/PonnamKarthik/FlutterToast" + source: git + version: "8.2.12" + form_builder_validators: + dependency: "direct overridden" + description: + path: "." + ref: "7a561b8aff3739d80c54c394f9b0cc9c861a01b8" + resolved-ref: "7a561b8aff3739d80c54c394f9b0cc9c861a01b8" + url: "https://github.com/flutter-form-builder-ecosystem/form_builder_validators" + source: git + version: "11.3.0" + freezed_annotation: + dependency: "direct overridden" + description: + path: "packages/freezed_annotation" + ref: "4f7c141c6d2573622b5ea29fe305a8f08db1483b" + resolved-ref: "4f7c141c6d2573622b5ea29fe305a8f08db1483b" + url: "https://github.com/rrousselGit/freezed" + source: git + version: "2.4.4" + frontend_server_client: + dependency: "direct overridden" + description: + path: frontend_server_client + ref: "74e95837adf3d4ea64a003ccc4f8f09704c1d866" + resolved-ref: "74e95837adf3d4ea64a003ccc4f8f09704c1d866" + url: "https://github.com/dart-lang/webdev" + source: git + version: "4.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + gap: + dependency: "direct overridden" + description: + path: "." + ref: b385a5888b1582badf22bbd93283ec22de8a75d7 + resolved-ref: b385a5888b1582badf22bbd93283ec22de8a75d7 + url: "https://github.com/letsar/gap" + source: git + version: "3.0.1" + get_it: + dependency: "direct main" + description: + path: "." + ref: "974c0b367c58fd75e78f0d036147a6963392f975" + resolved-ref: "974c0b367c58fd75e78f0d036147a6963392f975" + url: "https://github.com/fluttercommunity/get_it" + source: git + version: "7.7.0" + glob: + dependency: "direct overridden" + description: + path: "pkgs/glob" + ref: "92114ab8a16eef77be1cd7bad3f5af28b5b1dc63" + resolved-ref: "92114ab8a16eef77be1cd7bad3f5af28b5b1dc63" + url: "https://github.com/dart-lang/tools" + source: git + version: "2.1.3" + go_router: + dependency: "direct overridden" + description: + path: "packages/go_router" + ref: "6d191c59e6f31c0133955c88bede437745659452" + resolved-ref: "6d191c59e6f31c0133955c88bede437745659452" + url: "https://github.com/flutter/packages" + source: git + version: "14.8.1" + google_identity_services_web: + dependency: "direct overridden" + description: + path: "packages/google_identity_services_web" + ref: "41211cf4c9a801f8d8ad527e54062d457a7cfbff" + resolved-ref: "41211cf4c9a801f8d8ad527e54062d457a7cfbff" + url: "https://github.com/flutter/packages" + source: git + version: "0.3.3+1" + googleapis_auth: + dependency: "direct overridden" + description: + path: googleapis_auth + ref: "1631558038c7e30511295512527d8ade2bd64c40" + resolved-ref: "1631558038c7e30511295512527d8ade2bd64c40" + url: "https://github.com/google/googleapis.dart" + source: git + version: "1.6.0" + graphs: + dependency: "direct overridden" + description: + path: "pkgs/graphs" + ref: "55dbd6e09042bc1b935c019d8e70b3f41e6b90ea" + resolved-ref: "55dbd6e09042bc1b935c019d8e70b3f41e6b90ea" + url: "https://github.com/dart-lang/tools" + source: git + version: "2.3.2" + grpc: + dependency: "direct overridden" + description: + path: "." + ref: "4f6fe9b1114aa5bd9d97e5d3b5ae2cb354804a1f" + resolved-ref: "4f6fe9b1114aa5bd9d97e5d3b5ae2cb354804a1f" + url: "https://github.com/grpc/grpc-dart" + source: git + version: "4.0.1" + hashlib: + dependency: "direct main" + description: + path: "." + ref: "07848d0ebc5ff67dac0d2ecb638c3f4cd670d0cf" + resolved-ref: "07848d0ebc5ff67dac0d2ecb638c3f4cd670d0cf" + url: "https://github.com/bitanon/hashlib" + source: git + version: "1.19.2" + hashlib_codecs: + dependency: "direct overridden" + description: + path: "." + ref: b15b231bbced2bb076890f8cfd384f024e9eba71 + resolved-ref: b15b231bbced2bb076890f8cfd384f024e9eba71 + url: "https://github.com/bitanon/hashlib_codecs" + source: git + version: "2.6.0" + hex: + dependency: "direct overridden" + description: + path: "." + ref: "262f0113430f7c5662f0578d86334fce0e008ea7" + resolved-ref: "262f0113430f7c5662f0578d86334fce0e008ea7" + url: "https://github.com/stevenroose/dart-hex" + source: git + version: "0.2.0" + hive: + dependency: "direct main" + description: + path: hive + ref: "470473ffc1ba39f6c90f31ababe0ee63b76b69fe" + resolved-ref: "470473ffc1ba39f6c90f31ababe0ee63b76b69fe" + url: "https://github.com/hivedb/hive" + source: git + version: "2.2.3" + hive_flutter: + dependency: "direct main" + description: + path: hive_flutter + ref: db56a26d5324a19373a35e365c50d808c6e1ce0c + resolved-ref: db56a26d5324a19373a35e365c50d808c6e1ce0c + url: "https://github.com/hivedb/hive" + source: git + version: "1.1.0" + hooks: + dependency: "direct overridden" + description: + path: "pkgs/hooks" + ref: "5e2b3d1171cabe90bae969cd098c85182c1751b3" + resolved-ref: "5e2b3d1171cabe90bae969cd098c85182c1751b3" + url: "https://github.com/dart-lang/native" + source: git + version: "2.0.2" + hooks_riverpod: + dependency: "direct overridden" + description: + path: "packages/hooks_riverpod" + ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + resolved-ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + url: "https://github.com/rrousselGit/riverpod" + source: git + version: "3.3.2" + html: + dependency: "direct overridden" + description: + path: "pkgs/html" + ref: "11f4cf7ee79632be370062dad67b7dd81bc28d55" + resolved-ref: "11f4cf7ee79632be370062dad67b7dd81bc28d55" + url: "https://github.com/dart-lang/tools" + source: git + version: "0.15.6" + http: + dependency: "direct main" + description: + path: "pkgs/http" + ref: "907782f5a792e7a5b0ed92f118c0ad91f3ecde51" + resolved-ref: "907782f5a792e7a5b0ed92f118c0ad91f3ecde51" + url: "https://github.com/dart-lang/http" + source: git + version: "1.6.0" + http2: + dependency: "direct overridden" + description: + path: "pkgs/http2" + ref: "5e2281edd25f9addbf26242a0658d8f2dfa1134b" + resolved-ref: "5e2281edd25f9addbf26242a0658d8f2dfa1134b" + url: "https://github.com/dart-lang/http" + source: git + version: "2.3.1" + http_multi_server: + dependency: "direct overridden" + description: + path: "pkgs/http_multi_server" + ref: c27d6c780bae0207e938f09596c2cf8d9bb4a963 + resolved-ref: c27d6c780bae0207e938f09596c2cf8d9bb4a963 + url: "https://github.com/dart-lang/http" + source: git + version: "3.2.2" + http_parser: + dependency: "direct overridden" + description: + path: "pkgs/http_parser" + ref: "6ecd13a88b82c2fdc8a555f218bafb0ad0370f51" + resolved-ref: "6ecd13a88b82c2fdc8a555f218bafb0ad0370f51" + url: "https://github.com/dart-lang/http" + source: git + version: "4.1.2" + image: + dependency: "direct overridden" + description: + path: "." + ref: a5cc03b65592616bb423254cdea8ce4b093b4a04 + resolved-ref: a5cc03b65592616bb423254cdea8ce4b093b4a04 + url: "https://github.com/brendan-duncan/image" + source: git + version: "4.8.0" + image_picker: + dependency: "direct main" + description: + path: "packages/image_picker/image_picker" + ref: "2900bc94e9912486e3454223df2683a372f4e137" + resolved-ref: "2900bc94e9912486e3454223df2683a372f4e137" + url: "https://github.com/flutter/packages" + source: git + version: "1.2.3" + image_picker_android: + dependency: "direct overridden" + description: + path: "packages/image_picker/image_picker_android" + ref: "5f14a8010690b33f8f71d888dd6a3de665164e21" + resolved-ref: "5f14a8010690b33f8f71d888dd6a3de665164e21" + url: "https://github.com/flutter/packages" + source: git + version: "0.8.13+17" + image_picker_for_web: + dependency: "direct overridden" + description: + path: "packages/image_picker/image_picker_for_web" + ref: "34746bb64150c7bbf319a9eee4164b4a5d733b2e" + resolved-ref: "34746bb64150c7bbf319a9eee4164b4a5d733b2e" + url: "https://github.com/flutter/packages" + source: git + version: "3.1.1" + image_picker_ios: + dependency: "direct overridden" + description: + path: "packages/image_picker/image_picker_ios" + ref: "44a58ab4aab0b78fab2b51e0d093561be0b4964c" + resolved-ref: "44a58ab4aab0b78fab2b51e0d093561be0b4964c" + url: "https://github.com/flutter/packages" + source: git + version: "0.8.13+6" + image_picker_linux: + dependency: "direct overridden" + description: + path: "packages/image_picker/image_picker_linux" + ref: b26262b5034d59c9575b708a031ecfdfe12e5118 + resolved-ref: b26262b5034d59c9575b708a031ecfdfe12e5118 + url: "https://github.com/flutter/packages" + source: git + version: "0.2.2" + image_picker_macos: + dependency: "direct overridden" + description: + path: "packages/image_picker/image_picker_macos" + ref: "7ebd635db5c71197877a48cc31a7edba9a3f067b" + resolved-ref: "7ebd635db5c71197877a48cc31a7edba9a3f067b" + url: "https://github.com/flutter/packages" + source: git + version: "0.2.2+1" + image_picker_platform_interface: + dependency: "direct overridden" + description: + path: "packages/image_picker/image_picker_platform_interface" + ref: "501d8c9bd36577f1af17d799cb69fefd6c4b2f4b" + resolved-ref: "501d8c9bd36577f1af17d799cb69fefd6c4b2f4b" + url: "https://github.com/flutter/packages" + source: git + version: "2.11.1" + image_picker_windows: + dependency: "direct overridden" + description: + path: "packages/image_picker/image_picker_windows" + ref: b26262b5034d59c9575b708a031ecfdfe12e5118 + resolved-ref: b26262b5034d59c9575b708a031ecfdfe12e5118 + url: "https://github.com/flutter/packages" + source: git + version: "0.2.2" + in_app_review: + dependency: "direct main" + description: + path: in_app_review + ref: a08b2fcb98c74f2fa12b5f3c61b588b763430368 + resolved-ref: a08b2fcb98c74f2fa12b5f3c61b588b763430368 + url: "https://github.com/britannio/in_app_review" + source: git + version: "2.0.12" + in_app_review_platform_interface: + dependency: "direct overridden" + description: + path: in_app_review_platform_interface + ref: "54fcef429fc6f9ed50660d23741ef7e38a684a1f" + resolved-ref: "54fcef429fc6f9ed50660d23741ef7e38a684a1f" + url: "https://github.com/britannio/in_app_review" + source: git + version: "2.0.5" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + intl: + dependency: "direct main" + description: + path: "pkgs/intl" + ref: a1dd8e1ff32e5b53bdf38511cd5d7524694af95a + resolved-ref: a1dd8e1ff32e5b53bdf38511cd5d7524694af95a + url: "https://github.com/dart-lang/i18n" + source: git + version: "0.20.2" + io: + dependency: "direct overridden" + description: + path: "pkgs/io" + ref: faf2b86b71e633e956ff1489eb60885b21fa100d + resolved-ref: faf2b86b71e633e956ff1489eb60885b21fa100d + url: "https://github.com/dart-lang/tools" + source: git + version: "1.0.5" + jni: + dependency: "direct overridden" + description: + path: "pkgs/jni" + ref: "3b0c7beded15ef47a3dba4b5c0093cbe195e7aba" + resolved-ref: "3b0c7beded15ef47a3dba4b5c0093cbe195e7aba" + url: "https://github.com/dart-lang/native" + source: git + version: "1.0.3" + jni_flutter: + dependency: "direct overridden" + description: + path: "pkgs/jni_flutter" + ref: "6e3efdc1afa0462b1aff38c087cb50f0e6925cda" + resolved-ref: "6e3efdc1afa0462b1aff38c087cb50f0e6925cda" + url: "https://github.com/dart-lang/native" + source: git + version: "1.0.2" + jni_util: + dependency: "direct overridden" + description: + path: "pkgs/jni_util" + ref: "7990d3a3806fa6c161e2340a95574d3a92d9bca2" + resolved-ref: "7990d3a3806fa6c161e2340a95574d3a92d9bca2" + url: "https://github.com/dart-lang/native" + source: git + version: "1.0.0" + js: + dependency: "direct overridden" + description: + path: "pkg/js" + ref: c70f78e7d682c158c15ca0c26c729b3ccb932284 + resolved-ref: c70f78e7d682c158c15ca0c26c729b3ccb932284 + url: "https://github.com/dart-lang/sdk" + source: git + version: "0.7.2" + json_annotation: + dependency: "direct overridden" + description: + path: json_annotation + ref: "61e7b879b22af58f2f942ccf6c0ae81acd0cb1bc" + resolved-ref: "61e7b879b22af58f2f942ccf6c0ae81acd0cb1bc" + url: "https://github.com/google/json_serializable.dart" + source: git + version: "4.12.0" + json_bigint: + dependency: "direct overridden" + description: + path: "." + ref: "5528e714cb048860a3fd700fd3f2e406828e9cd8" + resolved-ref: "5528e714cb048860a3fd700fd3f2e406828e9cd8" + url: "https://github.com/ozaner/json_bigint" + source: git + version: "3.1.0" + json_rpc_2: + dependency: "direct overridden" + description: + path: "pkgs/json_rpc_2" + ref: "88087ae253cab7ff9eccadb3c8cbf550ee071226" + resolved-ref: "88087ae253cab7ff9eccadb3c8cbf550ee071226" + url: "https://github.com/dart-lang/tools" + source: git + version: "3.0.3" + kepler: + dependency: "direct overridden" + description: + path: "." + ref: e2c671389c18a5149147f598627c946c311e36b8 + resolved-ref: e2c671389c18a5149147f598627c946c311e36b8 + url: "https://github.com/tjcampanella/kepler" + source: git + version: "1.0.3" + keyboard_actions: + dependency: "direct main" + description: + path: "." + ref: e197412c52cd75d8a7c7ac74558610c0f92635e4 + resolved-ref: e197412c52cd75d8a7c7ac74558610c0f92635e4 + url: "https://github.com/diegoveloper/flutter_keyboard_actions" + source: git + version: "4.2.2" + leak_tracker: + dependency: "direct overridden" + description: + path: "pkgs/leak_tracker" + ref: "64bae50ca89528f73d6a440c22b7e3e1713bb7f0" + resolved-ref: "64bae50ca89528f73d6a440c22b7e3e1713bb7f0" + url: "https://github.com/dart-lang/leak_tracker" + source: git + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: "direct overridden" + description: + path: "pkgs/leak_tracker_flutter_testing" + ref: "84d523d8ea34ecf889a3f383e206bc231af31686" + resolved-ref: "84d523d8ea34ecf889a3f383e206bc231af31686" + url: "https://github.com/dart-lang/leak_tracker" + source: git + version: "3.0.10" + leak_tracker_testing: + dependency: "direct overridden" + description: + path: "pkgs/leak_tracker_testing" + ref: "84d523d8ea34ecf889a3f383e206bc231af31686" + resolved-ref: "84d523d8ea34ecf889a3f383e206bc231af31686" + url: "https://github.com/dart-lang/leak_tracker" + source: git + version: "3.0.2" + ledger_bitcoin: + dependency: "direct overridden" + 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_ethereum: + dependency: "direct overridden" + description: + path: "packages/ledger-ethereum" + ref: f4761cd5171d4c1e2e42fd3298261650539fb2db + resolved-ref: f4761cd5171d4c1e2e42fd3298261650539fb2db + url: "https://github.com/cake-tech/ledger-flutter-plus-plugins" + source: git + version: "0.0.5" + ledger_flutter_plus: + dependency: "direct main" + description: + path: "." + ref: eaf49764ad0863e8dec97ad30ff6aea0a1d1bd28 + resolved-ref: eaf49764ad0863e8dec97ad30ff6aea0a1d1bd28 + url: "https://github.com/cake-tech/ledger-flutter-plus" + source: git + version: "1.6.0+1" + ledger_litecoin: + dependency: "direct overridden" + description: + path: "packages/ledger-litecoin" + ref: "75bba8632c529debf30ee2b1858530009fa6440b" + resolved-ref: "75bba8632c529debf30ee2b1858530009fa6440b" + url: "https://github.com/cake-tech/ledger-flutter-plus-plugins" + source: git + version: "0.0.2" + ledger_usb_plus: + dependency: "direct overridden" + description: + path: "." + ref: 40af7c48cf34211ba3cc9e87dd05ed1af8a429a2 + resolved-ref: 40af7c48cf34211ba3cc9e87dd05ed1af8a429a2 + url: "https://github.com/cake-tech/ledger-usb-plus" + source: git + version: "1.0.8" + libcrypto: + dependency: "direct overridden" + description: + path: "." + ref: "98be84e0a2c7b423842d1fbbd2d920ff03180235" + resolved-ref: "98be84e0a2c7b423842d1fbbd2d920ff03180235" + url: "https://github.com/MrCyjaneK/libcrypto" + source: git + version: "0.2.2" + local_auth: + dependency: "direct overridden" + description: + path: "packages/local_auth/local_auth" + ref: db8bfed397145b7c5a1ade3c374a74053649ce12 + resolved-ref: db8bfed397145b7c5a1ade3c374a74053649ce12 + url: "https://github.com/flutter/packages" + source: git + version: "2.3.0" + local_auth_android: + dependency: "direct main" + description: + path: "packages/local_auth/local_auth_android" + ref: "1c0be204c45eea42927eb6005bb45f16a8fffb07" + resolved-ref: "1c0be204c45eea42927eb6005bb45f16a8fffb07" + url: "https://github.com/flutter/packages" + source: git + version: "1.0.56" + local_auth_darwin: + dependency: "direct overridden" + description: + path: "packages/local_auth/local_auth_darwin" + ref: d3e0285a6bf353f4bed9ba01d2b37a68fa63d741 + resolved-ref: d3e0285a6bf353f4bed9ba01d2b37a68fa63d741 + url: "https://github.com/flutter/packages" + source: git + version: "1.6.1" + local_auth_platform_interface: + dependency: "direct overridden" + description: + path: "packages/local_auth/local_auth_platform_interface" + ref: "321a5846838d2bfa5f3dd463e3833b951da0db32" + resolved-ref: "321a5846838d2bfa5f3dd463e3833b951da0db32" + url: "https://github.com/flutter/packages" + source: git + version: "1.1.0" + local_auth_windows: + dependency: "direct overridden" + description: + path: "packages/local_auth/local_auth_windows" + ref: e978e06eb9207e4bd7a56b2139b2906d3150edb5 + resolved-ref: e978e06eb9207e4bd7a56b2139b2906d3150edb5 + url: "https://github.com/flutter/packages" + source: git + version: "1.0.11" + logger: + dependency: "direct overridden" + description: + path: "." + ref: "4c56353a5060f403650f0c728a6438d3db2de669" + resolved-ref: "4c56353a5060f403650f0c728a6438d3db2de669" + url: "https://github.com/SourceHorizon/logger" + source: git + version: "2.7.0" + logging: + dependency: "direct dev" + description: + path: "pkgs/logging" + ref: "8151b9f57fa3fee10421a19ce24470e143c0dee5" + resolved-ref: "8151b9f57fa3fee10421a19ce24470e143c0dee5" + url: "https://github.com/dart-lang/core" + source: git + version: "1.3.0" + lottie: + dependency: "direct main" + description: + path: "." + ref: "1eef993a7a69cd05cfcc4c9eac4f2d89ecfab2d1" + resolved-ref: "1eef993a7a69cd05cfcc4c9eac4f2d89ecfab2d1" + url: "https://github.com/xvrh/lottie-flutter" + source: git + version: "3.3.3" + matcher: + dependency: "direct overridden" + description: + path: "pkgs/matcher" + ref: "45e4ef287d70dad449f13d4f284f9faea2d9188b" + resolved-ref: "45e4ef287d70dad449f13d4f284f9faea2d9188b" + url: "https://github.com/dart-lang/test" + source: git + version: "0.12.19" + material_color_utilities: + dependency: "direct overridden" + description: + path: dart + ref: "5d4397afe1830b09ff99c1cb3cf901038951282a" + resolved-ref: "5d4397afe1830b09ff99c1cb3cf901038951282a" + url: "https://github.com/material-foundation/material-color-utilities" + source: git + version: "0.13.0" + memoize: + dependency: "direct overridden" + description: + path: "." + ref: f541e50b3be0e7b9e83bbd3858d3a25356140570 + resolved-ref: f541e50b3be0e7b9e83bbd3858d3a25356140570 + url: "https://github.com/wrike/memoize_dart" + source: git + version: "3.0.0" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + mime: + dependency: "direct overridden" + description: + path: "pkgs/mime" + ref: "3440b74e430051304b56d4acd71b7ed30ab1855d" + resolved-ref: "3440b74e430051304b56d4acd71b7ed30ab1855d" + url: "https://github.com/dart-lang/tools" + source: git + version: "2.0.0" + mobx: + dependency: "direct main" + description: + path: mobx + ref: d677b8d361301b60577267703371013749b7b7de + resolved-ref: d677b8d361301b60577267703371013749b7b7de + url: "https://github.com/mobxjs/mobx.dart" + source: git + version: "2.6.0" + mobx_codegen: + dependency: "direct dev" + description: + path: mobx_codegen + ref: "39a1f18c2e76a564b5e5358426d335569bc332ec" + resolved-ref: "39a1f18c2e76a564b5e5358426d335569bc332ec" + url: "https://github.com/mobxjs/mobx.dart" + source: git + version: "2.7.7" + mockito: + dependency: "direct overridden" + description: + path: "builder_pkgs/mockito" + ref: f550d53994b429f48f2b86f9c70956bf50d4e0c2 + resolved-ref: f550d53994b429f48f2b86f9c70956bf50d4e0c2 + url: "https://github.com/dart-lang/build" + source: git + version: "5.6.4" + mocktail: + dependency: "direct dev" + description: + path: "packages/mocktail" + ref: "12989138eb6beb3d1cad330ebfd88fef005a4e3e" + resolved-ref: "12989138eb6beb3d1cad330ebfd88fef005a4e3e" + url: "https://github.com/felangel/mocktail" + source: git + version: "1.0.5" + modal_bottom_sheet: + dependency: "direct main" + description: + path: modal_bottom_sheet + ref: b1cca111c53d41b9f07123a8c67cfe06fb1b69bf + resolved-ref: b1cca111c53d41b9f07123a8c67cfe06fb1b69bf + url: "https://github.com/cake-tech/modal_bottom_sheet" + source: git + version: "3.0.0" + monero: + dependency: "direct overridden" + description: + path: "impls/monero.dart" + ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d" + resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d" + url: "https://github.com/mrcyjanek/monero_c.git" + source: git + version: "0.0.0" + msgpack_dart: + dependency: "direct overridden" + description: + path: "." + ref: "2527c0a1e2eabf92a7f5db50983d3ee4ec71ccaa" + resolved-ref: "2527c0a1e2eabf92a7f5db50983d3ee4ec71ccaa" + url: "https://github.com/knopp/msgpack_dart" + source: git + version: "1.0.1" + msix: + dependency: "direct dev" + description: + path: "." + ref: "1ab4df346a92ef4dc7bf02fd857d2975be04d47c" + resolved-ref: "1ab4df346a92ef4dc7bf02fd857d2975be04d47c" + url: "https://github.com/YehudaKremer/msix" + source: git + version: "3.16.9" + mutex: + dependency: "direct overridden" + description: + path: "." + ref: "84ca903a3ac863735e3228c75a212133621f680f" + resolved-ref: "84ca903a3ac863735e3228c75a212133621f680f" + url: "https://github.com/hoylen/dart-mutex" + source: git + version: "3.1.0" + nanodart: + dependency: "direct overridden" + description: + path: "." + ref: "5c1b352fc02d94a34129f3848bedcec441c2b8c7" + resolved-ref: "5c1b352fc02d94a34129f3848bedcec441c2b8c7" + url: "https://github.com/appditto/nanodart" + source: git + version: "2.0.0" + nanoutil: + dependency: "direct overridden" + description: + path: "." + ref: c01a9c552917008d8fbc6b540db657031625b04f + resolved-ref: c01a9c552917008d8fbc6b540db657031625b04f + url: "https://github.com/perishllc/nanoutil.git" + source: git + version: "1.0.3" + native_toolchain_c: + dependency: "direct overridden" + description: + path: "pkgs/native_toolchain_c" + ref: "7dbb51d78534b3c037f3f063448cc45e5ca80a58" + resolved-ref: "7dbb51d78534b3c037f3f063448cc45e5ca80a58" + url: "https://github.com/dart-lang/native" + source: git + version: "0.19.2" + nested: + dependency: "direct overridden" + description: + path: "." + ref: "23dbf54af127301839927831695800edd5cc3dc0" + resolved-ref: "23dbf54af127301839927831695800edd5cc3dc0" + url: "https://github.com/rrousselGit/nested" + source: git + version: "1.0.0" + nm: + dependency: "direct overridden" + description: + path: "." + ref: "6568c7666071f56177e45333c80dc1978ae14483" + resolved-ref: "6568c7666071f56177e45333c80dc1978ae14483" + url: "https://github.com/canonical/nm.dart" + source: git + version: "0.5.0" + node_preamble: + dependency: "direct overridden" + description: + path: "." + ref: ddd4f12ddddf94ad53ec17a742008c23ad666cef + resolved-ref: ddd4f12ddddf94ad53ec17a742008c23ad666cef + url: "https://github.com/mbullington/node_preamble.dart" + source: git + version: "2.0.2" + nostr_tools: + dependency: "direct main" + description: + path: "." + ref: "089d5a2dd751429a040ba10fb24fcbae564053e5" + resolved-ref: "089d5a2dd751429a040ba10fb24fcbae564053e5" + url: "https://github.com/cake-tech/nostr_tools.git" + source: git + version: "1.0.9" + objective_c: + dependency: "direct overridden" + description: + path: "pkgs/objective_c" + ref: "7990d3a3806fa6c161e2340a95574d3a92d9bca2" + resolved-ref: "7990d3a3806fa6c161e2340a95574d3a92d9bca2" + url: "https://github.com/dart-lang/native" + source: git + version: "9.5.0" + on_chain: + dependency: "direct main" + 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: "direct overridden" + description: + path: "pkgs/package_config" + ref: "9c533582195b12ea006dc7188767b5a288b4c5c8" + resolved-ref: "9c533582195b12ea006dc7188767b5a288b4c5c8" + url: "https://github.com/dart-lang/tools" + source: git + version: "2.2.0" + package_info_plus: + dependency: "direct main" + description: + path: "packages/package_info_plus/package_info_plus" + ref: "9f03424b7916b195ec6a4bebe4cc1a310ba40d4a" + resolved-ref: "9f03424b7916b195ec6a4bebe4cc1a310ba40d4a" + url: "https://github.com/fluttercommunity/plus_plugins" + source: git + version: "8.3.1" + package_info_plus_platform_interface: + dependency: "direct overridden" + description: + path: "packages/package_info_plus/package_info_plus_platform_interface" + ref: "9f03424b7916b195ec6a4bebe4cc1a310ba40d4a" + resolved-ref: "9f03424b7916b195ec6a4bebe4cc1a310ba40d4a" + url: "https://github.com/fluttercommunity/plus_plugins" + source: git + version: "3.2.1" + path: + dependency: "direct overridden" + description: + path: "pkgs/path" + ref: "010a343e71238b3ed7fcd55dad5869ecaa40991a" + resolved-ref: "010a343e71238b3ed7fcd55dad5869ecaa40991a" + url: "https://github.com/dart-lang/core" + source: git + version: "1.9.1" + path_drawing: + dependency: "direct overridden" + description: + path: "." + ref: "27ce967273429ce505962d4cf68c17a5b16b5aef" + resolved-ref: "27ce967273429ce505962d4cf68c17a5b16b5aef" + url: "https://github.com/dnfield/flutter_path_drawing" + source: git + version: "1.0.1" + path_parsing: + dependency: "direct overridden" + description: + path: "third_party/packages/path_parsing" + ref: "3c3181c2cfcd0557e12a95ace0e347141f63e384" + resolved-ref: "3c3181c2cfcd0557e12a95ace0e347141f63e384" + url: "https://github.com/flutter/packages" + source: git + version: "1.1.0" + path_provider: + dependency: "direct main" + description: + path: "packages/path_provider/path_provider" + ref: aa964a3ed6d97e4e9778feed85fa9ef1255a0477 + resolved-ref: aa964a3ed6d97e4e9778feed85fa9ef1255a0477 + url: "https://github.com/flutter/packages" + source: git + version: "2.1.6" + path_provider_android: + dependency: "direct main" + description: + path: "packages/path_provider/path_provider_android" + ref: f52df418da6ef2ba666112b4b9e87d9a1c43a0d0 + resolved-ref: f52df418da6ef2ba666112b4b9e87d9a1c43a0d0 + url: "https://github.com/flutter/packages" + source: git + version: "2.3.1" + path_provider_foundation: + dependency: "direct overridden" + description: + path: "packages/path_provider/path_provider_foundation" + ref: "2ada7838737b6ea374c3ef1fffba95bd097eed92" + resolved-ref: "2ada7838737b6ea374c3ef1fffba95bd097eed92" + url: "https://github.com/flutter/packages" + source: git + version: "2.6.0" + path_provider_linux: + dependency: "direct overridden" + description: + path: "packages/path_provider/path_provider_linux" + ref: af136ccab198bc7dfa25f5fa5ace23fdbcdaadc7 + resolved-ref: af136ccab198bc7dfa25f5fa5ace23fdbcdaadc7 + url: "https://github.com/flutter/packages" + source: git + version: "2.2.2" + path_provider_platform_interface: + dependency: "direct overridden" + description: + path: "packages/path_provider/path_provider_platform_interface" + ref: aa964a3ed6d97e4e9778feed85fa9ef1255a0477 + resolved-ref: aa964a3ed6d97e4e9778feed85fa9ef1255a0477 + url: "https://github.com/flutter/packages" + source: git + version: "2.1.3" + path_provider_windows: + dependency: "direct overridden" + description: + path: "packages/path_provider/path_provider_windows" + ref: "47a92dbdea9bc433779c76b404af9c5ab6fa40cc" + resolved-ref: "47a92dbdea9bc433779c76b404af9c5ab6fa40cc" + url: "https://github.com/flutter/packages" + source: git + version: "2.3.0" + pausable_timer: + dependency: "direct overridden" + description: + path: "." + ref: "41e21b6444749a5d8cdb720128c9be66168b83cf" + resolved-ref: "41e21b6444749a5d8cdb720128c9be66168b83cf" + url: "https://github.com/llucax/pausable_timer" + source: git + version: "3.1.0+3" + payjoin_flutter: + dependency: "direct overridden" + description: + path: "." + ref: b28c825b1d63381e8c2b25ef2ccabacbf833ce53 + resolved-ref: b28c825b1d63381e8c2b25ef2ccabacbf833ce53 + url: "https://github.com/konstantinullrich/payjoin-flutter" + source: git + version: "0.23.0" + pedantic: + dependency: "direct dev" + description: + path: "." + ref: bdcb962e3d2bda31a0e6dadb58b670aa633046e9 + resolved-ref: bdcb962e3d2bda31a0e6dadb58b670aa633046e9 + url: "https://github.com/google/pedantic" + source: git + version: "1.11.1" + permission_handler: + dependency: "direct main" + description: + path: permission_handler + ref: "441c53c4e02ac9b6417f758495a4b04618c6e600" + resolved-ref: "441c53c4e02ac9b6417f758495a4b04618c6e600" + url: "https://github.com/baseflow/flutter-permission-handler" + source: git + version: "11.4.0" + permission_handler_android: + dependency: "direct overridden" + description: + path: permission_handler_android + ref: "1dd6dc265a8f7b8b8dd0dd04f7202b8c17e4aa59" + resolved-ref: "1dd6dc265a8f7b8b8dd0dd04f7202b8c17e4aa59" + url: "https://github.com/baseflow/flutter-permission-handler" + source: git + version: "12.1.0" + permission_handler_apple: + dependency: "direct overridden" + description: + path: permission_handler_apple + ref: "5c989b1be9abbbb325424ad96e5be4efdc0987c2" + resolved-ref: "5c989b1be9abbbb325424ad96e5be4efdc0987c2" + url: "https://github.com/baseflow/flutter-permission-handler" + source: git + version: "9.6.1" + permission_handler_html: + dependency: "direct overridden" + description: + path: permission_handler_html + ref: f93a58bb2b993b831f48cf1ec0b3537905643e7e + resolved-ref: f93a58bb2b993b831f48cf1ec0b3537905643e7e + url: "https://github.com/baseflow/flutter-permission-handler" + source: git + version: "0.1.4+1" + permission_handler_platform_interface: + dependency: "direct overridden" + description: + path: permission_handler_platform_interface + ref: b0bdda5faabb912dc6d0b3f330f9d801727db76e + resolved-ref: b0bdda5faabb912dc6d0b3f330f9d801727db76e + url: "https://github.com/baseflow/flutter-permission-handler" + source: git + version: "4.4.0" + permission_handler_windows: + dependency: "direct overridden" + description: + path: permission_handler_windows + ref: "41c2485eb698d055dcf59a373c07dee537b8aa01" + resolved-ref: "41c2485eb698d055dcf59a373c07dee537b8aa01" + url: "https://github.com/baseflow/flutter-permission-handler" + source: git + version: "0.2.2" + petitparser: + dependency: "direct overridden" + description: + path: "." + ref: "3d3c2155df8c427027660f8ca37ddc6e7b894748" + resolved-ref: "3d3c2155df8c427027660f8ca37ddc6e7b894748" + url: "https://github.com/petitparser/dart-petitparser" + source: git + version: "6.1.0" + pinenacl: + dependency: "direct overridden" + description: + path: "." + ref: "30c38f30a34137aa748217cf2d6fc978740d8da8" + resolved-ref: "30c38f30a34137aa748217cf2d6fc978740d8da8" + url: "https://github.com/ilap/pinenacl-dart" + source: git + version: "0.6.0" + platform: + dependency: "direct overridden" + description: + path: "pkgs/platform" + ref: "07aff972869412010a73bbe33af0909bc0536e78" + resolved-ref: "07aff972869412010a73bbe33af0909bc0536e78" + url: "https://github.com/dart-lang/core" + source: git + version: "3.1.6" + plugin_platform_interface: + dependency: "direct overridden" + description: + path: "packages/plugin_platform_interface" + ref: bb97da8ec627466fdb45cdd36e2c0e35dee40e9e + resolved-ref: bb97da8ec627466fdb45cdd36e2c0e35dee40e9e + url: "https://github.com/flutter/packages" + source: git + version: "2.1.8" + pointycastle: + dependency: "direct overridden" + description: + path: "." + ref: c7009dbf7785f4ff865ddb4eefdaed8c18ef3baa + resolved-ref: c7009dbf7785f4ff865ddb4eefdaed8c18ef3baa + url: "https://github.com/bcgit/pc-dart" + source: git + version: "3.9.1" + polyseed: + dependency: "direct main" + description: + path: "." + ref: "1a8280ac2b6f01d202d8bff71527fe1ce498c4ed" + resolved-ref: "1a8280ac2b6f01d202d8bff71527fe1ce498c4ed" + url: "https://github.com/cake-tech/polyseed_dart" + source: git + version: "0.0.7" + pool: + dependency: "direct overridden" + description: + path: "pkgs/pool" + ref: "042b03e8284032088f851172ab7b2aed06da1d72" + resolved-ref: "042b03e8284032088f851172ab7b2aed06da1d72" + url: "https://github.com/dart-lang/tools" + source: git + version: "1.5.2" + posix: + dependency: "direct overridden" + description: + path: "." + ref: "3c544340f3e4ffc64b20e6959ae8229c98638a0a" + resolved-ref: "3c544340f3e4ffc64b20e6959ae8229c98638a0a" + url: "https://github.com/onepub-dev/dart_posix" + source: git + version: "6.5.2" + process: + dependency: "direct overridden" + description: + path: "pkgs/process" + ref: "5e977d6f0698a220279a50538c89a440d56b0c44" + resolved-ref: "5e977d6f0698a220279a50538c89a440d56b0c44" + url: "https://github.com/dart-lang/tools" + source: git + version: "5.0.5" + progressive_blur: + dependency: "direct main" + description: + path: "." + ref: "6ec8d0ccf46b1629a46ab68f31e26df489bac958" + resolved-ref: "6ec8d0ccf46b1629a46ab68f31e26df489bac958" + url: "https://github.com/kekland/progressive_blur" + source: git + version: "0.0.2" + protobuf: + dependency: "direct overridden" + description: + path: protobuf + ref: a852ba4e4b6f319c655fc938864dac8442b7c4ad + resolved-ref: a852ba4e4b6f319c655fc938864dac8442b7c4ad + url: "https://github.com/google/protobuf.dart" + source: git + version: "3.1.0" + provider: + dependency: "direct overridden" + description: + path: "packages/provider" + ref: "558bdcd26ddb2b922bec06e3fa0d91bc59479baf" + resolved-ref: "558bdcd26ddb2b922bec06e3fa0d91bc59479baf" + url: "https://github.com/rrousselGit/provider" + source: git + version: "6.1.5+1" + pub_semver: + dependency: "direct overridden" + description: + path: "pkgs/pub_semver" + ref: d67cd0022095a138c66df94f100e5a129c15a65e + resolved-ref: d67cd0022095a138c66df94f100e5a129c15a65e + url: "https://github.com/dart-lang/tools" + source: git + version: "2.2.0" + pubspec_parse: + dependency: "direct overridden" + description: + path: "pkgs/pubspec_parse" + ref: "070355ee7014c4d37bdc50fa2b4a597f2774f9ca" + resolved-ref: "070355ee7014c4d37bdc50fa2b4a597f2774f9ca" + url: "https://github.com/dart-lang/tools" + source: git + version: "1.5.0" + qr: + dependency: "direct overridden" + description: + path: "." + ref: "792288784e200301b323b1e36852ae60a3ac2431" + resolved-ref: "792288784e200301b323b1e36852ae60a3ac2431" + url: "https://github.com/kevmoo/qr.dart" + source: git + version: "3.0.2" + qr_flutter: + dependency: "direct main" + description: + path: "." + ref: dced28909a82e1906e7c510ae8ca807a1658c898 + resolved-ref: dced28909a82e1906e7c510ae8ca807a1658c898 + url: "https://github.com/cake-tech/qr.flutter.git" + source: git + version: "4.0.1" + quick_actions: + dependency: "direct main" + description: + path: "packages/quick_actions/quick_actions" + ref: "8238e1c5ada8c6a99f7fb6087484b52face33721" + resolved-ref: "8238e1c5ada8c6a99f7fb6087484b52face33721" + url: "https://github.com/flutter/packages" + source: git + version: "1.1.0" + quick_actions_android: + dependency: "direct overridden" + description: + path: "packages/quick_actions/quick_actions_android" + ref: c05ab81dddf0f145c57b43df80903ce17ba84baf + resolved-ref: c05ab81dddf0f145c57b43df80903ce17ba84baf + url: "https://github.com/flutter/packages" + source: git + version: "1.0.30" + quick_actions_ios: + dependency: "direct overridden" + description: + path: "packages/quick_actions/quick_actions_ios" + ref: "7ae082a7f6cd1bc6a219c6ab0adf27a3d8ffdc23" + resolved-ref: "7ae082a7f6cd1bc6a219c6ab0adf27a3d8ffdc23" + url: "https://github.com/flutter/packages" + source: git + version: "1.2.4" + quick_actions_platform_interface: + dependency: "direct overridden" + description: + path: "packages/quick_actions/quick_actions_platform_interface" + ref: "761812665448c7e5a1bd5810aeabfac1ac027038" + resolved-ref: "761812665448c7e5a1bd5810aeabfac1ac027038" + url: "https://github.com/flutter/packages" + source: git + version: "1.1.0" + quiver: + dependency: "direct overridden" + description: + path: "." + ref: "6ec3568dee63ae02e8676e28a6df0157f4d20e84" + resolved-ref: "6ec3568dee63ae02e8676e28a6df0157f4d20e84" + url: "https://github.com/google/quiver-dart" + source: git + version: "3.2.2" + rational: + dependency: "direct overridden" + description: + path: "." + ref: "09b5adc5be7a27c349a36b73d0d616b133ad8730" + resolved-ref: "09b5adc5be7a27c349a36b73d0d616b133ad8730" + url: "https://github.com/a14n/dart-rational" + source: git + version: "2.2.3" + record_use: + dependency: "direct overridden" + description: + path: "pkgs/record_use" + ref: abe17706806e8aa3cdafcbdab02cbbb5d1d2f884 + resolved-ref: abe17706806e8aa3cdafcbdab02cbbb5d1d2f884 + url: "https://github.com/dart-lang/native" + source: git + version: "0.6.0" + reown_core: + dependency: transitive + description: + path: "scripts/reown_flutter/packages/reown_core" + relative: true + source: path + version: "1.2.1" + reown_sign: + dependency: transitive + description: + path: "scripts/reown_flutter/packages/reown_sign" + relative: true + source: path + version: "1.2.0" + reown_walletkit: + dependency: "direct main" + description: + path: "scripts/reown_flutter/packages/reown_walletkit" + relative: true + source: path + version: "1.2.0" + reown_yttrium: + dependency: transitive + description: + path: "scripts/reown_flutter/packages/reown_yttrium" + relative: true + source: path + version: "0.0.1" + rive: + dependency: "direct overridden" + description: + path: "." + ref: "2dbfe918a3d38340f378ab2734b1c97ebcb4ab26" + resolved-ref: "2dbfe918a3d38340f378ab2734b1c97ebcb4ab26" + url: "https://github.com/MrCyjaneK/rive-flutter-no-lfs" + source: git + version: "0.13.20" + rive_common: + dependency: "direct overridden" + description: + path: "." + ref: "9457422fce3f1524437f6a1429200f048931a2fe" + resolved-ref: "9457422fce3f1524437f6a1429200f048931a2fe" + url: "https://github.com/MrCyjaneK/rive_common" + source: git + version: "0.4.15" + riverpod: + dependency: "direct overridden" + description: + path: "packages/riverpod" + ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + resolved-ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + url: "https://github.com/rrousselGit/riverpod" + source: git + version: "3.3.2" + riverpod_annotation: + dependency: "direct overridden" + description: + path: "packages/riverpod_annotation" + ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + resolved-ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + url: "https://github.com/rrousselGit/riverpod" + source: git + version: "4.0.3" + rlz: + dependency: "direct overridden" + description: + path: rust_builder + ref: "36e72b530c274c4a54a6127aadb94886e84d67bf" + resolved-ref: "36e72b530c274c4a54a6127aadb94886e84d67bf" + url: "https://github.com/cake-tech/zkool2.git" + source: git + version: "0.0.1" + rxdart: + dependency: "direct main" + description: + path: "packages/rxdart" + ref: "6852efa646198d8a75fcaee52a5227682f8016e7" + resolved-ref: "6852efa646198d8a75fcaee52a5227682f8016e7" + url: "https://github.com/ReactiveX/rxdart" + source: git + version: "0.28.0" + searchable_listview: + dependency: "direct overridden" + description: + path: "." + ref: "87c203ac2737c3103929e2a2cd0f23becc4c3334" + resolved-ref: "87c203ac2737c3103929e2a2cd0f23becc4c3334" + url: "https://github.com/koukibadr/Searchable-Listview" + source: git + version: "2.19.5" + sec: + dependency: "direct overridden" + description: + path: "." + ref: "1a53c7983d0e8b5e3842eff85cebc27fd474d8f0" + resolved-ref: "1a53c7983d0e8b5e3842eff85cebc27fd474d8f0" + url: "https://github.com/xclud/dart_sec" + source: git + version: "1.1.0" + sensitive_clipboard: + dependency: "direct main" + description: + path: "." + ref: "288c7ee2d63b459bc735f7dc89321b29a1f12fae" + resolved-ref: "288c7ee2d63b459bc735f7dc89321b29a1f12fae" + url: "https://github.com/cake-tech/sensitive_clipboard" + source: git + version: "1.0.0" + sha3: + dependency: "direct overridden" + description: + path: "." + ref: "6d879eb52dec2b5e110d11957f5512ceb0eaa664" + resolved-ref: "6d879eb52dec2b5e110d11957f5512ceb0eaa664" + url: "https://github.com/maoxs2/dart_sha3" + source: git + version: "0.2.1" + share_plus: + dependency: "direct main" + description: + path: "packages/share_plus/share_plus" + ref: "8e5fab7bfb1685f5a56f53020a49b2ff5bece25d" + resolved-ref: "8e5fab7bfb1685f5a56f53020a49b2ff5bece25d" + url: "https://github.com/fluttercommunity/plus_plugins" + source: git + version: "10.1.4" + share_plus_platform_interface: + dependency: "direct overridden" + description: + path: "packages/share_plus/share_plus_platform_interface" + ref: b5d24a0e3927314e50be041c9f5b7da487d69313 + resolved-ref: b5d24a0e3927314e50be041c9f5b7da487d69313 + url: "https://github.com/fluttercommunity/plus_plugins" + source: git + version: "5.0.2" + shared_preferences: + dependency: "direct main" + description: + path: "packages/shared_preferences/shared_preferences" + ref: "064b0b26568728342a550dc876b0a0e0f2fbaa84" + resolved-ref: "064b0b26568728342a550dc876b0a0e0f2fbaa84" + url: "https://github.com/flutter/packages" + source: git + version: "2.5.3" + shared_preferences_android: + dependency: "direct main" + description: + path: "packages/shared_preferences/shared_preferences_android" + ref: "371106fe7d9864a157fc9366f57d0b0e64fab932" + resolved-ref: "371106fe7d9864a157fc9366f57d0b0e64fab932" + url: "https://github.com/flutter/packages" + source: git + version: "2.4.23" + shared_preferences_foundation: + dependency: "direct overridden" + description: + path: "packages/shared_preferences/shared_preferences_foundation" + ref: "18b9cc5f2b0820cb6164f0150958ba76db75c61a" + resolved-ref: "18b9cc5f2b0820cb6164f0150958ba76db75c61a" + url: "https://github.com/flutter/packages" + source: git + version: "2.5.6" + shared_preferences_linux: + dependency: "direct overridden" + description: + path: "packages/shared_preferences/shared_preferences_linux" + ref: cdd6e1368ffdf6a4fc9c0c11b72cfc5388f90f2d + resolved-ref: cdd6e1368ffdf6a4fc9c0c11b72cfc5388f90f2d + url: "https://github.com/flutter/packages" + source: git + version: "2.4.1" + shared_preferences_platform_interface: + dependency: "direct overridden" + description: + path: "packages/shared_preferences/shared_preferences_platform_interface" + ref: "371106fe7d9864a157fc9366f57d0b0e64fab932" + resolved-ref: "371106fe7d9864a157fc9366f57d0b0e64fab932" + url: "https://github.com/flutter/packages" + source: git + version: "2.4.2" + shared_preferences_web: + dependency: "direct overridden" + description: + path: "packages/shared_preferences/shared_preferences_web" + ref: cb4fb13e19756cbbcb523bc33fbf7b7a5923e787 + resolved-ref: cb4fb13e19756cbbcb523bc33fbf7b7a5923e787 + url: "https://github.com/flutter/packages" + source: git + version: "2.4.3" + shared_preferences_windows: + dependency: "direct overridden" + description: + path: "packages/shared_preferences/shared_preferences_windows" + ref: cdd6e1368ffdf6a4fc9c0c11b72cfc5388f90f2d + resolved-ref: cdd6e1368ffdf6a4fc9c0c11b72cfc5388f90f2d + url: "https://github.com/flutter/packages" + source: git + version: "2.4.1" + shelf: + dependency: "direct overridden" + description: + path: "pkgs/shelf" + ref: "2536c15a562cb183dabbc628824a215663830325" + resolved-ref: "2536c15a562cb183dabbc628824a215663830325" + url: "https://github.com/dart-lang/shelf" + source: git + version: "1.4.2" + shelf_packages_handler: + dependency: "direct overridden" + description: + path: "pkgs/shelf_packages_handler" + ref: "25861e55406c1f66cce066b6ed575f420b480e45" + resolved-ref: "25861e55406c1f66cce066b6ed575f420b480e45" + url: "https://github.com/dart-lang/shelf" + source: git + version: "3.0.2" + shelf_static: + dependency: "direct overridden" + description: + path: "pkgs/shelf_static" + ref: d53a8f9a98ccbe69078d397d45c2c6b3e7c243b6 + resolved-ref: d53a8f9a98ccbe69078d397d45c2c6b3e7c243b6 + url: "https://github.com/dart-lang/shelf" + source: git + version: "1.1.3" + shelf_web_socket: + dependency: "direct overridden" + description: + path: "pkgs/shelf_web_socket" + ref: "2a7442f7d6d3e63fdc7b387128619b263dcb7e78" + resolved-ref: "2a7442f7d6d3e63fdc7b387128619b263dcb7e78" + url: "https://github.com/dart-lang/shelf" + source: git + version: "3.0.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + smooth_page_indicator: + dependency: "direct main" + description: + path: "." + ref: "519df3304d58c9d77e91725318076bc3aaa6e852" + resolved-ref: "519df3304d58c9d77e91725318076bc3aaa6e852" + url: "https://github.com/Milad-Akarie/smooth_page_indicator" + source: git + version: "1.2.1" + socks5_proxy: + dependency: "direct main" + description: + path: "." + ref: "27ad7c2efae8d7460325c74b90f660085cbd0685" + resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685" + url: "https://github.com/LacticWhale/socks_dart.git" + source: git + version: "2.1.0" + socks_socket: + dependency: "direct overridden" + description: + path: "." + ref: e6232c53c1595469931ababa878759a067c02e94 + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 + url: "https://github.com/sneurlax/socks_socket" + source: git + version: "1.1.1" + solana: + dependency: "direct main" + description: + path: "packages/solana" + ref: ab60e9d4c7d7271037597154ad2a835812054ed6 + resolved-ref: ab60e9d4c7d7271037597154ad2a835812054ed6 + url: "https://github.com/espresso-cash/espresso-cash-public" + source: git + version: "0.31.2+1" + source_gen: + dependency: "direct overridden" + description: + path: source_gen + ref: "98cbdb6b17cdccabb0fec6e37fd66e2790d05092" + resolved-ref: "98cbdb6b17cdccabb0fec6e37fd66e2790d05092" + url: "https://github.com/dart-lang/source_gen" + source: git + version: "4.2.4" + source_map_stack_trace: + dependency: "direct overridden" + description: + path: "pkgs/source_map_stack_trace" + ref: "56db6f3d085fa4e70b0286b30989654a5db90c94" + resolved-ref: "56db6f3d085fa4e70b0286b30989654a5db90c94" + url: "https://github.com/dart-lang/tools" + source: git + version: "2.1.2" + source_maps: + dependency: "direct overridden" + description: + path: "pkgs/source_maps" + ref: db47a844e03cbd076ac7e5a0f4f46cadcba28da8 + resolved-ref: db47a844e03cbd076ac7e5a0f4f46cadcba28da8 + url: "https://github.com/dart-lang/tools" + source: git + version: "0.10.13" + source_span: + dependency: "direct overridden" + description: + path: "pkgs/source_span" + ref: e501121027c0a9014161ff79cbf519c1813e3153 + resolved-ref: e501121027c0a9014161ff79cbf519c1813e3153 + url: "https://github.com/dart-lang/tools" + source: git + version: "1.10.2" + sp_scanner: + dependency: "direct overridden" + description: + path: "." + ref: "40ed3ce8319744907bef3b25bc6e0af8428c8724" + resolved-ref: "40ed3ce8319744907bef3b25bc6e0af8428c8724" + url: "https://github.com/cake-tech/sp_scanner" + source: git + version: "0.0.1" + sqflite: + dependency: "direct overridden" + description: + path: sqflite + ref: "094cc31b82df7f9ba04f330f13b50e345f777079" + resolved-ref: "094cc31b82df7f9ba04f330f13b50e345f777079" + url: "https://github.com/tekartik/sqflite" + source: git + version: "2.4.2+1" + sqflite_android: + dependency: "direct overridden" + description: + path: sqflite_android + ref: "7e7159b59572e04024258417072428d1cffca1cc" + resolved-ref: "7e7159b59572e04024258417072428d1cffca1cc" + url: "https://github.com/tekartik/sqflite" + source: git + version: "2.4.2+3" + sqflite_common: + dependency: "direct overridden" + description: + path: sqflite_common + ref: "018def1518b3ce9efcb25bbf57809153e9252da7" + resolved-ref: "018def1518b3ce9efcb25bbf57809153e9252da7" + url: "https://github.com/tekartik/sqflite" + source: git + version: "2.5.8" + sqflite_common_ffi: + dependency: "direct overridden" + description: + path: sqflite_common_ffi + ref: "7482da6f456feb715eecdff8a6287bb30d01481f" + resolved-ref: "7482da6f456feb715eecdff8a6287bb30d01481f" + url: "https://github.com/tekartik/sqflite" + source: git + version: "2.4.0+3" + sqflite_darwin: + dependency: "direct overridden" + description: + path: sqflite_darwin + ref: e2d87c863f33e8981dfb589d4784ab14d8f5cc77 + resolved-ref: e2d87c863f33e8981dfb589d4784ab14d8f5cc77 + url: "https://github.com/tekartik/sqflite" + source: git + version: "2.4.2" + sqflite_platform_interface: + dependency: "direct overridden" + description: + path: sqflite_platform_interface + ref: "03e86a1aa7f8ebea7c40d2b02248cadc7630c2f0" + resolved-ref: "03e86a1aa7f8ebea7c40d2b02248cadc7630c2f0" + url: "https://github.com/tekartik/sqflite" + source: git + version: "2.4.0" + sqlite3: + dependency: "direct overridden" + description: + path: sqlite3 + ref: ac40b296e7069c4e83503bcbe4a3b22dfe5431a7 + resolved-ref: ac40b296e7069c4e83503bcbe4a3b22dfe5431a7 + url: "https://github.com/simolus3/sqlite3.dart" + source: git + version: "3.5.1" + sqlite3_flutter_libs: + dependency: "direct overridden" + description: + path: sqlite3_flutter_libs + ref: "808a60becaa3f9fae41e0590b853c3283b5f6afb" + resolved-ref: "808a60becaa3f9fae41e0590b853c3283b5f6afb" + url: "https://github.com/simolus3/sqlite3.dart" + source: git + version: "0.5.40" + stack_trace: + dependency: "direct overridden" + description: + path: "pkgs/stack_trace" + ref: "07648c8269244506d83c15dc8cc50aa53d24bf35" + resolved-ref: "07648c8269244506d83c15dc8cc50aa53d24bf35" + url: "https://github.com/dart-lang/tools" + source: git + version: "1.12.1" + state_notifier: + dependency: "direct overridden" + description: + path: "packages/state_notifier" + ref: "061abfc682881d5da4716b211cd4e7d41805a9ac" + resolved-ref: "061abfc682881d5da4716b211cd4e7d41805a9ac" + url: "https://github.com/rrousselGit/state_notifier" + source: git + version: "1.0.0" + stream_channel: + dependency: "direct overridden" + description: + path: "pkgs/stream_channel" + ref: "5265a85f307ce7be94553378589205df97736a1b" + resolved-ref: "5265a85f307ce7be94553378589205df97736a1b" + url: "https://github.com/dart-lang/tools" + source: git + version: "2.1.4" + stream_transform: + dependency: "direct overridden" + description: + path: "pkgs/stream_transform" + ref: "46cc745458f93bdbd39972a925d7530e57f84f5c" + resolved-ref: "46cc745458f93bdbd39972a925d7530e57f84f5c" + url: "https://github.com/dart-lang/tools" + source: git + version: "2.1.1" + string_scanner: + dependency: "direct overridden" + description: + path: "pkgs/string_scanner" + ref: "3815ff3fd2aee5212586c3fc4d2bcf08584c98f3" + resolved-ref: "3815ff3fd2aee5212586c3fc4d2bcf08584c98f3" + url: "https://github.com/dart-lang/tools" + source: git + version: "1.4.1" + sync_http: + dependency: "direct overridden" + description: + path: "." + ref: "39509d69fd5a9c3da46eab48fcafdf62e6ad4580" + resolved-ref: "39509d69fd5a9c3da46eab48fcafdf62e6ad4580" + url: "https://github.com/google/sync_http.dart" + source: git + version: "0.3.1" + synchronized: + dependency: "direct overridden" + description: + path: synchronized + ref: b38010355b23e3baed85e263ca7f9e222d57b00a + resolved-ref: b38010355b23e3baed85e263ca7f9e222d57b00a + url: "https://github.com/tekartik/synchronized.dart" + source: git + version: "3.4.0+1" + term_glyph: + dependency: "direct overridden" + description: + path: "pkgs/term_glyph" + ref: c90e95b1f2a130b2e951466719b28c3d13b8dab5 + resolved-ref: c90e95b1f2a130b2e951466719b28c3d13b8dab5 + url: "https://github.com/dart-lang/tools" + source: git + version: "1.2.2" + test: + dependency: "direct overridden" + description: + path: "pkgs/test" + ref: "45e4ef287d70dad449f13d4f284f9faea2d9188b" + resolved-ref: "45e4ef287d70dad449f13d4f284f9faea2d9188b" + url: "https://github.com/dart-lang/test" + source: git + version: "1.30.0" + test_api: + dependency: "direct overridden" + description: + path: "pkgs/test_api" + ref: "45e4ef287d70dad449f13d4f284f9faea2d9188b" + resolved-ref: "45e4ef287d70dad449f13d4f284f9faea2d9188b" + url: "https://github.com/dart-lang/test" + source: git + version: "0.7.10" + test_core: + dependency: "direct overridden" + description: + path: "pkgs/test_core" + ref: "45e4ef287d70dad449f13d4f284f9faea2d9188b" + resolved-ref: "45e4ef287d70dad449f13d4f284f9faea2d9188b" + url: "https://github.com/dart-lang/test" + source: git + version: "0.6.16" + timezone: + dependency: "direct overridden" + description: + path: "." + ref: "64db18e450c10247e23ee36546865007b01cf135" + resolved-ref: "64db18e450c10247e23ee36546865007b01cf135" + url: "https://github.com/srawlins/timezone" + source: git + version: "0.10.1" + toastification: + dependency: "direct overridden" + description: + path: "." + ref: "4f1068f5265a0d189aee6881d125e8a35adec74f" + resolved-ref: "4f1068f5265a0d189aee6881d125e8a35adec74f" + url: "https://github.com/payam-zahedi/toastification" + source: git + version: "3.2.0" + torch_dart: + dependency: "direct main" + description: + path: "scripts/torch_dart" + relative: true + source: path + version: "0.0.1" + translator: + dependency: "direct dev" + description: + path: "." + ref: b36571ec11efd838afda010adcc21a4e95302745 + resolved-ref: b36571ec11efd838afda010adcc21a4e95302745 + url: "https://github.com/cake-tech/google-translator.git" + source: git + version: "1.0.0" + 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" + trezor_flutter: + dependency: "direct overridden" + description: + path: trezor-flutter + ref: "7d27e19b7bcdcd6241df35953f9a6ec2df0c7a97" + resolved-ref: "7d27e19b7bcdcd6241df35953f9a6ec2df0c7a97" + url: "https://github.com/cake-tech/trezor-flutter.git" + source: git + version: "0.1.0" + trezor_usb_transport: + dependency: "direct overridden" + description: + path: trezor_usb_transport + ref: "7d27e19b7bcdcd6241df35953f9a6ec2df0c7a97" + resolved-ref: "7d27e19b7bcdcd6241df35953f9a6ec2df0c7a97" + url: "https://github.com/cake-tech/trezor-flutter.git" + source: git + version: "0.0.1" + tuple: + dependency: "direct overridden" + description: + path: "." + ref: "91bcce6e0672c4b071d270aafde5cd86103668dd" + resolved-ref: "91bcce6e0672c4b071d270aafde5cd86103668dd" + url: "https://github.com/google/tuple.dart" + source: git + version: "2.0.2" + typed_data: + dependency: "direct overridden" + description: + path: "pkgs/typed_data" + ref: "5ed932323581a4791672c25fe154c622b535c264" + resolved-ref: "5ed932323581a4791672c25fe154c622b535c264" + url: "https://github.com/dart-lang/core" + source: git + version: "1.4.0" + uni_links: + dependency: "direct main" + description: + path: uni_links + ref: "1989db3f5d625e2fffbad7b85a3b1b8c78c6dfa1" + resolved-ref: "1989db3f5d625e2fffbad7b85a3b1b8c78c6dfa1" + url: "https://github.com/cake-tech/uni_links" + source: git + version: "0.5.1" + uni_links_platform_interface: + dependency: "direct overridden" + description: + path: uni_links_platform_interface + ref: cdd7a217d351a32c418afad18f8ea6893cfed05a + resolved-ref: cdd7a217d351a32c418afad18f8ea6893cfed05a + url: "https://github.com/avioli/uni_links" + source: git + version: "1.0.0" + uni_links_web: + dependency: "direct overridden" + description: + path: uni_links_web + ref: cf9d2b64dc3e890015d1dd6df7b6414123835663 + resolved-ref: cf9d2b64dc3e890015d1dd6df7b6414123835663 + url: "https://github.com/avioli/uni_links" + source: git + version: "0.1.0" + universal_ble: + dependency: "direct overridden" + description: + path: "." + ref: 6735c1bdf7f42c501d51c20564eb957c3a12b981 + resolved-ref: 6735c1bdf7f42c501d51c20564eb957c3a12b981 + url: "https://github.com/cake-tech/universal_ble.git" + source: git + version: "2.0.0" + universal_io: + dependency: "direct overridden" + description: + path: "." + ref: ed92942d149674621e7ae4ac46325e55ecee9368 + resolved-ref: ed92942d149674621e7ae4ac46325e55ecee9368 + url: "https://github.com/dart-io-packages/universal_io" + source: git + version: "2.3.1" + universal_platform: + dependency: "direct overridden" + description: + path: "." + ref: f4fc405630cdd541d78457b0b4521b89456ea068 + resolved-ref: f4fc405630cdd541d78457b0b4521b89456ea068 + url: "https://github.com/gskinnerTeam/flutter-universal-platform" + source: git + version: "1.1.0" + unorm_dart: + dependency: "direct overridden" + description: + path: "." + ref: "3301bdc74e9644c69201db31e0daefb24fd10cd8" + resolved-ref: "3301bdc74e9644c69201db31e0daefb24fd10cd8" + url: "https://github.com/yshrsmz/unorm-dart" + source: git + version: "0.3.2" + 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: "direct main" + description: + path: "packages/url_launcher/url_launcher" + ref: "3fe6a0149acebc9cb8707cf508d13f59fc372986" + resolved-ref: "3fe6a0149acebc9cb8707cf508d13f59fc372986" + url: "https://github.com/flutter/packages" + source: git + version: "6.3.2" + url_launcher_android: + dependency: "direct main" + description: + path: "packages/url_launcher/url_launcher_android" + ref: "7287c7b7f1d51e8842f49df46dbd0af3bd1c1077" + resolved-ref: "7287c7b7f1d51e8842f49df46dbd0af3bd1c1077" + url: "https://github.com/flutter/packages" + source: git + version: "6.3.14" + url_launcher_ios: + dependency: "direct overridden" + description: + path: "packages/url_launcher/url_launcher_ios" + ref: "9cac0573363b7bbe6bf32aca44582fb75ee67521" + resolved-ref: "9cac0573363b7bbe6bf32aca44582fb75ee67521" + url: "https://github.com/flutter/packages" + source: git + version: "6.4.1" + url_launcher_linux: + dependency: "direct main" + description: + path: "packages/url_launcher/url_launcher_linux" + ref: "73d2f3eb966d36a44cbb943ea0e96dda3a2f8da2" + resolved-ref: "73d2f3eb966d36a44cbb943ea0e96dda3a2f8da2" + url: "https://github.com/flutter/packages" + source: git + version: "3.1.1" + url_launcher_macos: + dependency: "direct overridden" + description: + path: "packages/url_launcher/url_launcher_macos" + ref: "18b9cc5f2b0820cb6164f0150958ba76db75c61a" + resolved-ref: "18b9cc5f2b0820cb6164f0150958ba76db75c61a" + url: "https://github.com/flutter/packages" + source: git + version: "3.2.5" + url_launcher_platform_interface: + dependency: "direct overridden" + description: + path: "packages/url_launcher/url_launcher_platform_interface" + ref: ef349bec8ee9d5fa3f69d73aa78ab9bb84ae0aa7 + resolved-ref: ef349bec8ee9d5fa3f69d73aa78ab9bb84ae0aa7 + url: "https://github.com/flutter/packages" + source: git + version: "2.3.2" + url_launcher_web: + dependency: "direct overridden" + description: + path: "packages/url_launcher/url_launcher_web" + ref: "67ec0d36293eb963590e0606c8bede379be4d142" + resolved-ref: "67ec0d36293eb963590e0606c8bede379be4d142" + url: "https://github.com/flutter/packages" + source: git + version: "2.4.3" + url_launcher_windows: + dependency: "direct overridden" + description: + path: "packages/url_launcher/url_launcher_windows" + ref: "18b9cc5f2b0820cb6164f0150958ba76db75c61a" + resolved-ref: "18b9cc5f2b0820cb6164f0150958ba76db75c61a" + url: "https://github.com/flutter/packages" + source: git + version: "3.1.5" + uuid: + dependency: "direct overridden" + description: + path: "." + ref: d602950818e4b11d097d26f5408b461f38248130 + resolved-ref: d602950818e4b11d097d26f5408b461f38248130 + url: "https://github.com/Daegalus/dart-uuid" + source: git + version: "4.6.0" + vector_graphics: + dependency: "direct overridden" + description: + path: "packages/vector_graphics" + ref: caddb39d831fc9e7f9a2cbe5c87d75629adc35ac + resolved-ref: caddb39d831fc9e7f9a2cbe5c87d75629adc35ac + url: "https://github.com/flutter/packages" + source: git + version: "1.2.3" + vector_graphics_codec: + dependency: "direct overridden" + description: + path: "packages/vector_graphics_codec" + ref: "11a9fa8bf6e5a49d02aef0ba5c5a95037a2acbc3" + resolved-ref: "11a9fa8bf6e5a49d02aef0ba5c5a95037a2acbc3" + url: "https://github.com/flutter/packages" + source: git + version: "1.1.13" + vector_graphics_compiler: + dependency: "direct overridden" + description: + path: "packages/vector_graphics_compiler" + ref: "3d05e51b22d99c5362d2f1f7f5b80358dd4e9cb3" + resolved-ref: "3d05e51b22d99c5362d2f1f7f5b80358dd4e9cb3" + url: "https://github.com/flutter/packages" + source: git + version: "1.3.0" + vector_math: + dependency: "direct overridden" + description: + path: "." + ref: "13f185f7e97d559e003f5ac79201da12f9a01049" + resolved-ref: "13f185f7e97d559e003f5ac79201da12f9a01049" + url: "https://github.com/google/vector_math.dart" + source: git + version: "2.2.0" + vm_service: + dependency: "direct overridden" + description: + path: "pkg/vm_service" + ref: c70f78e7d682c158c15ca0c26c729b3ccb932284 + resolved-ref: c70f78e7d682c158c15ca0c26c729b3ccb932284 + url: "https://github.com/dart-lang/sdk" + source: git + version: "15.1.0" + wakelock_plus: + dependency: "direct main" + description: + path: wakelock_plus + ref: e7301f64397c946fac4ee66acdfb545b666f4a43 + resolved-ref: e7301f64397c946fac4ee66acdfb545b666f4a43 + url: "https://github.com/fluttercommunity/wakelock_plus" + source: git + version: "1.3.3" + wakelock_plus_platform_interface: + dependency: "direct overridden" + description: + path: wakelock_plus_platform_interface + ref: "302991238a66dd1f6b1e50b38f58d97d177cd9ab" + resolved-ref: "302991238a66dd1f6b1e50b38f58d97d177cd9ab" + url: "https://github.com/fluttercommunity/wakelock_plus" + source: git + version: "1.6.0" + wallet: + dependency: "direct overridden" + description: + path: "." + ref: aa5ba16f7a8a3a7789ca78330ce3877913f29a83 + resolved-ref: aa5ba16f7a8a3a7789ca78330ce3877913f29a83 + url: "https://github.com/xclud/dart_wallet" + source: git + version: "0.0.13" + watcher: + dependency: "direct overridden" + description: + path: "pkgs/watcher" + ref: "67a0fea10d8402d427aca8aff95cdc3b16004fc2" + resolved-ref: "67a0fea10d8402d427aca8aff95cdc3b16004fc2" + url: "https://github.com/dart-lang/tools" + source: git + version: "1.2.1" + web: + dependency: "direct overridden" + description: + path: web + ref: "222164b5010cb0324d4132666f1d43750ffc6448" + resolved-ref: "222164b5010cb0324d4132666f1d43750ffc6448" + url: "https://github.com/dart-lang/web" + source: git + version: "1.1.1" + web3dart: + dependency: "direct overridden" + description: + path: "." + ref: aa3f932dbf54eda651b7bd01ad00204acf998bd0 + resolved-ref: aa3f932dbf54eda651b7bd01ad00204acf998bd0 + url: "https://github.com/cake-tech/web3dart.git" + source: git + version: "2.7.2" + web_socket: + dependency: "direct overridden" + description: + path: "pkgs/web_socket" + ref: "31da3556357cd9ba9205e20c9299a1d48c149382" + resolved-ref: "31da3556357cd9ba9205e20c9299a1d48c149382" + url: "https://github.com/dart-lang/http" + source: git + version: "1.0.1" + web_socket_channel: + dependency: "direct overridden" + description: + path: "pkgs/web_socket_channel" + ref: "63c477b466f650e8f5505d6d78dc283c2c2f9845" + resolved-ref: "63c477b466f650e8f5505d6d78dc283c2c2f9845" + url: "https://github.com/dart-lang/http" + source: git + version: "3.0.3" + webdriver: + dependency: "direct overridden" + description: + path: "." + ref: e84e9ccbee3e0c38a149b7d964eb7ab6ccc78384 + resolved-ref: e84e9ccbee3e0c38a149b7d964eb7ab6ccc78384 + url: "https://github.com/google/webdriver.dart" + source: git + version: "3.1.0" + webkit_inspection_protocol: + dependency: "direct overridden" + description: + path: "." + ref: "82f0c1c46dfdba5edf7c5fa84456233121dd69e1" + resolved-ref: "82f0c1c46dfdba5edf7c5fa84456233121dd69e1" + url: "https://github.com/google/webkit_inspection_protocol.dart" + source: git + version: "1.2.1" + win32: + dependency: "direct overridden" + description: + path: "packages/win32" + ref: "64b0a07ab7e1e3e7db6fca60c6b121d6cfd73709" + resolved-ref: "64b0a07ab7e1e3e7db6fca60c6b121d6cfd73709" + url: "https://github.com/halildurmus/win32" + source: git + version: "5.15.0" + win32_registry: + dependency: "direct overridden" + description: + path: "." + ref: fd20025f9b6f0ce6937b3e7e4b923e51ae11e40f + resolved-ref: fd20025f9b6f0ce6937b3e7e4b923e51ae11e40f + url: "https://github.com/halildurmus/win32_registry" + source: git + version: "1.1.5" + x25519: + dependency: "direct overridden" + description: + path: "." + ref: "61b636d53e03cd12c9d9f728f8be6821fb6e2581" + resolved-ref: "61b636d53e03cd12c9d9f728f8be6821fb6e2581" + url: "https://github.com/Tougee/curve25519" + source: git + version: "0.1.1" + xdg_directories: + dependency: "direct overridden" + description: + path: "packages/xdg_directories" + ref: b33972233ecb894f2fd3d61a74dd1c300fac10c2 + resolved-ref: b33972233ecb894f2fd3d61a74dd1c300fac10c2 + url: "https://github.com/flutter/packages" + source: git + version: "1.1.0" + xml: + dependency: "direct overridden" + description: + path: "." + ref: "83796f3dd0923590561d9d169d6ee2db46580099" + resolved-ref: "83796f3dd0923590561d9d169d6ee2db46580099" + url: "https://github.com/renggli/dart-xml" + source: git + version: "6.5.0" + yaml: + dependency: "direct main" + description: + path: "pkgs/yaml" + ref: "27f829e3752382beae9deb1e87029f9ed52ef32e" + resolved-ref: "27f829e3752382beae9deb1e87029f9ed52ef32e" + url: "https://github.com/dart-lang/tools" + source: git + version: "3.1.3" + yaml_edit: + dependency: "direct overridden" + description: + path: "pkgs/yaml_edit" + ref: "119a499068a903222fbbefdea18ea59efdd417b9" + resolved-ref: "119a499068a903222fbbefdea18ea59efdd417b9" + url: "https://github.com/dart-lang/tools" + source: git + version: "2.2.4" + zkool: + dependency: "direct overridden" + description: + path: "." + ref: "36e72b530c274c4a54a6127aadb94886e84d67bf" + resolved-ref: "36e72b530c274c4a54a6127aadb94886e84d67bf" + url: "https://github.com/cake-tech/zkool2.git" + source: git + version: "6.24.0" +sdks: + dart: ">=3.9.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec_base.yaml b/pubspec_base.yaml index dc0b0bf62..809c8d081 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -8,8 +8,7 @@ dependencies: qr_flutter: git: url: https://github.com/cake-tech/qr.flutter.git - ref: cake-4.0.2 - version: 4.0.2 + ref: dced28909a82e1906e7c510ae8ca807a1658c898 shared_preferences: 2.5.3 # provider: ^6.0.3 rxdart: ^0.28.0 @@ -86,8 +85,7 @@ dependencies: cake_backup: git: url: https://github.com/cake-tech/cake_backup.git - ref: main - version: 1.0.0 + ref: 3aba867dcab6737f6707782f5db15d71f303db38 flutter_plugin_android_lifecycle: 2.0.23 path_provider_android: ^2.2.1 shared_preferences_android: ^2.4.8 @@ -142,7 +140,7 @@ dependencies: blockchain_utils: git: url: https://github.com/cake-tech/blockchain_utils - ref: cake-update-v2 + ref: 59fdf29d72068e0522a96a8953ed7272833a9f57 flutter_daemon: git: url: https://github.com/MrCyjaneK/flutter_daemon @@ -182,50 +180,69 @@ dev_dependencies: translator: git: url: https://github.com/cake-tech/google-translator.git - version: 1.0.0 + ref: b36571ec11efd838afda010adcc21a4e95302745 msix: ^3.16.9 -dependency_overrides: - bech32: - git: - url: https://github.com/cake-tech/bech32.git - web3dart: - git: - url: https://github.com/cake-tech/web3dart.git - ref: cake - protobuf: ^3.1.0 - bitcoin_base: - git: - url: https://github.com/cake-tech/bitcoin_base - ref: cake-update-v11 - ffi: 2.1.0 - ledger_flutter_plus: - git: - url: https://github.com/vespr-wallet/ledger-flutter-plus - ref: eaf49764ad0863e8dec97ad30ff6aea0a1d1bd28 - socks5_proxy: - git: - url: https://github.com/LacticWhale/socks_dart.git - ref: 27ad7c2efae8d7460325c74b90f660085cbd0685 - web_socket_channel: ^3.0.2 - freezed_annotation: 2.4.4 - intl: 0.20.2 - qr_flutter: - git: - url: https://github.com/cake-tech/qr.flutter.git - ref: cake-4.0.2 - version: 4.0.2 - file_picker: - git: - url: https://github.com/cake-tech/flutter_file_picker.git - ref: c414574bc5ac349450f601e7f72c7b9f31b4d087 - decimal: ^2.3.3 - flutter_rust_bridge: 2.11.1 - flutter_secure_storage_windows: 3.1.2 - universal_ble: - git: - url: https://github.com/cake-tech/universal_ble.git - ref: 6735c1bdf7f42c501d51c20564eb957c3a12b981 +# These are required for the app to build. +# Note that this comment is parsed by scripts/create_overrides.sh, so plz don't break/remove it. +# dependency_overrides: +# bech32: +# git: +# url: https://github.com/cake-tech/bech32.git +# ref: 05755063b593aa6cca0a4820a318e0ce17de6192 +# web3dart: +# git: +# url: https://github.com/cake-tech/web3dart.git +# ref: aa3f932dbf54eda651b7bd01ad00204acf998bd0 +# protobuf: ^3.1.0 +# bitcoin_base: +# git: +# url: https://github.com/cake-tech/bitcoin_base +# ref: 4e41f96f4838139895c65c3f49109d05af5d46aa +# ffi: 2.1.0 +# ledger_flutter_plus: +# git: +# url: https://github.com/cake-tech/ledger-flutter-plus +# ref: eaf49764ad0863e8dec97ad30ff6aea0a1d1bd28 +# ledger_usb_plus: +# git: +# url: https://github.com/cake-tech/ledger-usb-plus +# ref: 40af7c48cf34211ba3cc9e87dd05ed1af8a429a2 +# socks5_proxy: +# git: +# url: https://github.com/LacticWhale/socks_dart.git +# ref: 27ad7c2efae8d7460325c74b90f660085cbd0685 +# web_socket_channel: ^3.0.2 +# freezed_annotation: 2.4.4 +# intl: 0.20.2 +# qr_flutter: +# git: +# url: https://github.com/cake-tech/qr.flutter.git +# ref: dced28909a82e1906e7c510ae8ca807a1658c898 +# file_picker: +# git: +# url: https://github.com/cake-tech/flutter_file_picker.git +# ref: c414574bc5ac349450f601e7f72c7b9f31b4d087 +# decimal: ^2.3.3 +# flutter_rust_bridge: 2.11.1 +# flutter_secure_storage_windows: 3.1.2 +# universal_ble: +# git: +# url: https://github.com/cake-tech/universal_ble.git +# ref: 6735c1bdf7f42c501d51c20564eb957c3a12b981 +# flutter_secure_storage: +# git: +# url: https://github.com/cake-tech/flutter_secure_storage.git +# path: flutter_secure_storage +# ref: ca897a08677edb443b366352dd7412735e098e7b +# blockchain_utils: +# git: +# url: https://github.com/cake-tech/blockchain_utils +# ref: 59fdf29d72068e0522a96a8953ed7272833a9f57 +# cake_backup: +# git: +# url: https://github.com/cake-tech/cake_backup.git +# ref: 3aba867dcab6737f6707782f5db15d71f303db38 flutter_icons: image_path: "assets/images/app_logo.png" diff --git a/pubspec_overrides.yaml b/pubspec_overrides.yaml new file mode 100644 index 000000000..94a1cf6c9 --- /dev/null +++ b/pubspec_overrides.yaml @@ -0,0 +1,1684 @@ +dependency_overrides: + adaptive_number: + git: + url: https://github.com/lemoony/adaptive_number_dart + ref: c3f06de08064acca1b04975abcd4c3977c0b5256 + animate_do: + git: + url: https://github.com/Klerith/animate_do_package + ref: 94ca5c43abd93901fcd97b47102b6e5d37ce67ca + animated_reorderable_list: + git: + url: https://github.com/canopas/animated_reorderable_list + ref: 4a6810d0a912018fb0b193337f46973a478fcc4b + another_flushbar: + git: + url: https://github.com/ideployed/another-flushbar + ref: a334e8e2dfbe3d5e531b63f72164093aa399047b + ansicolor: + git: + url: https://github.com/google/ansicolor-dart + ref: 35e67e6eb2da5e6d726fadfa90ccf437981c1e65 + archive: + git: + url: https://github.com/brendan-duncan/archive + ref: f01d6a340ffe24e0ef46fa682d1b6bcc7b7aef13 + args: + git: + url: https://github.com/dart-lang/core + ref: 61e677100b06d56a1b3731ab1178ebf9102ecb1f + path: ./pkgs/args + asn1lib: + git: + url: https://github.com/wstrange/asn1lib + ref: 1616ff662cd84301e029d1fa936acb8192a2b165 + async: + git: + url: https://github.com/dart-lang/core + ref: 158d80dc6d17c7b967e655e27a859cbc1c6aa71d + path: ./pkgs/async + auto_size_text: + git: + url: https://github.com/leisim/auto_size_text + ref: 2178f0821132636bc4f0dea1bc4d40a889d8249b + awesome_dialog: + git: + url: https://github.com/marcos930807/awesomeDialogs + ref: c7923f15d1d22de5c9077fff0bab6f9cc6463540 + base32: + git: + url: https://github.com/Daegalus/dart-base32 + ref: 6ed989354aee7865ee74f3f1802268dd81bb234d + base58check: + git: + url: https://github.com/dartcoin/base58check + ref: 240913d11885ee80506ff6f51033ddf527106086 + base_x: + git: + url: https://github.com/litaoh/base-x + ref: b434cc7890337af7c04004c681018a2f32689217 + basic_utils: + git: + url: https://github.com/Ephenodrom/Dart-Basic-Utils + ref: 6a5034927857a08f3bdf5a177529e361179f6dab + bbqrdart: + git: + url: https://github.com/mrcyjanek/bbqrdart + ref: e867e3d0156d0b29858100f30adc2625b9dae586 + bech32: + git: + url: https://github.com/cake-tech/bech32.git + ref: 05755063b593aa6cca0a4820a318e0ce17de6192 + bip32: + git: + url: https://github.com/dart-bitcoin/bip32-dart + ref: b5c6a6e891b89f92529799b42af62b8a8af09eaf + bip340: + git: + url: https://github.com/fiatjaf/dart-bip340 + ref: bbab1a01b6b6ab7c18f26294febb3bee38b24798 + bip39: + git: + url: https://github.com/anicdh/bip39 + ref: 3633daa2026b98c523ae9a091322be2903f7a8ab + bitbox: + git: + url: https://github.com/cake-tech/bitbox-flutter.git + ref: 57b78afb85bd2c30d3cdb9f7884f3878a62be442 + bitcoin_base: + git: + url: https://github.com/cake-tech/bitcoin_base + ref: 4e41f96f4838139895c65c3f49109d05af5d46aa + bloc: + git: + url: https://github.com/felangel/bloc + ref: 60892540c1faec3fd01cc8c8fea378a59cf42e3d + path: ./packages/bloc + bloc_concurrency: + git: + url: https://github.com/felangel/bloc + ref: 13dbe0ce078e7efaebb54b37489879daeb57459d + path: ./packages/bloc_concurrency + blockchain_utils: + git: + url: https://github.com/cake-tech/blockchain_utils + ref: 59fdf29d72068e0522a96a8953ed7272833a9f57 + bluez: + git: + url: https://github.com/canonical/bluez.dart + ref: f02727e93b61585ea6c5a6a18ebf84b7374a71d3 + boolean_selector: + git: + url: https://github.com/dart-lang/tools + ref: b1312b18df67b0be3101ca15c03dfd8d7c9383bb + path: ./pkgs/boolean_selector + borsh_annotation: + git: + url: https://github.com/espresso-cash/espresso-cash-public + ref: ab60e9d4c7d7271037597154ad2a835812054ed6 + path: ./packages/borsh_annotation + breez_sdk_spark_flutter: + git: + url: https://github.com/breez/breez-sdk-spark-flutter + ref: e18b6437daaf0572de6aea2439c2ec4d22658bbb + bs58: + git: + url: https://github.com/litaoh/base58 + ref: 637d7b4bef20ac4edb553ef20e40725c4a213736 + bs58check: + git: + url: https://github.com/MrCyjaneK/bs58check + ref: 1216b214e26332ccc4a3de4c9eac87de7fd47b5a + bubble: + git: + url: https://github.com/vi-k/bubble + ref: 6a90afbbb8fee0dccfd7843248c74c1f8460e813 + buffer: + git: + url: https://github.com/isoos/buffer + ref: 96be675b6f2bbca859a13da6c5f551ffd7eebc1c + build: + git: + url: https://github.com/dart-lang/build + ref: 565856b394c26a0d4c8cda88b69b6dcfaa2acd1f + path: ./build + build_cli_annotations: + git: + url: https://github.com/kevmoo/build_cli + ref: d01ba0ba11a73b4e541ff65508ae55842a8f887f + path: ./build_cli_annotations + build_config: + git: + url: https://github.com/dart-lang/build + ref: 7d6c879a01d80056b3eae52f7fab2237103a7fe7 + path: ./build_config + build_daemon: + git: + url: https://github.com/dart-lang/build + ref: f20f2a24e0e1259f6ee53c6828d7c396d5b23bbf + path: ./build_daemon + build_runner: + git: + url: https://github.com/dart-lang/build + ref: 565856b394c26a0d4c8cda88b69b6dcfaa2acd1f + path: ./build_runner + built_collection: + git: + url: https://github.com/google/built_collection.dart + ref: 8153cc41299a28e4426b22959f87dca0f7f8cd19 + built_value: + git: + url: https://github.com/google/built_value.dart + ref: b66790e815350e8c569bfe723d5263925df5a46d + path: ./built_value + cake_backup: + git: + url: https://github.com/cake-tech/cake_backup.git + ref: 3aba867dcab6737f6707782f5db15d71f303db38 + characters: + git: + url: https://github.com/dart-lang/core + ref: b59ecf4ceebe6153e1c0166b7c9a7fdd9458a89d + path: ./pkgs/characters + checked_yaml: + git: + url: https://github.com/google/json_serializable.dart + ref: d30c2fdb0598d548c25705931531842957623fdd + path: ./checked_yaml + cli_config: + git: + url: https://github.com/dart-lang/tools + ref: 378790dd8cdaecd8cb48283de445f7cf80419cc0 + path: ./pkgs/cli_config + cli_util: + git: + url: https://github.com/dart-lang/tools + ref: d7a7e2ebba2fdc25e78000a1af08508b60beb7fc + path: ./pkgs/cli_util + clock: + git: + url: https://github.com/dart-lang/tools + ref: 04f7512ab6d7d554e33abd124a41e2aeec97dcbd + path: ./pkgs/clock + code_assets: + git: + url: https://github.com/dart-lang/native + ref: fca756b953bc94f109039dd553f0bc18de620338 + path: ./pkgs/code_assets + code_builder: + git: + url: https://github.com/dart-lang/tools + ref: 125b9a9a5556fa88ecec26f649e1cddb1623aa2f + path: ./pkgs/code_builder + collection: + git: + url: https://github.com/dart-lang/core + ref: dec28c1d477cd191e2af868579817b926b07d9f5 + path: ./pkgs/collection + connectivity_plus: + git: + url: https://github.com/fluttercommunity/plus_plugins + ref: 9f03424b7916b195ec6a4bebe4cc1a310ba40d4a + path: ./packages/connectivity_plus/connectivity_plus + connectivity_plus_platform_interface: + git: + url: https://github.com/fluttercommunity/plus_plugins + ref: c46ab89942b2be24aedf79555f247c566d99777f + path: ./packages/connectivity_plus/connectivity_plus_platform_interface + console: + git: + url: https://github.com/DirectMyFile/console.dart + ref: f391b6d289490e1735566c63fe539d1c3fc40818 + convert: + git: + url: https://github.com/dart-lang/core + ref: 16f396fcf87da1db940187db3564b3a490015678 + path: ./pkgs/convert + coverage: + git: + url: https://github.com/dart-lang/tools + ref: 176ad7aea84d9fccc5c17795568ea2165a0414f9 + path: ./pkgs/coverage + cross_file: + git: + url: https://github.com/flutter/packages + ref: b967797f07f1e4fc4fb264f5c8e5181b1385d9d9 + path: ./packages/cross_file + crypto: + git: + url: https://github.com/dart-lang/core + ref: e6c3810cdbbd6b483973f4685e950644114b495e + path: ./pkgs/crypto + cryptography: + git: + url: https://github.com/dint-dev/cryptography + ref: 87f42fad6f7f120feb8e47854164016ceac3dfd0 + path: ./cryptography + csslib: + git: + url: https://github.com/dart-lang/tools + ref: 91a840b6bc02e5e4b57fb55a047267923b894c89 + path: ./pkgs/csslib + cupertino_icons: + git: + url: https://github.com/flutter/packages + ref: f330175dbf168a7bf94a127c492e025b4cc0bfba + path: ./third_party/packages/cupertino_icons + dart_style: + git: + url: https://github.com/dart-lang/dart_style + ref: a0f21e86a7a0ba52f11f46e3ed2ad1144616b512 + dart_varuint_bitcoin: + git: + url: https://github.com/dart-bitcoin-lib/dart-varuint-bitcoin + ref: 51f9656d5937659c9f034cb0910dd0144459f137 + data_table_2: + git: + url: https://github.com/maxim-saplin/data_table_2 + ref: 4db30aa145e4e831e5527708cf77d9ed4d8e9700 + dbus: + git: + url: https://github.com/canonical/dbus.dart + ref: 2db8509d7f7081025e7246511e823287fdd09abc + decimal: + git: + url: https://github.com/a14n/dart-decimal + ref: bc9771127e4c26f068fc9b016269f0ddabe9b475 + device_display_brightness: + git: + url: https://github.com/MrCyjaneK/device_display_brightness.git + ref: 4cac18c446ce686f3d75b1565badbd7da439bbd9 + device_info_plus: + git: + url: https://github.com/fluttercommunity/plus_plugins + ref: 83f86a357da31c7e9c47ee668fe3142bafea9c91 + path: ./packages/device_info_plus/device_info_plus + device_info_plus_platform_interface: + git: + url: https://github.com/fluttercommunity/plus_plugins + ref: 1b37ba220c99b16693991042c3fcc69eae98864a + path: ./packages/device_info_plus/device_info_plus_platform_interface + devicelocale: + git: + url: https://github.com/magnatronus/flutter-devicelocale + ref: 3ed4bcc443a40da200af162f4b97d63d7b00d291 + dio: + git: + url: https://github.com/cfug/dio + ref: ef9dbb860c085a8e81ecd36d5bcf29d5672947e1 + path: ./dio + dio_web_adapter: + git: + url: https://github.com/cfug/dio + ref: f72e83c8e832e81169f621b13c9e39aeaf9286b8 + path: ./plugins/web_adapter + dnssec_proof: + git: + url: https://github.com/MrCyjaneK/dnssec_proof.git + ref: b48a9defddce036048bae02e2069ebcbd6824afc + dotenv: + git: + url: https://github.com/mockturtl/dotenv + ref: 08216384e8a03b0aa55e0fcb81f4d03a52f7ea76 + dotted_border: + git: + url: https://github.com/ajilo297/Flutter-Dotted-Border + ref: a0168f4a4d410087afb378a06deb058cb92a9fb1 + easy_debounce: + git: + url: https://github.com/magnuswikhog/easy_debounce + ref: ed3f2aff0f080aa21cecd86e3a7c108340a9f17d + easy_stepper: + git: + url: https://github.com/ma7moud3osman/easy_stepper + ref: cec4390aef9e5ff9fe064a44ed06b4f2c6dae1d2 + ed25519_edwards: + git: + url: https://github.com/Tougee/ed25519 + ref: 944daea677c4d7f3abea608f55b34aec93bb79fb + ed25519_hd_key: + git: + url: https://github.com/alepop/dart-ed25519-hd-key + ref: be3939527511af23dbfd97b5abde56215a5ce60d + eip1559: + git: + url: https://github.com/xclud/dart_eip1559 + ref: d1888bf05e99cca1638e7fcc10d7f82d21857f9a + eip55: + git: + url: https://github.com/xclud/dart_eip55 + ref: 1dd7172b6d8f7e21f11378a4bf3489a8d1ff890f + encrypt: + git: + url: https://github.com/leocavalcante/encrypt + ref: 8581b81c060cde1c531e35a6eaa4b7324e9ab813 + ens_dart: + git: + url: https://github.com/cake-tech/ens_dart.git + ref: 9fa09b9db69b8645d5d50a844652aa570451d101 + equatable: + git: + url: https://github.com/felangel/equatable + ref: f98a58960545ba72b51d0eacf746af393a0c6b24 + erc20: + git: + url: https://github.com/xclud/dart_erc20 + ref: 759c4363d1dc9d6a3c2604ceb4261b5bcdfc68b1 + eth_sig_util: + git: + url: https://github.com/wakumo/eth-sig-util + ref: 6acd66a126f470b5541f089fdd1c079d35a59c9a + event: + git: + url: https://github.com/aryehof/dart-event + ref: 93e1c474cf736481a0ef07c15a8c8bbdc5f21b60 + fake_async: + git: + url: https://github.com/dart-lang/test + ref: 82417ab30b95ff471ded4bf6a3eea005ca97774f + path: ./pkgs/fake_async + fast_base58: + git: + url: https://github.com/maoxs2/dart_fast_base58 + ref: 46955c19e499ce5c15755f6f573479d5f5218a45 + fast_scanner: + git: + url: https://github.com/MrCyjaneK/fast_scanner + ref: 69b3276b090fa6ac01b4483ca3adca93a8e615be + ffi: + git: + url: https://github.com/dart-lang/native + ref: 6bd0935f29c7294ebb9aab21c06b47b513def933 + path: ./pkgs/ffi + ffigen: + git: + url: https://github.com/dart-lang/native + ref: c837526da8808501b53255caea0364eaa2c84afb + path: ./pkgs/ffigen + file: + git: + url: https://github.com/dart-lang/tools + ref: 3f7a46606496f826c2f60586ab71c2b7a9bfbf15 + path: ./pkgs/file + file_picker: + git: + url: https://github.com/cake-tech/flutter_file_picker.git + ref: c414574bc5ac349450f601e7f72c7b9f31b4d087 + file_selector_linux: + git: + url: https://github.com/flutter/packages + ref: e67b6be3f57927f6831ec41afd3444adb31be3d3 + path: ./packages/file_selector/file_selector_linux + file_selector_macos: + git: + url: https://github.com/flutter/packages + ref: e67b6be3f57927f6831ec41afd3444adb31be3d3 + path: ./packages/file_selector/file_selector_macos + file_selector_platform_interface: + git: + url: https://github.com/flutter/packages + ref: 29211e8b56107f477d4521dd30e8ad713007860e + path: ./packages/file_selector/file_selector_platform_interface + file_selector_windows: + git: + url: https://github.com/flutter/packages + ref: 18b9cc5f2b0820cb6164f0150958ba76db75c61a + path: ./packages/file_selector/file_selector_windows + fixed: + git: + url: https://github.com/onepub-dev/fixed + ref: 1bdd715b95d8ed9c7fdffa6735bdcf2bf5ff8e65 + fixnum: + git: + url: https://github.com/dart-lang/core + ref: 17d1b2cd13991f3cf844886db1c7ad18910a8908 + path: ./pkgs/fixnum + fixnum_nanodart: + git: + url: https://github.com/MrCyjaneK/fixnum_nanodart + ref: 332e879371f175b52f688383d6ff795609aece85 + fl_chart: + git: + url: https://github.com/imaNNeo/fl_chart + ref: be14b9722b7f18310c869c930562b7871b0165ed + flat_buffers: + git: + url: https://github.com/google/flatbuffers + ref: 187240970746d00bbd26b0f5873ed54d2477f9f3 + path: ./dart + flex_color_scheme: + git: + url: https://github.com/rydmike/flex_color_scheme + ref: c0e810b1eba7cd2b2be1f5c6130b86672858db3d + flex_seed_scheme: + git: + url: https://github.com/rydmike/flex_seed_scheme + ref: aa7be701ad58dc8e61637373db2bef0f28d2606e + flutter_bloc: + git: + url: https://github.com/felangel/bloc + ref: 59098d33f3eed63001d3170295d2bfa76fa84351 + path: ./packages/flutter_bloc + flutter_daemon: + git: + url: https://github.com/MrCyjaneK/flutter_daemon + ref: c24ee99f2f3070ea02d8108bbdd7727d73f7e5f1 + flutter_form_builder: + git: + url: https://github.com/flutter-form-builder-ecosystem/flutter_form_builder + ref: c55646b1d7f995752dbf5a9bd63da7592d342ffb + flutter_hooks: + git: + url: https://github.com/rrousselGit/flutter_hooks + ref: 9a2245f922bbd0ec397562fc7dc4b22b98c9199e + path: ./packages/flutter_hooks + flutter_inappwebview: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview + ref: f67ae1f34868c7660c16a2473f53a7a7bfb6f784 + path: ./flutter_inappwebview + flutter_inappwebview_android: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview + ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + path: ./flutter_inappwebview_android + flutter_inappwebview_internal_annotations: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview + ref: 5be1ade739ab2a385e94a1bd5936c5a2000d52a9 + path: ./dev_packages/flutter_inappwebview_internal_annotations + flutter_inappwebview_ios: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview + ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + path: ./flutter_inappwebview_ios + flutter_inappwebview_macos: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview + ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + path: ./flutter_inappwebview_macos + flutter_inappwebview_platform_interface: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview + ref: 60f1012e804f785421878ba1ee34403458e6baf2 + path: ./flutter_inappwebview_platform_interface + flutter_inappwebview_web: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview + ref: a17ca9d0b8d8d98b53c6759768f1df4d0a058984 + path: ./flutter_inappwebview_web + flutter_inappwebview_windows: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview + ref: 952aa783912c9b0fd98d01e3c2c707d97512cd63 + path: ./flutter_inappwebview_windows + flutter_local_authentication: + git: + url: https://github.com/cake-tech/flutter_local_authentication + ref: 75c8681ebef62398a87c8ae0cccb7cfddffa9734 + flutter_local_notifications: + git: + url: https://github.com/MaikuB/flutter_local_notifications + ref: 6c7378ddb1ed7f885e1e80caa3df3bcfb0fe8707 + path: ./flutter_local_notifications + flutter_local_notifications_linux: + git: + url: https://github.com/MaikuB/flutter_local_notifications + ref: 314b432f98bcaef768468e5755317e10213a59bf + path: ./flutter_local_notifications_linux + flutter_local_notifications_platform_interface: + git: + url: https://github.com/MaikuB/flutter_local_notifications + ref: 816a1ddbf733bba3fb8d87ac3a9c2673ec15881b + path: ./flutter_local_notifications_platform_interface + flutter_local_notifications_windows: + git: + url: https://github.com/MaikuB/flutter_local_notifications + ref: ecd66b1515d17e327a62ca4ff8e94f925e97d688 + path: ./flutter_local_notifications_windows + flutter_mailer: + git: + url: https://github.com/taljacobson/flutter_mailer + ref: 9c4ed111a9151a2bbfb9afe2c18a37599c6f84f3 + flutter_mobx: + git: + url: https://github.com/mobxjs/mobx.dart + ref: 0cadcd03551baaae57788b7288e1245e6408d5cf + path: ./flutter_mobx + flutter_native_splash: + git: + url: https://github.com/jonbhanson/flutter_native_splash + ref: 8c65117f0a4adc04f93deeb595a699a0d6dac559 + flutter_plugin_android_lifecycle: + git: + url: https://github.com/flutter/packages + ref: 4afc383a6db56cb969af5d8ad02a1a0220758b66 + path: ./packages/flutter_plugin_android_lifecycle + flutter_riverpod: + git: + url: https://github.com/rrousselGit/riverpod + ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + path: ./packages/flutter_riverpod + flutter_rust_bridge: + git: + url: https://github.com/fzyzcjy/flutter_rust_bridge + ref: f19087cd0cac019b82d52cfa5153ce81b1b6e902 + path: ./frb_dart + flutter_secure_storage: + git: + url: https://github.com/cake-tech/flutter_secure_storage.git + path: flutter_secure_storage + ref: ca897a08677edb443b366352dd7412735e098e7b + flutter_secure_storage_linux: + git: + url: https://github.com/mogol/flutter_secure_storage + ref: 1355e56cd48404fdbb0848979de72ee317b0c6c9 + path: ./flutter_secure_storage_linux + flutter_secure_storage_macos: + git: + url: https://github.com/cake-tech/flutter_secure_storage.git + ref: ca897a08677edb443b366352dd7412735e098e7b + path: ./flutter_secure_storage_macos + flutter_secure_storage_platform_interface: + git: + url: https://github.com/mogol/flutter_secure_storage + ref: 3d5466cc3b93196bc9d8287f67f85a45ab6ebd3e + path: ./flutter_secure_storage_platform_interface + flutter_secure_storage_web: + git: + url: https://github.com/mogol/flutter_secure_storage + ref: 62cb9ec42b78fca2a1e64d729423367735134c11 + path: ./flutter_secure_storage_web + flutter_secure_storage_windows: + git: + url: https://github.com/mogol/flutter_secure_storage + ref: 908d3f3f5fb1ba90927ceebde8b253f413f833d7 + path: ./flutter_secure_storage_windows + flutter_shaders: + git: + url: https://github.com/jonahwilliams/flutter_shaders + ref: e331377d58755fe914a2ce54b0f70ba34898dfdd + flutter_slidable: + git: + url: https://github.com/letsar/flutter_slidable + ref: 7dbeb6667bf410d9a8401f0f8412e14669e7338f + flutter_spinkit: + git: + url: https://github.com/jogboms/flutter_spinkit + ref: bf8508db798f1e31dea152b9b762f223d90d3449 + flutter_svg: + git: + url: https://github.com/flutter/packages + ref: ddc9430a0080bea73c5511732f396acde1f48fe0 + path: ./third_party/packages/flutter_svg + flutter_web_bluetooth: + git: + url: https://github.com/jeroen1602/flutter_web_bluetooth + ref: 82d12cda1b65efc1d96b53b27b8b5451e34c96ef + fluttertoast: + git: + url: https://github.com/PonnamKarthik/FlutterToast + ref: e875d071da02fe6f3090794d1ac623093c3b7074 + form_builder_validators: + git: + url: https://github.com/flutter-form-builder-ecosystem/form_builder_validators + ref: 7a561b8aff3739d80c54c394f9b0cc9c861a01b8 + freezed_annotation: + git: + url: https://github.com/rrousselGit/freezed + ref: 4f7c141c6d2573622b5ea29fe305a8f08db1483b + path: ./packages/freezed_annotation + frontend_server_client: + git: + url: https://github.com/dart-lang/webdev + ref: 74e95837adf3d4ea64a003ccc4f8f09704c1d866 + path: ./frontend_server_client + gap: + git: + url: https://github.com/letsar/gap + ref: b385a5888b1582badf22bbd93283ec22de8a75d7 + get_it: + git: + url: https://github.com/fluttercommunity/get_it + ref: 974c0b367c58fd75e78f0d036147a6963392f975 + glob: + git: + url: https://github.com/dart-lang/tools + ref: 92114ab8a16eef77be1cd7bad3f5af28b5b1dc63 + path: ./pkgs/glob + go_router: + git: + url: https://github.com/flutter/packages + ref: 6d191c59e6f31c0133955c88bede437745659452 + path: ./packages/go_router + google_identity_services_web: + git: + url: https://github.com/flutter/packages + ref: 41211cf4c9a801f8d8ad527e54062d457a7cfbff + path: ./packages/google_identity_services_web + googleapis_auth: + git: + url: https://github.com/google/googleapis.dart + ref: 1631558038c7e30511295512527d8ade2bd64c40 + path: ./googleapis_auth + graphs: + git: + url: https://github.com/dart-lang/tools + ref: 55dbd6e09042bc1b935c019d8e70b3f41e6b90ea + path: ./pkgs/graphs + grpc: + git: + url: https://github.com/grpc/grpc-dart + ref: 4f6fe9b1114aa5bd9d97e5d3b5ae2cb354804a1f + hashlib: + git: + url: https://github.com/bitanon/hashlib + ref: 07848d0ebc5ff67dac0d2ecb638c3f4cd670d0cf + hashlib_codecs: + git: + url: https://github.com/bitanon/hashlib_codecs + ref: b15b231bbced2bb076890f8cfd384f024e9eba71 + hex: + git: + url: https://github.com/stevenroose/dart-hex + ref: 262f0113430f7c5662f0578d86334fce0e008ea7 + hive: + git: + url: https://github.com/hivedb/hive + ref: 470473ffc1ba39f6c90f31ababe0ee63b76b69fe + path: ./hive + hive_flutter: + git: + url: https://github.com/hivedb/hive + ref: db56a26d5324a19373a35e365c50d808c6e1ce0c + path: ./hive_flutter + hooks: + git: + url: https://github.com/dart-lang/native + ref: 5e2b3d1171cabe90bae969cd098c85182c1751b3 + path: ./pkgs/hooks + hooks_riverpod: + git: + url: https://github.com/rrousselGit/riverpod + ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + path: ./packages/hooks_riverpod + html: + git: + url: https://github.com/dart-lang/tools + ref: 11f4cf7ee79632be370062dad67b7dd81bc28d55 + path: ./pkgs/html + http: + git: + url: https://github.com/dart-lang/http + ref: 907782f5a792e7a5b0ed92f118c0ad91f3ecde51 + path: ./pkgs/http + http2: + git: + url: https://github.com/dart-lang/http + ref: 5e2281edd25f9addbf26242a0658d8f2dfa1134b + path: ./pkgs/http2 + http_multi_server: + git: + url: https://github.com/dart-lang/http + ref: c27d6c780bae0207e938f09596c2cf8d9bb4a963 + path: ./pkgs/http_multi_server + http_parser: + git: + url: https://github.com/dart-lang/http + ref: 6ecd13a88b82c2fdc8a555f218bafb0ad0370f51 + path: ./pkgs/http_parser + image: + git: + url: https://github.com/brendan-duncan/image + ref: a5cc03b65592616bb423254cdea8ce4b093b4a04 + image_picker: + git: + url: https://github.com/flutter/packages + ref: 2900bc94e9912486e3454223df2683a372f4e137 + path: ./packages/image_picker/image_picker + image_picker_android: + git: + url: https://github.com/flutter/packages + ref: 5f14a8010690b33f8f71d888dd6a3de665164e21 + path: ./packages/image_picker/image_picker_android + image_picker_for_web: + git: + url: https://github.com/flutter/packages + ref: 34746bb64150c7bbf319a9eee4164b4a5d733b2e + path: ./packages/image_picker/image_picker_for_web + image_picker_ios: + git: + url: https://github.com/flutter/packages + ref: 44a58ab4aab0b78fab2b51e0d093561be0b4964c + path: ./packages/image_picker/image_picker_ios + image_picker_linux: + git: + url: https://github.com/flutter/packages + ref: b26262b5034d59c9575b708a031ecfdfe12e5118 + path: ./packages/image_picker/image_picker_linux + image_picker_macos: + git: + url: https://github.com/flutter/packages + ref: 7ebd635db5c71197877a48cc31a7edba9a3f067b + path: ./packages/image_picker/image_picker_macos + image_picker_platform_interface: + git: + url: https://github.com/flutter/packages + ref: 501d8c9bd36577f1af17d799cb69fefd6c4b2f4b + path: ./packages/image_picker/image_picker_platform_interface + image_picker_windows: + git: + url: https://github.com/flutter/packages + ref: b26262b5034d59c9575b708a031ecfdfe12e5118 + path: ./packages/image_picker/image_picker_windows + in_app_review: + git: + url: https://github.com/britannio/in_app_review + ref: a08b2fcb98c74f2fa12b5f3c61b588b763430368 + path: ./in_app_review + in_app_review_platform_interface: + git: + url: https://github.com/britannio/in_app_review + ref: 54fcef429fc6f9ed50660d23741ef7e38a684a1f + path: ./in_app_review_platform_interface + intl: + git: + url: https://github.com/dart-lang/i18n + ref: a1dd8e1ff32e5b53bdf38511cd5d7524694af95a + path: ./pkgs/intl + io: + git: + url: https://github.com/dart-lang/tools + ref: faf2b86b71e633e956ff1489eb60885b21fa100d + path: ./pkgs/io + jni: + git: + url: https://github.com/dart-lang/native + ref: 3b0c7beded15ef47a3dba4b5c0093cbe195e7aba + path: ./pkgs/jni + jni_flutter: + git: + url: https://github.com/dart-lang/native + ref: 6e3efdc1afa0462b1aff38c087cb50f0e6925cda + path: ./pkgs/jni_flutter + jni_util: + git: + url: https://github.com/dart-lang/native + ref: 7990d3a3806fa6c161e2340a95574d3a92d9bca2 + path: ./pkgs/jni_util + js: + git: + url: https://github.com/dart-lang/sdk + ref: c70f78e7d682c158c15ca0c26c729b3ccb932284 + path: ./pkg/js + json_annotation: + git: + url: https://github.com/google/json_serializable.dart + ref: 61e7b879b22af58f2f942ccf6c0ae81acd0cb1bc + path: ./json_annotation + json_bigint: + git: + url: https://github.com/ozaner/json_bigint + ref: 5528e714cb048860a3fd700fd3f2e406828e9cd8 + json_rpc_2: + git: + url: https://github.com/dart-lang/tools + ref: 88087ae253cab7ff9eccadb3c8cbf550ee071226 + path: ./pkgs/json_rpc_2 + kepler: + git: + url: https://github.com/tjcampanella/kepler + ref: e2c671389c18a5149147f598627c946c311e36b8 + keyboard_actions: + git: + url: https://github.com/diegoveloper/flutter_keyboard_actions + ref: e197412c52cd75d8a7c7ac74558610c0f92635e4 + leak_tracker: + git: + url: https://github.com/dart-lang/leak_tracker + ref: 64bae50ca89528f73d6a440c22b7e3e1713bb7f0 + path: ./pkgs/leak_tracker + leak_tracker_flutter_testing: + git: + url: https://github.com/dart-lang/leak_tracker + ref: 84d523d8ea34ecf889a3f383e206bc231af31686 + path: ./pkgs/leak_tracker_flutter_testing + leak_tracker_testing: + git: + url: https://github.com/dart-lang/leak_tracker + ref: 84d523d8ea34ecf889a3f383e206bc231af31686 + path: ./pkgs/leak_tracker_testing + ledger_bitcoin: + git: + url: https://github.com/cake-tech/ledger-flutter-plus-plugins + ref: 75bba8632c529debf30ee2b1858530009fa6440b + path: ./packages/ledger-bitcoin + ledger_ethereum: + git: + url: https://github.com/cake-tech/ledger-flutter-plus-plugins + ref: f4761cd5171d4c1e2e42fd3298261650539fb2db + path: ./packages/ledger-ethereum + ledger_flutter_plus: + git: + url: https://github.com/cake-tech/ledger-flutter-plus + ref: eaf49764ad0863e8dec97ad30ff6aea0a1d1bd28 + ledger_litecoin: + git: + url: https://github.com/cake-tech/ledger-flutter-plus-plugins + ref: 75bba8632c529debf30ee2b1858530009fa6440b + path: ./packages/ledger-litecoin + ledger_usb_plus: + git: + url: https://github.com/cake-tech/ledger-usb-plus + ref: 40af7c48cf34211ba3cc9e87dd05ed1af8a429a2 + libcrypto: + git: + url: https://github.com/MrCyjaneK/libcrypto + ref: 98be84e0a2c7b423842d1fbbd2d920ff03180235 + local_auth: + git: + url: https://github.com/flutter/packages + ref: db8bfed397145b7c5a1ade3c374a74053649ce12 + path: ./packages/local_auth/local_auth + local_auth_android: + git: + url: https://github.com/flutter/packages + ref: 1c0be204c45eea42927eb6005bb45f16a8fffb07 + path: ./packages/local_auth/local_auth_android + local_auth_darwin: + git: + url: https://github.com/flutter/packages + ref: d3e0285a6bf353f4bed9ba01d2b37a68fa63d741 + path: ./packages/local_auth/local_auth_darwin + local_auth_platform_interface: + git: + url: https://github.com/flutter/packages + ref: 321a5846838d2bfa5f3dd463e3833b951da0db32 + path: ./packages/local_auth/local_auth_platform_interface + local_auth_windows: + git: + url: https://github.com/flutter/packages + ref: e978e06eb9207e4bd7a56b2139b2906d3150edb5 + path: ./packages/local_auth/local_auth_windows + logger: + git: + url: https://github.com/SourceHorizon/logger + ref: 4c56353a5060f403650f0c728a6438d3db2de669 + logging: + git: + url: https://github.com/dart-lang/core + ref: 8151b9f57fa3fee10421a19ce24470e143c0dee5 + path: ./pkgs/logging + lottie: + git: + url: https://github.com/xvrh/lottie-flutter + ref: 1eef993a7a69cd05cfcc4c9eac4f2d89ecfab2d1 + matcher: + git: + url: https://github.com/dart-lang/test + ref: 45e4ef287d70dad449f13d4f284f9faea2d9188b + path: ./pkgs/matcher + material_color_utilities: + git: + url: https://github.com/material-foundation/material-color-utilities + ref: 5d4397afe1830b09ff99c1cb3cf901038951282a + path: ./dart + memoize: + git: + url: https://github.com/wrike/memoize_dart + ref: f541e50b3be0e7b9e83bbd3858d3a25356140570 + mime: + git: + url: https://github.com/dart-lang/tools + ref: 3440b74e430051304b56d4acd71b7ed30ab1855d + path: ./pkgs/mime + mobx: + git: + url: https://github.com/mobxjs/mobx.dart + ref: d677b8d361301b60577267703371013749b7b7de + path: ./mobx + mobx_codegen: + git: + url: https://github.com/mobxjs/mobx.dart + ref: 39a1f18c2e76a564b5e5358426d335569bc332ec + path: ./mobx_codegen + mockito: + git: + url: https://github.com/dart-lang/build + ref: f550d53994b429f48f2b86f9c70956bf50d4e0c2 + path: ./builder_pkgs/mockito + mocktail: + git: + url: https://github.com/felangel/mocktail + ref: 12989138eb6beb3d1cad330ebfd88fef005a4e3e + path: ./packages/mocktail + modal_bottom_sheet: + git: + url: https://github.com/cake-tech/modal_bottom_sheet + ref: b1cca111c53d41b9f07123a8c67cfe06fb1b69bf + path: ./modal_bottom_sheet + monero: + git: + url: https://github.com/mrcyjanek/monero_c.git + ref: 3bfb3856a838f2bf6b729501837bb0295dedf25d + path: ./impls/monero.dart + msgpack_dart: + git: + url: https://github.com/knopp/msgpack_dart + ref: 2527c0a1e2eabf92a7f5db50983d3ee4ec71ccaa + msix: + git: + url: https://github.com/YehudaKremer/msix + ref: 1ab4df346a92ef4dc7bf02fd857d2975be04d47c + mutex: + git: + url: https://github.com/hoylen/dart-mutex + ref: 84ca903a3ac863735e3228c75a212133621f680f + nanodart: + git: + url: https://github.com/appditto/nanodart + ref: 5c1b352fc02d94a34129f3848bedcec441c2b8c7 + nanoutil: + git: + url: https://github.com/perishllc/nanoutil.git + ref: c01a9c552917008d8fbc6b540db657031625b04f + native_toolchain_c: + git: + url: https://github.com/dart-lang/native + ref: 7dbb51d78534b3c037f3f063448cc45e5ca80a58 + path: ./pkgs/native_toolchain_c + nested: + git: + url: https://github.com/rrousselGit/nested + ref: 23dbf54af127301839927831695800edd5cc3dc0 + nm: + git: + url: https://github.com/canonical/nm.dart + ref: 6568c7666071f56177e45333c80dc1978ae14483 + node_preamble: + git: + url: https://github.com/mbullington/node_preamble.dart + ref: ddd4f12ddddf94ad53ec17a742008c23ad666cef + nostr_tools: + git: + url: https://github.com/cake-tech/nostr_tools.git + ref: 089d5a2dd751429a040ba10fb24fcbae564053e5 + objective_c: + git: + url: https://github.com/dart-lang/native + ref: 7990d3a3806fa6c161e2340a95574d3a92d9bca2 + path: ./pkgs/objective_c + on_chain: + git: + url: https://github.com/cake-tech/on_chain.git + ref: 096865a8c6b89c260beadfec04f7e184c40a3273 + package_config: + git: + url: https://github.com/dart-lang/tools + ref: 9c533582195b12ea006dc7188767b5a288b4c5c8 + path: ./pkgs/package_config + package_info_plus: + git: + url: https://github.com/fluttercommunity/plus_plugins + ref: 9f03424b7916b195ec6a4bebe4cc1a310ba40d4a + path: ./packages/package_info_plus/package_info_plus + package_info_plus_platform_interface: + git: + url: https://github.com/fluttercommunity/plus_plugins + ref: 9f03424b7916b195ec6a4bebe4cc1a310ba40d4a + path: ./packages/package_info_plus/package_info_plus_platform_interface + path: + git: + url: https://github.com/dart-lang/core + ref: 010a343e71238b3ed7fcd55dad5869ecaa40991a + path: ./pkgs/path + path_drawing: + git: + url: https://github.com/dnfield/flutter_path_drawing + ref: 27ce967273429ce505962d4cf68c17a5b16b5aef + path_parsing: + git: + url: https://github.com/flutter/packages + ref: 3c3181c2cfcd0557e12a95ace0e347141f63e384 + path: ./third_party/packages/path_parsing + path_provider: + git: + url: https://github.com/flutter/packages + ref: aa964a3ed6d97e4e9778feed85fa9ef1255a0477 + path: ./packages/path_provider/path_provider + path_provider_android: + git: + url: https://github.com/flutter/packages + ref: f52df418da6ef2ba666112b4b9e87d9a1c43a0d0 + path: ./packages/path_provider/path_provider_android + path_provider_foundation: + git: + url: https://github.com/flutter/packages + ref: 2ada7838737b6ea374c3ef1fffba95bd097eed92 + path: ./packages/path_provider/path_provider_foundation + path_provider_linux: + git: + url: https://github.com/flutter/packages + ref: af136ccab198bc7dfa25f5fa5ace23fdbcdaadc7 + path: ./packages/path_provider/path_provider_linux + path_provider_platform_interface: + git: + url: https://github.com/flutter/packages + ref: aa964a3ed6d97e4e9778feed85fa9ef1255a0477 + path: ./packages/path_provider/path_provider_platform_interface + path_provider_windows: + git: + url: https://github.com/flutter/packages + ref: 47a92dbdea9bc433779c76b404af9c5ab6fa40cc + path: ./packages/path_provider/path_provider_windows + pausable_timer: + git: + url: https://github.com/llucax/pausable_timer + ref: 41e21b6444749a5d8cdb720128c9be66168b83cf + payjoin_flutter: + git: + url: https://github.com/konstantinullrich/payjoin-flutter + ref: b28c825b1d63381e8c2b25ef2ccabacbf833ce53 + pedantic: + git: + url: https://github.com/google/pedantic + ref: bdcb962e3d2bda31a0e6dadb58b670aa633046e9 + permission_handler: + git: + url: https://github.com/baseflow/flutter-permission-handler + ref: 441c53c4e02ac9b6417f758495a4b04618c6e600 + path: ./permission_handler + permission_handler_android: + git: + url: https://github.com/baseflow/flutter-permission-handler + ref: 1dd6dc265a8f7b8b8dd0dd04f7202b8c17e4aa59 + path: ./permission_handler_android + permission_handler_apple: + git: + url: https://github.com/baseflow/flutter-permission-handler + ref: 5c989b1be9abbbb325424ad96e5be4efdc0987c2 + path: ./permission_handler_apple + permission_handler_html: + git: + url: https://github.com/baseflow/flutter-permission-handler + ref: f93a58bb2b993b831f48cf1ec0b3537905643e7e + path: ./permission_handler_html + permission_handler_platform_interface: + git: + url: https://github.com/baseflow/flutter-permission-handler + ref: b0bdda5faabb912dc6d0b3f330f9d801727db76e + path: ./permission_handler_platform_interface + permission_handler_windows: + git: + url: https://github.com/baseflow/flutter-permission-handler + ref: 41c2485eb698d055dcf59a373c07dee537b8aa01 + path: ./permission_handler_windows + petitparser: + git: + url: https://github.com/petitparser/dart-petitparser + ref: 3d3c2155df8c427027660f8ca37ddc6e7b894748 + pinenacl: + git: + url: https://github.com/ilap/pinenacl-dart + ref: 30c38f30a34137aa748217cf2d6fc978740d8da8 + platform: + git: + url: https://github.com/dart-lang/core + ref: 07aff972869412010a73bbe33af0909bc0536e78 + path: ./pkgs/platform + plugin_platform_interface: + git: + url: https://github.com/flutter/packages + ref: bb97da8ec627466fdb45cdd36e2c0e35dee40e9e + path: ./packages/plugin_platform_interface + pointycastle: + git: + url: https://github.com/bcgit/pc-dart + ref: c7009dbf7785f4ff865ddb4eefdaed8c18ef3baa + polyseed: + git: + url: https://github.com/cake-tech/polyseed_dart + ref: 1a8280ac2b6f01d202d8bff71527fe1ce498c4ed + pool: + git: + url: https://github.com/dart-lang/tools + ref: 042b03e8284032088f851172ab7b2aed06da1d72 + path: ./pkgs/pool + posix: + git: + url: https://github.com/onepub-dev/dart_posix + ref: 3c544340f3e4ffc64b20e6959ae8229c98638a0a + process: + git: + url: https://github.com/dart-lang/tools + ref: 5e977d6f0698a220279a50538c89a440d56b0c44 + path: ./pkgs/process + progressive_blur: + git: + url: https://github.com/kekland/progressive_blur + ref: 6ec8d0ccf46b1629a46ab68f31e26df489bac958 + protobuf: + git: + url: https://github.com/google/protobuf.dart + ref: a852ba4e4b6f319c655fc938864dac8442b7c4ad + path: ./protobuf + provider: + git: + url: https://github.com/rrousselGit/provider + ref: 558bdcd26ddb2b922bec06e3fa0d91bc59479baf + path: ./packages/provider + pub_semver: + git: + url: https://github.com/dart-lang/tools + ref: d67cd0022095a138c66df94f100e5a129c15a65e + path: ./pkgs/pub_semver + pubspec_parse: + git: + url: https://github.com/dart-lang/tools + ref: 070355ee7014c4d37bdc50fa2b4a597f2774f9ca + path: ./pkgs/pubspec_parse + qr: + git: + url: https://github.com/kevmoo/qr.dart + ref: 792288784e200301b323b1e36852ae60a3ac2431 + qr_flutter: + git: + url: https://github.com/cake-tech/qr.flutter.git + ref: dced28909a82e1906e7c510ae8ca807a1658c898 + quick_actions: + git: + url: https://github.com/flutter/packages + ref: 8238e1c5ada8c6a99f7fb6087484b52face33721 + path: ./packages/quick_actions/quick_actions + quick_actions_android: + git: + url: https://github.com/flutter/packages + ref: c05ab81dddf0f145c57b43df80903ce17ba84baf + path: ./packages/quick_actions/quick_actions_android + quick_actions_ios: + git: + url: https://github.com/flutter/packages + ref: 7ae082a7f6cd1bc6a219c6ab0adf27a3d8ffdc23 + path: ./packages/quick_actions/quick_actions_ios + quick_actions_platform_interface: + git: + url: https://github.com/flutter/packages + ref: 761812665448c7e5a1bd5810aeabfac1ac027038 + path: ./packages/quick_actions/quick_actions_platform_interface + quiver: + git: + url: https://github.com/google/quiver-dart + ref: 6ec3568dee63ae02e8676e28a6df0157f4d20e84 + rational: + git: + url: https://github.com/a14n/dart-rational + ref: 09b5adc5be7a27c349a36b73d0d616b133ad8730 + record_use: + git: + url: https://github.com/dart-lang/native + ref: abe17706806e8aa3cdafcbdab02cbbb5d1d2f884 + path: ./pkgs/record_use + rive: + git: + url: https://github.com/MrCyjaneK/rive-flutter-no-lfs + ref: 2dbfe918a3d38340f378ab2734b1c97ebcb4ab26 + rive_common: + git: + url: https://github.com/MrCyjaneK/rive_common + ref: 9457422fce3f1524437f6a1429200f048931a2fe + riverpod: + git: + url: https://github.com/rrousselGit/riverpod + ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + path: ./packages/riverpod + riverpod_annotation: + git: + url: https://github.com/rrousselGit/riverpod + ref: eb3651b42e368fc9a227aeffc9736fdc9a82f1b7 + path: ./packages/riverpod_annotation + rlz: + git: + url: https://github.com/cake-tech/zkool2.git + ref: 36e72b530c274c4a54a6127aadb94886e84d67bf + path: ./rust_builder + rxdart: + git: + url: https://github.com/ReactiveX/rxdart + ref: 6852efa646198d8a75fcaee52a5227682f8016e7 + path: ./packages/rxdart + searchable_listview: + git: + url: https://github.com/koukibadr/Searchable-Listview + ref: 87c203ac2737c3103929e2a2cd0f23becc4c3334 + sec: + git: + url: https://github.com/xclud/dart_sec + ref: 1a53c7983d0e8b5e3842eff85cebc27fd474d8f0 + sensitive_clipboard: + git: + url: https://github.com/cake-tech/sensitive_clipboard + ref: 288c7ee2d63b459bc735f7dc89321b29a1f12fae + sha3: + git: + url: https://github.com/maoxs2/dart_sha3 + ref: 6d879eb52dec2b5e110d11957f5512ceb0eaa664 + share_plus: + git: + url: https://github.com/fluttercommunity/plus_plugins + ref: 8e5fab7bfb1685f5a56f53020a49b2ff5bece25d + path: ./packages/share_plus/share_plus + share_plus_platform_interface: + git: + url: https://github.com/fluttercommunity/plus_plugins + ref: b5d24a0e3927314e50be041c9f5b7da487d69313 + path: ./packages/share_plus/share_plus_platform_interface + shared_preferences: + git: + url: https://github.com/flutter/packages + ref: 064b0b26568728342a550dc876b0a0e0f2fbaa84 + path: ./packages/shared_preferences/shared_preferences + shared_preferences_android: + git: + url: https://github.com/flutter/packages + ref: 371106fe7d9864a157fc9366f57d0b0e64fab932 + path: ./packages/shared_preferences/shared_preferences_android + shared_preferences_foundation: + git: + url: https://github.com/flutter/packages + ref: 18b9cc5f2b0820cb6164f0150958ba76db75c61a + path: ./packages/shared_preferences/shared_preferences_foundation + shared_preferences_linux: + git: + url: https://github.com/flutter/packages + ref: cdd6e1368ffdf6a4fc9c0c11b72cfc5388f90f2d + path: ./packages/shared_preferences/shared_preferences_linux + shared_preferences_platform_interface: + git: + url: https://github.com/flutter/packages + ref: 371106fe7d9864a157fc9366f57d0b0e64fab932 + path: ./packages/shared_preferences/shared_preferences_platform_interface + shared_preferences_web: + git: + url: https://github.com/flutter/packages + ref: cb4fb13e19756cbbcb523bc33fbf7b7a5923e787 + path: ./packages/shared_preferences/shared_preferences_web + shared_preferences_windows: + git: + url: https://github.com/flutter/packages + ref: cdd6e1368ffdf6a4fc9c0c11b72cfc5388f90f2d + path: ./packages/shared_preferences/shared_preferences_windows + shelf: + git: + url: https://github.com/dart-lang/shelf + ref: 2536c15a562cb183dabbc628824a215663830325 + path: ./pkgs/shelf + shelf_packages_handler: + git: + url: https://github.com/dart-lang/shelf + ref: 25861e55406c1f66cce066b6ed575f420b480e45 + path: ./pkgs/shelf_packages_handler + shelf_static: + git: + url: https://github.com/dart-lang/shelf + ref: d53a8f9a98ccbe69078d397d45c2c6b3e7c243b6 + path: ./pkgs/shelf_static + shelf_web_socket: + git: + url: https://github.com/dart-lang/shelf + ref: 2a7442f7d6d3e63fdc7b387128619b263dcb7e78 + path: ./pkgs/shelf_web_socket + smooth_page_indicator: + git: + url: https://github.com/Milad-Akarie/smooth_page_indicator + ref: 519df3304d58c9d77e91725318076bc3aaa6e852 + socks5_proxy: + git: + url: https://github.com/LacticWhale/socks_dart.git + ref: 27ad7c2efae8d7460325c74b90f660085cbd0685 + socks_socket: + git: + url: https://github.com/sneurlax/socks_socket + ref: e6232c53c1595469931ababa878759a067c02e94 + solana: + git: + url: https://github.com/espresso-cash/espresso-cash-public + ref: ab60e9d4c7d7271037597154ad2a835812054ed6 + path: ./packages/solana + source_gen: + git: + url: https://github.com/dart-lang/source_gen + ref: 98cbdb6b17cdccabb0fec6e37fd66e2790d05092 + path: ./source_gen + source_map_stack_trace: + git: + url: https://github.com/dart-lang/tools + ref: 56db6f3d085fa4e70b0286b30989654a5db90c94 + path: ./pkgs/source_map_stack_trace + source_maps: + git: + url: https://github.com/dart-lang/tools + ref: db47a844e03cbd076ac7e5a0f4f46cadcba28da8 + path: ./pkgs/source_maps + source_span: + git: + url: https://github.com/dart-lang/tools + ref: e501121027c0a9014161ff79cbf519c1813e3153 + path: ./pkgs/source_span + sp_scanner: + git: + url: https://github.com/cake-tech/sp_scanner + ref: 40ed3ce8319744907bef3b25bc6e0af8428c8724 + sqflite: + git: + url: https://github.com/tekartik/sqflite + ref: 094cc31b82df7f9ba04f330f13b50e345f777079 + path: ./sqflite + sqflite_android: + git: + url: https://github.com/tekartik/sqflite + ref: 7e7159b59572e04024258417072428d1cffca1cc + path: ./sqflite_android + sqflite_common: + git: + url: https://github.com/tekartik/sqflite + ref: 018def1518b3ce9efcb25bbf57809153e9252da7 + path: ./sqflite_common + sqflite_common_ffi: + git: + url: https://github.com/tekartik/sqflite + ref: 7482da6f456feb715eecdff8a6287bb30d01481f + path: ./sqflite_common_ffi + sqflite_darwin: + git: + url: https://github.com/tekartik/sqflite + ref: e2d87c863f33e8981dfb589d4784ab14d8f5cc77 + path: ./sqflite_darwin + sqflite_platform_interface: + git: + url: https://github.com/tekartik/sqflite + ref: 03e86a1aa7f8ebea7c40d2b02248cadc7630c2f0 + path: ./sqflite_platform_interface + sqlite3: + git: + url: https://github.com/simolus3/sqlite3.dart + ref: ac40b296e7069c4e83503bcbe4a3b22dfe5431a7 + path: ./sqlite3 + sqlite3_flutter_libs: + git: + url: https://github.com/simolus3/sqlite3.dart + ref: 808a60becaa3f9fae41e0590b853c3283b5f6afb + path: ./sqlite3_flutter_libs + stack_trace: + git: + url: https://github.com/dart-lang/tools + ref: 07648c8269244506d83c15dc8cc50aa53d24bf35 + path: ./pkgs/stack_trace + state_notifier: + git: + url: https://github.com/rrousselGit/state_notifier + ref: 061abfc682881d5da4716b211cd4e7d41805a9ac + path: ./packages/state_notifier + stream_channel: + git: + url: https://github.com/dart-lang/tools + ref: 5265a85f307ce7be94553378589205df97736a1b + path: ./pkgs/stream_channel + stream_transform: + git: + url: https://github.com/dart-lang/tools + ref: 46cc745458f93bdbd39972a925d7530e57f84f5c + path: ./pkgs/stream_transform + string_scanner: + git: + url: https://github.com/dart-lang/tools + ref: 3815ff3fd2aee5212586c3fc4d2bcf08584c98f3 + path: ./pkgs/string_scanner + sync_http: + git: + url: https://github.com/google/sync_http.dart + ref: 39509d69fd5a9c3da46eab48fcafdf62e6ad4580 + synchronized: + git: + url: https://github.com/tekartik/synchronized.dart + ref: b38010355b23e3baed85e263ca7f9e222d57b00a + path: ./synchronized + term_glyph: + git: + url: https://github.com/dart-lang/tools + ref: c90e95b1f2a130b2e951466719b28c3d13b8dab5 + path: ./pkgs/term_glyph + test: + git: + url: https://github.com/dart-lang/test + ref: 45e4ef287d70dad449f13d4f284f9faea2d9188b + path: ./pkgs/test + test_api: + git: + url: https://github.com/dart-lang/test + ref: 45e4ef287d70dad449f13d4f284f9faea2d9188b + path: ./pkgs/test_api + test_core: + git: + url: https://github.com/dart-lang/test + ref: 45e4ef287d70dad449f13d4f284f9faea2d9188b + path: ./pkgs/test_core + timezone: + git: + url: https://github.com/srawlins/timezone + ref: 64db18e450c10247e23ee36546865007b01cf135 + toastification: + git: + url: https://github.com/payam-zahedi/toastification + ref: 4f1068f5265a0d189aee6881d125e8a35adec74f + translator: + git: + url: https://github.com/cake-tech/google-translator.git + ref: b36571ec11efd838afda010adcc21a4e95302745 + trezor_connect: + git: + url: https://github.com/cake-tech/trezor_connect + ref: d1242cea90f84b00200e7bcab914a5af750e23fb + trezor_flutter: + git: + url: https://github.com/cake-tech/trezor-flutter.git + ref: 7d27e19b7bcdcd6241df35953f9a6ec2df0c7a97 + path: ./trezor-flutter + trezor_usb_transport: + git: + url: https://github.com/cake-tech/trezor-flutter.git + ref: 7d27e19b7bcdcd6241df35953f9a6ec2df0c7a97 + path: ./trezor_usb_transport + tuple: + git: + url: https://github.com/google/tuple.dart + ref: 91bcce6e0672c4b071d270aafde5cd86103668dd + typed_data: + git: + url: https://github.com/dart-lang/core + ref: 5ed932323581a4791672c25fe154c622b535c264 + path: ./pkgs/typed_data + uni_links: + git: + url: https://github.com/cake-tech/uni_links + ref: 1989db3f5d625e2fffbad7b85a3b1b8c78c6dfa1 + path: ./uni_links + uni_links_platform_interface: + git: + url: https://github.com/avioli/uni_links + ref: cdd7a217d351a32c418afad18f8ea6893cfed05a + path: ./uni_links_platform_interface + uni_links_web: + git: + url: https://github.com/avioli/uni_links + ref: cf9d2b64dc3e890015d1dd6df7b6414123835663 + path: ./uni_links_web + universal_ble: + git: + url: https://github.com/cake-tech/universal_ble.git + ref: 6735c1bdf7f42c501d51c20564eb957c3a12b981 + universal_io: + git: + url: https://github.com/dart-io-packages/universal_io + ref: ed92942d149674621e7ae4ac46325e55ecee9368 + universal_platform: + git: + url: https://github.com/gskinnerTeam/flutter-universal-platform + ref: f4fc405630cdd541d78457b0b4521b89456ea068 + unorm_dart: + git: + url: https://github.com/yshrsmz/unorm-dart + ref: 3301bdc74e9644c69201db31e0daefb24fd10cd8 + ur: + git: + url: https://github.com/bukata-sa/bc-ur-dart + ref: 5738f70d0ec3d50977ac3dd01fed62939600238b + url_launcher: + git: + url: https://github.com/flutter/packages + ref: 3fe6a0149acebc9cb8707cf508d13f59fc372986 + path: ./packages/url_launcher/url_launcher + url_launcher_android: + git: + url: https://github.com/flutter/packages + ref: 7287c7b7f1d51e8842f49df46dbd0af3bd1c1077 + path: ./packages/url_launcher/url_launcher_android + url_launcher_ios: + git: + url: https://github.com/flutter/packages + ref: 9cac0573363b7bbe6bf32aca44582fb75ee67521 + path: ./packages/url_launcher/url_launcher_ios + url_launcher_linux: + git: + url: https://github.com/flutter/packages + ref: 73d2f3eb966d36a44cbb943ea0e96dda3a2f8da2 + path: ./packages/url_launcher/url_launcher_linux + url_launcher_macos: + git: + url: https://github.com/flutter/packages + ref: 18b9cc5f2b0820cb6164f0150958ba76db75c61a + path: ./packages/url_launcher/url_launcher_macos + url_launcher_platform_interface: + git: + url: https://github.com/flutter/packages + ref: ef349bec8ee9d5fa3f69d73aa78ab9bb84ae0aa7 + path: ./packages/url_launcher/url_launcher_platform_interface + url_launcher_web: + git: + url: https://github.com/flutter/packages + ref: 67ec0d36293eb963590e0606c8bede379be4d142 + path: ./packages/url_launcher/url_launcher_web + url_launcher_windows: + git: + url: https://github.com/flutter/packages + ref: 18b9cc5f2b0820cb6164f0150958ba76db75c61a + path: ./packages/url_launcher/url_launcher_windows + uuid: + git: + url: https://github.com/Daegalus/dart-uuid + ref: d602950818e4b11d097d26f5408b461f38248130 + vector_graphics: + git: + url: https://github.com/flutter/packages + ref: caddb39d831fc9e7f9a2cbe5c87d75629adc35ac + path: ./packages/vector_graphics + vector_graphics_codec: + git: + url: https://github.com/flutter/packages + ref: 11a9fa8bf6e5a49d02aef0ba5c5a95037a2acbc3 + path: ./packages/vector_graphics_codec + vector_graphics_compiler: + git: + url: https://github.com/flutter/packages + ref: 3d05e51b22d99c5362d2f1f7f5b80358dd4e9cb3 + path: ./packages/vector_graphics_compiler + vector_math: + git: + url: https://github.com/google/vector_math.dart + ref: 13f185f7e97d559e003f5ac79201da12f9a01049 + vm_service: + git: + url: https://github.com/dart-lang/sdk + ref: c70f78e7d682c158c15ca0c26c729b3ccb932284 + path: ./pkg/vm_service + wakelock_plus: + git: + url: https://github.com/fluttercommunity/wakelock_plus + ref: e7301f64397c946fac4ee66acdfb545b666f4a43 + path: ./wakelock_plus + wakelock_plus_platform_interface: + git: + url: https://github.com/fluttercommunity/wakelock_plus + ref: 302991238a66dd1f6b1e50b38f58d97d177cd9ab + path: ./wakelock_plus_platform_interface + wallet: + git: + url: https://github.com/xclud/dart_wallet + ref: aa5ba16f7a8a3a7789ca78330ce3877913f29a83 + watcher: + git: + url: https://github.com/dart-lang/tools + ref: 67a0fea10d8402d427aca8aff95cdc3b16004fc2 + path: ./pkgs/watcher + web: + git: + url: https://github.com/dart-lang/web + ref: 222164b5010cb0324d4132666f1d43750ffc6448 + path: ./web + web3dart: + git: + url: https://github.com/cake-tech/web3dart.git + ref: aa3f932dbf54eda651b7bd01ad00204acf998bd0 + web_socket: + git: + url: https://github.com/dart-lang/http + ref: 31da3556357cd9ba9205e20c9299a1d48c149382 + path: ./pkgs/web_socket + web_socket_channel: + git: + url: https://github.com/dart-lang/http + ref: 63c477b466f650e8f5505d6d78dc283c2c2f9845 + path: ./pkgs/web_socket_channel + webdriver: + git: + url: https://github.com/google/webdriver.dart + ref: e84e9ccbee3e0c38a149b7d964eb7ab6ccc78384 + webkit_inspection_protocol: + git: + url: https://github.com/google/webkit_inspection_protocol.dart + ref: 82f0c1c46dfdba5edf7c5fa84456233121dd69e1 + win32: + git: + url: https://github.com/halildurmus/win32 + ref: 64b0a07ab7e1e3e7db6fca60c6b121d6cfd73709 + path: ./packages/win32 + win32_registry: + git: + url: https://github.com/halildurmus/win32_registry + ref: fd20025f9b6f0ce6937b3e7e4b923e51ae11e40f + x25519: + git: + url: https://github.com/Tougee/curve25519 + ref: 61b636d53e03cd12c9d9f728f8be6821fb6e2581 + xdg_directories: + git: + url: https://github.com/flutter/packages + ref: b33972233ecb894f2fd3d61a74dd1c300fac10c2 + path: ./packages/xdg_directories + xml: + git: + url: https://github.com/renggli/dart-xml + ref: 83796f3dd0923590561d9d169d6ee2db46580099 + yaml: + git: + url: https://github.com/dart-lang/tools + ref: 27f829e3752382beae9deb1e87029f9ed52ef32e + path: ./pkgs/yaml + yaml_edit: + git: + url: https://github.com/dart-lang/tools + ref: 119a499068a903222fbbefdea18ea59efdd417b9 + path: ./pkgs/yaml_edit + zkool: + git: + url: https://github.com/cake-tech/zkool2.git + ref: 36e72b530c274c4a54a6127aadb94886e84d67bf diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index fa26c3e91..5d3eb9f2d 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -93,6 +93,7 @@ "available": "متاح", "available_balance": "الرصيد المتاح", "available_balance_description": "يشير “Available Balance” أو “Confirmed Balance” إلى الأموال التي يمكن إنفاقها فورًا. إذا ظهرت الأموال في الرصيد السفلي ولكن ليس في الرصيد العلوي، فعليك الانتظار بضع دقائق حتى تحصل الأموال الواردة على المزيد من تأكيدات الشبكة. بعد حصولها على المزيد من التأكيدات، ستصبح قابلة للإنفاق.", + "available_balance_short": "المبلغ الإجمالي: ${amount}", "avg_savings": "متوسط التوفير", "avl": "AVL", "awaitDAppProcessing": "يرجى الانتظار حتى ينتهي الـ dApp من المعالجة.", @@ -1149,6 +1150,8 @@ "swap_id": "معرّف المبادلة", "swap_provider_initial_desc": "اختر نوع مزوّد المبادلة الذي تفضّل استخدامه عند إجراء المبادلة داخل التطبيق", "swap_providers": "مزودو المبادلة", + "swap_unavailable_needs_network_wallet": "لا يمكن لهذا النوع من العنوان تلقي الأموال من المبادلة. أنت بحاجة إلى محفظة ${network} لإرسالها إلى هذا العنوان.", + "swap_unavailable_switch_to_network": "لا يمكن لهذا النوع من العنوان تلقي الأموال من المبادلة. قم بالتبديل إلى محفظة ${network} الخاصة بك للمتابعة.", "sweeping_wallet": "محفظة السحب الشامل", "sweeping_wallet_alert": "لن يستغرق هذا وقتًا طويلًا. لا تغادر هذه الشاشة وإلا فقد تُفقد الأموال المُسحوبة.", "swipe_to_bridge": "اسحب لإجراء الجسر", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "جارٍ المزامنة", "sync_status_timed_out": "انتهت المهلة", "sync_status_unsupported": "عقدة غير مدعومة", + "sync_synced": "تمت المزامنة", "sync_syncing": "جارٍ المزامنة", "sync_timed_out": "انتهت مهلة المزامنة", "sync_unsupported_node": "عقدة غير مدعومة", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index c818c866d..d14612fb7 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -93,6 +93,7 @@ "available": "Налично", "available_balance": "Наличен баланс", "available_balance_description": "„Наличният баланс“ или „Потвърденият баланс“ са средства, които могат да бъдат изразходвани веднага. Ако средствата се появяват в долния баланс, но не и в горния, трябва да изчакате няколко минути, докато входящите средства получат повече мрежови потвърждения. След като получат повече потвърждения, те ще могат да бъдат изразходвани.", + "available_balance_short": "Ср.: ${amount}", "avg_savings": "Средни спестявания", "avl": "Avl", "awaitDAppProcessing": "Моля, изчакайте dApp да завърши обработката.", @@ -1149,6 +1150,8 @@ "swap_id": "ID на суап", "swap_provider_initial_desc": "Изберете типа доставчик за суап, който предпочитате да използвате при суапване в", "swap_providers": "Доставчици за суап", + "swap_unavailable_needs_network_wallet": "Този тип адрес не може да получава средства от суап. Имате нужда от ${network} портфейл, за да изпратите на този адрес.", + "swap_unavailable_switch_to_network": "Този тип адрес не може да получава средства от суап. Превключете към вашия ${network} портфейл, за да продължите.", "sweeping_wallet": "Изчистване на портфейл", "sweeping_wallet_alert": "Това не би трябвало да отнеме много време. НЕ НАПУСКАЙТЕ ТОЗИ ЕКРАН, ИНАЧЕ ИЗМЕТЕНИТЕ СРЕДСТВА МОГАТ ДА БЪДАТ ЗАГУБЕНИ.", "swipe_to_bridge": "Плъзнете, за да прехвърлите", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "СИНХРОНИЗИРАНЕ", "sync_status_timed_out": "ИЗТЕЧЕ ВРЕМЕТО", "sync_status_unsupported": "НЕПОДДЪРЖАН ВЪЗЕЛ", + "sync_synced": "Синхронизирано", "sync_syncing": "Синхронизиране", "sync_timed_out": "Времето за синхронизиране изтече", "sync_unsupported_node": "Неподдържан възел", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 1961102c4..c0c0815d6 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -93,6 +93,7 @@ "available": "Dostupné", "available_balance": "Dostupný zůstatek", "available_balance_description": "„Dostupný zůstatek“ nebo „Potvrzený zůstatek“ jsou prostředky, které lze okamžitě utratit. Pokud se prostředky zobrazují ve spodním zůstatku, ale ne v horním, musíte několik minut počkat, než příchozí prostředky získají více síťových potvrzení. Jakmile získají více potvrzení, bude možné je utratit.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Prům. úspora", "avl": "Avl", "awaitDAppProcessing": "Počkejte prosím, až dApp dokončí zpracování.", @@ -1149,6 +1150,8 @@ "swap_id": "ID směny", "swap_provider_initial_desc": "Vyberte typ poskytovatele swapu, kterého chcete používat při swapování v", "swap_providers": "Poskytovatelé swapu", + "swap_unavailable_needs_network_wallet": "Tento typ adresy nemůže přijímat prostředky ze swapu. K odeslání na tuto adresu potřebujete peněženku ${network}.", + "swap_unavailable_switch_to_network": "Tento typ adresy nemůže přijímat prostředky ze swapu. Chcete-li pokračovat, přepněte na svou peněženku ${network}.", "sweeping_wallet": "Peněženka pro sweep", "sweeping_wallet_alert": "To by nemělo trvat dlouho. NEOPUŠTĚJTE TUTO OBRAZOVKU, JINAK MOHOU BÝT PŘESUNUTÉ PROSTŘEDKY ZTRACENY.", "swipe_to_bridge": "Přemostění přejetím prstem", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "SYNCHRONIZUJE SE", "sync_status_timed_out": "VYPRŠEL ČAS", "sync_status_unsupported": "NEPODPOROVANÝ UZEL", + "sync_synced": "Synchronizováno", "sync_syncing": "Synchronizace", "sync_timed_out": "Vypršel časový limit synchronizace", "sync_unsupported_node": "Nepodporovaný uzel", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 954898284..a0f89e794 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -96,6 +96,7 @@ "available": "Verfügbar", "available_balance": "Verfügbares Guthaben", "available_balance_description": "Der „Verfügbare Kontostand“ bzw. „Bestätigter Kontostand“ sind Guthaben, die sofort ausgegeben werden können. Wenn Guthaben im unteren Kontostand angezeigt wird, aber nicht im oberen, müssen Sie ein paar Minuten warten, bis die eingehenden Gelder weitere Netzwerkbestätigungen erhalten. Sobald sie mehr Bestätigungen haben, können sie ausgegeben werden.", + "available_balance_short": "Durchschnitt: ${amount}", "avg_savings": "Durchschn. Ersparnis", "avl": "Avl", "awaitDAppProcessing": "Bitte warten Sie, bis die dApp die Verarbeitung abgeschlossen hat.", @@ -1183,6 +1184,8 @@ "swap_provider_initial_desc": "Wählen Sie die Art des Swap-Anbieters aus, die Sie beim Tauschen bevorzugen.", "swap_providers": "Swap-Anbieter", "swap_reverse_direction": "Swap-Richtung umkehren", + "swap_unavailable_needs_network_wallet": "Dieser Adresstyp kann keine Gelder von einem Swap erhalten. Sie benötigen ein ${network}-Wallet, um es an diese Adresse zu senden.", + "swap_unavailable_switch_to_network": "Dieser Adresstyp kann keine Gelder von einem Swap erhalten. Wechseln Sie zu Ihrem ${network}-Wallet, um fortzufahren.", "sweeping_wallet": "Wallet leeren", "sweeping_wallet_alert": "Das sollte nicht lange dauern. Verlassen Sie diesen Bildschirm nicht, sonst können die geleerten Guthaben verloren gehen.", "swipe_to_bridge": "Zum Bridging wischen", @@ -1217,6 +1220,7 @@ "sync_status_syncronizing": "SYNCHRONISIEREN", "sync_status_timed_out": "ZEITÜBERSCHREITUNG", "sync_status_unsupported": "NICHT UNTERSTÜTZTER NODE", + "sync_synced": "Synchronisiert", "sync_syncing": "Synchronisiere", "sync_timed_out": "Synchronisierung abgelaufen", "sync_unsupported_node": "Nicht unterstützter Node", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 874339ccb..40896399e 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -96,7 +96,7 @@ "available": "Available", "available_balance": "Available Balance", "available_balance_description": "The “Available Balance” or “Confirmed Balance” are funds that can be spent immediately. If funds appear in the lower balance but not the top balance, then you must wait a few minutes for the incoming funds to get more network confirmations. After they get more confirmations, they will be spendable.", - "available_providers": "Available Providers", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Avg. Savings", "avl": "Avl", "awaitDAppProcessing": "Kindly wait for the dApp to finish processing.", @@ -1200,6 +1200,8 @@ "swap_provider_initial_desc": "Select the type of swap provider you prefer to use when swapping in", "swap_providers": "Swap providers", "swap_reverse_direction": "Reverse swap direction", + "swap_unavailable_needs_network_wallet": "This address type can't receive funds from a swap. You need a ${network} wallet to send to this address.", + "swap_unavailable_switch_to_network": "This address type can't receive funds from a swap. Switch to your ${network} wallet to continue.", "sweeping_wallet": "Sweeping wallet", "sweeping_wallet_alert": "This shouldn’t take long. DO NOT LEAVE THIS SCREEN OR THE SWEPT FUNDS MAY BE LOST.", "swipe_to_bridge": "Swipe to bridge", @@ -1234,6 +1236,7 @@ "sync_status_syncronizing": "SYNCHRONIZING", "sync_status_timed_out": "TIMED OUT", "sync_status_unsupported": "UNSUPPORTED NODE", + "sync_synced": "Synced", "sync_syncing": "Syncing", "sync_timed_out": "Sync Timed Out", "sync_unsupported_node": "Unsupported node", @@ -1534,4 +1537,4 @@ "zcash_network_upgrade_desc_1": "Zcash has undergone a network upgrade called Ironwood that requires migration of funds before they can be spent. This migration is automatic, privacy-preserving, and starts as soon as you open your Zcash wallet.", "zcash_network_upgrade_desc_2": "When the migration finishes, your Available Balance will return to normal, and you can continue to send and receive Zcash as usual.", "zcash_network_upgrade_desc_3": "Please allow your Zcash wallet to finishing syncing, and then leave the app open until migration finishes which can take a few minutes depending on the balance." -} +} \ No newline at end of file diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 1f678f338..1e29a5c19 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -93,6 +93,7 @@ "available": "Disponible", "available_balance": "Saldo disponible", "available_balance_description": "El “Saldo Disponible” o “Saldo Confirmado” son fondos que pueden gastarse de inmediato. Si los fondos aparecen en el saldo inferior pero no en el saldo superior, deberás esperar unos minutos a que los fondos entrantes obtengan más confirmaciones de la red. Una vez que tengan más confirmaciones, podrás gastarlos.", + "available_balance_short": "Valor medio: ${amount}", "avg_savings": "Ahorro prom.", "avl": "Avl", "awaitDAppProcessing": "Espere a que la dApp termine de procesar.", @@ -1151,6 +1152,8 @@ "swap_id": "ID de intercambio", "swap_provider_initial_desc": "Seleccione el tipo de proveedor de intercambio que prefiere usar al intercambiar", "swap_providers": "Proveedores de intercambio", + "swap_unavailable_needs_network_wallet": "Este tipo de dirección no puede recibir fondos de un swap. Necesitas una billetera ${network} para enviar a esta dirección.", + "swap_unavailable_switch_to_network": "Este tipo de dirección no puede recibir fondos de un swap. Cambie a su billetera ${network} para continuar.", "sweeping_wallet": "Cartera de barrido", "sweeping_wallet_alert": "Esto no debería tardar mucho. NO SALGAS DE ESTA PANTALLA O LOS FONDOS BARRIDOS PODRÍAN PERDERSE.", "swipe_to_bridge": "Desliza para transferir entre cadenas", @@ -1183,6 +1186,7 @@ "sync_status_syncronizing": "SINCRONIZANDO", "sync_status_timed_out": "TIEMPO DE ESPERA AGOTADO", "sync_status_unsupported": "NODO NO COMPATIBLE", + "sync_synced": "Sincronizado", "sync_syncing": "Sincronizando", "sync_timed_out": "Tiempo de espera de sincronización agotado", "sync_unsupported_node": "Nodo no compatible", diff --git a/res/values/strings_fa.arb b/res/values/strings_fa.arb index 268b48215..f40a8e113 100644 --- a/res/values/strings_fa.arb +++ b/res/values/strings_fa.arb @@ -93,6 +93,7 @@ "available": "در دسترس", "available_balance": "موجودی در دسترس", "available_balance_description": "«موجودی قابل‌دسترس» یا «موجودی تأییدشده» وجوهی هستند که می‌توان بلافاصله خرج کرد.\nاگر وجوه در موجودی پایین‌تر ظاهر شوند اما در موجودی بالا نباشند، باید چند دقیقه صبر کنید تا وجوه ورودی تأییدهای شبکه بیشتری دریافت کنند.\nپس از دریافت تأییدهای بیشتر، قابل خرج کردن خواهند بود.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "میانگین صرفه‌جویی", "avl": "Avl", "awaitDAppProcessing": "لطفاً منتظر بمانید تا پردازش dApp به پایان برسد.", @@ -1149,6 +1150,8 @@ "swap_id": "شناسهٔ سواپ", "swap_provider_initial_desc": "نوع ارائه‌دهندهٔ سواپ را که ترجیح می‌دهید هنگام سواپ از آن استفاده کنید، انتخاب کنید", "swap_providers": "ارائه‌دهندگان سواپ", + "swap_unavailable_needs_network_wallet": "این نوع آدرس نمی‌تواند وجوهی را از مبادله دریافت کند. برای ارسال به این آدرس به یک کیف پول ${network} نیاز دارید.", + "swap_unavailable_switch_to_network": "این نوع آدرس نمی‌تواند وجوهی را از مبادله دریافت کند. برای ادامه به کیف پول ${network} خود بروید.", "sweeping_wallet": "در حال انتقال موجودی کیف پول", "sweeping_wallet_alert": "این کار نباید طول بکشد.\nاین صفحه را ترک نکنید، وگرنه ممکن است وجوه انتقال‌یافته از دست برود.", "swipe_to_bridge": "برای پل‌زدن، انگشت خود را بکشید", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "در حال همگام‌سازی", "sync_status_timed_out": "اتمام زمان", "sync_status_unsupported": "نود پشتیبانی‌نشده", + "sync_synced": "همگام سازی شد", "sync_syncing": "در حال همگام‌سازی", "sync_timed_out": "مهلت همگام‌سازی به پایان رسید", "sync_unsupported_node": "گره پشتیبانی‌نشده", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 01c14e0eb..0ced5ec4d 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -93,6 +93,7 @@ "available": "Disponible", "available_balance": "Solde disponible", "available_balance_description": "Le « Solde disponible » ou le « Solde confirmé » correspond aux fonds que vous pouvez dépenser immédiatement. Si des fonds apparaissent dans le solde inférieur mais pas dans le solde supérieur, vous devez attendre quelques minutes pour que les fonds entrants obtiennent davantage de confirmations sur le réseau. Une fois qu’ils auront reçu plus de confirmations, ils pourront être dépensés.", + "available_balance_short": "Valeur moyenne : ${amount}", "avg_savings": "Économies moy.", "avl": "Avl", "awaitDAppProcessing": "Veuillez patienter pendant que la dApp termine le traitement.", @@ -1149,6 +1150,8 @@ "swap_id": "ID d’échange", "swap_provider_initial_desc": "Sélectionnez le type de fournisseur de swap que vous préférez utiliser lors d’un swap", "swap_providers": "Fournisseurs de swap", + "swap_unavailable_needs_network_wallet": "Ce type d'adresse ne peut pas recevoir de fonds provenant d'un swap. Vous avez besoin d'un portefeuille ${network} pour envoyer à cette adresse.", + "swap_unavailable_switch_to_network": "Ce type d'adresse ne peut pas recevoir de fonds provenant d'un swap. Basculez vers votre portefeuille ${network} pour continuer.", "sweeping_wallet": "Balayage du portefeuille", "sweeping_wallet_alert": "Cela ne devrait pas prendre longtemps. NE QUITTEZ PAS CET ÉCRAN, SINON LES FONDS BALAYÉS RISQUENT D’ÊTRE PERDUS.", "swipe_to_bridge": "Glissez pour transférer (bridge)", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "SYNCHRONISATION", "sync_status_timed_out": "DÉLAI DÉPASSÉ", "sync_status_unsupported": "NŒUD NON PRIS EN CHARGE", + "sync_synced": "Synchronisé", "sync_syncing": "Synchronisation en cours", "sync_timed_out": "Délai de synchronisation dépassé", "sync_unsupported_node": "Nœud non pris en charge", diff --git a/res/values/strings_gn.arb b/res/values/strings_gn.arb index e170211ea..679d73244 100644 --- a/res/values/strings_gn.arb +++ b/res/values/strings_gn.arb @@ -93,6 +93,7 @@ "available": "Oĩva", "available_balance": "Saldo ojepurukuaáva", "available_balance_description": "Pe “Available Balance” térã “Confirmed Balance” ha'e umi fondo ikatúva reipuru pya'e. Umi fondo ojehecháramo pe saldo yvýpe ha ndaha'éi pe saldo yvate gotyo, upéicharõ eha'arõ sapy'ami hag̃ua umi fondo og̃uahẽva ohupytyve hag̃ua confirmación de red. Oguerekóvo hetave confirmación, ikatúta reipuru.", + "available_balance_short": "Avl: ${amount}.", "avg_savings": "Ñongatu mbytegua", "avl": "Avl", "awaitDAppProcessing": "Eha'arõmi pe dApp omohu'ã hag̃ua hembiapo.", @@ -1155,6 +1156,8 @@ "swap_id": "ID ñemoambue rehegua", "swap_provider_initial_desc": "Eiporavo mba’eichagua swap puruhára reipuruséva rembojopyru hag̃ua swap jave.", "swap_providers": "Proveedor-kuéra intercambio rehegua", + "swap_unavailable_needs_network_wallet": "Ko tipo dirección ndikatúi ohupyty fondo peteî swap-gui. Tekotevẽ peteĩ ${network} billetera emondo hag̃ua ko dirección-pe.", + "swap_unavailable_switch_to_network": "Ko tipo dirección ndikatúi ohupyty fondo peteî swap-gui. Embohasa nde ${network} billetera-pe eñepyrũ hag̃ua.", "sweeping_wallet": "Billetera ñemopotĩ", "sweeping_wallet_alert": "Kóva ndoguerahámo’ãi heta aravo. ANI REHEJA KO PANTALLA, térã umi fondo oñemopotĩva ikatu okañy.", "swipe_to_bridge": "Embosyryry embridge hag̃ua", @@ -1187,6 +1190,7 @@ "sync_status_syncronizing": "Oñembojuehehína", "sync_status_timed_out": "Ohasáma", "sync_status_unsupported": "NODO NOÑEMONEĨRIVA", + "sync_synced": "Oñembojoaju", "sync_syncing": "Oñembojuehe", "sync_timed_out": "Sincronización ohasáma aravo", "sync_unsupported_node": "Nodo ndojehechaukáiva", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 9ae47ffc7..1df9ce6fa 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -93,6 +93,7 @@ "available": "Akwai", "available_balance": "Ma’aunin da ake da shi", "available_balance_description": "“Ma'aunin da ake da shi” ko “Tabbataccen Ma'auni” su ne kuɗaɗen da za a iya kashewa nan take. Idan kuɗaɗe sun bayyana a ƙananan ma'auni amma ba a babban ma'auni ba, to dole ne ku jira 'yan mintoci kaɗan domin kuɗaɗen da ke shigowa su sami ƙarin tabbaci daga hanyar sadarwa. Bayan sun sami ƙarin tabbaci, za a iya kashe su.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Matsakaitan Ajiya", "avl": "Avl", "awaitDAppProcessing": "Da fatan za a jira dApp ya kammala sarrafawa.", @@ -1151,6 +1152,8 @@ "swap_id": "ID na Musanya", "swap_provider_initial_desc": "Zaɓi nau'in mai ba da sabis na musanyawa da ka fi so ka yi amfani da shi lokacin musanyawa", "swap_providers": "Masu samar da Swap", + "swap_unavailable_needs_network_wallet": "Wannan nau'in adireshin ba zai iya karɓar kuɗi daga musanyawa ba. Kuna buƙatar walat ɗin ${network} don aikawa zuwa wannan adireshin.", + "swap_unavailable_switch_to_network": "Wannan nau'in adireshin ba zai iya karɓar kuɗi daga musanyawa ba. Canja zuwa jakar kuɗin ku na ${network} don ci gaba.", "sweeping_wallet": "Ana kwashe kuɗi daga walat", "sweeping_wallet_alert": "Wannan bai kamata ya ɗauki lokaci mai tsawo ba. KADA KA BAR WANNAN ALLON KO KUDADEN DA AKA KWASO NA IYA ɓACEWA.", "swipe_to_bridge": "Zame don gada", @@ -1183,6 +1186,7 @@ "sync_status_syncronizing": "ANA DAIDAITAWA", "sync_status_timed_out": "LOKACI YA WUCE", "sync_status_unsupported": "NODE MARA GOYON BAYA", + "sync_synced": "An daidaita", "sync_syncing": "Ana aiki tare", "sync_timed_out": "Lokacin aiki tare ya ƙare", "sync_unsupported_node": "Node da ba a tallafa ba", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 01e260fe5..0aa460024 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -93,6 +93,7 @@ "available": "उपलब्ध", "available_balance": "उपलब्ध शेष राशि", "available_balance_description": "“Available Balance” या “Confirmed Balance” वे धनराशि हैं जिन्हें तुरंत खर्च किया जा सकता है। यदि फंड नीचे वाले बैलेंस में दिखाई देते हैं, लेकिन ऊपर वाले बैलेंस में नहीं, तो आने वाले फंड को नेटवर्क पर और अधिक पुष्टिकरण मिलने के लिए आपको कुछ मिनट इंतज़ार करना होगा। अधिक पुष्टिकरण मिलने के बाद, वे खर्च करने योग्य हो जाएंगे।", + "available_balance_short": "एवीएल: ${amount}", "avg_savings": "औसत बचत", "avl": "अवल", "awaitDAppProcessing": "कृपया dApp की प्रोसेसिंग पूरी होने तक प्रतीक्षा करें।", @@ -1151,6 +1152,8 @@ "swap_id": "स्वैप आईडी", "swap_provider_initial_desc": "स्वैप करते समय आप जिस प्रकार के स्वैप प्रदाता का उपयोग करना पसंद करते हैं, उसका चयन करें", "swap_providers": "स्वैप प्रदाता", + "swap_unavailable_needs_network_wallet": "यह पता प्रकार स्वैप से धनराशि प्राप्त नहीं कर सकता। इस पते पर भेजने के लिए आपको एक ${network} वॉलेट की आवश्यकता है।", + "swap_unavailable_switch_to_network": "यह पता प्रकार स्वैप से धनराशि प्राप्त नहीं कर सकता। जारी रखने के लिए अपने ${network} वॉलेट पर स्विच करें।", "sweeping_wallet": "वॉलेट स्वीप करना", "sweeping_wallet_alert": "इसमें ज़्यादा समय नहीं लगना चाहिए। इस स्क्रीन को न छोड़ें, वरना स्वीप किए गए फंड खो सकते हैं।", "swipe_to_bridge": "ब्रिज करने के लिए स्वाइप करें", @@ -1183,6 +1186,7 @@ "sync_status_syncronizing": "सिंक्रनाइज़ हो रहा है", "sync_status_timed_out": "समय समाप्त", "sync_status_unsupported": "असमर्थित नोड", + "sync_synced": "सिंक किया गया", "sync_syncing": "सिंक हो रहा है", "sync_timed_out": "सिंक का समय समाप्त हो गया", "sync_unsupported_node": "असमर्थित नोड", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 895333a70..4f5271137 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -93,6 +93,7 @@ "available": "Dostupno", "available_balance": "Raspoloživo stanje", "available_balance_description": "“Dostupno stanje” ili “Potvrđeno stanje” su sredstva koja možete odmah potrošiti. Ako se sredstva prikazuju u donjem stanju, ali ne i u gornjem, morate pričekati nekoliko minuta da dolazna sredstva dobiju više mrežnih potvrda. Nakon što dobiju više potvrda, moći ćete ih potrošiti.", + "available_balance_short": "Prosjek: ${amount}", "avg_savings": "Prosj. ušteda", "avl": "Avl", "awaitDAppProcessing": "Molimo pričekajte da dApp završi s obradom.", @@ -1149,6 +1150,8 @@ "swap_id": "ID zamjene", "swap_provider_initial_desc": "Odaberite vrstu pružatelja zamjene koju želite koristiti pri zamjeni", "swap_providers": "Pružatelji usluga zamjene", + "swap_unavailable_needs_network_wallet": "Ova vrsta adrese ne može primiti sredstva od zamjene. Potreban vam je ${network} novčanik za slanje na ovu adresu.", + "swap_unavailable_switch_to_network": "Ova vrsta adrese ne može primiti sredstva od zamjene. Za nastavak prebacite se na svoj ${network} novčanik.", "sweeping_wallet": "Prebacivanje sredstava u novčanik", "sweeping_wallet_alert": "Ovo ne bi trebalo dugo trajati. NE NAPUŠTAJTE OVAJ ZASLON ILI PREBAČENA SREDSTVA MOGU BITI IZGUBLJENA.", "swipe_to_bridge": "Prijeđite prstom za premošćivanje", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "SINKRONIZIRANJE", "sync_status_timed_out": "ISTEKLO VRIJEME", "sync_status_unsupported": "NEPODRŽANI ČVOR", + "sync_synced": "Sinkronizirano", "sync_syncing": "Sinkroniziranje", "sync_timed_out": "Sinkronizacija je istekla", "sync_unsupported_node": "Nepodržani čvor", diff --git a/res/values/strings_hy.arb b/res/values/strings_hy.arb index a5658ff07..a5930373f 100644 --- a/res/values/strings_hy.arb +++ b/res/values/strings_hy.arb @@ -93,6 +93,7 @@ "available": "Հասանելի", "available_balance": "Հասանելի մնացորդ", "available_balance_description": "«Հասանելի մնացորդը» կամ «Հաստատված մնացորդը» միջոցներ են, որոնք կարելի է անմիջապես ծախսել։ Եթե միջոցները երևում են ստորին մնացորդում, բայց ոչ վերևի մնացորդում, ապա պետք է մի քանի րոպե սպասեք, մինչև մուտքագրվող միջոցները ստանան ավելի շատ ցանցային հաստատումներ։ Ավելի շատ հաստատումներ ստանալուց հետո դրանք հնարավոր կլինի ծախսել։", + "available_balance_short": "Ավլ՝ ${amount}", "avg_savings": "Միջին խնայողություն", "avl": "Ավլ", "awaitDAppProcessing": "Խնդրում ենք սպասել, մինչև dApp-ը ավարտի մշակումը։", @@ -1149,6 +1150,8 @@ "swap_id": "Փոխանակման ID", "swap_provider_initial_desc": "Ընտրեք փոխանակման մատակարարի տեսակը, որը նախընտրում եք օգտագործել փոխանակում կատարելիս", "swap_providers": "Փոխանակման մատակարարներ", + "swap_unavailable_needs_network_wallet": "Այս հասցեի տեսակը չի կարող գումարներ ստանալ փոխանակումից: Այս հասցեին ուղարկելու համար ձեզ հարկավոր է ${network} դրամապանակ:", + "swap_unavailable_switch_to_network": "Այս հասցեի տեսակը չի կարող գումարներ ստանալ փոխանակումից: Շարունակելու համար անցեք ձեր ${network} դրամապանակին:", "sweeping_wallet": "Դրամապանակի սվիպինգ", "sweeping_wallet_alert": "Սա երկար չի տևի։ ՄԻ ԼՔԵՔ ԱՅՍ ԷԿՐԱՆԸ, ՀԱԿԱՌԱԿ ԴԵՊՔՈՒՄ ՄԱՔՐՎՈՂ ՄԻՋՈՑՆԵՐԸ ԿԱՐՈՂ ԵՆ ԿՈՐՉԵԼ։", "swipe_to_bridge": "Սահեցրեք՝ կամրջելու համար", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "ՀԱՄԱԺԱՄԱՆԱԿԵՑՎՈՒՄ Է", "sync_status_timed_out": "ԺԱՄԱՆԱԿԸ ՍՊԱՌՎԵՑ", "sync_status_unsupported": "ՉԱՋԱԿՑՎՈՂ ՀԱՆԳՈՒՅՑ", + "sync_synced": "Համաժամեցված է", "sync_syncing": "Համաժամեցում", "sync_timed_out": "Համաժամացման ժամանակը սպառվել է", "sync_unsupported_node": "Չաջակցվող հանգույց", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index b8be9a732..16fcb4881 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -93,6 +93,7 @@ "available": "Tersedia", "available_balance": "Saldo Tersedia", "available_balance_description": "“Saldo Tersedia” atau “Saldo Terkonfirmasi” adalah dana yang dapat langsung dibelanjakan. Jika dana muncul di saldo bawah tetapi tidak di saldo atas, maka Anda harus menunggu beberapa menit agar dana masuk mendapatkan konfirmasi jaringan tambahan. Setelah mendapatkan lebih banyak konfirmasi, dana tersebut akan dapat dibelanjakan.", + "available_balance_short": "Rata-rata: ${amount}", "avg_savings": "Rata-rata Penghematan", "avl": "Rata-rata", "awaitDAppProcessing": "Mohon tunggu hingga dApp selesai memproses.", @@ -1152,6 +1153,8 @@ "swap_id": "ID Swap", "swap_provider_initial_desc": "Pilih jenis penyedia swap yang Anda inginkan untuk digunakan saat melakukan swap", "swap_providers": "Penyedia swap", + "swap_unavailable_needs_network_wallet": "Jenis alamat ini tidak dapat menerima dana dari swap. Anda memerlukan dompet ${network} untuk mengirim ke alamat ini.", + "swap_unavailable_switch_to_network": "Jenis alamat ini tidak dapat menerima dana dari swap. Beralih ke dompet ${network} Anda untuk melanjutkan.", "sweeping_wallet": "Dompet sweep", "sweeping_wallet_alert": "Ini seharusnya tidak memakan waktu lama. JANGAN TINGGALKAN LAYAR INI ATAU DANA YANG DISAPU DAPAT HILANG.", "swipe_to_bridge": "Geser untuk menjembatani", @@ -1184,6 +1187,7 @@ "sync_status_syncronizing": "MENYINKRONKAN", "sync_status_timed_out": "WAKTU HABIS", "sync_status_unsupported": "NODE TIDAK DIDUKUNG", + "sync_synced": "Disinkronkan", "sync_syncing": "Menyinkronkan", "sync_timed_out": "Sinkronisasi Habis Waktu", "sync_unsupported_node": "Node tidak didukung", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 820edc590..a7f73b629 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -93,6 +93,7 @@ "available": "Disponibile", "available_balance": "Saldo disponibile", "available_balance_description": "Il “Saldo disponibile” o “Saldo confermato” sono fondi che possono essere spesi immediatamente. Se i fondi compaiono nel saldo in basso ma non in quello in alto, devi attendere qualche minuto affinché i fondi in arrivo ottengano ulteriori conferme di rete. Dopo aver ricevuto più conferme, saranno spendibili.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Risparmio medio", "avl": "Avl", "awaitDAppProcessing": "Attendi che la dApp completi l'elaborazione.", @@ -1150,6 +1151,8 @@ "swap_id": "ID swap", "swap_provider_initial_desc": "Seleziona il tipo di fornitore di swap che preferisci utilizzare quando effettui uno swap in", "swap_providers": "Provider di swap", + "swap_unavailable_needs_network_wallet": "Questo tipo di indirizzo non può ricevere fondi da uno swap. Hai bisogno di un portafoglio ${network} per inviare a questo indirizzo.", + "swap_unavailable_switch_to_network": "Questo tipo di indirizzo non può ricevere fondi da uno swap. Passa al tuo portafoglio ${network} per continuare.", "sweeping_wallet": "Svuotamento del portafoglio", "sweeping_wallet_alert": "Questo non dovrebbe richiedere molto tempo. NON LASCIARE QUESTA SCHERMATA O I FONDI SPOSTATI POTREBBERO ANDARE PERSI.", "swipe_to_bridge": "Scorri per il bridge", @@ -1182,6 +1185,7 @@ "sync_status_syncronizing": "SINCRONIZZAZIONE IN CORSO", "sync_status_timed_out": "TEMPO SCADUTO", "sync_status_unsupported": "NODO NON SUPPORTATO", + "sync_synced": "Sincronizzato", "sync_syncing": "Sincronizzazione in corso", "sync_timed_out": "Sincronizzazione scaduta", "sync_unsupported_node": "Nodo non supportato", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 57f464120..8acfdaf15 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -93,6 +93,7 @@ "available": "利用可能", "available_balance": "利用可能残高", "available_balance_description": "「利用可能な残高」または「承認済み残高」は、すぐに使用できる資金です。下の残高には表示されているのに上の残高に表示されない場合は、受信した資金がネットワークでさらに承認(確認)されるまで数分待つ必要があります。承認数が増えると、使用できるようになります。", + "available_balance_short": "平均: ${amount}", "avg_savings": "平均節約額", "avl": "アヴル", "awaitDAppProcessing": "dAppの処理が完了するまでお待ちください。", @@ -1150,6 +1151,8 @@ "swap_id": "スワップID", "swap_provider_initial_desc": "スワップイン時に使用するスワッププロバイダーの種類を選択してください", "swap_providers": "スワッププロバイダー", + "swap_unavailable_needs_network_wallet": "このアドレスタイプはスワップから資金を受け取ることができません。このアドレスに送信するには ${network} ウォレットが必要です。", + "swap_unavailable_switch_to_network": "このアドレスタイプはスワップから資金を受け取ることができません。 ${network} ウォレットに切り替えて続行してください。", "sweeping_wallet": "スイーピングウォレット", "sweeping_wallet_alert": "すぐに完了します。この画面から離れないでください。離れると、スイープした資金が失われる可能性があります。", "swipe_to_bridge": "スワイプしてブリッジ", @@ -1182,6 +1185,7 @@ "sync_status_syncronizing": "同期中", "sync_status_timed_out": "タイムアウト", "sync_status_unsupported": "未対応のノード", + "sync_synced": "同期済み", "sync_syncing": "同期中", "sync_timed_out": "同期がタイムアウトしました", "sync_unsupported_node": "未対応のノード", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index f57f301fb..2777da024 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -93,6 +93,7 @@ "available": "사용 가능", "available_balance": "사용 가능 잔액", "available_balance_description": "“사용 가능 잔액” 또는 “확정 잔액”은 즉시 사용할 수 있는 자금입니다. 자금이 아래 잔액에는 표시되지만 위 잔액에는 표시되지 않는 경우, 입금된 자금이 네트워크에서 더 많은 컨펌(확인)을 받을 때까지 몇 분 정도 기다려야 합니다. 더 많은 컨펌을 받은 후에는 사용할 수 있습니다.", + "available_balance_short": "평균: ${amount}", "avg_savings": "평균 절감액", "avl": "Avl", "awaitDAppProcessing": "dApp의 처리가 완료될 때까지 잠시 기다려 주세요.", @@ -1149,6 +1150,8 @@ "swap_id": "스왑 ID", "swap_provider_initial_desc": "스왑 인할 때 사용하려는 스왑 제공자 유형을 선택하세요.", "swap_providers": "스왑 제공업체", + "swap_unavailable_needs_network_wallet": "이 주소 유형은 스왑에서 자금을 받을 수 없습니다. 이 주소로 보내려면 ${network} 지갑이 필요합니다.", + "swap_unavailable_switch_to_network": "이 주소 유형은 스왑에서 자금을 받을 수 없습니다. 계속하려면 ${network} 지갑으로 전환하세요.", "sweeping_wallet": "지갑 스윕", "sweeping_wallet_alert": "오래 걸리지 않습니다. 이 화면을 떠나지 마세요. 그렇지 않으면 스윕된 자금이 손실될 수 있습니다.", "swipe_to_bridge": "스와이프하여 브리지", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "동기화 중", "sync_status_timed_out": "시간 초과", "sync_status_unsupported": "지원되지 않는 노드", + "sync_synced": "동기화됨", "sync_syncing": "동기화 중", "sync_timed_out": "동기화 시간이 초과되었습니다", "sync_unsupported_node": "지원되지 않는 노드", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 682846d42..e8e9eac61 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -93,6 +93,7 @@ "available": "ရရှိနိုင်သည်", "available_balance": "ရရှိနိုင်သော လက်ကျန်", "available_balance_description": "“Available Balance” သို့မဟုတ် “Confirmed Balance” သည် ချက်ချင်းသုံးစွဲနိုင်သော လက်ကျန်ငွေဖြစ်သည်။ လက်ကျန်အောက်ပိုင်းတွင်သာ ဝင်လာသော်လည်း အပေါ်ပိုင်းလက်ကျန်တွင် မပေါ်သေးပါက ကွန်ယက်အတည်ပြုချက် (network confirmations) ပိုမိုရရှိရန် မိနစ်အနည်းငယ် စောင့်ရပါမည်။ အတည်ပြုချက်များ ပိုမိုရရှိပြီးနောက် ထိုငွေများကို သုံးစွဲနိုင်ပါလိမ့်မည်။", + "available_balance_short": "Avl- ${amount}", "avg_savings": "ပျမ်းမျှ ချွေတာမှု", "avl": "Avl", "awaitDAppProcessing": "ကျေးဇူးပြု၍ dApp ၏ စီမံဆောင်ရွက်မှု ပြီးဆုံးသည်အထိ စောင့်ပါ။", @@ -1149,6 +1150,8 @@ "swap_id": "Swap ID", "swap_provider_initial_desc": "Swap လုပ်ရာတွင် သင်အသုံးပြုလိုသည့် swap provider အမျိုးအစားကို ရွေးချယ်ပါ။", "swap_providers": "Swap ဝန်ဆောင်မှုပေးသူများ", + "swap_unavailable_needs_network_wallet": "ဤလိပ်စာအမျိုးအစားသည် လဲလှယ်မှုတစ်ခုမှ ရံပုံငွေများကို လက်ခံမရနိုင်ပါ။ ဤလိပ်စာသို့ ပေးပို့ရန် ${network} ပိုက်ဆံအိတ်တစ်ခု လိုအပ်ပါသည်။", + "swap_unavailable_switch_to_network": "ဤလိပ်စာအမျိုးအစားသည် လဲလှယ်မှုတစ်ခုမှ ရံပုံငွေများကို လက်ခံမရနိုင်ပါ။ ရှေ့ဆက်ရန် သင်၏ ${network} ပိုက်ဆံအိတ်သို့ ပြောင်းပါ။", "sweeping_wallet": "ပိုက်ဆံအိတ် ရှင်းလင်းခြင်း", "sweeping_wallet_alert": "ဒါက ကြာကြာမခံသင့်ပါဘူး။ ဒီစခရင်ကနေ မထွက်ပါနဲ့၊ မဟုတ်ရင် sweep လုပ်ထားတဲ့ ရန်ပုံငွေတွေ ပျောက်ဆုံးနိုင်ပါတယ်။", "swipe_to_bridge": "Bridge လုပ်ရန် ပွတ်ဆွဲပါ", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "ထပ်တူချိန်ညှိနေသည်", "sync_status_timed_out": "အချိန်ကုန်သွားသည်", "sync_status_unsupported": "မထောက်ပံ့သော Node", + "sync_synced": "ထပ်တူပြုထားသည်။", "sync_syncing": "စင့်ခ်လုပ်နေသည်", "sync_timed_out": "စင့်ခ်ချိန်ကုန်သွားပါပြီ", "sync_unsupported_node": "မပံ့ပိုးထားသော node", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 333e30026..d9d677a95 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -93,6 +93,7 @@ "available": "Beschikbaar", "available_balance": "Beschikbaar saldo", "available_balance_description": "Het “Beschikbare saldo” of “Bevestigde saldo” zijn fondsen die direct kunnen worden uitgegeven. Als fondsen in het lagere saldo verschijnen maar niet in het bovenste saldo, dan moet je een paar minuten wachten tot de inkomende fondsen meer netwerkbevestigingen krijgen. Daarna kan het worden uitgegeven.", + "available_balance_short": "Gem.: ${amount}", "avg_savings": "Gem. besparingen", "avl": "Gem", "awaitDAppProcessing": "Wacht tot de dApp klaar is met verwerken.", @@ -1149,6 +1150,8 @@ "swap_id": "Swap-ID", "swap_provider_initial_desc": "Selecteer het type swapprovider dat je wilt gebruiken bij het swappen", "swap_providers": "Swapproviders", + "swap_unavailable_needs_network_wallet": "Dit adrestype kan geen geld ontvangen van een swap. U heeft een portemonnee van ${network} nodig om naar dit adres te kunnen verzenden.", + "swap_unavailable_switch_to_network": "Dit adrestype kan geen geld ontvangen van een swap. Schakel over naar uw ${network}-portemonnee om door te gaan.", "sweeping_wallet": "Wallet wordt geveegd", "sweeping_wallet_alert": "Dit duurt niet lang. VERLAAT DIT SCHERM NIET, ANDERS KUNNEN DE FONDSEN VERLOREN GAAN.", "swipe_to_bridge": "Veeg om te bridgen", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "SYNCHRONISEREN", "sync_status_timed_out": "TIME-OUT", "sync_status_unsupported": "NIET-ONDERSTEUNDE NODE", + "sync_synced": "Gesynchroniseerd", "sync_syncing": "Synchroniseren", "sync_timed_out": "Synchronisatie time-out", "sync_unsupported_node": "Niet-ondersteunde node", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 2cc48b0dc..8650bd0dc 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -93,6 +93,7 @@ "available": "Dostępne", "available_balance": "Dostępne saldo", "available_balance_description": "„Dostępne saldo” lub „Potwierdzone saldo” to środki, które można wydać od razu. Jeśli środki pojawiają się w dolnym saldzie, ale nie w górnym, musisz poczekać kilka minut, aż przychodzące środki uzyskają więcej potwierdzeń sieci. Gdy uzyskają więcej potwierdzeń, będzie można je wydać.", + "available_balance_short": "Średnia: ${amount}", "avg_savings": "Śr. oszczędności", "avl": "Avl", "awaitDAppProcessing": "Proszę poczekać, aż dApp zakończy przetwarzanie.", @@ -1149,6 +1150,8 @@ "swap_id": "ID wymiany", "swap_provider_initial_desc": "Wybierz typ dostawcy swapów, którego wolisz używać podczas swapowania w", "swap_providers": "Dostawcy wymiany", + "swap_unavailable_needs_network_wallet": "Ten typ adresu nie może otrzymywać środków z wymiany. Aby wysłać przesyłkę na ten adres, potrzebujesz portfela ${network}.", + "swap_unavailable_switch_to_network": "Ten typ adresu nie może otrzymywać środków z wymiany. Aby kontynuować, przejdź do portfela ${network}.", "sweeping_wallet": "Opróżnianie portfela", "sweeping_wallet_alert": "To nie powinno zająć dużo czasu. NIE OPUSZCZAJ TEGO EKRANU, W PRZECIWNYM RAZIE ZAMIATANE ŚRODKI MOGĄ ZOSTAĆ UTRACONE.", "swipe_to_bridge": "Przesuń, aby zmostkować", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "SYNCHRONIZOWANIE", "sync_status_timed_out": "PRZEKROCZONO LIMIT CZASU", "sync_status_unsupported": "NIEOBSŁUGIWANY WĘZEŁ", + "sync_synced": "Zsynchronizowane", "sync_syncing": "Synchronizowanie", "sync_timed_out": "Przekroczono limit czasu synchronizacji", "sync_unsupported_node": "Nieobsługiwany węzeł", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 081c372b7..2a392da2b 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -93,6 +93,7 @@ "available": "Disponível", "available_balance": "Saldo disponível", "available_balance_description": "O “Saldo Disponível” ou “Saldo Confirmado” são fundos que podem ser gastos imediatamente. Se os fundos aparecerem no saldo inferior, mas não no saldo superior, você deve aguardar alguns minutos para que os fundos recebidos obtenham mais confirmações na rede. Depois que tiverem mais confirmações, eles poderão ser gastos.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Poupança média", "avl": "Avl", "awaitDAppProcessing": "Por favor, aguarde o dApp concluir o processamento.", @@ -1151,6 +1152,8 @@ "swap_id": "ID da troca", "swap_provider_initial_desc": "Selecione o tipo de provedor de swap que você prefere usar ao fazer swaps em", "swap_providers": "Provedores de swap", + "swap_unavailable_needs_network_wallet": "Este tipo de endereço não pode receber fundos de um swap. Você precisa de uma carteira ${network} para enviar para este endereço.", + "swap_unavailable_switch_to_network": "Este tipo de endereço não pode receber fundos de um swap. Mude para sua carteira ${network} para continuar.", "sweeping_wallet": "Carteira de varredura", "sweeping_wallet_alert": "Isso não deve demorar muito. NÃO SAIA DESTA TELA OU OS FUNDOS VARRIDOS PODEM SER PERDIDOS.", "swipe_to_bridge": "Deslize para fazer bridge", @@ -1183,6 +1186,7 @@ "sync_status_syncronizing": "SINCRONIZANDO", "sync_status_timed_out": "TEMPO ESGOTADO", "sync_status_unsupported": "NÓ NÃO SUPORTADO", + "sync_synced": "Sincronizado", "sync_syncing": "Sincronizando", "sync_timed_out": "Tempo limite da sincronização esgotado", "sync_unsupported_node": "Nó não suportado", diff --git a/res/values/strings_pt_BR.arb b/res/values/strings_pt_BR.arb index f43bdf530..51e816979 100644 --- a/res/values/strings_pt_BR.arb +++ b/res/values/strings_pt_BR.arb @@ -88,6 +88,7 @@ "automatic": "Automático", "available_balance": "Saldo disponível", "available_balance_description": "O “Saldo disponível” ou “Saldo confirmado” são fundos que podem ser gastos imediatamente. Se os fundos aparecerem no saldo inferior, mas não no saldo superior, você deve aguardar alguns minutos para que os fundos recebidos obtenham mais confirmações na rede. Depois que tiverem mais confirmações, eles poderão ser gastos.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Economia média", "awaitDAppProcessing": "Aguarde até que o dApp termine de processar.", "awaiting_payment_confirmation": "Aguardando confirmação do pagamento", @@ -1099,6 +1100,8 @@ "swap_id": "ID do Swap", "swap_provider_initial_desc": "Selecione o tipo de provedor de swap que você prefere usar ao realizar swaps", "swap_providers": "Provedores de swap", + "swap_unavailable_needs_network_wallet": "Este tipo de endereço não pode receber fundos de um swap. Você precisa de uma carteira ${network} para enviar para este endereço.", + "swap_unavailable_switch_to_network": "Este tipo de endereço não pode receber fundos de um swap. Mude para sua carteira ${network} para continuar.", "sweeping_wallet": "Carteira em varredura", "sweeping_wallet_alert": "Isso não deve demorar muito. NÃO SAIA DESTA TELA OU OS FUNDOS VARRIDOS PODERÃO SER PERDIDOS.", "swipe_to_send": "Deslize para enviar", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index ee94d226f..1bdeee2a1 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -93,6 +93,7 @@ "available": "Доступно", "available_balance": "Доступный баланс", "available_balance_description": "«Доступный баланс» или «Подтверждённый баланс» — это средства, которые можно потратить сразу. Если средства отображаются в нижнем балансе, но не в верхнем, значит, нужно подождать несколько минут, пока входящие средства получат больше подтверждений сети. После получения дополнительных подтверждений их можно будет потратить.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Средняя экономия", "avl": "Авл", "awaitDAppProcessing": "Пожалуйста, подождите, пока dApp завершит обработку.", @@ -1150,6 +1151,8 @@ "swap_id": "ID обмена", "swap_provider_initial_desc": "Выберите тип провайдера свопа, который вы предпочитаете использовать при свопе в", "swap_providers": "Провайдеры обмена", + "swap_unavailable_needs_network_wallet": "Этот тип адреса не может получать средства от свопа. Для отправки на этот адрес вам понадобится кошелек ${network}.", + "swap_unavailable_switch_to_network": "Этот тип адреса не может получать средства от свопа. Чтобы продолжить, переключитесь на свой кошелек ${network}.", "sweeping_wallet": "Сканирование кошелька", "sweeping_wallet_alert": "Это не должно занять много времени. НЕ ПОКИДАЙТЕ ЭТОТ ЭКРАН, ИНАЧЕ ПЕРЕНЕСЁННЫЕ СРЕДСТВА МОГУТ БЫТЬ ПОТЕРЯНЫ.", "swipe_to_bridge": "Проведите, чтобы выполнить перенос через мост", @@ -1182,6 +1185,7 @@ "sync_status_syncronizing": "СИНХРОНИЗАЦИЯ", "sync_status_timed_out": "ИСТЕКЛО ВРЕМЯ ОЖИДАНИЯ", "sync_status_unsupported": "НЕПОДДЕРЖИВАЕМЫЙ УЗЕЛ", + "sync_synced": "Синхронизировано", "sync_syncing": "Синхронизация", "sync_timed_out": "Время ожидания синхронизации истекло", "sync_unsupported_node": "Неподдерживаемый узел", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 9baf75823..b8e98d11b 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -93,6 +93,7 @@ "available": "พร้อมใช้งาน", "available_balance": "ยอดคงเหลือที่ใช้ได้", "available_balance_description": "“ยอดคงเหลือที่ใช้ได้” หรือ “ยอดคงเหลือที่ยืนยันแล้ว” คือเงินที่สามารถใช้จ่ายได้ทันที หากเงินปรากฏในยอดคงเหลือด้านล่างแต่ไม่ปรากฏในยอดคงเหลือด้านบน คุณต้องรอสักครู่เพื่อให้เงินที่เข้ามาได้รับการยืนยันจากเครือข่ายเพิ่มขึ้น เมื่อได้รับการยืนยันมากขึ้นแล้ว เงินนั้นจะสามารถใช้จ่ายได้", + "available_balance_short": "จำนวน: ${amount}", "avg_savings": "การประหยัดเฉลี่ย", "avl": "เฉลี่ย", "awaitDAppProcessing": "โปรดรอให้ dApp ประมวลผลให้เสร็จสิ้น", @@ -1149,6 +1150,8 @@ "swap_id": "รหัส Swap", "swap_provider_initial_desc": "เลือกประเภทผู้ให้บริการ Swap ที่คุณต้องการใช้เมื่อทำการ Swap", "swap_providers": "ผู้ให้บริการสวอป", + "swap_unavailable_needs_network_wallet": "ที่อยู่ประเภทนี้ไม่สามารถรับเงินจากการแลกเปลี่ยนได้ คุณต้องมีกระเป๋าเงิน ${network} เพื่อส่งไปยังที่อยู่นี้", + "swap_unavailable_switch_to_network": "ที่อยู่ประเภทนี้ไม่สามารถรับเงินจากการแลกเปลี่ยนได้ เปลี่ยนไปใช้กระเป๋าเงิน ${network} ของคุณเพื่อดำเนินการต่อ", "sweeping_wallet": "กระเป๋าสตางค์สำหรับกวาดเหรียญ", "sweeping_wallet_alert": "การดำเนินการนี้ใช้เวลาไม่นาน ห้ามออกจากหน้าจอนี้ มิฉะนั้นเงินที่กวาดอาจสูญหาย", "swipe_to_bridge": "ปัดเพื่อบริดจ์", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "กำลังซิงโครไนซ์", "sync_status_timed_out": "หมดเวลา", "sync_status_unsupported": "โหนดที่ไม่รองรับ", + "sync_synced": "ซิงค์แล้ว", "sync_syncing": "กำลังซิงค์", "sync_timed_out": "การซิงค์หมดเวลา", "sync_unsupported_node": "โหนดที่ไม่รองรับ", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 311e762dd..86a0d4519 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -93,6 +93,7 @@ "available": "Available", "available_balance": "Magagamit na Balanse", "available_balance_description": "Ang “Magagamit na Balanse” o “Nakumpirmang Balanse” ay mga pondong maaari nang gastusin kaagad. Kung lumalabas ang mga pondo sa mas mababang balanse ngunit wala sa itaas na balanse, kailangan mong maghintay ng ilang minuto para makakuha ng mas maraming kumpirmasyon sa network ang mga papasok na pondo. Kapag nakakuha na sila ng mas maraming kumpirmasyon, maaari na silang gastusin.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Avg. Matitipid", "avl": "Avl", "awaitDAppProcessing": "Mangyaring maghintay hanggang matapos ang pagproseso ng dApp.", @@ -1149,6 +1150,8 @@ "swap_id": "Swap ID", "swap_provider_initial_desc": "Piliin ang uri ng swap provider na mas gusto mong gamitin kapag nagsa-swap", "swap_providers": "Mga provider ng swap", + "swap_unavailable_needs_network_wallet": "Ang uri ng address na ito ay hindi makakatanggap ng mga pondo mula sa isang swap. Kailangan mo ng ${network} wallet upang maipadala sa address na ito.", + "swap_unavailable_switch_to_network": "Ang uri ng address na ito ay hindi makakatanggap ng mga pondo mula sa isang swap. Lumipat sa iyong ${network} wallet upang magpatuloy.", "sweeping_wallet": "Sweeping wallet", "sweeping_wallet_alert": "Hindi ito dapat magtagal. HUWAG UMALIS SA SCREEN NA ITO O MAARING MAWALA ANG MGA NA-SWEEP NA PONDO.", "swipe_to_bridge": "Mag-swipe para mag-bridge", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "NAGSI-SYNC", "sync_status_timed_out": "NAG-TIMEOUT", "sync_status_unsupported": "HINDI SUPORTADONG NODE", + "sync_synced": "Naka-sync", "sync_syncing": "Nagsi-sync", "sync_timed_out": "Nag-time out ang Sync", "sync_unsupported_node": "Hindi suportadong node", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 88debbd7d..a2f6a18b6 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -93,6 +93,7 @@ "available": "Kullanılabilir", "available_balance": "Kullanılabilir Bakiye", "available_balance_description": "“Kullanılabilir Bakiye” veya “Onaylanmış Bakiye”, hemen harcanabilen fonlardır. Fonlar alt bakiyede görünüp üst bakiyede görünmüyorsa, gelen fonların ağda daha fazla onay alması için birkaç dakika beklemeniz gerekir. Daha fazla onay aldıktan sonra harcanabilir olacaktır.", + "available_balance_short": "Ortalama: ${amount}", "avg_savings": "Ort. Tasarruf", "avl": "Avl", "awaitDAppProcessing": "Lütfen dApp'in işlemi tamamlamasını bekleyin.", @@ -1149,6 +1150,8 @@ "swap_id": "Swap Kimliği", "swap_provider_initial_desc": "Swap yaparken kullanmayı tercih ettiğiniz swap sağlayıcı türünü seçin", "swap_providers": "Takas sağlayıcıları", + "swap_unavailable_needs_network_wallet": "Bu adres türü takastan para alamaz. Bu adrese göndermek için bir ${network} cüzdanına ihtiyacınız var.", + "swap_unavailable_switch_to_network": "Bu adres türü takastan para alamaz. Devam etmek için ${network} cüzdanınıza geçin.", "sweeping_wallet": "Cüzdan süpürme", "sweeping_wallet_alert": "Bu uzun sürmemeli. BU EKRANDAN AYRILMAYIN, AKSİ TAKDİRDE SÜPÜRÜLEN FONLAR KAYBOLABİLİR.", "swipe_to_bridge": "Köprülemek için kaydırın", @@ -1181,6 +1184,7 @@ "sync_status_syncronizing": "SENKRONİZE EDİLİYOR", "sync_status_timed_out": "ZAMAN AŞIMINA UĞRADI", "sync_status_unsupported": "DESTEKLENMEYEN DÜĞÜM", + "sync_synced": "Senkronize edildi", "sync_syncing": "Senkronize ediliyor", "sync_timed_out": "Senkronizasyon zaman aşımına uğradı", "sync_unsupported_node": "Desteklenmeyen düğüm", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 88ba22417..93ae72c1e 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -93,6 +93,7 @@ "available": "Доступно", "available_balance": "Доступний баланс", "available_balance_description": "«Доступний баланс» або «Підтверджений баланс» — це кошти, які можна витратити негайно. Якщо кошти відображаються в нижньому балансі, але не у верхньому, потрібно зачекати кілька хвилин, доки вхідні кошти отримають більше підтверджень мережі. Після отримання додаткових підтверджень їх можна буде витратити.", + "available_balance_short": "Середня сума: ${amount}", "avg_savings": "Сер. заощадження", "avl": "Avl", "awaitDAppProcessing": "Будь ласка, зачекайте, доки dApp завершить обробку.", @@ -1150,6 +1151,8 @@ "swap_id": "ID обміну", "swap_provider_initial_desc": "Виберіть тип провайдера свопу, який ви бажаєте використовувати під час обміну", "swap_providers": "Провайдери обміну", + "swap_unavailable_needs_network_wallet": "Цей тип адреси не може отримати кошти від обміну. Щоб надіслати на цю адресу, вам потрібен гаманець ${network}.", + "swap_unavailable_switch_to_network": "Цей тип адреси не може отримати кошти від обміну. Щоб продовжити, перейдіть на гаманець ${network}.", "sweeping_wallet": "Змітання гаманця", "sweeping_wallet_alert": "Це не повинно зайняти багато часу. НЕ ЗАЛИШАЙТЕ ЦЕЙ ЕКРАН, ІНАКШЕ ЗМЕТЕНІ КОШТИ МОЖУТЬ БУТИ ВТРАЧЕНІ.", "swipe_to_bridge": "Проведіть, щоб перенести між мережами", @@ -1182,6 +1185,7 @@ "sync_status_syncronizing": "СИНХРОНІЗУЄТЬСЯ", "sync_status_timed_out": "ЧАС ВИЙШОВ", "sync_status_unsupported": "НЕПІДТРИМУВАНИЙ ВУЗОЛ", + "sync_synced": "Синхронізовано", "sync_syncing": "Синхронізація", "sync_timed_out": "Час очікування синхронізації вичерпано", "sync_unsupported_node": "Непідтримуваний вузол", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index b583f5ec7..80e93d207 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -93,6 +93,7 @@ "available": "دستیاب", "available_balance": "دستیاب بیلنس", "available_balance_description": "”دستیاب بیلنس” یا ”تصدیق شدہ بیلنس” وہ فنڈز ہیں جنہیں فوراً خرچ کیا جا سکتا ہے۔ اگر فنڈز نیچے والے بیلنس میں نظر آئیں لیکن اوپر والے بیلنس میں نہیں، تو آپ کو آنے والے فنڈز کے مزید نیٹ ورک کنفرمیشنز حاصل ہونے کے لیے چند منٹ انتظار کرنا ہوگا۔ جب انہیں مزید کنفرمیشنز مل جائیں گی تو وہ خرچ کے قابل ہو جائیں گے۔", + "available_balance_short": "Avl: ${amount}", "avg_savings": "اوسط بچت", "avl": "Avl", "awaitDAppProcessing": "براہِ کرم dApp کی پروسیسنگ مکمل ہونے تک انتظار کریں۔", @@ -1151,6 +1152,8 @@ "swap_id": "سواپ آئی ڈی", "swap_provider_initial_desc": "سواپ کرتے وقت استعمال کے لیے اپنی پسند کے سواپ فراہم کنندہ کی قسم منتخب کریں", "swap_providers": "سویپ فراہم کنندگان", + "swap_unavailable_needs_network_wallet": "ایڈریس کی یہ قسم سویپ سے فنڈز وصول نہیں کر سکتی۔ اس پتے پر بھیجنے کے لیے آپ کو ایک ${network} والیٹ کی ضرورت ہے۔", + "swap_unavailable_switch_to_network": "ایڈریس کی یہ قسم سویپ سے فنڈز وصول نہیں کر سکتی۔ جاری رکھنے کے لیے اپنے ${network} والیٹ پر جائیں۔", "sweeping_wallet": "والٹ سویپ کرنا", "sweeping_wallet_alert": "اس میں زیادہ وقت نہیں لگنا چاہیے۔ اس اسکرین کو مت چھوڑیں، ورنہ سویپ کیے گئے فنڈز ضائع ہو سکتے ہیں۔", "swipe_to_bridge": "برج کرنے کے لیے سوائپ کریں", @@ -1183,6 +1186,7 @@ "sync_status_syncronizing": "ہم آہنگ ہو رہا ہے", "sync_status_timed_out": "وقت ختم ہو گیا", "sync_status_unsupported": "غیر معاون نوڈ", + "sync_synced": "مطابقت پذیر", "sync_syncing": "ہم آہنگ ہو رہا ہے", "sync_timed_out": "سنک کا وقت ختم ہو گیا", "sync_unsupported_node": "غیر معاون نوڈ", diff --git a/res/values/strings_vi.arb b/res/values/strings_vi.arb index 75a581b81..68fd9afd1 100644 --- a/res/values/strings_vi.arb +++ b/res/values/strings_vi.arb @@ -93,6 +93,7 @@ "available": "Khả dụng", "available_balance": "Số dư khả dụng", "available_balance_description": "“Số dư khả dụng” hoặc “Số dư đã xác nhận” là số tiền có thể chi tiêu ngay lập tức. Nếu tiền xuất hiện ở số dư phía dưới nhưng không xuất hiện ở số dư phía trên, thì bạn phải đợi vài phút để khoản tiền đến có thêm xác nhận từ mạng. Sau khi có thêm xác nhận, chúng sẽ có thể chi tiêu.", + "available_balance_short": "Trung bình: ${amount}", "avg_savings": "Tiết kiệm TB", "avl": "trung bình", "awaitDAppProcessing": "Vui lòng đợi dApp xử lý xong.", @@ -1150,6 +1151,8 @@ "swap_id": "ID Swap", "swap_provider_initial_desc": "Chọn loại nhà cung cấp hoán đổi mà bạn muốn sử dụng khi hoán đổi trong ứng dụng", "swap_providers": "Nhà cung cấp hoán đổi", + "swap_unavailable_needs_network_wallet": "Loại địa chỉ này không thể nhận tiền từ trao đổi. Bạn cần có ví ${network} để gửi tới địa chỉ này.", + "swap_unavailable_switch_to_network": "Loại địa chỉ này không thể nhận tiền từ trao đổi. Chuyển sang ví ${network} của bạn để tiếp tục.", "sweeping_wallet": "Quét ví", "sweeping_wallet_alert": "Việc này sẽ không mất nhiều thời gian. KHÔNG RỜI KHỎI MÀN HÌNH NÀY, NẾU KHÔNG SỐ TIỀN ĐÃ QUÉT CÓ THỂ BỊ MẤT.", "swipe_to_bridge": "Vuốt để bắc cầu", @@ -1182,6 +1185,7 @@ "sync_status_syncronizing": "ĐANG ĐỒNG BỘ HÓA", "sync_status_timed_out": "HẾT THỜI GIAN", "sync_status_unsupported": "NÚT KHÔNG ĐƯỢC HỖ TRỢ", + "sync_synced": "Đã đồng bộ hóa", "sync_syncing": "Đang đồng bộ", "sync_timed_out": "Đồng bộ hóa đã hết thời gian", "sync_unsupported_node": "Nút không được hỗ trợ", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 44a159e9c..6ca70f8e1 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -93,6 +93,7 @@ "available": "Ó wà", "available_balance": "Ìwọ̀ntúnwọ̀nsì tó wà", "available_balance_description": "“Iwọntunwọnsi Wa” tabi “Iwọntunwọnsi Ti a Jẹ́rìí” jẹ́ àwọn owó tí o lè na lẹ́sẹ̀kẹsẹ. Bí àwọn owó bá hàn ní iwọntunwọnsi ìsàlẹ̀ ṣùgbọ́n kì í hàn ní iwọntunwọnsi òkè, nígbà náà o gbọdọ̀ dúró fún ìṣẹ́jú díẹ̀ kí àwọn owó tí ń wọlé lè gba ìjẹ́rìí nẹ́tíwọ́ọ̀kì púpọ̀ síi. Lẹ́yìn tí wọ́n bá ti gba ìjẹ́rìí púpọ̀ síi, o lè na wọ́n.", + "available_balance_short": "Avl: ${amount}", "avg_savings": "Ìpamọ́ àpapọ̀", "avl": "Avl", "awaitDAppProcessing": "Jọ̀wọ́, dúró kí dApp parí ìṣiṣẹ́.", @@ -1150,6 +1151,8 @@ "swap_id": "ID Swap", "swap_provider_initial_desc": "Yan iru olupese swap ti o fẹ́ lò nígbà tí o bá ń swap sínú", "swap_providers": "Awọn olupese swap", + "swap_unavailable_needs_network_wallet": "Iru adirẹsi yii ko le gba owo lati swap kan. O nilo apamọwọ ${network} lati fi ranṣẹ si adirẹsi yii.", + "swap_unavailable_switch_to_network": "Iru adirẹsi yii ko le gba owo lati swap kan. Yipada si apamọwọ ${network} rẹ lati tẹsiwaju.", "sweeping_wallet": "Wallet ìkó", "sweeping_wallet_alert": "Eyi kò yẹ kí ó pẹ́. MÁ ṢE KÚRÒ LÓRÍ IBÓJÚ YÌÍ TÁBÍ OWÓ TÍ A TI SWEEP LÈ SỌ́NÙ.", "swipe_to_bridge": "Fà láti so ìjápọ̀", @@ -1182,6 +1185,7 @@ "sync_status_syncronizing": "Ń ṢÀMÚDỌ̀GBÀ", "sync_status_timed_out": "AKOKO TI PARI", "sync_status_unsupported": "NÓÒDÙ TI KÒ NI ÀTÌLẸ́YÌN", + "sync_synced": "Amuṣiṣẹpọ", "sync_syncing": "Ń ṣàtúnṣe", "sync_timed_out": "Akoko amuṣiṣẹpọ ti parí", "sync_unsupported_node": "Node tí kò ní ìtìlẹ́yìn", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index b8c0fa0e9..8e3256b97 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -93,6 +93,7 @@ "available": "可用", "available_balance": "可用余额", "available_balance_description": "“可用余额”或“确认余额”是指可立即花费的资金。如果资金显示在下方余额中但未显示在上方余额中,则需要等待几分钟,让转入资金获得更多网络确认。获得更多确认后,这些资金即可花费。", + "available_balance_short": "平均价值:${amount}", "avg_savings": "平均节省", "avl": "平均", "awaitDAppProcessing": "请稍候,等待 dApp 完成处理。", @@ -1150,6 +1151,8 @@ "swap_id": "兑换 ID", "swap_provider_initial_desc": "选择您在换入时偏好使用的兑换服务提供商类型", "swap_providers": "兑换服务提供商", + "swap_unavailable_needs_network_wallet": "此地址类型无法从交换中接收资金。您需要一个 ${network} 钱包才能发送到此地址。", + "swap_unavailable_switch_to_network": "此地址类型无法从交换中接收资金。切换到您的 ${network} 钱包以继续。", "sweeping_wallet": "正在归集钱包", "sweeping_wallet_alert": "这应该不会花很长时间。请勿离开此屏幕,否则被归集的资金可能会丢失。", "swipe_to_bridge": "滑动以跨链桥接", @@ -1182,6 +1185,7 @@ "sync_status_syncronizing": "同步中", "sync_status_timed_out": "超时", "sync_status_unsupported": "不受支持的节点", + "sync_synced": "已同步", "sync_syncing": "同步中", "sync_timed_out": "同步超时", "sync_unsupported_node": "不受支持的节点", diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index 3e7784b97..b71f25d1a 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -14,15 +14,15 @@ TYPES=($MONERO_COM $CAKEWALLET) APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="6.4.0" -MONERO_COM_BUILD_NUMBER=4164 +MONERO_COM_VERSION="6.4.1" +MONERO_COM_BUILD_NUMBER=4165 MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.4.0" -CAKEWALLET_BUILD_NUMBER=4419 +CAKEWALLET_VERSION="6.4.1" +CAKEWALLET_BUILD_NUMBER=4420 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_SCHEME="cakewallet" diff --git a/scripts/android/app_icon.sh b/scripts/android/app_icon.sh index c8af25c75..677d1c1a2 100755 --- a/scripts/android/app_icon.sh +++ b/scripts/android/app_icon.sh @@ -34,7 +34,7 @@ cp -a $APP_LOGO $APP_LOGO_DEST_PATH cp -a $ANDROID_ICON $ANDROID_ICON_DEST_PATH cp -a $ANDROID_ICON_SET/. $ANDROID_ICON_SET_DEST_PATH/ -set -x +set +x if [[ $GITHUB_HUH == "yeah" ]]; then pwd for file in $(find $CAKE_ROOT/android/app/src/main/res -name "*.png") $APP_LOGO $CAKEWALLET_PATH $ASSETS_DIR/images/cakewallet_logo.png $ASSETS_DIR/images/cakewallet_icon_*.png $(find $CAKEWALLET_ICON_SET_PATH -name "*.png"); do @@ -42,7 +42,4 @@ if [[ $GITHUB_HUH == "yeah" ]]; then bash $CAKE_ROOT/scripts/branch_icon.sh ${BRANCH_NAME}-asd $file &> /dev/null done fi -set +x - - - +set -x \ No newline at end of file diff --git a/scripts/android/docker/Dockerfile.mwebd b/scripts/android/docker/Dockerfile.mwebd index 7019742ce..856ac8c00 100644 --- a/scripts/android/docker/Dockerfile.mwebd +++ b/scripts/android/docker/Dockerfile.mwebd @@ -3,6 +3,8 @@ FROM --platform=linux/amd64 ${BASE_IMAGE} AS build RUN mkdir -p /w/scripts/android COPY pubspec_base.yaml /w/pubspec.yaml +COPY pubspec_overrides.yaml /w/pubspec_overrides.yaml +COPY pubspec_overrides.yaml /w/cw_mweb/pubspec_overrides.yaml COPY cw_mweb/pubspec.yaml /w/cw_mweb/pubspec.yaml COPY cw_mweb/ffigen_config.yaml /w/cw_mweb/ffigen_config.yaml COPY cw_mweb/go /w/cw_mweb/go diff --git a/scripts/android/docker/build.sh b/scripts/android/docker/build.sh index 74e213799..a6d7719ef 100755 --- a/scripts/android/docker/build.sh +++ b/scripts/android/docker/build.sh @@ -55,7 +55,7 @@ torch_ver="$(tinysha $SCRIPT_DIR/Dockerfile.torch $REPO_ROOT/scripts/prepare_tor reown_ver=$(tinysha $SCRIPT_DIR/Dockerfile.reown $REPO_ROOT/scripts/prepare_reown.sh $REPO_ROOT/scripts/android/build_reown_deps.sh) bitbox_ver=$(tinysha $SCRIPT_DIR/Dockerfile.bitbox $REPO_ROOT/scripts/build_bitbox_flutter.sh) monero_ver=$(tinysha $SCRIPT_DIR/Dockerfile.monero $REPO_ROOT/scripts/prepare_moneroc.sh $REPO_ROOT/scripts/android/build_monero_all.sh) -mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $(find $REPO_ROOT/cw_mweb/go -type f)) +mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $REPO_ROOT/pubspec_overrides.yaml $(find $REPO_ROOT/cw_mweb/go -type f)) zcash_ver=$(tinysha $SCRIPT_DIR/Dockerfile.zcash $REPO_ROOT/scripts/prepare_zcash.sh $REPO_ROOT/scripts/android/build_zcash.sh) decred_ver=$(tinysha $SCRIPT_DIR/Dockerfile.torch $SCRIPT_DIR/Dockerfile.decred $REPO_ROOT/scripts/android/build_decred.sh $REPO_ROOT/cw_decred/pubspec.yaml) echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $zcash_ver $decred_ver > /tmp/docker_build_versions diff --git a/scripts/compare_overrides.sh b/scripts/compare_overrides.sh new file mode 100755 index 000000000..c242e3e87 --- /dev/null +++ b/scripts/compare_overrides.sh @@ -0,0 +1,222 @@ +#!/bin/bash + +# usage: +# ./compare_overrides.sh GIT_HASH_A GIT_HASH_B + +set -e +cd "$(dirname "$0")/.." + +HASH_A=${1:?usage: ./compare_overrides.sh GIT_HASH_A GIT_HASH_B} +HASH_B=${2:?usage: ./compare_overrides.sh GIT_HASH_A GIT_HASH_B} + +sdk_git_url=https://github.com/dart-lang/sdk + +yq() { + go run github.com/mikefarah/yq/v4@latest "$@" +} + +normalize_url() { + echo "$1" | sed 's|\.git$||' +} + +repo_cache_dir() { + echo "scripts/.cache/repos/$(normalize_url "$1" | sed 's|https://github.com/||; s|/|_|g')" +} + +ensure_repo_clone() { + local url=$1 cache_dir=$2 + if [[ -d "${cache_dir}/.git" ]]; then + git -C "$cache_dir" fetch --quiet origin + else + mkdir -p "$(dirname "$cache_dir")" + if [[ "$(normalize_url "$url")" == "$sdk_git_url" ]]; then + git clone --quiet --filter=blob:none "$url" "$cache_dir" || return 1 + else + git clone --quiet "$url" "$cache_dir" || return 1 + fi + fi +} + +normalize_repo_path() { + local path=$1 + [[ -z "$path" || "$path" == "-" ]] && return 0 + echo "${path#./}" +} + +ensure_ref() { + local cache_dir=$1 ref=$2 + git -C "$cache_dir" cat-file -e "${ref}^{commit}" 2>/dev/null && return 0 + git -C "$cache_dir" fetch --quiet origin "$ref" 2>/dev/null || true + git -C "$cache_dir" cat-file -e "${ref}^{commit}" 2>/dev/null +} + +count_lines_at_ref() { + local cache_dir=$1 ref=$2 path=$3 + local repo_path file lines total=0 + + ensure_ref "$cache_dir" "$ref" || return 1 + repo_path=$(normalize_repo_path "$path") + + while IFS= read -r file; do + [[ -z "$file" ]] && continue + lines=$(git -C "$cache_dir" show "$ref:$file" 2>/dev/null | wc -l | tr -d ' ') + total=$((total + lines)) + done < <( + if [[ -n "$repo_path" ]]; then + git -C "$cache_dir" ls-tree -r --name-only "$ref" -- "$repo_path" 2>/dev/null + else + git -C "$cache_dir" ls-tree -r --name-only "$ref" 2>/dev/null + fi + ) + + echo "$total" +} + +print_ref_diff() { + local cache_dir=$1 old_ref=$2 new_ref=$3 old_path=$4 new_path=$5 + local repo_path diff_paths=() path + + ensure_ref "$cache_dir" "$old_ref" || { + echo " diff (old ref not found: $old_ref)" + return 1 + } + ensure_ref "$cache_dir" "$new_ref" || { + echo " diff (new ref not found: $new_ref)" + return 1 + } + + for path in "$old_path" "$new_path"; do + repo_path=$(normalize_repo_path "$path") + [[ -z "$repo_path" ]] && continue + [[ " ${diff_paths[*]} " == *" $repo_path "* ]] && continue + diff_paths+=("$repo_path") + done + + if [[ ${#diff_paths[@]} -eq 0 ]]; then + git -C "$cache_dir" diff --stat "$old_ref" "$new_ref" | sed 's/^/ /' + else + git -C "$cache_dir" diff --stat "$old_ref" "$new_ref" -- "${diff_paths[@]}" | sed 's/^/ /' + fi +} + +overrides_json_git() { + git show "${1}:pubspec_overrides.yaml" | yq -o=json '.dependency_overrides // {}' +} + +overrides_json_worktree() { + yq -o=json '.dependency_overrides // {}' pubspec_overrides.yaml +} + +print_git_fields() { + local pkg=$1 old_url=$2 new_url=$3 old_ref=$4 new_ref=$5 old_path=$6 new_path=$7 + echo " $pkg" + echo " url $old_url -> $new_url" + echo " ref $old_ref -> $new_ref" + echo " path $old_path -> $new_path" +} + +print_new_repo_stats() { + local new_url=$1 new_ref=$2 new_path=$3 cache_dir loc + + [[ "$new_url" == "-" || "$new_ref" == "-" ]] && return 0 + + cache_dir=$(repo_cache_dir "$new_url") + if ! ensure_repo_clone "$new_url" "$cache_dir"; then + echo " loc (clone failed)" + return 0 + fi + + if loc=$(count_lines_at_ref "$cache_dir" "$new_ref" "$new_path"); then + echo " loc $loc lines" + else + echo " loc (ref not found: $new_ref)" + fi +} + +print_changed_ref_stats() { + local url=$1 old_ref=$2 new_ref=$3 old_path=$4 new_path=$5 cache_dir + + [[ "$url" == "-" || "$old_ref" == "-" || "$new_ref" == "-" ]] && return 0 + + cache_dir=$(repo_cache_dir "$url") + if ! ensure_repo_clone "$url" "$cache_dir"; then + echo " diff (clone failed)" + return 0 + fi + + print_ref_diff "$cache_dir" "$old_ref" "$new_ref" "$old_path" "$new_path" +} + +compare_overrides_jq=' + def git($obj; $pkg): $obj[$pkg].git // null; + def fields($obj; $pkg): + git($obj; $pkg) as $g | + [($g.url // ""), ($g.ref // ""), ($g.path // "")]; + def dash($v): if $v == "" then "-" else $v end; +' + +resolved_a=$(git rev-parse "$HASH_A") +resolved_b=$(git rev-parse "$HASH_B") +resolved_head=$(git rev-parse HEAD) + +if [[ "$resolved_a" == "$resolved_b" ]]; then + json_a=$(overrides_json_git "$HASH_A") + json_b=$(overrides_json_git "$HASH_B") +elif [[ "$resolved_b" == "$resolved_head" ]]; then + json_a=$(overrides_json_git "$HASH_A") + json_b=$(overrides_json_worktree) +else + json_a=$(overrides_json_git "$HASH_A") + json_b=$(overrides_json_git "$HASH_B") +fi + +new_output=$( + jq -r -n --argjson a "$json_a" --argjson b "$json_b" "$compare_overrides_jq"' + ($b | keys[] | select(git($b; .))) as $pkg | + select((git($a; $pkg) | not) or git($a; $pkg).url != git($b; $pkg).url) | + (fields($a; $pkg)) as $old | + (fields($b; $pkg)) as $new | + [ + $pkg, + dash($old[0]), dash($new[0]), + dash($old[1]), dash($new[1]), + dash($old[2]), dash($new[2]) + ] | @tsv + ' | while IFS=$'\t' read -r pkg old_url new_url old_ref new_ref old_path new_path; do + print_git_fields "$pkg" "$old_url" "$new_url" "$old_ref" "$new_ref" "$old_path" "$new_path" + print_new_repo_stats "$new_url" "$new_ref" "$new_path" + done +) + +changed_output=$( + jq -r -n --argjson a "$json_a" --argjson b "$json_b" "$compare_overrides_jq"' + ($b | keys[] | select(git($b; .) and git($a; .))) as $pkg | + select(git($a; $pkg).url == git($b; $pkg).url) | + select((git($a; $pkg).ref // "") != (git($b; $pkg).ref // "")) | + (fields($a; $pkg)) as $old | + (fields($b; $pkg)) as $new | + [ + $pkg, + dash($old[0]), dash($new[0]), + dash($old[1]), dash($new[1]), + dash($old[2]), dash($new[2]) + ] | @tsv + ' | while IFS=$'\t' read -r pkg old_url new_url old_ref new_ref old_path new_path; do + print_git_fields "$pkg" "$old_url" "$new_url" "$old_ref" "$new_ref" "$old_path" "$new_path" + print_changed_ref_stats "$new_url" "$old_ref" "$new_ref" "$old_path" "$new_path" + done +) + +if [[ -n "$new_output" ]]; then + echo "new git repos:" + echo "$new_output" +fi + +if [[ -n "$new_output" && -n "$changed_output" ]]; then + echo +fi + +if [[ -n "$changed_output" ]]; then + echo "changed git refs:" + echo "$changed_output" +fi diff --git a/scripts/create_overrides.sh b/scripts/create_overrides.sh new file mode 100755 index 000000000..5cecb643f --- /dev/null +++ b/scripts/create_overrides.sh @@ -0,0 +1,624 @@ +#!/bin/bash + +# Hello! o/ +# If you are think there's a chance that you +# 1) want to update flutter sdk +# 2) want to update some dependency +# 3) want to add some dependency +# 4) are forking a dependency +# 5) something in the build process broke and you want to blame dependency pinning +# 6) the script is failing +# +# In cases 1, 2, 3 you don't need to edit this script at all. Just add the dependency +# to either pubspec_base.yaml or cw_*/pubspec.yaml. and re-run this script. +# In case 4 (or 6), do the same and add the dependency to +# package_repo_redirects - to redirect the dependency to your fork. +# repo_redirects - if the dependency was moved between git repos. +# version_ref_maps / dart_sdk_packages - if the dependency cannot be found upstream. +# In case 5 remove pubspec_overrides.yaml, and just build the app. There is a non-zero +# chance that it won't work. And if it works look for the diff between whatever is on git +# and whatever is published on pub.dev tarball. +# The script is designed in a way in which it is optional (so not using it should +# still result in a working build). +# In case of doubt git blame and ask the author ^^ + +set -e + +cd "$(dirname "$0")/.." + +yq() { + go run github.com/mikefarah/yq/v4@latest "$@" +} + +lockfile="$(pwd)/pubspec.lock" +pubspec_base="$(pwd)/pubspec_base.yaml" +overrides_file="$(pwd)/pubspec_overrides.yaml" +sdk_git_url=https://github.com/dart-lang/sdk + +resolved_git_path="" +resolved_ref="" +git_url="" +override_url="" +override_path="" +version_ref_map_skip_verify=0 + +# old git url|new git url +repo_redirects=( + "https://github.com/cmdrootaccess/another-flushbar|https://github.com/ideployed/another-flushbar" + "https://github.com/anicdh|https://github.com/MrCyjaneK/bs58check.git" + "https://github.com/MedzikUser/libcrypto-dart|https://github.com/MrCyjaneK/libcrypto.git" + "https://github.com/rive-app/rive-flutter|https://github.com/MrCyjaneK/rive-flutter-no-lfs" + "https://github.com/dart-lang/ffi|https://github.com/dart-lang/native" +) + +# package|old git url|new git url (to move only one package out of a shared repo) +package_repo_redirects=( + "rive_common|https://github.com/rive-app/rive-flutter|https://github.com/MrCyjaneK/rive_common" + "fixnum_nanodart|https://github.com/dart-lang/fixnum|https://github.com/MrCyjaneK/fixnum_nanodart" +) + +# package-version|git hash (exact match, or package-* to skip version check) +version_ref_maps=( + "ffi-2.1.0|6bd0935f29c7294ebb9aab21c06b47b513def933" + "flutter_rust_bridge-2.11.1|f19087cd0cac019b82d52cfa5153ce81b1b6e902" +) + +dart_sdk_ref=$(cat $(dirname $(dirname $(which flutter)))/bin/cache/dart-sdk/revision) +dart_sdk_packages=( + js vm_service +) + +# Kept on pub.dev +skip_git_pin_packages=( + _fe_analyzer_shared + analyzer + meta +) + +lookup_version_ref_map() { + local pkg=$1 ver=$2 entry key ref sdk_pkg + version_ref_map_skip_verify=0 + for sdk_pkg in "${dart_sdk_packages[@]}"; do + [[ "$pkg" == "$sdk_pkg" ]] || continue + version_ref_map_skip_verify=1 + echo "$dart_sdk_ref" + return 0 + done + for entry in "${version_ref_maps[@]}"; do + key="${entry%%|*}" + ref="${entry#*|}" + if [[ "$key" == "${pkg}-${ver}" ]]; then + echo "$ref" + return 0 + fi + if [[ "$key" == "${pkg}-*" ]]; then + version_ref_map_skip_verify=1 + echo "$ref" + return 0 + fi + done + return 1 +} + +is_dart_sdk_package() { + local pkg=$1 sdk_pkg + for sdk_pkg in "${dart_sdk_packages[@]}"; do + [[ "$pkg" == "$sdk_pkg" ]] && return 0 + done + return 1 +} + +is_skip_git_pin_package() { + local pkg=$1 skip_pkg + for skip_pkg in "${skip_git_pin_packages[@]}"; do + [[ "$pkg" == "$skip_pkg" ]] && return 0 + done + return 1 +} + +apply_default_overrides() { + [[ -f "$pubspec_base" ]] || return 0 + + awk ' + /^# dependency_overrides:/ { + in_block = 1 + print "dependency_overrides:" + next + } + in_block && /^#[[:space:]]/ { + sub(/^#[[:space:]]?/, "") + print + next + } + in_block && /^#/ { + sub(/^#/, "") + print + next + } + in_block { exit } + ' "$pubspec_base" > "$overrides_file" + + if [[ ! -s "$overrides_file" ]]; then + rm -f "$overrides_file" + return 0 + fi + + echo "applied default overrides from ${pubspec_base}" +} + +normalize_url() { + echo "$1" | sed 's|\.git$||' +} + +normalize_git_path() { + local path=$1 + [[ -z "$path" || "$path" == "." ]] && return 0 + [[ "$path" == ./* ]] && { echo "$path"; return 0; } + echo "./${path}" +} + +redirect_git_url() { + local url=$1 package=${2:-} entry rest old new + url=$(normalize_url "$url") + + if [[ -n "$package" ]]; then + for entry in "${package_repo_redirects[@]}"; do + [[ "${entry%%|*}" != "$package" ]] && continue + rest="${entry#*|}" + old=$(normalize_url "${rest%%|*}") + new=$(normalize_url "${rest#*|}") + [[ "$url" == "$old" ]] && { echo "$new"; return 0; } + done + fi + + for entry in "${repo_redirects[@]}"; do + old=$(normalize_url "${entry%%|*}") + new=$(normalize_url "${entry#*|}") + [[ "$url" == "$old" ]] && { echo "$new"; return 0; } + done + echo "$1" +} + +parse_github_repo_url() { + local url=$1 + if [[ "$url" =~ github\.com/([^/]+)/([^/?#]+) ]]; then + git_owner="${BASH_REMATCH[1]}" + git_repo="${BASH_REMATCH[2]%.git}" + git_url="https://github.com/${git_owner}/${git_repo}" + if [[ "$url" =~ github\.com/[^/]+/[^/]+/(tree|blob)/[^/]+/(.+) ]]; then + git_path="./${BASH_REMATCH[2]}" + else + git_path="" + fi + return 0 + fi + return 1 +} + +pubdev_cache_file() { + echo "$(pwd)/scripts/.cache/pubdev/${1}/${2}.json" +} + +pubdev_repo_url() { + local pkg=$1 ver=$2 cache_file + cache_file=$(pubdev_cache_file "$pkg" "$ver") + if [[ -f "$cache_file" ]]; then + jq -r '.pubspec.repository // .pubspec.homepage // empty' "$cache_file" + return 0 + fi + mkdir -p "$(dirname "$cache_file")" + curl -sf "https://pub.dev/api/packages/${pkg}/versions/${ver}" >"$cache_file" + jq -r '.pubspec.repository // .pubspec.homepage // empty' "$cache_file" +} + +repo_cache_dir() { + echo "scripts/.cache/repos/$(normalize_url "$1" | sed 's|https://github.com/||; s|/|_|g')" +} + +locks_dir="$(pwd)/scripts/.cache/locks" +rm -rf $locks_dir +mkdir -p $locks_dir + +repo_lock_file() { + local key=$1 + if [[ "$key" == */* || "$key" == scripts/* ]]; then + echo "${locks_dir}/repo-$(basename "$key").lock" + else + echo "${locks_dir}/repo-$(normalize_url "$key" | sed 's|https://github.com/||; s|/|_|g').lock" + fi +} + +with_lock() { + local lockpath=$1; shift + mkdir -p "$(dirname "$lockpath")" + while ! mkdir "$lockpath" 2>/dev/null; do + sleep 0.05 + done + local rc=0 + "$@" || rc=$? + rmdir "$lockpath" 2>/dev/null || true + return "$rc" +} + +with_repo_lock() { + with_lock "$(repo_lock_file "$1")" "${@:2}" +} + +with_overrides_lock() { + with_lock "${locks_dir}/overrides.lock" "$@" +} + +_ensure_repo_clone() { + local url=$1 cache_dir=$2 + [[ -d "${cache_dir}/.git" ]] && return 0 + mkdir -p "$(dirname "$cache_dir")" + if [[ "$(normalize_url "$url")" == "$sdk_git_url" ]]; then + git clone --quiet --filter=blob:none "$url" "$cache_dir" || return 1 + else + git clone --quiet "$url" "$cache_dir" || return 1 + fi +} + +ensure_repo_clone() { + local url=$1 cache_dir=$2 + with_repo_lock "$cache_dir" _ensure_repo_clone "$url" "$cache_dir" +} + +_ensure_git_ref() { + local cache_dir=$1 ref=$2 + git -C "$cache_dir" cat-file -e "${ref}^{commit}" 2>/dev/null +} + +ensure_git_ref() { + with_repo_lock "$1" _ensure_git_ref "$@" +} + +pubspec_field() { + local content=$1 field=$2 + echo "$content" | + grep -E "^${field}:[[:space:]]*" | + head -1 | + sed "s/^${field}:[[:space:]]*//" | + tr -d "\"'" | + sed 's/[[:space:]]*$//' +} + +pubspec_matches() { + local content=$1 package=$2 ver=${3:-} + [[ "$(pubspec_field "$content" name)" == "$package" ]] || return 1 + [[ -z "$ver" || "$(pubspec_field "$content" version)" == "$ver" ]] +} + +build_path_candidates() { + local url=$1 package=$2 path=$3 + local candidate candidates=() seen="" + + add_candidate() { + local c=$1 + if [[ -z "$c" ]]; then + [[ " $seen " == *" __ROOT__ "* ]] && return + seen="$seen __ROOT__" + candidates+=("") + return + fi + [[ " $seen " == *" $c "* ]] && return + seen="$seen $c" + candidates+=("$c") + } + + if [[ -n "$path" ]]; then + local normalized="${path#./}" + normalized="${normalized%/}" + if [[ "$normalized" != "packages" ]]; then + local cache_dir content + cache_dir=$(repo_cache_dir "$url") + if ensure_repo_clone "$url" "$cache_dir"; then + content=$(git -C "$cache_dir" show "HEAD:${normalized}/pubspec.yaml" 2>/dev/null) || content="" + pubspec_matches "$content" "$package" && add_candidate "$normalized" + fi + fi + fi + + local cache_dir pubspec_path dir content + cache_dir=$(repo_cache_dir "$url") + if ensure_repo_clone "$url" "$cache_dir"; then + while IFS= read -r pubspec_path; do + dir=$(dirname "$pubspec_path") + content=$(git -C "$cache_dir" show "HEAD:${pubspec_path}" 2>/dev/null) || continue + pubspec_matches "$content" "$package" || continue + add_candidate "$dir" + done < <(git -C "$cache_dir" ls-files | grep '/pubspec.yaml$') + fi + + add_candidate "pkgs/${package}" + add_candidate "packages/${package}" + add_candidate "${package}" + add_candidate "" + printf '%s\n' "${candidates[@]}" +} + +find_path_at_ref() { + local url=$1 ref=$2 package=$3 ver=$4 hint_path=$5 + local cache_dir candidate pubspec_file content + + cache_dir=$(repo_cache_dir "$url") + ensure_repo_clone "$url" "$cache_dir" || return 1 + ensure_git_ref "$cache_dir" "$ref" || return 1 + + while IFS= read -r candidate; do + pubspec_file=$([[ -n "$candidate" ]] && echo "${candidate}/pubspec.yaml" || echo "pubspec.yaml") + content=$(git -C "$cache_dir" show "${ref}:${pubspec_file}" 2>/dev/null) || continue + pubspec_matches "$content" "$package" "$ver" || continue + [[ -n "$candidate" ]] && echo "./${candidate}" + return 0 + done < <(build_path_candidates "$url" "$package" "$hint_path") + return 1 +} + +_resolve_tag_ref() { + local url=$1 pkg=$2 ver=$3 cache_dir ref tag + + cache_dir=$(repo_cache_dir "$url") + _ensure_repo_clone "$url" "$cache_dir" || return 1 + + for tag in "${ver}" "v${ver}" "${pkg}-${ver}" "${pkg}-v${ver}"; do + ref=$(git -C "$cache_dir" rev-parse -q "refs/tags/${tag}^{commit}" 2>/dev/null) && { + echo "$ref" + return 0 + } + ref=$(git -C "$cache_dir" rev-parse -q "refs/tags/${tag}" 2>/dev/null) && { + echo "$ref" + return 0 + } + done + return 1 +} + +resolve_tag_ref() { + with_repo_lock "$1" _resolve_tag_ref "$@" +} + +find_commit_for_package_version() { + local url=$1 package=$2 ver=$3 hint_path=$4 + local cache_dir candidate pubspec_file ref content ver_try log_args + local -a version_attempts=("$ver") + + [[ "$ver" != *-dev ]] && version_attempts+=("${ver}-dev") + + cache_dir=$(repo_cache_dir "$url") + ensure_repo_clone "$url" "$cache_dir" || return 1 + + while IFS= read -r candidate; do + pubspec_file=$([[ -n "$candidate" ]] && echo "${candidate}/pubspec.yaml" || echo "pubspec.yaml") + for ver_try in "${version_attempts[@]}"; do + [[ "$ver_try" == "$ver" ]] && log_args=(--reverse) || log_args=() + for ref in $(git -C "$cache_dir" log "${log_args[@]}" --format=%H -- "$pubspec_file" 2>/dev/null); do + content=$(git -C "$cache_dir" show "${ref}:${pubspec_file}" 2>/dev/null) || continue + pubspec_matches "$content" "$package" "$ver_try" || continue + resolved_git_path="" + [[ -n "$candidate" ]] && resolved_git_path="./${candidate}" + resolved_ref="$ref" + return 0 + done + done + done < <(build_path_candidates "$url" "$package" "$hint_path") + return 1 +} + +resolve_git_override_for_package() { + local package=$1 version=$2 repo_url=$3 + local original_git_url hint_path tag_ref path + + repo_url=$(redirect_git_url "$repo_url" "$package") + parse_github_repo_url "$repo_url" || return 1 + + original_git_url="$git_url" + hint_path="$git_path" + + path=$(find_path_at_ref "$git_url" HEAD "$package" "" "$hint_path" || true) + if [[ -n "$path" ]]; then + hint_path="$path" + elif [[ -z "$hint_path" && "$git_url" != "$original_git_url" ]]; then + path=$(find_path_at_ref "$original_git_url" HEAD "$package" "" "" || true) + if [[ -n "$path" ]]; then + git_url="$original_git_url" + hint_path="$path" + fi + fi + + resolved_git_path="" + resolved_ref="" + + tag_ref=$(resolve_tag_ref "$git_url" "$package" "$version" || true) + if [[ -n "$tag_ref" ]] && + path=$(find_path_at_ref "$git_url" "$tag_ref" "$package" "$version" "$hint_path"); then + resolved_git_path="$path" + resolved_ref="$tag_ref" + return 0 + fi + + find_commit_for_package_version "$git_url" "$package" "$version" "$hint_path" +} + +resolve_mapped_override() { + local package=$1 version=$2 source=$3 lock_git_url=$4 lock_git_path=$5 mapped_ref=$6 + local repo_url path_ver + + if is_dart_sdk_package "$package"; then + override_url="$sdk_git_url" + override_path="./pkg/${package}" + return 0 + fi + + if [[ "$source" == "git" ]]; then + [[ -n "$lock_git_url" ]] || return 1 + override_url=$(redirect_git_url "$lock_git_url" "$package") + override_path=$(normalize_git_path "$lock_git_path") + return 0 + fi + + [[ "$source" == "hosted" ]] || return 1 + repo_url=$(pubdev_repo_url "$package" "$version") + [[ -n "$repo_url" ]] || return 1 + repo_url=$(redirect_git_url "$repo_url" "$package") + parse_github_repo_url "$repo_url" || return 1 + override_url="$git_url" + path_ver="$version" + [[ "$version_ref_map_skip_verify" == 1 ]] && path_ver="" + override_path=$(find_path_at_ref "$git_url" "$mapped_ref" "$package" "$path_ver" "" || true) + [[ -n "$override_path" ]] +} + +has_git_override_in_yaml() { + local pkg=$1 + [[ -f "$overrides_file" ]] || return 1 + yq -e ".dependency_overrides.\"${pkg}\".git" "$overrides_file" >/dev/null 2>&1 +} + +_add_git_override_to_yaml() { + local pkg=$1 url=$2 path=$3 ref=$4 yq_expr + + [[ -f "$overrides_file" ]] || printf 'dependency_overrides: {}\n' > "$overrides_file" + if has_git_override_in_yaml "$pkg"; then + echo "$pkg: OK (default override)" + return 0 + fi + + yq -i "del(.dependency_overrides.\"${pkg}\")" "$overrides_file" + yq_expr=".dependency_overrides.\"${pkg}\".git.url = \"${url}\" | .dependency_overrides.\"${pkg}\".git.ref = \"${ref}\"" + [[ -n "$path" ]] && yq_expr+=" | .dependency_overrides.\"${pkg}\".git.path = \"${path}\"" + + yq -i "$yq_expr" "$overrides_file" || { + echo "$pkg: failed to update ${overrides_file}" >&2 + return 1 + } + + echo "added to ${overrides_file}:" + echo " ${pkg}:" + echo " git:" + echo " url: ${url}" + [[ -n "$path" ]] && echo " path: ${path}" + echo " ref: ${ref}" +} + +add_git_override_to_yaml() { + with_overrides_lock _add_git_override_to_yaml "$@" +} + +sort_overrides_yaml() { + yq -i \ + '.dependency_overrides = (.dependency_overrides | to_entries | sort_by(.key) | from_entries)' \ + "$overrides_file" +} + +rm -f "$overrides_file" +apply_default_overrides +./configure_cake_wallet.sh android +flutter pub get + +apply_default_overrides + +mkdir -p "$locks_dir" + +process_package() { + local pkg=$1 package source version git_url git_ref git_path mapped_ref repo_url + + eval "$(jq -r '@sh " + package=\(.package) + source=\(.source) + version=\(.version) + git_url=\(.git_url) + git_ref=\(.git_ref) + git_path=\(.git_path) + "' <<< "$pkg")" + + if has_git_override_in_yaml "$package"; then + echo "$package: OK (default override)" + return 0 + fi + + if is_skip_git_pin_package "$package"; then + echo "$package: OK (version pinned, skipped)" + return 0 + fi + + mapped_ref=$(lookup_version_ref_map "$package" "$version" || true) + if [[ -n "$mapped_ref" ]]; then + if ! resolve_mapped_override "$package" "$version" "$source" "$git_url" "$git_path" "$mapped_ref"; then + echo "$package: NOT OK - could not apply version_ref_maps entry for ${version}" >&2 + return 1 + fi + add_git_override_to_yaml "$package" "$override_url" "$override_path" "$mapped_ref" || return 1 + return 0 + fi + + case "$source" in + git) + if [[ -z "$git_url" || -z "$git_ref" ]]; then + echo "$package: NOT OK - git dependency missing url or ref in ${lockfile}" >&2 + return 1 + fi + add_git_override_to_yaml \ + "$package" \ + "$(redirect_git_url "$git_url" "$package")" \ + "$(normalize_git_path "$git_path")" \ + "$git_ref" || return 1 + ;; + sdk) + echo "$package: OK (sdk, skipped)" + ;; + hosted) + repo_url=$(pubdev_repo_url "$package" "$version") + if [[ -z "$repo_url" ]]; then + echo "$package: NOT OK - could not find repository or homepage on pub.dev for ${version}" + return 1 + fi + if ! resolve_git_override_for_package "$package" "$version" "$repo_url"; then + echo "$package: NOT OK - could not resolve git ref for version ${version} in ${git_url}" + echo "# add manual mapping to version_ref_maps in scripts/create_overrides.sh:" + echo "# \"${package}-${version}|GIT_HASH\"" + echo "# repository: ${repo_url}" + return 1 + fi + add_git_override_to_yaml "$package" "$git_url" "$resolved_git_path" "$resolved_ref" || return 1 + ;; + path) + echo "$package: OK (path, skipped)" + ;; + *) + echo "$package: NOT OK - source=${source} (cannot auto-generate git override)" + return 1 + ;; + esac +} + +max_jobs=16 +failed=0 +batch=() +while IFS= read -r pkg; do + process_package "$pkg" & + batch+=($!) + if ((${#batch[@]} >= max_jobs)); then + for pid in "${batch[@]}"; do + wait "$pid" || failed=1 + done + batch=() + fi +done < <( + yq -o json '.packages' "$lockfile" | jq -c ' + to_entries[] | { + package: .key, + source: (.value.source // ""), + version: (.value.version // ""), + git_url: (if (.value.description | type) == "object" then .value.description.url // "" else "" end), + git_ref: (if (.value.description | type) == "object" then (.value.description["resolved-ref"] // .value.description.ref // "") else "" end), + git_path: (if (.value.description | type) == "object" then .value.description.path // "" else "" end) + } + ' +) +for pid in "${batch[@]}"; do + wait "$pid" || failed=1 +done +[[ "$failed" -eq 0 ]] || exit 1 + +sort_overrides_yaml diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index 1c9dd1464..270efdb27 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -12,13 +12,13 @@ TYPES=($MONERO_COM $CAKEWALLET) APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="6.4.0" -MONERO_COM_BUILD_NUMBER=170 +MONERO_COM_VERSION="6.4.1" +MONERO_COM_BUILD_NUMBER=171 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.4.0" -CAKEWALLET_BUILD_NUMBER=433 +CAKEWALLET_VERSION="6.4.1" +CAKEWALLET_BUILD_NUMBER=434 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" diff --git a/scripts/linux/app_env.sh b/scripts/linux/app_env.sh index b0cbb833e..ba08cabd9 100755 --- a/scripts/linux/app_env.sh +++ b/scripts/linux/app_env.sh @@ -14,8 +14,8 @@ if [ -n "$1" ]; then fi CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.3.0" -CAKEWALLET_BUILD_NUMBER=80 +CAKEWALLET_VERSION="6.4.1" +CAKEWALLET_BUILD_NUMBER=81 if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then echo "Wrong app type." diff --git a/scripts/linux/build_torch.sh b/scripts/linux/build_torch.sh index 4947e9340..66865aa0c 100755 --- a/scripts/linux/build_torch.sh +++ b/scripts/linux/build_torch.sh @@ -6,4 +6,4 @@ cd "$(dirname "$0")" cd ../torch_dart -# ./build.sh x86_64-linux-gnu +./build.sh x86_64-linux-gnu diff --git a/scripts/linux/docker/Dockerfile.mwebd b/scripts/linux/docker/Dockerfile.mwebd index ef24c1bd7..856ac8c00 100644 --- a/scripts/linux/docker/Dockerfile.mwebd +++ b/scripts/linux/docker/Dockerfile.mwebd @@ -3,8 +3,8 @@ FROM --platform=linux/amd64 ${BASE_IMAGE} AS build RUN mkdir -p /w/scripts/android COPY pubspec_base.yaml /w/pubspec.yaml -# COPY pubspec_overrides.yaml /w/pubspec_overrides.yaml -# COPY pubspec_overrides.yaml /w/cw_mweb/pubspec_overrides.yaml +COPY pubspec_overrides.yaml /w/pubspec_overrides.yaml +COPY pubspec_overrides.yaml /w/cw_mweb/pubspec_overrides.yaml COPY cw_mweb/pubspec.yaml /w/cw_mweb/pubspec.yaml COPY cw_mweb/ffigen_config.yaml /w/cw_mweb/ffigen_config.yaml COPY cw_mweb/go /w/cw_mweb/go diff --git a/scripts/linux/docker/Dockerfile.torch b/scripts/linux/docker/Dockerfile.torch index 433286e42..14b752a1b 100644 --- a/scripts/linux/docker/Dockerfile.torch +++ b/scripts/linux/docker/Dockerfile.torch @@ -14,7 +14,7 @@ RUN groupadd -g "$GID" "$USER" && \ RUN sudo chown $UID:$GID -R /w /root USER builder -RUN /w/scripts/prepare_torch.sh +RUN /w/scripts/linux/build_torch.sh && rm -rf /w/scripts/torch_dart/simplybs FROM --platform=linux/amd64 alpine COPY --from=build /w /w diff --git a/scripts/linux/docker/build.sh b/scripts/linux/docker/build.sh index 3c76b6d81..f4a502d95 100755 --- a/scripts/linux/docker/build.sh +++ b/scripts/linux/docker/build.sh @@ -55,7 +55,7 @@ torch_ver="$(tinysha $SCRIPT_DIR/Dockerfile.torch $REPO_ROOT/scripts/prepare_tor reown_ver=$(tinysha $SCRIPT_DIR/Dockerfile.reown $REPO_ROOT/scripts/prepare_reown.sh $REPO_ROOT/scripts/android/build_reown_deps.sh) bitbox_ver=$(tinysha $SCRIPT_DIR/Dockerfile.bitbox $REPO_ROOT/scripts/build_bitbox_flutter.sh) monero_ver=$(tinysha $SCRIPT_DIR/Dockerfile.monero $REPO_ROOT/scripts/prepare_moneroc.sh $REPO_ROOT/scripts/linux/build_monero_all.sh) -mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $REPO_ROOT/cw_mweb/pubspec.yaml $(find $REPO_ROOT/cw_mweb/go -type f)) +mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $REPO_ROOT/pubspec_overrides.yaml $(find $REPO_ROOT/cw_mweb/go -type f)) zcash_ver=$(tinysha $SCRIPT_DIR/Dockerfile.zcash $REPO_ROOT/scripts/prepare_zcash.sh $REPO_ROOT/scripts/linux/build_zcash.sh) echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $zcash_ver > /tmp/docker_build_versions final_ver=$(tinysha /tmp/docker_build_versions) diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 63e317798..e92693a06 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -16,13 +16,13 @@ if [ -n "$1" ]; then fi MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="6.3.0" -MONERO_COM_BUILD_NUMBER=81 +MONERO_COM_VERSION="6.4.1" +MONERO_COM_BUILD_NUMBER=82 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.3.0" -CAKEWALLET_BUILD_NUMBER=149 +CAKEWALLET_VERSION="6.4.1" +CAKEWALLET_BUILD_NUMBER=150 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then diff --git a/scripts/windows/build_exe_installer.iss b/scripts/windows/build_exe_installer.iss index 9fba68e60..4343c799d 100644 --- a/scripts/windows/build_exe_installer.iss +++ b/scripts/windows/build_exe_installer.iss @@ -1,5 +1,5 @@ #define MyAppName "Cake Wallet" -#define MyAppVersion "6.3.0" +#define MyAppVersion "6.4.1" #define MyAppPublisher "Cake Labs LLC" #define MyAppURL "https://cakewallet.com/" #define MyAppExeName "CakeWallet.exe" diff --git a/test/core/anypay/anypay_parser_test.dart b/test/core/anypay/anypay_parser_test.dart new file mode 100644 index 000000000..76651eb86 --- /dev/null +++ b/test/core/anypay/anypay_parser_test.dart @@ -0,0 +1,103 @@ +import "package:cake_wallet/core/anypay/anypay_models.dart"; +import "package:cake_wallet/core/anypay/anypay_parser.dart"; +import "package:cake_wallet/utils/payment_request.dart"; +import "package:flutter_test/flutter_test.dart"; + +void main() { + const recipient = "0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41"; + const usdtEthContract = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; + + group("chain binding", () { + test("explicit ethereum chain binds explicitly", () { + final request = AnyPayParser.fromRaw( + "ethereum:$recipient@8453?value=1e18", + ); + + expect(request.chainBinding, isA()); + expect((request.chainBinding as ExplicitEvmChain).chainId, 8453); + }); + + test("ethereum without a chain id stays chainless", () { + final request = AnyPayParser.fromRaw( + "ethereum:$usdtEthContract/transfer?address=$recipient&uint256=1000000", + ); + + expect(request.chainBinding, isA()); + expect(request.hasContract, true); + }); + + test("non evm schemes bind no evm chain", () { + final request = AnyPayParser.fromRaw( + "bitcoin:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq", + ); + + expect(request.chainBinding, isA()); + }); + + test("raw evm addresses bind no evm chain", () { + final request = AnyPayParser.fromRaw(recipient); + + expect(request.chainBinding, isA()); + expect(request.detection.isValid, true); + }); + + test("an evm chain scheme binds its chain explicitly", () { + final request = AnyPayParser.fromRaw("polygon:$recipient"); + + expect((request.chainBinding as ExplicitEvmChain).chainId, 137); + }); + }); + + group("payment request reconstruction", () { + test("an explicit chain request keeps its chain and raw amount", () { + final original = PaymentRequest.fromUri( + Uri.parse("ethereum:$usdtEthContract@8453/transfer?address=$recipient&uint256=3000000"), + ); + + final request = AnyPayParser.fromPaymentRequest(original); + + expect(request.rawInput.contains("@8453"), true); + expect(request.paymentRequest.rawTokenAmount, "3000000"); + expect((request.chainBinding as ExplicitEvmChain).chainId, 8453); + }); + + test("a chainless request rebuilds with a placeholder but keeps the chainless binding", () { + final original = PaymentRequest.fromUri( + Uri.parse("ethereum:$usdtEthContract/transfer?address=$recipient&uint256=1000000"), + ); + + final request = AnyPayParser.fromPaymentRequest(original); + + expect(request.rawInput.contains("@1/"), true); + expect(request.chainBinding, isA()); + expect(request.detection.isValid, true); + }); + + test("a tron token request keeps its contract on the payment request", () { + final original = PaymentRequest.fromUri( + Uri.parse("tron:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t?token=TTokenContract111111111111111111"), + ); + + final request = AnyPayParser.fromPaymentRequest(original); + + expect(request.contractAddress, "TTokenContract111111111111111111"); + expect(request.chainBinding, isA()); + }); + + test("a non evm request rebuilds scheme address and amount", () { + final original = PaymentRequest("someaddress", "1.25", "", "monero", null); + + final request = AnyPayParser.fromPaymentRequest(original); + + expect(request.rawInput, "monero:someaddress?amount=1.25"); + }); + + test("a lightning request passes the invoice through untouched", () { + final original = PaymentRequest("lnbc1invoice", "", "", "lightning", null); + + final request = AnyPayParser.fromPaymentRequest(original); + + expect(request.rawInput, "lnbc1invoice"); + }); + }); +} diff --git a/test/core/anypay/anypay_resolver_test.dart b/test/core/anypay/anypay_resolver_test.dart new file mode 100644 index 000000000..0132e817c --- /dev/null +++ b/test/core/anypay/anypay_resolver_test.dart @@ -0,0 +1,201 @@ +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:cw_core/crypto_currency.dart"; +import "package:cw_core/erc20_token.dart"; +import "package:cw_core/wallet_type.dart"; +import "package:flutter_test/flutter_test.dart"; + +class _FakeTokenLookup implements AnyPayTokenLookup { + _FakeTokenLookup({this.onFindToken, this.onFindChainId}); + + final Future Function({required WalletType walletType, required String address})? + onFindToken; + final Future Function(String contractAddress, {int? excludingChainId})? onFindChainId; + + @override + Future findTokenByAddress({ + required WalletType walletType, + required String address, + }) { + if (onFindToken == null) { + fail("no token lookup expected"); + } + return onFindToken!(walletType: walletType, address: address); + } + + @override + Future findEvmChainIdForContract(String contractAddress, {int? excludingChainId}) { + if (onFindChainId == null) { + fail("no chain sweep expected"); + } + return onFindChainId!(contractAddress, excludingChainId: excludingChainId); + } +} + +void main() { + const recipient = "0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41"; + const usdtEthContract = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; + const solAddress = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; + const usdcSolMint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; + + final usdt = Erc20Token( + name: "Tether", + symbol: "USDT", + contractAddress: usdtEthContract, + decimal: 6, + ); + + WalletSnapshot snapshot({ + WalletType type = WalletType.ethereum, + int? chainId, + bool hasEvmProxy = true, + }) => + WalletSnapshot( + type: type, + currentWalletIsEvm: + type == WalletType.ethereum || type == WalletType.polygon || type == WalletType.base, + currentChainId: chainId, + wallets: const [], + // The service builds an empty chain map when the evm proxy is absent. + supportedEvmChains: hasEvmProxy + ? const { + 1: WalletType.ethereum, + 137: WalletType.polygon, + 8453: WalletType.base, + } + : const {}, + hasEvmProxy: hasEvmProxy, + hasSolanaProxy: true, + hasTronProxy: true, + ); + + AnyPayRequest parse(String input) => AnyPayParser.fromRaw(input); + + test("a request without a contract needs no resolution", () async { + final resolver = AnyPayResolver(tokenLookup: _FakeTokenLookup()); + + final resolution = await resolver.resolve( + parse("ethereum:$recipient@1?value=1e18"), + snapshot(chainId: 1), + ); + + expect(resolution, isA()); + }); + + test("a token on the explicit target chain resolves with its amount", () async { + final lookedUp = []; + final resolver = AnyPayResolver( + tokenLookup: _FakeTokenLookup( + onFindToken: ({required walletType, required address}) async { + lookedUp.add(walletType); + return walletType == WalletType.ethereum ? usdt : null; + }, + ), + ); + + final resolution = await resolver.resolve( + parse("ethereum:$usdtEthContract@1/transfer?address=$recipient&uint256=1000000"), + snapshot(type: WalletType.base, chainId: 8453), + ); + + final resolved = resolution as TokenResolved; + expect(lookedUp, [WalletType.ethereum]); + expect(resolved.chainId, 1); + expect(resolved.token, usdt); + expect(resolved.amountOverride, "1"); + }); + + test("an unknown token on an explicit chain is not swept to other chains", () async { + bool sweepCalled = false; + final resolver = AnyPayResolver( + tokenLookup: _FakeTokenLookup( + onFindToken: ({required walletType, required address}) async => null, + onFindChainId: (contract, {excludingChainId}) async { + sweepCalled = true; + return 137; + }, + ), + ); + + final resolution = await resolver.resolve( + parse("ethereum:$usdtEthContract@1/transfer?address=$recipient&uint256=1000000"), + snapshot(chainId: 1), + ); + + expect(resolution, isA()); + expect(sweepCalled, false); + }); + + test("a chainless token unknown on the current chain reroutes through the sweep", () async { + final resolver = AnyPayResolver( + tokenLookup: _FakeTokenLookup( + onFindToken: ({required walletType, required address}) async => + walletType == WalletType.ethereum ? usdt : null, + onFindChainId: (contract, {excludingChainId}) async { + expect(excludingChainId, 8453); + return 1; + }, + ), + ); + + final resolution = await resolver.resolve( + parse("ethereum:$usdtEthContract/transfer?address=$recipient&uint256=2000000"), + snapshot(type: WalletType.base, chainId: 8453), + ); + + final resolved = resolution as TokenResolved; + expect(resolved.chainId, 1); + expect(resolved.amountOverride, "2"); + }); + + test("a chainless token unknown everywhere stays unknown", () async { + final resolver = AnyPayResolver( + tokenLookup: _FakeTokenLookup( + onFindToken: ({required walletType, required address}) async => null, + onFindChainId: (contract, {excludingChainId}) async => null, + ), + ); + + final resolution = await resolver.resolve( + parse("ethereum:$usdtEthContract/transfer?address=$recipient&uint256=2000000"), + snapshot(chainId: 1), + ); + + expect((resolution as TokenUnknown).contract, usdtEthContract); + }); + + test("a solana token resolves against the detected wallet type", () async { + const usdcSol = CryptoCurrency.usdtSol; + final resolver = AnyPayResolver( + tokenLookup: _FakeTokenLookup( + onFindToken: ({required walletType, required address}) async { + expect(walletType, WalletType.solana); + expect(address, usdcSolMint); + return usdcSol; + }, + ), + ); + + final resolution = await resolver.resolve( + parse("solana:$solAddress?amount=3&spl-token=$usdcSolMint"), + snapshot(type: WalletType.monero), + ); + + final resolved = resolution as TokenResolved; + expect(resolved.chainId, null); + expect(resolved.token, usdcSol); + expect(resolved.amountOverride, "3"); + }); + + test("an evm contract without the evm proxy stays unknown without any lookups", () async { + final resolver = AnyPayResolver(tokenLookup: _FakeTokenLookup()); + + final resolution = await resolver.resolve( + parse("ethereum:$usdtEthContract@1/transfer?address=$recipient&uint256=1000000"), + snapshot(hasEvmProxy: false), + ); + + expect(resolution, isA()); + }); +} diff --git a/test/core/anypay/anypay_router_test.dart b/test/core/anypay/anypay_router_test.dart new file mode 100644 index 000000000..681e9d755 --- /dev/null +++ b/test/core/anypay/anypay_router_test.dart @@ -0,0 +1,414 @@ +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_router.dart"; +import "package:cake_wallet/reactions/wallet_connect.dart"; +import "package:cw_core/crypto_currency.dart"; +import "package:cw_core/erc20_token.dart"; +import "package:cw_core/wallet_info.dart"; +import "package:cw_core/wallet_type.dart"; +import "package:flutter_test/flutter_test.dart"; + +void main() { + const recipient = "0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41"; + const usdtEthContract = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; + const btcAddress = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"; + const xmrAddress = + "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A"; + const tronAddress = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"; + const solAddress = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; + + final usdt = Erc20Token( + name: "Tether", + symbol: "USDT", + contractAddress: usdtEthContract, + decimal: 6, + ); + + WalletInfo walletOf(WalletType type) => WalletInfo.external( + id: "id-${type.name}", + name: "wallet-${type.name}", + type: type, + isRecovery: false, + restoreHeight: 0, + date: DateTime(2026), + dirPath: "", + path: "", + address: "", + ); + + WalletSnapshot snapshot({ + WalletType type = WalletType.ethereum, + int? chainId, + List wallets = const [], + bool hasEvmProxy = true, + bool hasSolanaProxy = true, + bool hasTronProxy = true, + }) => + WalletSnapshot( + type: type, + currentWalletIsEvm: isEVMCompatibleChain(type), + currentChainId: chainId, + wallets: wallets, + supportedEvmChains: hasEvmProxy + ? const { + 1: WalletType.ethereum, + 137: WalletType.polygon, + 8453: WalletType.base, + } + : const {}, + hasEvmProxy: hasEvmProxy, + hasSolanaProxy: hasSolanaProxy, + hasTronProxy: hasTronProxy, + ); + + AnyPayRequest parse(String input) => AnyPayParser.fromRaw(input); + + group("evm routing", () { + test("explicit chain matching the current wallet applies directly", () { + final decision = AnyPayRouter.route( + parse("ethereum:$recipient@1?value=1e18"), + snapshot(chainId: 1), + const NoTokenRequested(), + ); + + expect(decision, isA()); + }); + + test("explicit chain differing from the current wallet goes cross chain", () { + final decision = AnyPayRouter.route( + parse("ethereum:$recipient@8453?value=1e18"), + snapshot(chainId: 1, wallets: [walletOf(WalletType.base)]), + const NoTokenRequested(), + ); + + expect(decision, isA()); + final crossChain = decision as AnyPayCrossChainPayment; + expect(crossChain.targetChainId, 8453); + expect(crossChain.targetWalletType, WalletType.base); + expect(crossChain.hasCompatibleWallet, true); + }); + + test("cross chain with no wallet for the target offers no compatible wallet", () { + final decision = AnyPayRouter.route( + parse("ethereum:$recipient@8453?value=1e18"), + snapshot(chainId: 1), + const NoTokenRequested(), + ); + + expect((decision as AnyPayCrossChainPayment).hasCompatibleWallet, false); + }); + + test("unsupported explicit chain is rejected with its id", () { + final decision = AnyPayRouter.route( + parse("ethereum:$recipient@10?value=1e18"), + snapshot(chainId: 1), + const NoTokenRequested(), + ); + + expect((decision as AnyPayUnsupportedNetwork).chainId, 10); + }); + + test("chainless request binds to the current evm chain", () { + final decision = AnyPayRouter.route( + parse("ethereum:$recipient?value=1e18"), + snapshot(type: WalletType.base, chainId: 8453), + const NoTokenRequested(), + ); + + expect(decision, isA()); + }); + + test("chainless request at a non evm wallet targets mainnet cross chain", () { + final decision = AnyPayRouter.route( + parse("ethereum:$recipient?value=1e18"), + snapshot(type: WalletType.monero, wallets: [walletOf(WalletType.ethereum)]), + const NoTokenRequested(), + ); + + expect((decision as AnyPayCrossChainPayment).targetChainId, 1); + }); + + test("raw evm address at an evm wallet applies directly", () { + final decision = AnyPayRouter.route( + parse(recipient), + snapshot(chainId: 1), + const NoTokenRequested(), + ); + + expect(decision, isA()); + }); + + test("raw evm address at a non evm wallet asks for a network choice", () { + final decision = AnyPayRouter.route( + parse(recipient), + snapshot(type: WalletType.solana), + const NoTokenRequested(), + ); + + expect(decision, isA()); + }); + + test("resolved token on the current chain applies with the token", () { + final decision = AnyPayRouter.route( + parse("ethereum:$usdtEthContract/transfer?address=$recipient&uint256=2000000"), + snapshot(type: WalletType.base, chainId: 8453), + TokenResolved(token: usdt, chainId: 8453, amountOverride: "2"), + ); + + final apply = decision as AnyPayApplyToCurrentWallet; + expect(apply.token, usdt); + expect(apply.amountOverride, "2"); + }); + + test("chainless token resolved on another chain reroutes there", () { + final decision = AnyPayRouter.route( + parse("ethereum:$usdtEthContract/transfer?address=$recipient&uint256=2000000"), + snapshot(type: WalletType.base, chainId: 8453, wallets: [walletOf(WalletType.ethereum)]), + TokenResolved(token: usdt, chainId: 1, amountOverride: "2"), + ); + + final crossChain = decision as AnyPayCrossChainPayment; + expect(crossChain.targetChainId, 1); + expect(crossChain.token, usdt); + }); + + test("an unknown token never falls back to the native asset", () { + final decision = AnyPayRouter.route( + parse("ethereum:$usdtEthContract@1/transfer?address=$recipient&uint256=2000000"), + snapshot(chainId: 1), + const TokenUnknown(usdtEthContract), + ); + + expect(decision, isA()); + expect((decision as AnyPayUnsupportedToken).contract, usdtEthContract); + }); + + test("an unsupported network wins over an unknown token", () { + final decision = AnyPayRouter.route( + parse("ethereum:$usdtEthContract@10/transfer?address=$recipient&uint256=2000000"), + snapshot(chainId: 1), + const TokenUnknown(usdtEthContract), + ); + + expect((decision as AnyPayUnsupportedNetwork).chainId, 10); + }); + + test("evm address without the evm proxy applies as plain input", () { + final decision = AnyPayRouter.route( + parse(recipient), + snapshot(type: WalletType.monero, hasEvmProxy: false), + const NoTokenRequested(), + ); + + expect(decision, isA()); + expect((decision as AnyPayApplyToCurrentWallet).token, null); + }); + }); + + group("non evm routing", () { + test("address matching the current wallet applies directly", () { + final decision = AnyPayRouter.route( + parse(xmrAddress), + snapshot(type: WalletType.monero), + const NoTokenRequested(), + ); + + expect(decision, isA()); + }); + + test("btc address at another wallet goes cross chain with its wallets", () { + final decision = AnyPayRouter.route( + parse(btcAddress), + snapshot(type: WalletType.monero, wallets: [walletOf(WalletType.bitcoin)]), + const NoTokenRequested(), + ); + + final crossChain = decision as AnyPayCrossChainPayment; + expect(crossChain.targetWalletType, WalletType.bitcoin); + expect(crossChain.hasCompatibleWallet, true); + }); + + test("btc address with no bitcoin wallet leaves only the swap offer", () { + final decision = AnyPayRouter.route( + parse(btcAddress), + snapshot(type: WalletType.monero), + const NoTokenRequested(), + ); + + expect((decision as AnyPayCrossChainPayment).hasCompatibleWallet, false); + }); + + test("tron address at another wallet goes cross chain to tron", () { + final decision = AnyPayRouter.route( + parse(tronAddress), + snapshot(chainId: 1, wallets: [walletOf(WalletType.tron)]), + const NoTokenRequested(), + ); + + final crossChain = decision as AnyPayCrossChainPayment; + expect(crossChain.targetWalletType, WalletType.tron); + expect(crossChain.targetChainId, null); + expect(crossChain.wallets.length, 1); + }); + + test("solana address without the solana proxy applies as plain input", () { + final decision = AnyPayRouter.route( + parse(solAddress), + snapshot(chainId: 1, hasSolanaProxy: false), + const NoTokenRequested(), + ); + + expect(decision, isA()); + }); + + test("an unknown non evm token never falls back to the native asset", () { + final decision = AnyPayRouter.route( + parse("solana:$solAddress?amount=3&spl-token=$solAddress"), + snapshot(type: WalletType.solana), + const TokenUnknown(solAddress), + ); + + expect(decision, isA()); + }); + + test("solana token resolved on the current wallet applies with the token", () { + const splToken = CryptoCurrency.usdtSol; + final decision = AnyPayRouter.route( + parse("solana:$solAddress?amount=3&spl-token=$solAddress"), + snapshot(type: WalletType.solana), + const TokenResolved(token: splToken, amountOverride: "3"), + ); + + final apply = decision as AnyPayApplyToCurrentWallet; + expect(apply.token, splToken); + expect(apply.amountOverride, "3"); + }); + }); + + group("native request currency", () { + test("an explicit native request with an amount carries its currency", () { + final decision = AnyPayRouter.route( + parse("ethereum:$recipient@1?value=2e18"), + snapshot(chainId: 1), + const NoTokenRequested(), + ); + + expect((decision as AnyPayApplyToCurrentWallet).fallbackCurrency, CryptoCurrency.eth); + }); + + test("a raw address carries no fallback currency", () { + final decision = AnyPayRouter.route( + parse(recipient), + snapshot(chainId: 1), + const NoTokenRequested(), + ); + + expect((decision as AnyPayApplyToCurrentWallet).fallbackCurrency, null); + }); + }); + + group("degenerate input", () { + test("empty input is invalid", () { + final decision = AnyPayRouter.route( + parse(""), + snapshot(chainId: 1), + const NoTokenRequested(), + ); + + expect(decision, isA()); + }); + + test("undetectable text applies as plain input for the validator to reject", () { + final decision = AnyPayRouter.route( + parse("definitelynotanaddress"), + snapshot(chainId: 1), + const NoTokenRequested(), + ); + + expect(decision, isA()); + }); + }); + + group("requested evm chain", () { + test("explicit binding wins over the wallet chain", () { + final request = parse("ethereum:$recipient@137?value=1e18"); + + expect(AnyPayRouter.requestedEvmChainId(request, snapshot(chainId: 1)), 137); + }); + + test("chainless binding takes the wallet chain", () { + final request = parse("ethereum:$recipient?value=1e18"); + + expect( + AnyPayRouter.requestedEvmChainId( + request, + snapshot(type: WalletType.base, chainId: 8453), + ), + 8453, + ); + }); + + test("chainless binding defaults to mainnet without an evm wallet", () { + final request = parse("ethereum:$recipient?value=1e18"); + + expect( + AnyPayRouter.requestedEvmChainId(request, snapshot(type: WalletType.monero)), + 1, + ); + }); + + test("raw addresses bind no target", () { + expect(AnyPayRouter.requestedEvmChainId(parse(recipient), snapshot(chainId: 1)), null); + }); + }); + + group("swap incompatible recipients", () { + final spAddress = "sp1${"q" * 113}"; + final mwebAddress = "ltcmweb1q${"a" * 90}"; + + test("a silent payment address with a bitcoin wallet switches without a swap offer", () { + final decision = AnyPayRouter.route( + parse(spAddress), + snapshot(type: WalletType.monero, wallets: [walletOf(WalletType.bitcoin)]), + const NoTokenRequested(), + ); + + final crossChain = decision as AnyPayCrossChainPayment; + expect(crossChain.targetWalletType, WalletType.bitcoin); + expect(crossChain.hasCompatibleWallet, true); + expect(crossChain.canSwap, false); + }); + + test("a silent payment address with no bitcoin wallet cannot swap either", () { + final decision = AnyPayRouter.route( + parse(spAddress), + snapshot(type: WalletType.monero), + const NoTokenRequested(), + ); + + final crossChain = decision as AnyPayCrossChainPayment; + expect(crossChain.hasCompatibleWallet, false); + expect(crossChain.canSwap, false); + }); + + test("an mweb address never offers a swap", () { + final decision = AnyPayRouter.route( + parse(mwebAddress), + snapshot(), + const NoTokenRequested(), + ); + + expect((decision as AnyPayCrossChainPayment).canSwap, false); + }); + + test("a plain btc address keeps the swap offer", () { + final decision = AnyPayRouter.route( + parse(btcAddress), + snapshot(type: WalletType.monero), + const NoTokenRequested(), + ); + + expect((decision as AnyPayCrossChainPayment).canSwap, true); + }); + }); +} diff --git a/test/core/universal_address_detector_test.dart b/test/core/universal_address_detector_test.dart index 9525aed88..c74afe5c9 100644 --- a/test/core/universal_address_detector_test.dart +++ b/test/core/universal_address_detector_test.dart @@ -196,6 +196,38 @@ void main() { }); }); + group("Zcash Address Detection", () { + test("detects Zcash transparent address", () { + const address = "t1V9mnyk5Z5cTNMCkLbaDwSskgJZucTLdgW"; + final result = UniversalAddressDetector.detectAddress(address); + + expect(result.isValid, true); + expect(result.detectedCurrency, CryptoCurrency.zec); + expect(result.detectedWalletType, WalletType.zcash); + expect(result.address, address); + }); + + test("detects Zcash shielded address", () { + const address = + "zsab12cd34efab12cd34efab12cd34efab12cd34efab12cd34efab12cd34efab12cd34efgh56kl"; + final result = UniversalAddressDetector.detectAddress(address); + + expect(result.isValid, true); + expect(result.detectedCurrency, CryptoCurrency.zec); + expect(result.detectedWalletType, WalletType.zcash); + }); + + test("detects Zcash unified address", () { + const address = + "u1z9y8x7w6v5z9y8x7w6v5z9y8x7w6v5z9y8x7w6v5z9y8x7w6v5z9y8x7w6v5z9y8x7w6v5z9y8x7w6v5z9y8x7w6v5z9y8x7w6v5"; + final result = UniversalAddressDetector.detectAddress(address); + + expect(result.isValid, true); + expect(result.detectedCurrency, CryptoCurrency.zec); + expect(result.detectedWalletType, WalletType.zcash); + }); + }); + group('Wownero Address Detection', () { test('detects Wownero address', () { const address = diff --git a/test/utils/anypay_matrix_test.dart b/test/utils/anypay_matrix_test.dart new file mode 100644 index 000000000..1bbe9fc39 --- /dev/null +++ b/test/utils/anypay_matrix_test.dart @@ -0,0 +1,344 @@ +import "package:cake_wallet/core/universal_address_detector.dart"; +import "package:cake_wallet/utils/payment_request.dart"; +import "package:cw_core/erc20_token.dart"; +import "package:cw_core/payment_uris.dart"; +import "package:cw_core/wallet_type.dart"; +import "package:flutter_test/flutter_test.dart"; + +void main() { + const recipient = "0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41"; + const usdtEthContract = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; + const daiEthContract = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; + const usdtBaseContract = "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2"; + + final usdt = Erc20Token( + name: "Tether", + symbol: "USDT", + contractAddress: usdtEthContract, + decimal: 6, + ); + final dai = Erc20Token( + name: "Dai", + symbol: "DAI", + contractAddress: daiEthContract, + decimal: 18, + ); + + group("cross generation QR matrix", () { + test("new app mainnet USDT QR parses with explicit chain and amount", () { + final uri = ERC681URI( + chainId: 1, + address: recipient, + amount: "200.172148", + contractAddress: usdtEthContract, + tokenDecimals: 6, + ).toString(); + + final request = PaymentRequest.fromUri(Uri.parse(uri)); + expect(request.chainId, 1); + expect(request.contractAddress, usdtEthContract); + expect(request.resolveTokenAmount(usdt), "200.172148"); + }); + + test("new app mainnet DAI QR emits both params and the amount wins", () { + final uri = ERC681URI( + chainId: 1, + address: recipient, + amount: "1.5", + contractAddress: daiEthContract, + ).toString(); + + expect(uri.contains("uint256=1500000000000000000"), true); + expect(uri.contains("amount=1.5"), true); + + final request = PaymentRequest.fromUri(Uri.parse(uri)); + expect(request.chainId, 1); + expect(request.resolveTokenAmount(dai), "1.5"); + }); + + test("old app chainless USDT QR resolves through the legacy fallback", () { + final request = PaymentRequest.fromUri( + Uri.parse( + "ethereum:$usdtEthContract/transfer?address=$recipient&uint256=2000000000000000000", + ), + ); + + expect(request.chainId, null); + expect(request.resolveTokenAmount(usdt), "2"); + }); + + test("team lead legacy URI resolves to the intended two USDT", () { + final request = PaymentRequest.fromUri( + Uri.parse( + "ethereum:$usdtEthContract@1/transfer?address=$recipient&uint256=2013999999999999744", + ), + ); + + expect(request.chainId, 1); + expect(request.resolveTokenAmount(usdt), "2.013999999999999744"); + }); + + test("external QR with a true six decimal uint256 resolves directly", () { + final request = PaymentRequest.fromUri( + Uri.parse("ethereum:$usdtEthContract@1/transfer?address=$recipient&uint256=1000000"), + ); + + expect(request.resolveTokenAmount(usdt), "1"); + }); + + test("old app native scientific value parses without a chain", () { + final request = PaymentRequest.fromUri(Uri.parse("ethereum:$recipient?value=2.014e18")); + + expect(request.chainId, null); + expect(request.amount, "2.014"); + }); + + test("new app native QR round trips with the explicit chain", () { + final uri = ERC681URI(chainId: 1, address: recipient, amount: "2.5", contractAddress: null) + .toString(); + expect(uri, "ethereum:$recipient@1?value=2.5e18"); + + final request = PaymentRequest.fromUri(Uri.parse(uri)); + expect(request.chainId, 1); + expect(request.amount, "2.5"); + }); + + test("new app base token QR carries the base chain", () { + final uri = ERC681URI( + chainId: 8453, + address: recipient, + amount: "3", + contractAddress: usdtBaseContract, + tokenDecimals: 6, + ).toString(); + + final request = PaymentRequest.fromUri(Uri.parse(uri)); + expect(request.chainId, 8453); + expect(request.contractAddress, usdtBaseContract); + expect(request.amount, "3"); + }); + }); + + group("emitter invariants", () { + test("every emitted ethereum URI names its chain", () { + final uris = [ + ERC681URI(chainId: 1, address: recipient, amount: "", contractAddress: null), + ERC681URI(chainId: 1, address: recipient, amount: "1", contractAddress: null), + ERC681URI( + chainId: 1, + address: recipient, + amount: "1", + contractAddress: usdtEthContract, + tokenDecimals: 6, + ), + ERC681URI(chainId: 8453, address: recipient, amount: "", contractAddress: usdtBaseContract), + ]; + + for (final uri in uris) { + expect(uri.toString().contains("@"), true, reason: uri.toString()); + } + }); + + test("six decimal tokens emit no uint256", () { + final uri = ERC681URI( + chainId: 1, + address: recipient, + amount: "1.5", + contractAddress: usdtEthContract, + tokenDecimals: 6, + ).toString(); + + expect(uri.contains("uint256"), false); + expect(uri.contains("amount=1.5"), true); + }); + + test("a stored raw amount is passed through verbatim", () { + final uri = ERC681URI( + chainId: 1, + address: recipient, + amount: "", + contractAddress: usdtEthContract, + tokenDecimals: 6, + rawTokenAmount: "1000000", + ).toString(); + + expect(uri, "ethereum:$usdtEthContract@1/transfer?address=$recipient&uint256=1000000"); + }); + + test("comma decimal separators are normalized", () { + final uri = ERC681URI( + chainId: 1, + address: recipient, + amount: "2,5", + contractAddress: usdtEthContract, + tokenDecimals: 6, + ).toString(); + + expect(uri.contains("amount=2.5"), true); + }); + }); + + group("hostile and external input", () { + test("EIP681 pay- prefix parses for native transfers", () { + final request = PaymentRequest.fromUri(Uri.parse("ethereum:pay-$recipient@1?value=1e18")); + + expect(request.address, recipient); + expect(request.chainId, 1); + expect(request.amount, "1"); + }); + + test("EIP681 pay- prefix parses for token transfers", () { + final request = PaymentRequest.fromUri( + Uri.parse("ethereum:pay-$usdtEthContract@1/transfer?address=$recipient&uint256=1000000"), + ); + + expect(request.contractAddress, usdtEthContract); + expect(request.address, recipient); + expect(request.resolveTokenAmount(usdt), "1"); + }); + + test("a trailing chain separator defaults to mainnet", () { + final request = PaymentRequest.fromUri(Uri.parse("ethereum:$recipient@?value=1e18")); + + expect(request.address, recipient); + expect(request.chainId, 1); + }); + + test("a non numeric chain id defaults to mainnet", () { + final request = PaymentRequest.fromUri(Uri.parse("ethereum:$recipient@abc")); + + expect(request.address, recipient); + expect(request.chainId, 1); + }); + + test("an ENS style target degrades to the raw name without throwing", () { + final request = PaymentRequest.fromUri(Uri.parse("ethereum:vitalik.eth?amount=1")); + + expect(request.address, "vitalik.eth"); + expect(request.amount, "1"); + }); + + test("junk after the scheme does not throw", () { + final request = PaymentRequest.fromUri(Uri.parse("ethereum:junk")); + + expect(request.address, "junk"); + }); + + test("an empty ethereum URI does not throw", () { + final request = PaymentRequest.fromUri(Uri.parse("ethereum:")); + + expect(request.address, ""); + }); + + test("a non numeric native value yields no amount", () { + final request = PaymentRequest.fromUri(Uri.parse("ethereum:$recipient?value=abc")); + + expect(request.address, recipient); + expect(request.amount, ""); + }); + + test("an unknown contract function still extracts the contract", () { + final request = PaymentRequest.fromUri( + Uri.parse("ethereum:$usdtEthContract@1/approve?address=$recipient"), + ); + + expect(request.contractAddress, usdtEthContract); + expect(request.address, recipient); + }); + + test("plain text input falls back to an address passthrough", () { + final request = PaymentRequest.fromString("definitelynotauri"); + + expect(request.address, "definitelynotauri"); + expect(request.scheme, ""); + }); + }); + + group("resolveTokenAmount boundaries", () { + test("one billion whole tokens is still read with the token decimals", () { + final request = + PaymentRequest("addr", "", "", "ethereum", null, rawTokenAmount: "1000000000000000"); + + expect(request.resolveTokenAmount(usdt), "1000000000"); + }); + + test("just past the plausibility bound flips to the legacy reading", () { + final request = + PaymentRequest("addr", "", "", "ethereum", null, rawTokenAmount: "1000000000000001"); + + expect(request.resolveTokenAmount(usdt), "0.001000000000000001"); + }); + + test("eighteen decimal tokens never take the legacy branch", () { + final request = + PaymentRequest("addr", "", "", "ethereum", null, rawTokenAmount: "50000000000000000000"); + + expect(request.resolveTokenAmount(dai), "50"); + }); + + test("garbage raw amounts resolve to null", () { + final request = + PaymentRequest("addr", "", "", "ethereum", null, rawTokenAmount: "not a number"); + + expect(request.resolveTokenAmount(usdt), null); + }); + }); + + group("send page reconstruction round trip", () { + test("an explicit chain request rebuilds into the same payment", () { + final original = PaymentRequest.fromUri( + Uri.parse("ethereum:$usdtBaseContract@8453/transfer?address=$recipient&uint256=3000000"), + ); + + final rebuilt = ERC681URI( + address: original.address, + amount: original.amount, + contractAddress: original.contractAddress, + chainId: original.chainId ?? 1, + rawTokenAmount: original.rawTokenAmount, + ).toString(); + + final reparsed = PaymentRequest.fromUri(Uri.parse(rebuilt)); + expect(reparsed.chainId, 8453); + expect(reparsed.contractAddress, usdtBaseContract); + expect(reparsed.rawTokenAmount, "3000000"); + expect(reparsed.address, recipient); + }); + + test("a dual param request survives reconstruction with the raw intact", () { + final original = PaymentRequest.fromUri( + Uri.parse( + "ethereum:$daiEthContract@1/transfer?address=$recipient&uint256=1500000000000000000&amount=1.5", + ), + ); + + final rebuilt = ERC681URI( + address: original.address, + amount: original.amount, + contractAddress: original.contractAddress, + chainId: original.chainId ?? 1, + rawTokenAmount: original.rawTokenAmount, + ).toString(); + + final reparsed = PaymentRequest.fromUri(Uri.parse(rebuilt)); + expect(reparsed.amount, "1.5"); + expect(reparsed.rawTokenAmount, "1500000000000000000"); + }); + }); + + group("detector supplements", () { + test("pay- prefixed URIs are detected as EVM payments", () { + final result = UniversalAddressDetector.detectAddress("ethereum:pay-$recipient@1?value=1e18"); + + expect(result.isValid, true); + expect(result.detectedWalletType, WalletType.ethereum); + }); + + test("an unsupported chain id is still surfaced for routing", () { + final result = UniversalAddressDetector.detectAddress("ethereum:$recipient@10?value=1e18"); + + expect(result.isValid, true); + expect(result.chainId, 10); + }); + }); +} diff --git a/test/utils/payment_request_test.dart b/test/utils/payment_request_test.dart index add579fda..b825b0a68 100644 --- a/test/utils/payment_request_test.dart +++ b/test/utils/payment_request_test.dart @@ -7,7 +7,8 @@ void main() { group("Ethereum URIs", () { test("extract address and raw token amount from EIP681 Uri with contract", () { final uri = Uri.parse( - "ethereum:0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174@1/transfer?address=0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41&uint256=2000000000000000000"); + "ethereum:0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174@1/transfer?address=0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41&uint256=2000000000000000000", + ); final paymentRequest = PaymentRequest.fromUri(uri); expect(paymentRequest.address, "0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41"); @@ -17,7 +18,8 @@ void main() { test("extract address and amount from EIP681 Uri", () { final uri = Uri.parse( - "ethereum:0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41@1?value=2000000000000000000"); + "ethereum:0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41@1?value=2000000000000000000", + ); final paymentRequest = PaymentRequest.fromUri(uri); expect(paymentRequest.address, "0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41"); @@ -34,7 +36,8 @@ void main() { test("extract address from EIP681 Uri with contract", () { final uri = Uri.parse( - "ethereum:0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174@1/transfer?address=0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41"); + "ethereum:0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174@1/transfer?address=0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41", + ); final paymentRequest = PaymentRequest.fromUri(uri); expect(paymentRequest.address, "0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41"); @@ -43,7 +46,8 @@ void main() { test("extract address and raw token amount from EIP681 Uri with contract and no chainId", () { final uri = Uri.parse( - "ethereum:0x1234567890abcdef1234567890abcdef12345678/transfer?address=0xabcdef1234567890abcdef1234567890abcdef12&uint256=1000000000000000000"); + "ethereum:0x1234567890abcdef1234567890abcdef12345678/transfer?address=0xabcdef1234567890abcdef1234567890abcdef12&uint256=1000000000000000000", + ); final paymentRequest = PaymentRequest.fromUri(uri); expect(paymentRequest.address, "0xabcdef1234567890abcdef1234567890abcdef12"); @@ -76,7 +80,8 @@ void main() { test("converts the raw uint256 using the token decimals", () { final uri = Uri.parse( - "ethereum:0xdAC17F958D2ee523a2206206994597C13D831ec7@1/transfer?address=0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41&uint256=1000000"); + "ethereum:0xdAC17F958D2ee523a2206206994597C13D831ec7@1/transfer?address=0xCfc1650da7C961FD82998e7e30ca5f699D0aBf41&uint256=1000000", + ); final paymentRequest = PaymentRequest.fromUri(uri); expect(paymentRequest.resolveTokenAmount(usdt), "1"); @@ -90,8 +95,14 @@ void main() { }); test("falls back to the legacy 18 decimal reading for implausibly large amounts", () { - final paymentRequest = PaymentRequest("addr", "", "", "ethereum", null, - rawTokenAmount: "50000000000000000000"); + final paymentRequest = PaymentRequest( + "addr", + "", + "", + "ethereum", + null, + rawTokenAmount: "50000000000000000000", + ); expect(paymentRequest.resolveTokenAmount(usdt), "50"); });