mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Merge branch 'dev' into cw-1440-new-buy-sell-flow
This commit is contained in:
@@ -159,11 +159,8 @@ jobs:
|
|||||||
- name: Build generated code
|
- name: Build generated code
|
||||||
run: |
|
run: |
|
||||||
flutter --version
|
flutter --version
|
||||||
flutter clean
|
|
||||||
rm -rf .dart_tool
|
|
||||||
rm pubspec.lock
|
|
||||||
flutter pub get
|
flutter pub get
|
||||||
./model_generator.sh async
|
./model_generator.sh
|
||||||
|
|
||||||
- name: Generate key properties
|
- name: Generate key properties
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,18 +1,21 @@
|
|||||||
name: Cake Wallet Linux
|
name: Cake Wallet Linux
|
||||||
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
PR_test_build:
|
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]
|
runs-on: [Linux, amd64, forlinux]
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.41.9-ndkr28-go1.24.1-ruststablenightly
|
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/.pub-cache/:/root/.pub-cache
|
||||||
- /opt/cw_cache_linux/root/go/pkg:/root/go/pkg
|
- /opt/cw_cache_linux/root/go/pkg:/root/go/pkg
|
||||||
- /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache
|
- /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Fix github actions messing up $HOME...
|
- name: Fix github actions messing up $HOME...
|
||||||
@@ -44,6 +48,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
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
|
- name: configure git
|
||||||
run: |
|
run: |
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
@@ -85,7 +97,6 @@ jobs:
|
|||||||
|
|
||||||
echo "${{ secrets.MAIN_SECRETS_FILE }}" | base64 --decode > lib/.secrets.g.dart
|
echo "${{ secrets.MAIN_SECRETS_FILE }}" | base64 --decode > lib/.secrets.g.dart
|
||||||
|
|
||||||
|
|
||||||
- name: Build dependencies utilizing ghcr cache
|
- name: Build dependencies utilizing ghcr cache
|
||||||
run: |
|
run: |
|
||||||
env \
|
env \
|
||||||
@@ -93,7 +104,6 @@ jobs:
|
|||||||
CW_DOCKER_USE_CLOUD=true \
|
CW_DOCKER_USE_CLOUD=true \
|
||||||
./scripts/linux/docker/build.sh
|
./scripts/linux/docker/build.sh
|
||||||
|
|
||||||
|
|
||||||
- name: Execute Build and Setup Commands
|
- name: Execute Build and Setup Commands
|
||||||
run: |
|
run: |
|
||||||
pushd scripts/linux
|
pushd scripts/linux
|
||||||
@@ -107,12 +117,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Build generated code
|
- name: Build generated code
|
||||||
run: |
|
run: |
|
||||||
./model_generator.sh async
|
./model_generator.sh
|
||||||
|
|
||||||
- name: Generate localization
|
- name: Generate localization
|
||||||
run: |
|
run: |
|
||||||
dart run tool/generate_localization.dart
|
dart run tool/generate_localization.dart
|
||||||
|
|
||||||
|
- name: Compile graphics
|
||||||
|
run: |
|
||||||
|
./compile_graphics.sh
|
||||||
|
|
||||||
- name: Build linux
|
- name: Build linux
|
||||||
run: |
|
run: |
|
||||||
flutter build linux --dart-define=hasDevOptions=true --release
|
flutter build linux --dart-define=hasDevOptions=true --release
|
||||||
|
|||||||
@@ -125,12 +125,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Build generated code
|
- name: Build generated code
|
||||||
run: |
|
run: |
|
||||||
flutter --version
|
./model_generator.sh
|
||||||
flutter clean
|
|
||||||
rm -rf .dart_tool
|
|
||||||
rm pubspec.lock
|
|
||||||
flutter pub get
|
|
||||||
./model_generator.sh async
|
|
||||||
|
|
||||||
- name: Generate key properties
|
- name: Generate key properties
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+2
-1
@@ -160,7 +160,6 @@ assets/images/app_logo.png
|
|||||||
assets/new-ui/**/*.svg.vec
|
assets/new-ui/**/*.svg.vec
|
||||||
|
|
||||||
/pubspec.yaml
|
/pubspec.yaml
|
||||||
/pubspec.lock
|
|
||||||
/android/app.properties
|
/android/app.properties
|
||||||
/android/app/src/main/AndroidManifest.xml
|
/android/app/src/main/AndroidManifest.xml
|
||||||
|
|
||||||
@@ -228,3 +227,5 @@ scripts/reown_flutter
|
|||||||
|
|
||||||
*.salive
|
*.salive
|
||||||
android/.kotlin
|
android/.kotlin
|
||||||
|
scripts/.cache
|
||||||
|
pubspec.lock
|
||||||
|
|||||||
@@ -90,7 +90,9 @@
|
|||||||
<data android:scheme="polygon" />
|
<data android:scheme="polygon" />
|
||||||
<data android:scheme="polygon-wallet" />
|
<data android:scheme="polygon-wallet" />
|
||||||
<data android:scheme="polygon_wallet" />
|
<data android:scheme="polygon_wallet" />
|
||||||
|
<data android:scheme="solana" />
|
||||||
<data android:scheme="solana-wallet" />
|
<data android:scheme="solana-wallet" />
|
||||||
|
<data android:scheme="solana_wallet" />
|
||||||
<data android:scheme="tron" />
|
<data android:scheme="tron" />
|
||||||
<data android:scheme="tron-wallet" />
|
<data android:scheme="tron-wallet" />
|
||||||
<data android:scheme="tron_wallet" />
|
<data android:scheme="tron_wallet" />
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[{"title":"مونيرو + تريزور","description":"قم بتأمين XMR الخاص بك من خلال دعم محفظة الأجهزة!"},{"title":"واجهة مستخدم WalletConnect الجديدة","description":"أصبح الاتصال بـ Web3 dApps أكثر أمانًا وسهولة"},{"title":"تحسينات واجهة المستخدم","description":"تمت إضافة بعض عناصر واجهة المستخدم الجديدة خصيصًا لك"},{"title":"تحسينات المزامنة","description":"المزامنة الأمثل للبيتكوين وLitecoin"},{"title":"إصلاحات الشوائب","description":"سحق المزيد من الأخطاء"}]
|
[{"title":"تحسينات زي كاش","description":"بعد الترحيل الناجح إلى IronWood الجديد، أضفنا المزيد من التحسينات إلى محفظة zcash"},{"title":"AnyPay على النحو المنشود","description":"الآن، سيؤدي لصق عنوان ما أو مسحه ضوئيًا من أي محفظة إلى توجيهك بشكل صحيح إما للتبديل أو الإرسال من المحفظة الصحيحة، والمزيد من التحسينات"},{"title":"تحسينات واجهة المستخدم","description":"تمت إضافة بعض عناصر واجهة المستخدم الجديدة خصيصًا لك"},{"title":"إصلاحات الشوائب","description":"سحق المزيد من الأخطاء"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"MONERO + TREZOR","description":"Защитете своя XMR с поддръжка на хардуерен портфейл!"},{"title":"НОВ потребителски интерфейс на WalletConnect","description":"свързването към Web3 dApps стана по-безопасно и по-лесно"},{"title":"Подобрения на потребителския интерфейс","description":"Добавени са някои нови елементи на потребителския интерфейс само за вас"},{"title":"Подобрения при синхронизиране","description":"Оптимизирана синхронизация за Bitcoin и Litecoin"},{"title":"Поправки на грешки","description":"Смачкани още грешки"}]
|
[{"title":"Подобрения на Zcash","description":"След успешната миграция към новия IronWood добавихме още подобрения към zcash портфейла"},{"title":"AnyPay според предназначението","description":"Сега поставянето или сканирането на адрес от който и да е портфейл ще ви насочи правилно към размяна или изпращане от правилния портфейл и много повече подобрения"},{"title":"Подобрения на потребителския интерфейс","description":"Добавени са някои нови елементи на потребителския интерфейс само за вас"},{"title":"Поправки на грешки","description":"Смачкани още грешки"}]
|
||||||
@@ -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"}]
|
[{"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ů"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -1,20 +1,16 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"title": "MONERO + TREZOR",
|
"title": "Zcash improvements",
|
||||||
"description": "Secure your XMR with hardware wallet support!"
|
"description": "After the successful migration to the new IronWood, we added more improvements to zcash wallet"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "NEW WalletConnect UI",
|
"title": "AnyPay as Intended",
|
||||||
"description": "connecting to Web3 dApps made safer and easier"
|
"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",
|
"title": "UI improvements",
|
||||||
"description": "Added some fresh UI elements just for you"
|
"description": "Added some fresh UI elements just for you"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"title": "Sync enhancements",
|
|
||||||
"description": "Optimized sync for Bitcoin and Litecoin"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"title": "Bug fixes",
|
"title": "Bug fixes",
|
||||||
"description": "Squashed more bugs"
|
"description": "Squashed more bugs"
|
||||||
|
|||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"MONERO + TREZOR","description":"XMR خود را با پشتیبانی کیف پول سخت افزاری ایمن کنید!"},{"title":"رابط کاربری جدید WalletConnect","description":"اتصال به Web3 dApps ایمن تر و آسان تر شده است"},{"title":"بهبودهای رابط کاربری","description":"برخی از عناصر رابط کاربری جدید را فقط برای شما اضافه کرد"},{"title":"همگام سازی پیشرفت ها","description":"همگام سازی بهینه شده برای بیت کوین و لایت کوین"},{"title":"رفع اشکال","description":"اشکالات بیشتری را له کرد"}]
|
[{"title":"بهبود Zcash","description":"پس از انتقال موفقیت آمیز به IronWood جدید، بهبودهای بیشتری را به کیف پول zcash اضافه کردیم"},{"title":"AnyPay همانطور که در نظر گرفته شده است","description":"اکنون چسباندن یا اسکن یک آدرس از هر کیف پولی، شما را به درستی به تعویض یا ارسال از کیف پول صحیح و پیشرفت های بسیار بیشتر راهنمایی می کند."},{"title":"بهبودهای رابط کاربری","description":"برخی از عناصر رابط کاربری جدید را فقط برای شما اضافه کرد"},{"title":"رفع اشکال","description":"اشکالات بیشتری را له کرد"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"मोनेरो + ट्रेज़ोर","description":"हार्डवेयर वॉलेट समर्थन के साथ अपने एक्सएमआर को सुरक्षित करें!"},{"title":"नया वॉलेटकनेक्ट यूआई","description":"Web3 dApps से कनेक्ट करना सुरक्षित और आसान बना दिया गया है"},{"title":"यूआई सुधार","description":"केवल आपके लिए कुछ ताज़ा यूआई तत्व जोड़े गए हैं"},{"title":"सिंक संवर्द्धन","description":"बिटकॉइन और लाइटकॉइन के लिए अनुकूलित सिंक"},{"title":"कंप्यूटर प्रोग्राम या प्रणाली में बग को दूर करना","description":"अधिक कीड़ों को कुचल दिया"}]
|
[{"title":"ज़कैश में सुधार","description":"नए आयरनवुड में सफल माइग्रेशन के बाद, हमने zcash वॉलेट में और सुधार जोड़े"},{"title":"इच्छानुसार कोई भी भुगतान करें","description":"अब किसी भी वॉलेट से किसी पते को चिपकाने या स्कैन करने से आपको स्वैपिंग या सही वॉलेट से भेजने का सही संकेत मिलेगा, और भी बहुत कुछ सुधार होगा"},{"title":"UI improvements","description":"केवल आपके लिए कुछ ताज़ा यूआई तत्व जोड़े गए हैं"},{"title":"कंप्यूटर प्रोग्राम या प्रणाली में बग को दूर करना","description":"अधिक कीड़ों को कुचल दिया"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"MONERO + TREZOR","description":"Ապահովեք ձեր XMR-ը ապարատային դրամապանակի աջակցությամբ:"},{"title":"ՆՈՐ WalletConnect UI","description":"Web3 dApps-ին միանալը դարձել է ավելի անվտանգ և հեշտ"},{"title":"UI բարելավումներ","description":"Ավելացրել է մի քանի թարմ UI տարրեր հենց ձեզ համար"},{"title":"Համաժամեցման բարելավումներ","description":"Օպտիմիզացված համաժամեցում Bitcoin-ի և Litecoin-ի համար"},{"title":"Սխալների շտկում","description":"Ճզմեց ավելի շատ սխալներ"}]
|
[{"title":"Zcash բարելավումներ","description":"Նոր IronWood-ի հաջող տեղափոխումից հետո մենք ավելի շատ բարելավումներ ենք ավելացրել zcash դրամապանակում"},{"title":"AnyPay, ինչպես նախատեսված է","description":"Այժմ ցանկացած դրամապանակից հասցե կպցնելը կամ սկանավորումը ձեզ ճիշտ կուղղորդի՝ կա՛մ փոխանակելու, կա՛մ ճիշտ դրամապանակից ուղարկելու և շատ ավելի բարելավումներ:"},{"title":"UI բարելավումներ","description":"Ավելացրել է մի քանի թարմ UI տարրեր հենց ձեզ համար"},{"title":"Սխալների շտկում","description":"Ճզմեց ավելի շատ սխալներ"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"モネロ + トレザー","description":"ハードウェアウォレットのサポートで XMR を保護してください!"},{"title":"新しい WalletConnect UI","description":"Web3 dApps への接続がより安全かつ簡単になりました"},{"title":"UIの改善","description":"あなたのためだけにいくつかの新しい UI 要素を追加しました"},{"title":"同期の機能強化","description":"ビットコインとライトコインの最適化された同期"},{"title":"バグ修正","description":"より多くのバグを潰しました"}]
|
[{"title":"Zcashの改善","description":"新しい IronWood への移行が成功した後、zcash ウォレットにさらに改良を加えました。"},{"title":"意図したとおりの AnyPay","description":"任意のウォレットからアドレスを貼り付けるかスキャンすると、正しいウォレットからの交換または送信が正しく示されるようになり、さらに多くの改善が行われました。"},{"title":"UIの改善","description":"あなたのためだけにいくつかの新しい UI 要素を追加しました"},{"title":"バグ修正","description":"より多くのバグを潰しました"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"모네로 + 트레저","description":"하드웨어 지갑 지원으로 XMR을 보호하세요!"},{"title":"새로운 WalletConnect UI","description":"Web3 dApp에 연결하는 것이 더 안전하고 쉬워졌습니다."},{"title":"UI 개선","description":"당신을 위한 새로운 UI 요소를 추가했습니다."},{"title":"동기화 향상","description":"비트코인과 라이트코인에 최적화된 동기화"},{"title":"버그 수정","description":"더 많은 버그를 해결했습니다."}]
|
[{"title":"Zcash 개선","description":"새로운 IronWood로 성공적으로 마이그레이션한 후 zcash 지갑에 더 많은 개선 사항을 추가했습니다."},{"title":"의도한 대로 AnyPay","description":"이제 지갑에서 주소를 붙여넣거나 스캔하면 올바른 지갑에서 주소를 교환하거나 보내는 것을 올바르게 가리킬 수 있으며 훨씬 더 많은 개선이 가능합니다."},{"title":"UI 개선","description":"당신을 위한 새로운 UI 요소를 추가했습니다."},{"title":"버그 수정","description":"더 많은 버그를 해결했습니다."}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"MONERO + TREZOR","description":"ဟာ့ဒ်ဝဲပိုက်ဆံအိတ်ပံ့ပိုးမှုဖြင့် သင်၏ XMR ကို လုံခြုံအောင်ထားပါ။"},{"title":"WalletConnect UI အသစ်","description":"Web3 dApps သို့ ချိတ်ဆက်ခြင်းသည် ပိုမိုလုံခြုံပြီး ပိုမိုလွယ်ကူစေသည်။"},{"title":"UI တိုးတက်မှုများ","description":"သင့်အတွက်သာ လတ်ဆတ်သော UI အစိတ်အပိုင်းအချို့ကို ထည့်ထားသည်။"},{"title":"ထပ်တူပြုခြင်း မြှင့်တင်မှုများ","description":"Bitcoin နှင့် Litecoin အတွက် အကောင်းဆုံး စင့်ခ်လုပ်ထားသည်။"},{"title":"ချွတ်ယွင်းချက်ပြင်ဆင်မှုများ","description":"နောက်ထပ် ပိုးကောင်များကို နှိမ်နင်းခဲ့သည်။"}]
|
[{"title":"Zcash တိုးတက်မှုများ","description":"IronWood အသစ်သို့ အောင်မြင်စွာ ပြောင်းရွှေ့ပြီးနောက်၊ ကျွန်ုပ်တို့သည် zcash ပိုက်ဆံအိတ်သို့ နောက်ထပ် တိုးတက်မှုများကို ထည့်သွင်းခဲ့သည်။"},{"title":"ရည်ရွယ်ထားသည့်အတိုင်း AnyPay","description":"ယခု မည်သည့်ပိုက်ဆံအိတ်မှ လိပ်စာတစ်ခုကို ကူးထည့်ခြင်း သို့မဟုတ် စကင်န်ဖတ်ခြင်းသည် သင့်အား မှန်ကန်သောပိုက်ဆံအိတ်မှ လဲလှယ်ရန် သို့မဟုတ် ပေးပို့ခြင်းတို့ကို မှန်ကန်စွာ ညွှန်ပြပေးမည်ဖြစ်ပြီး ပိုမိုကောင်းမွန်လာစေရန်၊"},{"title":"UI တိုးတက်မှုများ","description":"သင့်အတွက်သာ လတ်ဆတ်သော UI အစိတ်အပိုင်းအချို့ကို ထည့်ထားသည်။"},{"title":"ချွတ်ယွင်းချက်ပြင်ဆင်မှုများ","description":"နောက်ထပ် ပိုးကောင်များကို နှိမ်နင်းခဲ့သည်။"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"МОНЕРО + ТРЕЗОР","description":"Защитите свой XMR с помощью аппаратного кошелька!"},{"title":"НОВЫЙ интерфейс WallConnectConnect","description":"подключение к dApps Web3 стало безопаснее и проще"},{"title":"Улучшения пользовательского интерфейса","description":"Специально для вас добавлено несколько свежих элементов пользовательского интерфейса."},{"title":"Улучшения синхронизации","description":"Оптимизированная синхронизация для биткойнов и лайткойнов."},{"title":"Исправления ошибок","description":"Устранено больше ошибок"}]
|
[{"title":"Улучшения Zcash","description":"После успешного перехода на новый IronWood мы добавили дополнительные улучшения в кошелек zcash."},{"title":"AnyPay как задумано","description":"Теперь при вставке или сканировании адреса из любого кошелька вы сможете правильно выбрать обмен или отправку из правильного кошелька, а также множество других улучшений."},{"title":"Улучшения пользовательского интерфейса","description":"Специально для вас добавлено несколько свежих элементов пользовательского интерфейса."},{"title":"Исправления ошибок","description":"Устранено больше ошибок"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"โมเนโร + เทรเซอร์","description":"รักษาความปลอดภัย XMR ของคุณด้วยการสนับสนุนกระเป๋าเงินฮาร์ดแวร์!"},{"title":"UI WalletConnect ใหม่","description":"การเชื่อมต่อกับ Web3 dApps ทำให้ปลอดภัยและง่ายขึ้น"},{"title":"การปรับปรุง UI","description":"เพิ่มองค์ประกอบ UI ใหม่สำหรับคุณโดยเฉพาะ"},{"title":"การปรับปรุงการซิงค์","description":"การซิงค์ที่ปรับให้เหมาะสมสำหรับ Bitcoin และ Litecoin"},{"title":"แก้ไขข้อบกพร่อง","description":"กำจัดข้อบกพร่องเพิ่มเติม"}]
|
[{"title":"การปรับปรุง Zcash","description":"หลังจากการโยกย้ายไปยัง IronWood ใหม่ได้สำเร็จ เราได้เพิ่มการปรับปรุงเพิ่มเติมให้กับกระเป๋าเงิน zcash"},{"title":"AnyPay ตามที่ตั้งใจไว้","description":"ตอนนี้การวางหรือสแกนที่อยู่จากกระเป๋าเงินใด ๆ จะนำคุณไปสู่การแลกเปลี่ยนหรือส่งจากกระเป๋าเงินที่ถูกต้องอย่างถูกต้อง และการปรับปรุงอื่น ๆ อีกมากมาย"},{"title":"การปรับปรุง UI","description":"เพิ่มองค์ประกอบ UI ใหม่สำหรับคุณโดยเฉพาะ"},{"title":"แก้ไขข้อบกพร่อง","description":"กำจัดข้อบกพร่องเพิ่มเติม"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"MONERO + TREZOR","description":"Захистіть свій XMR за допомогою підтримки апаратного гаманця!"},{"title":"НОВИЙ інтерфейс WalletConnect","description":"підключення до Web3 dApps стало безпечнішим і простішим"},{"title":"Покращення інтерфейсу користувача","description":"Додано кілька свіжих елементів інтерфейсу спеціально для вас"},{"title":"Покращення синхронізації","description":"Оптимізована синхронізація для Bitcoin і Litecoin"},{"title":"Виправлення помилок","description":"Роздавив більше помилок"}]
|
[{"title":"Покращення Zcash","description":"Після успішного переходу на новий IronWood ми додали додаткові покращення до гаманця zcash"},{"title":"AnyPay за призначенням","description":"Тепер вставлення або сканування адреси з будь-якого гаманця правильно вкаже вас на обмін або надсилання з правильного гаманця, а також багато інших покращень"},{"title":"Покращення інтерфейсу користувача","description":"Додано кілька свіжих елементів інтерфейсу спеціально для вас"},{"title":"Виправлення помилок","description":"Роздавив більше помилок"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"مونیرو + ٹریزور","description":"ہارڈویئر والیٹ سپورٹ کے ساتھ اپنے XMR کو محفوظ بنائیں!"},{"title":"نیا WalletConnect UI","description":"Web3 dApps سے جڑنا محفوظ اور آسان بنا دیا ہے۔"},{"title":"UI میں بہتری","description":"صرف آپ کے لیے کچھ تازہ UI عناصر شامل کیے گئے۔"},{"title":"مطابقت پذیری میں اضافہ","description":"Bitcoin اور Litecoin کے لیے آپٹمائزڈ سنک"},{"title":"بگ کی اصلاحات","description":"مزید کیڑے کو کچل دیا۔"}]
|
[{"title":"Zcash میں بہتری","description":"نئے IronWood میں کامیاب منتقلی کے بعد، ہم نے zcash wallet میں مزید بہتری شامل کی۔"},{"title":"AnyPay جیسا کہ ارادہ ہے۔","description":"اب کسی بھی بٹوے سے ایڈریس پیسٹ یا اسکین کرنا آپ کو صحیح بٹوے سے تبدیل کرنے یا بھیجنے کی طرف صحیح طریقے سے اشارہ کرے گا، اور بہت زیادہ بہتری"},{"title":"UI میں بہتری","description":"صرف آپ کے لیے کچھ تازہ UI عناصر شامل کیے گئے۔"},{"title":"بگ کی اصلاحات","description":"مزید کیڑے کو کچل دیا۔"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -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"}]
|
[{"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"}]
|
||||||
@@ -1 +1 @@
|
|||||||
[{"title":"门罗+特雷佐","description":"通过硬件钱包支持保护您的 XMR!"},{"title":"新的 WalletConnect 用户界面","description":"连接到 Web3 dApp 变得更安全、更轻松"},{"title":"用户界面改进","description":"为您添加了一些新鲜的 UI 元素"},{"title":"同步增强功能","description":"优化比特币和莱特币的同步"},{"title":"错误修复","description":"消除了更多错误"}]
|
[{"title":"Zcash 的改进","description":"成功迁移到新的 IronWood 后,我们对 zcash 钱包添加了更多改进"},{"title":"AnyPay 符合预期","description":"现在,从任何钱包粘贴或扫描地址都会正确地指示您从正确的钱包进行交换或发送,以及更多改进"},{"title":"用户界面改进","description":"为您添加了一些新鲜的 UI 元素"},{"title":"错误修复","description":"消除了更多错误"}]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
sources:
|
||||||
|
exclude:
|
||||||
|
- "**/.secrets.g.dart"
|
||||||
|
- "integration_test/**"
|
||||||
|
- "test/**"
|
||||||
|
- "tool/**"
|
||||||
@@ -35,6 +35,7 @@ fi
|
|||||||
|
|
||||||
source ./app_env.sh cakewallet
|
source ./app_env.sh cakewallet
|
||||||
./app_config.sh
|
./app_config.sh
|
||||||
|
echo "flutter pub get may take a while, please wait..."
|
||||||
cd ../.. && flutter pub get
|
cd ../.. && flutter pub get
|
||||||
dart run tool/generate_localization.dart
|
dart run tool/generate_localization.dart
|
||||||
./compile_graphics.sh
|
./compile_graphics.sh
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
sources:
|
||||||
|
exclude:
|
||||||
|
- "**/.secrets.g.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_transaction_info.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.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/hardware/bitcoin_hardware_wallet_service.dart';
|
||||||
import 'package:cw_bitcoin/lightning/lightning_wallet.dart';
|
import 'package:cw_bitcoin/lightning/lightning_wallet.dart';
|
||||||
import 'package:cw_bitcoin/hardware/bitcoin_ledger_service.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/output_info.dart';
|
||||||
import 'package:cw_core/payjoin_session.dart';
|
import 'package:cw_core/payjoin_session.dart';
|
||||||
import 'package:cw_core/pending_transaction.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_coin_type.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.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(
|
return PSBTTransactionBuild(
|
||||||
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF, cwOutputs: cwOutputs)
|
inputs: psbtReadyInputs,
|
||||||
|
outputs: outputs,
|
||||||
|
enableRBF: enableRBF,
|
||||||
|
cwOutputs: cwOutputs,
|
||||||
|
locktime: locktime)
|
||||||
.psbt;
|
.psbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
int effectiveValue(int value, int inputCost) => value - inputCost;
|
||||||
|
|
||||||
|
class SelectedCoins {
|
||||||
|
final List<int> indices;
|
||||||
|
final bool hasChange;
|
||||||
|
const SelectedCoins(this.indices, this.hasChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedCoins? branchAndBound(List<int> effValues, int target, int costOfChange,
|
||||||
|
{int maxTries = 100000}) {
|
||||||
|
final n = effValues.length;
|
||||||
|
final order = List<int>.generate(n, (i) => i)
|
||||||
|
..sort((a, b) => effValues[b].compareTo(effValues[a]));
|
||||||
|
final sorted = [for (final i in order) effValues[i]];
|
||||||
|
final suffix = List<int>.filled(n + 1, 0);
|
||||||
|
for (var i = n - 1; i >= 0; i--) suffix[i] = suffix[i + 1] + sorted[i];
|
||||||
|
final upper = target + costOfChange;
|
||||||
|
List<int>? best;
|
||||||
|
final picked = <int>[];
|
||||||
|
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<int> effValues, int target, int minChange, Random rng) {
|
||||||
|
final order = List<int>.generate(effValues.length, (i) => i)..shuffle(rng);
|
||||||
|
final picked = <int>[]; 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<int> values,
|
||||||
|
required int target,
|
||||||
|
required List<int> inputCosts,
|
||||||
|
required int window,
|
||||||
|
int maxTries = 100000,
|
||||||
|
}) {
|
||||||
|
assert(values.length == inputCosts.length);
|
||||||
|
final keep = <int>[];
|
||||||
|
final eff = <int>[];
|
||||||
|
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<int> values, required int target,
|
||||||
|
required int inputCost, required int costOfChange, required int minChange, Random? rng}) {
|
||||||
|
final keep = <int>[]; final eff = <int>[];
|
||||||
|
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();
|
||||||
|
}
|
||||||
@@ -579,14 +579,29 @@ class ElectrumClient {
|
|||||||
return [];
|
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<List<int>> feeRates({BasedUtxoNetwork? network}) async {
|
Future<List<int>> feeRates({BasedUtxoNetwork? network}) async {
|
||||||
try {
|
try {
|
||||||
final topDoubleString = await estimatefee(p: 1);
|
final topDouble = await estimatefee(p: 1);
|
||||||
final middleDoubleString = await estimatefee(p: 5);
|
final middleDouble = await estimatefee(p: 5);
|
||||||
final bottomDoubleString = await estimatefee(p: 10);
|
final bottomDouble = await estimatefee(p: 10);
|
||||||
final top = (stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000).round();
|
final top = _sanitizeFeeRate(topDouble);
|
||||||
final middle = (stringDoubleToBitcoinAmount(middleDoubleString.toString()) / 1000).round();
|
final middle = _sanitizeFeeRate(middleDouble);
|
||||||
final bottom = (stringDoubleToBitcoinAmount(bottomDoubleString.toString()) / 1000).round();
|
final bottom = _sanitizeFeeRate(bottomDouble);
|
||||||
|
|
||||||
return [bottom, middle, top];
|
return [bottom, middle, top];
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:isolate';
|
import 'dart:isolate';
|
||||||
|
import 'dart:math' show Random;
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/lightning/lightning_wallet.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/hardware/hardware_wallet_service.dart';
|
||||||
import 'package:cw_core/root_dir.dart';
|
import 'package:cw_core/root_dir.dart';
|
||||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||||
|
import 'package:cw_bitcoin/coin_selection.dart';
|
||||||
import 'package:cw_bitcoin/litecoin_wallet.dart';
|
import 'package:cw_bitcoin/litecoin_wallet.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
@@ -260,6 +263,29 @@ abstract class ElectrumWalletBase
|
|||||||
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
||||||
inputsCount * 68 + outputsCounts * 34 + 10;
|
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.
|
// 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.
|
// e.g. "m/84'/0'/1'" → 1. Returns 0 for unrecognised formats.
|
||||||
static int _parseAccountIndex(String? derivationPath) {
|
static int _parseAccountIndex(String? derivationPath) {
|
||||||
@@ -448,6 +474,15 @@ abstract class ElectrumWalletBase
|
|||||||
return currentChainTip ?? 0;
|
return currentChainTip ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Anti-fee-sniping locktime (current tip, exact-tip), LE-encoded for
|
||||||
|
/// `BitcoinTransactionBuilder`.
|
||||||
|
Future<List<int>> _antiFeeSnipingLocktime() async {
|
||||||
|
return locktimeToBytes(antiFeeSnipingLocktime(
|
||||||
|
chainTip: await getCurrentChainTip(),
|
||||||
|
synced: syncStatus is SyncedSyncStatus,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
BitcoinWalletKeys get keys {
|
BitcoinWalletKeys get keys {
|
||||||
String? wif;
|
String? wif;
|
||||||
@@ -750,6 +785,9 @@ abstract class ElectrumWalletBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _isValidFeeRates(List<int> feeRates) =>
|
||||||
|
feeRates.length == 3 && feeRates.every((rate) => rate > 0);
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> updateFeeRates() async {
|
Future<void> updateFeeRates() async {
|
||||||
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
|
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
|
||||||
@@ -776,7 +814,7 @@ abstract class ElectrumWalletBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
final feeRates = await electrumClient.feeRates(network: network);
|
final feeRates = await electrumClient.feeRates(network: network);
|
||||||
if (feeRates != [0, 0, 0]) {
|
if (_isValidFeeRates(feeRates)) {
|
||||||
_feeRates = feeRates;
|
_feeRates = feeRates;
|
||||||
} else if (isTestnet) {
|
} else if (isTestnet) {
|
||||||
_feeRates = [1, 1, 1];
|
_feeRates = [1, 1, 1];
|
||||||
@@ -868,11 +906,23 @@ abstract class ElectrumWalletBase
|
|||||||
bool _isBelowDust(BigInt amount) =>
|
bool _isBelowDust(BigInt amount) =>
|
||||||
amount <= networkDustAmount && network != BitcoinNetwork.testnet;
|
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<String, int> _coinSelectionOrder = {};
|
||||||
|
|
||||||
|
int _coinSelectionPriority(BitcoinUnspent utx) => _coinSelectionOrder.putIfAbsent(
|
||||||
|
'${utx.hash}:${utx.vout}', () => _coinSelectionRng.nextInt(1 << 32));
|
||||||
|
|
||||||
UtxoDetails _createUTXOS({
|
UtxoDetails _createUTXOS({
|
||||||
required bool sendAll,
|
required bool sendAll,
|
||||||
required bool paysToSilentPayment,
|
required bool paysToSilentPayment,
|
||||||
int credentialsAmount = 0,
|
int credentialsAmount = 0,
|
||||||
int? inputsCount,
|
int? inputsCount,
|
||||||
|
int feeRate = 0,
|
||||||
|
int? outputsVBytes,
|
||||||
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
||||||
}) {
|
}) {
|
||||||
List<UtxoWithAddress> utxos = [];
|
List<UtxoWithAddress> utxos = [];
|
||||||
@@ -901,8 +951,52 @@ abstract class ElectrumWalletBase
|
|||||||
}).toList();
|
}).toList();
|
||||||
final unconfirmedCoins = availableInputs.where((utx) => utx.confirmations == 0).toList();
|
final unconfirmedCoins = availableInputs.where((utx) => utx.confirmations == 0).toList();
|
||||||
|
|
||||||
// sort the unconfirmed coins so that mweb coins are last:
|
// Single Random Draw: order the pool by each coin's random priority so selection is
|
||||||
availableInputs.sort((a, b) => a.bitcoinAddressRecord.type == SegwitAddresType.mweb ? 1 : -1);
|
// 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++) {
|
for (int i = 0; i < availableInputs.length; i++) {
|
||||||
final utx = availableInputs[i];
|
final utx = availableInputs[i];
|
||||||
@@ -1024,7 +1118,7 @@ abstract class ElectrumWalletBase
|
|||||||
vinOutpoints: utxoDetails.vinOutpoints,
|
vinOutpoints: utxoDetails.vinOutpoints,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (fee == 0) {
|
if (fee <= 0) {
|
||||||
throw BitcoinTransactionNoFeeException();
|
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(
|
final utxoDetails = _createUTXOS(
|
||||||
sendAll: false,
|
sendAll: false,
|
||||||
credentialsAmount: credentialsAmount.amount.toInt(),
|
credentialsAmount: credentialsAmount.amount.toInt(),
|
||||||
inputsCount: inputsCount,
|
inputsCount: inputsCount,
|
||||||
|
feeRate: feeRate,
|
||||||
|
outputsVBytes: outputsVBytes,
|
||||||
paysToSilentPayment: hasSilentPayment,
|
paysToSilentPayment: hasSilentPayment,
|
||||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||||
);
|
);
|
||||||
@@ -1205,7 +1314,7 @@ abstract class ElectrumWalletBase
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fee == 0) {
|
if (fee <= 0) {
|
||||||
throw BitcoinTransactionNoFeeException();
|
throw BitcoinTransactionNoFeeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1384,6 +1493,10 @@ abstract class ElectrumWalletBase
|
|||||||
@override
|
@override
|
||||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
try {
|
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
|
// start by updating unspent coins
|
||||||
await updateAllUnspents();
|
await updateAllUnspents();
|
||||||
|
|
||||||
@@ -1513,6 +1626,8 @@ abstract class ElectrumWalletBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final locktime = await _antiFeeSnipingLocktime();
|
||||||
|
|
||||||
BasedBitcoinTransacationBuilder txb;
|
BasedBitcoinTransacationBuilder txb;
|
||||||
if (network is BitcoinCashNetwork) {
|
if (network is BitcoinCashNetwork) {
|
||||||
txb = ForkedTransactionBuilder(
|
txb = ForkedTransactionBuilder(
|
||||||
@@ -1537,6 +1652,7 @@ abstract class ElectrumWalletBase
|
|||||||
inputOrdering: BitcoinOrdering.shuffle,
|
inputOrdering: BitcoinOrdering.shuffle,
|
||||||
outputOrdering: BitcoinOrdering.shuffle,
|
outputOrdering: BitcoinOrdering.shuffle,
|
||||||
enableRBF: !estimatedTx.spendsUnconfirmedTX,
|
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) {
|
if (remainingFee > BigInt.zero) {
|
||||||
final unusedUtxos = unspentCoins
|
final unusedUtxos = unspentCoins
|
||||||
.where((utxo) => utxo.isSending && !utxo.isFrozen && utxo.confirmations! > 0)
|
.where((utxo) => utxo.isSending && !utxo.isFrozen && utxo.confirmations! > 0)
|
||||||
.toList();
|
.toList()
|
||||||
|
..shuffle(Random.secure());
|
||||||
|
|
||||||
for (final utxo in unusedUtxos) {
|
for (final utxo in unusedUtxos) {
|
||||||
final address = RegexUtils.addressTypeFromStr(utxo.address, network);
|
final address = RegexUtils.addressTypeFromStr(utxo.address, network);
|
||||||
@@ -2303,6 +2421,7 @@ abstract class ElectrumWalletBase
|
|||||||
inputOrdering: BitcoinOrdering.shuffle,
|
inputOrdering: BitcoinOrdering.shuffle,
|
||||||
outputOrdering: BitcoinOrdering.shuffle,
|
outputOrdering: BitcoinOrdering.shuffle,
|
||||||
enableRBF: true,
|
enableRBF: true,
|
||||||
|
locktime: await _antiFeeSnipingLocktime(),
|
||||||
);
|
);
|
||||||
|
|
||||||
final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) {
|
final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) {
|
||||||
@@ -2513,16 +2632,16 @@ abstract class ElectrumWalletBase
|
|||||||
Map<String, ElectrumTransactionInfo> historiesWithDetails,
|
Map<String, ElectrumTransactionInfo> historiesWithDetails,
|
||||||
BitcoinAddressType type,
|
BitcoinAddressType type,
|
||||||
) async {
|
) async {
|
||||||
|
|
||||||
final addressesByType =
|
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 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 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 walletAddresses.saveAddressesInBox();
|
||||||
await Future.wait(addressesByType.map((addressRecord) async {
|
await Future.wait(addressesByType.map((addressRecord) async {
|
||||||
final history = await _fetchAddressHistory(addressRecord, await getCurrentChainTip());
|
final history = await _fetchAddressHistory(addressRecord, await getCurrentChainTip());
|
||||||
@@ -2637,13 +2756,13 @@ abstract class ElectrumWalletBase
|
|||||||
|
|
||||||
Future<void> fetchTransactionsForAddressTypeBatch(
|
Future<void> fetchTransactionsForAddressTypeBatch(
|
||||||
Map<String, ElectrumTransactionInfo> historiesWithDetails, BitcoinAddressType type) async {
|
Map<String, ElectrumTransactionInfo> historiesWithDetails, BitcoinAddressType type) async {
|
||||||
|
|
||||||
final receiveStandard = getAddressBranchByType(hidden: false, legacy: false, type: type);
|
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 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 walletAddresses.saveAddressesInBox();
|
||||||
|
|
||||||
await fetchTransactionsForAddressesBranchBatch(
|
await fetchTransactionsForAddressesBranchBatch(
|
||||||
@@ -2665,7 +2784,7 @@ abstract class ElectrumWalletBase
|
|||||||
await fetchTransactionsForAddressesBranchBatch(
|
await fetchTransactionsForAddressesBranchBatch(
|
||||||
historiesWithDetails,
|
historiesWithDetails,
|
||||||
type,
|
type,
|
||||||
receiveLegacy,
|
receiveLegacy,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
isLegacyDerivation: true,
|
isLegacyDerivation: true,
|
||||||
);
|
);
|
||||||
@@ -2749,10 +2868,13 @@ abstract class ElectrumWalletBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BitcoinAddressRecord> getAddressBranchByType({required bool hidden, required bool legacy, required BitcoinAddressType
|
List<BitcoinAddressRecord> getAddressBranchByType(
|
||||||
type}) => walletAddresses.allAddresses.where((addr) => addr.type == type && addr.isHidden == hidden && addr.isLegacyDerivation == legacy)
|
{required bool hidden, required bool legacy, required BitcoinAddressType type}) =>
|
||||||
.toList()
|
walletAddresses.allAddresses
|
||||||
..sort((a, b) => a.index.compareTo(b.index));
|
.where((addr) =>
|
||||||
|
addr.type == type && addr.isHidden == hidden && addr.isLegacyDerivation == legacy)
|
||||||
|
.toList()
|
||||||
|
..sort((a, b) => a.index.compareTo(b.index));
|
||||||
|
|
||||||
int _highestUsedIndex(List<BitcoinAddressRecord> addresses) {
|
int _highestUsedIndex(List<BitcoinAddressRecord> addresses) {
|
||||||
for (int i = addresses.length - 1; i >= 0; i--) {
|
for (int i = addresses.length - 1; i >= 0; i--) {
|
||||||
|
|||||||
@@ -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<int> locktimeToBytes(int locktime) => (ByteData(4)..setUint32(0, locktime, Endian.little)).buffer.asUint8List();
|
||||||
@@ -295,6 +295,9 @@ class PayjoinManager {
|
|||||||
await _wallet.updateAllUnspents();
|
await _wallet.updateAllUnspents();
|
||||||
utxos = _wallet.getUtxoWithPrivateKeys(confirmedOnly: true);
|
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({
|
mainToIsolateSendPort?.send({
|
||||||
'requestId': message['requestId'],
|
'requestId': message['requestId'],
|
||||||
'result': utxos,
|
'result': utxos,
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ class PSBTTransactionBuild {
|
|||||||
{required List<PSBTReadyUtxoWithAddress> inputs,
|
{required List<PSBTReadyUtxoWithAddress> inputs,
|
||||||
required List<BitcoinBaseOutput> outputs,
|
required List<BitcoinBaseOutput> outputs,
|
||||||
required List<OutputInfo> cwOutputs,
|
required List<OutputInfo> cwOutputs,
|
||||||
bool enableRBF = true}) {
|
bool enableRBF = true,
|
||||||
|
int locktime = 0}) {
|
||||||
psbt.setGlobalTxVersion(2);
|
psbt.setGlobalTxVersion(2);
|
||||||
|
psbt.setGlobalFallbackLocktime(locktime);
|
||||||
psbt.setGlobalInputCount(inputs.length);
|
psbt.setGlobalInputCount(inputs.length);
|
||||||
psbt.setGlobalOutputCount(outputs.length);
|
psbt.setGlobalOutputCount(outputs.length);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@ dependencies:
|
|||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/blockchain_utils
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
ref: cake-update-v2
|
ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
|
||||||
cw_mweb:
|
cw_mweb:
|
||||||
path: ../cw_mweb
|
path: ../cw_mweb
|
||||||
grpc: 4.0.1
|
grpc: 4.0.1
|
||||||
@@ -88,7 +88,7 @@ dependency_overrides:
|
|||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-update-v11
|
ref: bda0e2904effa799ec835b4578cc3fc5d31caa78
|
||||||
pointycastle: 3.7.4
|
pointycastle: 3.7.4
|
||||||
ffi: 2.1.0
|
ffi: 2.1.0
|
||||||
intl: any
|
intl: any
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
@@ -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<InsufficientFundsException>()));
|
||||||
|
});
|
||||||
|
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<int>.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]));
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -22,8 +22,6 @@ migrate_working_dir/
|
|||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
|
||||||
/pubspec.lock
|
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.packages
|
.packages
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ dependencies:
|
|||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/blockchain_utils
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
ref: cake-update-v2
|
ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -43,7 +43,7 @@ dependency_overrides:
|
|||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base
|
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
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
sources:
|
||||||
|
exclude:
|
||||||
|
- "**/.secrets.g.dart"
|
||||||
@@ -202,10 +202,6 @@ class Money implements Comparable<Money> {
|
|||||||
@override
|
@override
|
||||||
int get hashCode => amount.hashCode ^ currency.hashCode;
|
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
|
@override
|
||||||
String toString() => formatFixed(amount, currency.decimals);
|
String toString() => formatFixed(amount, currency.decimals);
|
||||||
|
|
||||||
|
|||||||
@@ -1007,6 +1007,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||||||
'bitcoin': btc,
|
'bitcoin': btc,
|
||||||
'bitcoincash': bch,
|
'bitcoincash': bch,
|
||||||
'polygon': maticpoly,
|
'polygon': maticpoly,
|
||||||
|
'solana': sol,
|
||||||
'nano-gpt': nano,
|
'nano-gpt': nano,
|
||||||
'secret': scrt,
|
'secret': scrt,
|
||||||
'stellar': xlm,
|
'stellar': xlm,
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ Future<void> _initDb({String? pathOverride}) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await db?.close();
|
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 {
|
onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
||||||
printV("migrating: $oldVersion, $newVersion");
|
printV("migrating: $oldVersion, $newVersion");
|
||||||
if (oldVersion <= 1) {
|
if (oldVersion <= 1) {
|
||||||
@@ -147,6 +147,11 @@ CREATE TABLE IF NOT EXISTS BalanceCardStyleSettings (
|
|||||||
definition: 'BOOLEAN DEFAULT FALSE',
|
definition: 'BOOLEAN DEFAULT FALSE',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (oldVersion <= 9) {
|
||||||
|
await _createErc20TokenTable(db);
|
||||||
|
await _createSplTokenTable(db);
|
||||||
|
await _createTronTokenTable(db);
|
||||||
|
}
|
||||||
}, onCreate: (Database db, int version) async {
|
}, onCreate: (Database db, int version) async {
|
||||||
await db.execute('''
|
await db.execute('''
|
||||||
CREATE TABLE WalletInfo (
|
CREATE TABLE WalletInfo (
|
||||||
@@ -242,6 +247,9 @@ CREATE TABLE BalanceCardStyleSettings (
|
|||||||
await _createBridgeTransferTable(db);
|
await _createBridgeTransferTable(db);
|
||||||
await _createNodeTable(db);
|
await _createNodeTable(db);
|
||||||
await _createTradeTable(db);
|
await _createTradeTable(db);
|
||||||
|
await _createErc20TokenTable(db);
|
||||||
|
await _createSplTokenTable(db);
|
||||||
|
await _createTronTokenTable(db);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,6 +378,71 @@ ON BridgeTransfer(wallet_id);
|
|||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _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<void> _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<void> _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<void> _createNodeTable(Database db) async {
|
Future<void> _createNodeTable(Database db) async {
|
||||||
db.execute("""
|
db.execute("""
|
||||||
CREATE TABLE Node (
|
CREATE TABLE Node (
|
||||||
|
|||||||
+153
-45
@@ -1,32 +1,8 @@
|
|||||||
import 'package:cw_core/crypto_currency.dart';
|
import "package:cw_core/crypto_currency.dart";
|
||||||
import 'package:cw_core/hive_type_ids.dart';
|
import "package:cw_core/db/sqlite.dart";
|
||||||
import 'package:hive/hive.dart';
|
import "package:sqflite/sqflite.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;
|
|
||||||
|
|
||||||
|
class Erc20Token extends CryptoCurrency {
|
||||||
Erc20Token({
|
Erc20Token({
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.symbol,
|
required this.symbol,
|
||||||
@@ -36,6 +12,9 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
|
|||||||
this.iconPath,
|
this.iconPath,
|
||||||
this.tag,
|
this.tag,
|
||||||
this.isPotentialScam = false,
|
this.isPotentialScam = false,
|
||||||
|
this.id = 0,
|
||||||
|
this.walletName,
|
||||||
|
this.chainId,
|
||||||
}) : _enabled = enabled,
|
}) : _enabled = enabled,
|
||||||
super(
|
super(
|
||||||
name: symbol.toLowerCase(),
|
name: symbol.toLowerCase(),
|
||||||
@@ -47,32 +26,161 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
|
|||||||
isPotentialScam: isPotentialScam,
|
isPotentialScam: isPotentialScam,
|
||||||
);
|
);
|
||||||
|
|
||||||
Erc20Token.copyWith(Erc20Token other, {String? icon, String? tag, bool? enabled})
|
Erc20Token.copyWith(
|
||||||
: this.name = other.name,
|
Erc20Token other, {
|
||||||
this.symbol = other.symbol,
|
String? icon,
|
||||||
this.contractAddress = other.contractAddress,
|
super.tag,
|
||||||
this.decimal = other.decimal,
|
bool? enabled,
|
||||||
this._enabled = enabled ?? other.enabled,
|
String? walletName,
|
||||||
this.tag = tag ?? other.tag,
|
int? chainId,
|
||||||
this.iconPath = icon ?? other.iconPath,
|
}) : name = other.name,
|
||||||
this.isPotentialScam = other.isPotentialScam,
|
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(
|
super(
|
||||||
name: other.name,
|
name: other.name,
|
||||||
title: other.symbol.toUpperCase(),
|
title: other.symbol.toUpperCase(),
|
||||||
fullName: other.name,
|
fullName: other.name,
|
||||||
tag: tag,
|
|
||||||
iconPath: icon,
|
iconPath: icon,
|
||||||
decimals: other.decimal,
|
decimals: other.decimal,
|
||||||
isPotentialScam: other.isPotentialScam,
|
isPotentialScam: other.isPotentialScam,
|
||||||
);
|
);
|
||||||
|
|
||||||
static const typeId = ERC20_TOKEN_TYPE_ID;
|
Erc20Token.fromMap(Map<String, Object?> map)
|
||||||
static const boxName = 'Erc20Tokens';
|
: this(
|
||||||
static const ethereumBoxName = 'EthereumErc20Tokens';
|
name: map["name"] as String? ?? "",
|
||||||
static const polygonBoxName = 'PolygonErc20Tokens';
|
symbol: map["symbol"] as String? ?? "",
|
||||||
static const baseBoxName = 'BaseErc20Tokens';
|
contractAddress: map["contractAddress"] as String? ?? "",
|
||||||
static const arbitrumBoxName = 'ArbitrumErc20Tokens';
|
decimal: (map["decimal"] ?? 0) as int,
|
||||||
static const bscBoxName = 'BscErc20Tokens';
|
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<String, dynamic> 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<int> 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<List<Erc20Token>> selectList(
|
||||||
|
String where,
|
||||||
|
List<dynamic> 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<List<Erc20Token>> getAllForWallet(String walletName, int chainId) =>
|
||||||
|
selectList("walletName = ? AND chainId = ?", [walletName, chainId]);
|
||||||
|
|
||||||
|
static Future<Erc20Token?> 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<int> deleteForWallet(String walletName, int chainId, String contractAddress) =>
|
||||||
|
db!.delete(
|
||||||
|
tableName,
|
||||||
|
where: "walletName = ? AND chainId = ? AND contractAddress = ?",
|
||||||
|
whereArgs: [walletName, chainId, contractAddress.toLowerCase()],
|
||||||
|
);
|
||||||
|
|
||||||
|
static Future<int> deleteAllForWallet(String walletName) =>
|
||||||
|
db!.delete(tableName, where: "walletName = ?", whereArgs: [walletName]);
|
||||||
|
|
||||||
|
static Future<void> 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
|
@override
|
||||||
bool operator ==(Object other) => other is Erc20Token && other.contractAddress == contractAddress;
|
bool operator ==(Object other) => other is Erc20Token && other.contractAddress == contractAddress;
|
||||||
|
|||||||
@@ -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<void> 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<void> migrateAllToSqlite(List<WalletInfo> wallets) async {
|
||||||
|
await _migrateLegacyGlobalBox(wallets);
|
||||||
|
|
||||||
|
final sanitizedToRawNames = <String, Set<String>>{};
|
||||||
|
for (final wallet in wallets) {
|
||||||
|
if (!evmWalletTypes.contains(wallet.type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitizedToRawNames
|
||||||
|
.putIfAbsent(wallet.name.replaceAll(" ", "_"), () => <String>{})
|
||||||
|
.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<Erc20Token>(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<void> _migrateLegacyGlobalBox(List<WalletInfo> wallets) async {
|
||||||
|
try {
|
||||||
|
if (!await CakeHive.boxExists(boxName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wallets.any((wallet) => wallet.type == WalletType.ethereum)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final box = await CakeHive.openBox<Erc20Token>(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<Erc20Token> box) {
|
||||||
|
final groups = <String, _MergedTokenGroup>{};
|
||||||
|
|
||||||
|
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<void> 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<dynamic> sourceKeys;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'erc20_token.dart';
|
part of "erc20_token_legacy.dart";
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// TypeAdapterGenerator
|
// TypeAdapterGenerator
|
||||||
@@ -70,3 +70,12 @@ class WalletDeprecationException implements Exception {
|
|||||||
|
|
||||||
WalletDeprecationException({required this.seed, required this.curr});
|
WalletDeprecationException({required this.seed, required this.curr});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WalletSwitchException implements Exception {
|
||||||
|
WalletSwitchException(this.message);
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => message;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,31 +4,44 @@ String formatFixed(BigInt value, int? decimals, {int? fractionalDigits, bool tri
|
|||||||
decimals ??= 0;
|
decimals ??= 0;
|
||||||
fractionalDigits ??= decimals;
|
fractionalDigits ??= decimals;
|
||||||
|
|
||||||
final multiplier = multiplierOf(decimals);
|
final multiplier = getMultiplier(decimals);
|
||||||
var negative = value.isNegative;
|
// Make sure wei is a big number (convert as necessary)
|
||||||
if (negative) value = -value;
|
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 < 0) {
|
||||||
if (fractionalDigits > decimals) fractionalDigits = decimals;
|
fractionalDigits = 0;
|
||||||
|
}
|
||||||
|
if (fractionalDigits > decimals) {
|
||||||
|
fractionalDigits = decimals;
|
||||||
|
}
|
||||||
fraction = fraction.substring(0, fractionalDigits);
|
fraction = fraction.substring(0, fractionalDigits);
|
||||||
|
|
||||||
if (trimZeros) {
|
if (trimZeros) {
|
||||||
fraction = removeTrailing("0", fraction);
|
fraction = removeTrailing("0", fraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
final whole = value ~/ multiplier;
|
final whole = value ~/ BigInt.parse(multiplier);
|
||||||
|
|
||||||
final valString = fraction.isEmpty ? "$whole" : "$whole.$fraction";
|
final valString = fraction.isEmpty ? "$whole" : "$whole.$fraction";
|
||||||
|
|
||||||
if (negative) return "-$valString";
|
if (negative) {
|
||||||
|
return "-$valString";
|
||||||
|
}
|
||||||
|
|
||||||
return valString;
|
return valString;
|
||||||
}
|
}
|
||||||
|
|
||||||
String removeTrailing(String pattern, String from) {
|
String removeTrailing(String pattern, String from) {
|
||||||
if (pattern.isEmpty) return from;
|
if (pattern.isEmpty) {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
var i = from.length;
|
var i = from.length;
|
||||||
while (i > 0 && from.startsWith(pattern, i - pattern.length)) {
|
while (i > 0 && from.startsWith(pattern, i - pattern.length)) {
|
||||||
i -= pattern.length;
|
i -= pattern.length;
|
||||||
|
|||||||
@@ -37,40 +37,44 @@ BigInt parseFixed(String value, int decimals) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final negative = value.startsWith("-");
|
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(".");
|
final comps = value.split(".");
|
||||||
if (comps.length > 2) {
|
if (comps.length > 2) {
|
||||||
throw FormatException("too many decimal points, value, $value");
|
throw FormatException("too many decimal points, value, $value");
|
||||||
}
|
}
|
||||||
|
|
||||||
var whole = comps.isNotEmpty ? comps[0] : "0";
|
final whole = comps.isNotEmpty ? comps[0] : "0";
|
||||||
var fraction = (comps.length == 2 ? comps[1] : "0").padRight(decimals, "0");
|
final fraction = (comps.length == 2 ? comps[1] : "0").padRight(decimals, "0");
|
||||||
|
|
||||||
if (fraction.length > multiplier.length - 1) {
|
if (fraction.length > multiplier.length - 1) {
|
||||||
throw FormatException(
|
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 wholeValue = BigInt.parse(whole);
|
||||||
final fractionValue = BigInt.parse(fraction);
|
final fractionValue = BigInt.parse(fraction);
|
||||||
final multiplierValue = multiplierOf(decimals);
|
final multiplierValue = BigInt.parse(multiplier);
|
||||||
|
|
||||||
var wei = (wholeValue * multiplierValue) + fractionValue;
|
var wei = (wholeValue * multiplierValue) + fractionValue;
|
||||||
|
|
||||||
if (negative) wei *= BigInt.from(-1);
|
if (negative) {
|
||||||
|
wei *= BigInt.from(-1);
|
||||||
|
}
|
||||||
|
|
||||||
return wei;
|
return wei;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a string "1" followed by decimal "0"s
|
// Returns a string "1" followed by decimal "0"s
|
||||||
String getMultiplier(int decimals) => "1".padRight(decimals + 1, "0");
|
String getMultiplier(int decimals) => "1".padRight(decimals + 1, "0");
|
||||||
|
|
||||||
final _multipliers = <int, BigInt>{};
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|||||||
@@ -283,8 +283,8 @@ class ERC681URI extends PaymentURI {
|
|||||||
} else {
|
} else {
|
||||||
final valueParam = uri.queryParameters["value"];
|
final valueParam = uri.queryParameters["value"];
|
||||||
if (valueParam != null) {
|
if (valueParam != null) {
|
||||||
final normalized = _normalizeToIntegerWei(valueParam);
|
final normalized = BigInt.tryParse(_normalizeToIntegerWei(valueParam));
|
||||||
formatedAmount = formatFixed(BigInt.parse(normalized), 18);
|
formatedAmount = normalized != null ? formatFixed(normalized, 18) : "";
|
||||||
} else {
|
} else {
|
||||||
formatedAmount = uri.queryParameters["amount"] ?? "";
|
formatedAmount = uri.queryParameters["amount"] ?? "";
|
||||||
}
|
}
|
||||||
@@ -313,9 +313,7 @@ class ERC681URI extends PaymentURI {
|
|||||||
final targetAddress = contractAddress ?? address;
|
final targetAddress = contractAddress ?? address;
|
||||||
uri += targetAddress;
|
uri += targetAddress;
|
||||||
|
|
||||||
if (chainId != 1) {
|
uri += "@$chainId";
|
||||||
uri += "@$chainId";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contractAddress != null) {
|
if (contractAddress != null) {
|
||||||
uri += "/transfer";
|
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",
|
RegExp(r"@\d*").firstMatch(path)?.group(0)?.replaceAll("@", "") ?? "1",
|
||||||
);
|
) ??
|
||||||
|
1;
|
||||||
|
|
||||||
static (bool, String) _getTargetAddress(String path) {
|
static (bool, String) _getTargetAddress(String path) {
|
||||||
final 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
|
||||||
RegExp(r"^(0x)?[0-9a-f]{40}", caseSensitive: false).firstMatch(path)!.group(0)!;
|
final cleaned = path.startsWith("pay-") ? path.substring(4) : path;
|
||||||
return (path.contains("/"), targetAddress);
|
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.
|
/// Normalize an input amount into an integer wei string.
|
||||||
|
|||||||
+130
-52
@@ -1,41 +1,8 @@
|
|||||||
import 'package:cw_core/crypto_currency.dart';
|
import "package:cw_core/crypto_currency.dart";
|
||||||
import 'package:cw_core/hive_type_ids.dart';
|
import "package:cw_core/db/sqlite.dart";
|
||||||
import 'package:hive/hive.dart';
|
import "package:sqflite/sqflite.dart";
|
||||||
|
|
||||||
part 'spl_token.part.dart';
|
class SPLToken extends CryptoCurrency {
|
||||||
|
|
||||||
// @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;
|
|
||||||
|
|
||||||
SPLToken({
|
SPLToken({
|
||||||
required this.name,
|
required this.name,
|
||||||
@@ -44,10 +11,12 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
required this.decimal,
|
required this.decimal,
|
||||||
required this.mint,
|
required this.mint,
|
||||||
this.iconPath,
|
this.iconPath,
|
||||||
this.tag = 'SOL',
|
this.tag = "SOL",
|
||||||
bool enabled = true,
|
bool enabled = true,
|
||||||
this.isPotentialScam = false,
|
this.isPotentialScam = false,
|
||||||
Set<String> groups = const {},
|
super.groups,
|
||||||
|
this.id = 0,
|
||||||
|
this.walletName,
|
||||||
}) : _enabled = enabled,
|
}) : _enabled = enabled,
|
||||||
super(
|
super(
|
||||||
name: mint.toLowerCase(),
|
name: mint.toLowerCase(),
|
||||||
@@ -57,7 +26,6 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
iconPath: iconPath,
|
iconPath: iconPath,
|
||||||
decimals: decimal,
|
decimals: decimal,
|
||||||
isPotentialScam: isPotentialScam,
|
isPotentialScam: isPotentialScam,
|
||||||
groups: groups,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
factory SPLToken.fromMetadata({
|
factory SPLToken.fromMetadata({
|
||||||
@@ -67,8 +35,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
required String mintAddress,
|
required String mintAddress,
|
||||||
String? iconPath,
|
String? iconPath,
|
||||||
bool isPotentialScam = false,
|
bool isPotentialScam = false,
|
||||||
}) {
|
}) => SPLToken(
|
||||||
return SPLToken(
|
|
||||||
name: name,
|
name: name,
|
||||||
symbol: symbol,
|
symbol: symbol,
|
||||||
mintAddress: mintAddress,
|
mintAddress: mintAddress,
|
||||||
@@ -77,15 +44,8 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
iconPath: iconPath,
|
iconPath: iconPath,
|
||||||
isPotentialScam: isPotentialScam,
|
isPotentialScam: isPotentialScam,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
SPLToken.copyWith(SPLToken other, {String? icon, String? tag, bool? enabled, String? walletName})
|
||||||
bool get enabled => _enabled;
|
|
||||||
|
|
||||||
@override
|
|
||||||
set enabled(bool value) => _enabled = value;
|
|
||||||
|
|
||||||
SPLToken.copyWith(SPLToken other, {String? icon, String? tag, bool? enabled})
|
|
||||||
: name = other.name,
|
: name = other.name,
|
||||||
symbol = other.symbol,
|
symbol = other.symbol,
|
||||||
mintAddress = other.mintAddress,
|
mintAddress = other.mintAddress,
|
||||||
@@ -95,6 +55,8 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
tag = tag ?? other.tag,
|
tag = tag ?? other.tag,
|
||||||
iconPath = icon ?? other.iconPath,
|
iconPath = icon ?? other.iconPath,
|
||||||
isPotentialScam = other.isPotentialScam,
|
isPotentialScam = other.isPotentialScam,
|
||||||
|
id = 0,
|
||||||
|
walletName = walletName ?? other.walletName,
|
||||||
super(
|
super(
|
||||||
title: other.symbol.toUpperCase(),
|
title: other.symbol.toUpperCase(),
|
||||||
name: other.symbol.toLowerCase(),
|
name: other.symbol.toLowerCase(),
|
||||||
@@ -106,8 +68,124 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
groups: other.groups,
|
groups: other.groups,
|
||||||
);
|
);
|
||||||
|
|
||||||
static const typeId = SPL_TOKEN_TYPE_ID;
|
SPLToken.fromMap(Map<String, Object?> map)
|
||||||
static const boxName = 'SPLTokens';
|
: 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<String, dynamic> 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<int> 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<List<SPLToken>> selectList(String where, List<dynamic> 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<List<SPLToken>> getAllForWallet(String walletName) async => selectList("walletName = ?", [walletName]);
|
||||||
|
|
||||||
|
static Future<SPLToken?> getByMint(String walletName, String mintAddress) async {
|
||||||
|
final list = await selectList("walletName = ? AND mintAddress = ?", [walletName, mintAddress]);
|
||||||
|
return list.isEmpty ? null : list.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<int> deleteForWallet(String walletName, String mintAddress) => db!.delete(
|
||||||
|
tableName,
|
||||||
|
where: "walletName = ? AND mintAddress = ?",
|
||||||
|
whereArgs: [walletName, mintAddress],
|
||||||
|
);
|
||||||
|
|
||||||
|
static Future<int> deleteAllForWallet(String walletName) => db!.delete(tableName, where: "walletName = ?", whereArgs: [walletName]);
|
||||||
|
|
||||||
|
static Future<void> 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
|
@override
|
||||||
bool operator ==(other) =>
|
bool operator ==(other) =>
|
||||||
|
|||||||
@@ -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<void> 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<void> migrateAllToSqlite(List<WalletInfo> wallets) async {
|
||||||
|
final sanitizedToRawNames = <String, Set<String>>{};
|
||||||
|
for (final wallet in wallets) {
|
||||||
|
if (wallet.type != WalletType.solana) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitizedToRawNames
|
||||||
|
.putIfAbsent(wallet.name.replaceAll(" ", "_"), () => <String>{})
|
||||||
|
.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<SPLToken>(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<void> 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'spl_token.dart';
|
part of "spl_token_legacy.dart";
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// TypeAdapterGenerator
|
// TypeAdapterGenerator
|
||||||
+132
-42
@@ -1,41 +1,8 @@
|
|||||||
// ignore_for_file: annotate_overrides, overridden_fields
|
import "package:cw_core/crypto_currency.dart";
|
||||||
|
import "package:cw_core/db/sqlite.dart";
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import "package:sqflite/sqflite.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;
|
|
||||||
|
|
||||||
|
class TronToken extends CryptoCurrency {
|
||||||
TronToken({
|
TronToken({
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.symbol,
|
required this.symbol,
|
||||||
@@ -43,8 +10,10 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
required this.decimal,
|
required this.decimal,
|
||||||
bool enabled = true,
|
bool enabled = true,
|
||||||
this.iconPath,
|
this.iconPath,
|
||||||
this.tag = 'TRX',
|
this.tag = "TRX",
|
||||||
this.isPotentialScam = false,
|
this.isPotentialScam = false,
|
||||||
|
this.id = 0,
|
||||||
|
this.walletName,
|
||||||
}) : _enabled = enabled,
|
}) : _enabled = enabled,
|
||||||
super(
|
super(
|
||||||
name: symbol.toLowerCase(),
|
name: symbol.toLowerCase(),
|
||||||
@@ -55,9 +24,27 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
decimals: decimal,
|
decimals: decimal,
|
||||||
isPotentialScam: isPotentialScam,
|
isPotentialScam: isPotentialScam,
|
||||||
);
|
);
|
||||||
|
TronToken.fromMap(Map<String, Object?> 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})
|
TronToken.copyWith(
|
||||||
: name = other.name,
|
TronToken other, {
|
||||||
|
String? icon,
|
||||||
|
String? tag,
|
||||||
|
bool? enabled,
|
||||||
|
String? walletName,
|
||||||
|
}) : name = other.name,
|
||||||
symbol = other.symbol,
|
symbol = other.symbol,
|
||||||
contractAddress = other.contractAddress,
|
contractAddress = other.contractAddress,
|
||||||
decimal = other.decimal,
|
decimal = other.decimal,
|
||||||
@@ -65,6 +52,8 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
tag = tag ?? other.tag,
|
tag = tag ?? other.tag,
|
||||||
iconPath = icon ?? other.iconPath,
|
iconPath = icon ?? other.iconPath,
|
||||||
isPotentialScam = other.isPotentialScam,
|
isPotentialScam = other.isPotentialScam,
|
||||||
|
id = 0,
|
||||||
|
walletName = walletName ?? other.walletName,
|
||||||
super(
|
super(
|
||||||
name: other.name,
|
name: other.name,
|
||||||
title: other.symbol.toUpperCase(),
|
title: other.symbol.toUpperCase(),
|
||||||
@@ -74,9 +63,110 @@ class TronToken extends CryptoCurrency with HiveObjectMixin {
|
|||||||
decimals: other.decimal,
|
decimals: other.decimal,
|
||||||
isPotentialScam: other.isPotentialScam,
|
isPotentialScam: other.isPotentialScam,
|
||||||
);
|
);
|
||||||
|
@override
|
||||||
|
final String name;
|
||||||
|
|
||||||
static const typeId = TRON_TOKEN_TYPE_ID;
|
@override
|
||||||
static const boxName = 'TronTokens';
|
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<String, dynamic> 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<int> 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<List<TronToken>> selectList(
|
||||||
|
String where,
|
||||||
|
List<dynamic> 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<List<TronToken>> getAllForWallet(String walletName) =>
|
||||||
|
selectList("walletName = ?", [walletName]);
|
||||||
|
|
||||||
|
static Future<TronToken?> getByContract(String walletName, String contractAddress) async {
|
||||||
|
final list =
|
||||||
|
await selectList("walletName = ? AND contractAddress = ?", [walletName, contractAddress]);
|
||||||
|
return list.isEmpty ? null : list.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<int> deleteForWallet(String walletName, String contractAddress) => db!.delete(
|
||||||
|
tableName,
|
||||||
|
where: "walletName = ? AND contractAddress = ?",
|
||||||
|
whereArgs: [walletName, contractAddress],
|
||||||
|
);
|
||||||
|
|
||||||
|
static Future<int> deleteAllForWallet(String walletName) =>
|
||||||
|
db!.delete(tableName, where: "walletName = ?", whereArgs: [walletName]);
|
||||||
|
|
||||||
|
static Future<void> 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
|
@override
|
||||||
bool operator ==(other) =>
|
bool operator ==(other) =>
|
||||||
|
|||||||
@@ -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<void> 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<void> migrateAllToSqlite(List<WalletInfo> wallets) async {
|
||||||
|
final sanitizedToRawNames = <String, Set<String>>{};
|
||||||
|
for (final wallet in wallets) {
|
||||||
|
if (wallet.type != WalletType.tron) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitizedToRawNames
|
||||||
|
.putIfAbsent(wallet.name.replaceAll(" ", "_"), () => <String>{})
|
||||||
|
.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<TronToken>(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<void> 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'tron_token.dart';
|
part of "tron_token_legacy.dart";
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// TypeAdapterGenerator
|
// TypeAdapterGenerator
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
import 'dart:convert';
|
import "dart:convert";
|
||||||
import 'dart:io';
|
import "dart:io";
|
||||||
|
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import "package:cw_core/pathForWallet.dart";
|
||||||
import 'package:cw_core/utils/file.dart';
|
import "package:cw_core/spl_token.dart";
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import "package:cw_core/tron_token.dart";
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import "package:cw_core/utils/file.dart";
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
import "package:cw_core/utils/print_verbose.dart";
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import "package:cw_core/wallet_base.dart";
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import "package:cw_core/wallet_credentials.dart";
|
||||||
import 'package:path/path.dart' as p;
|
import "package:cw_core/wallet_info.dart";
|
||||||
|
import "package:cw_core/wallet_type.dart";
|
||||||
|
import "package:path/path.dart" as p;
|
||||||
|
|
||||||
abstract class WalletService<N extends WalletCredentials, RFS extends WalletCredentials,
|
abstract class WalletService<N extends WalletCredentials, RFS extends WalletCredentials,
|
||||||
RFK extends WalletCredentials, RFH extends WalletCredentials> {
|
RFK extends WalletCredentials, RFH extends WalletCredentials> {
|
||||||
@@ -29,11 +31,13 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
|
|||||||
Future<void> remove(String wallet);
|
Future<void> remove(String wallet);
|
||||||
|
|
||||||
Future<void> rename(String currentName, String password, String newName) async {
|
Future<void> rename(String currentName, String password, String newName) async {
|
||||||
if (currentName == newName) return;
|
if (currentName == newName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final currentWalletInfo = await WalletInfo.get(currentName, getType());
|
final currentWalletInfo = await WalletInfo.get(currentName, getType());
|
||||||
if (currentWalletInfo == null) {
|
if (currentWalletInfo == null) {
|
||||||
throw Exception('Wallet not found');
|
throw Exception("Wallet not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
await copyWalletFilesTo(fromName: currentName, toName: newName, type: getType());
|
await copyWalletFilesTo(fromName: currentName, toName: newName, type: getType());
|
||||||
@@ -43,6 +47,8 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
|
|||||||
currentWalletInfo.name = newName;
|
currentWalletInfo.name = newName;
|
||||||
await currentWalletInfo.save();
|
await currentWalletInfo.save();
|
||||||
|
|
||||||
|
await _renameTokenRows(currentName, newName);
|
||||||
|
|
||||||
final oldDir = Directory(p.join(await pathForWalletTypeDir(type: getType()), currentName));
|
final oldDir = Directory(p.join(await pathForWalletTypeDir(type: getType()), currentName));
|
||||||
if (oldDir.existsSync()) {
|
if (oldDir.existsSync()) {
|
||||||
try {
|
try {
|
||||||
@@ -53,6 +59,16 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _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<void> restoreWalletFilesFromBackup(String name) async {
|
Future<void> restoreWalletFilesFromBackup(String name) async {
|
||||||
final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: getType());
|
final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: getType());
|
||||||
final walletDirPath = await pathForWalletDir(name: name, type: getType());
|
final walletDirPath = await pathForWalletDir(name: name, type: getType());
|
||||||
@@ -77,14 +93,14 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
|
|||||||
final jsonSource = await read(path: path, password: password);
|
final jsonSource = await read(path: path, password: password);
|
||||||
try {
|
try {
|
||||||
final data = json.decode(jsonSource) as Map;
|
final data = json.decode(jsonSource) as Map;
|
||||||
return data['mnemonic'] as String? ?? '';
|
return data["mnemonic"] as String? ?? "";
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// if not a valid json
|
// if not a valid json
|
||||||
return jsonSource.substring(0, 200);
|
return jsonSource.substring(0, 200);
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// if the file couldn't be opened or read
|
// if the file couldn't be opened or read
|
||||||
return '';
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,842 +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: "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: "direct main"
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: HEAD
|
|
||||||
resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
|
|
||||||
url: "https://github.com/cake-tech/bech32.git"
|
|
||||||
source: git
|
|
||||||
version: "0.2.2"
|
|
||||||
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"
|
|
||||||
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: "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: "direct main"
|
|
||||||
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"
|
|
||||||
dart_style:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: dart_style
|
|
||||||
sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.3"
|
|
||||||
decimal:
|
|
||||||
dependency: "direct main"
|
|
||||||
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: transitive
|
|
||||||
description:
|
|
||||||
name: ffi
|
|
||||||
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.3"
|
|
||||||
file:
|
|
||||||
dependency: "direct main"
|
|
||||||
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"
|
|
||||||
hive:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description:
|
|
||||||
name: hive
|
|
||||||
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.3"
|
|
||||||
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: "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"
|
|
||||||
nested:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: nested
|
|
||||||
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.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: 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"
|
|
||||||
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"
|
|
||||||
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: "direct main"
|
|
||||||
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"
|
|
||||||
sqflite:
|
|
||||||
dependency: "direct main"
|
|
||||||
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 main"
|
|
||||||
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: "direct main"
|
|
||||||
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: "direct main"
|
|
||||||
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: "direct main"
|
|
||||||
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.9.0 <4.0.0"
|
|
||||||
flutter: ">=3.27.0"
|
|
||||||
@@ -42,7 +42,7 @@ dependencies:
|
|||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/blockchain_utils
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
ref: cake-update-v2
|
ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
|
||||||
sqflite: ^2.4.1
|
sqflite: ^2.4.1
|
||||||
sqflite_common_ffi: ^2.3.4+4
|
sqflite_common_ffi: ^2.3.4+4
|
||||||
bech32:
|
bech32:
|
||||||
|
|||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
@@ -78,13 +78,13 @@ void main() {
|
|||||||
const recipient = "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6";
|
const recipient = "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6";
|
||||||
const contract = "0xdAC17F958D2ee523a2206206994597C13D831ec7";
|
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);
|
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);
|
final uri = ERC681URI(chainId: 137, address: recipient, amount: "", contractAddress: null);
|
||||||
|
|
||||||
expect(uri.toString(), "ethereum:$recipient@137");
|
expect(uri.toString(), "ethereum:$recipient@137");
|
||||||
@@ -93,7 +93,22 @@ void main() {
|
|||||||
test("emits the native amount in ERC-681 scientific notation", () {
|
test("emits the native amount in ERC-681 scientific notation", () {
|
||||||
final uri = ERC681URI(chainId: 1, address: recipient, amount: "1", contractAddress: null);
|
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", () {
|
test("builds the transfer form for a token", () {
|
||||||
@@ -189,7 +204,7 @@ void main() {
|
|||||||
rawTokenAmount: "1000000",
|
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", () {
|
test("parses a scientific notation value", () {
|
||||||
|
|||||||
@@ -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<String?> getApplicationDocumentsPath() async => root;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String?> getApplicationSupportPath() async => root;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> main() async {
|
||||||
|
final dataRoot = Directory("./test/data/token_migration");
|
||||||
|
|
||||||
|
Future<void> 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<erc20_legacy.Erc20Token>("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<erc20_legacy.Erc20Token>("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<erc20_legacy.Erc20Token>("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<spl_legacy.SPLToken>("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<tron_legacy.TronToken>("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<spl_legacy.SPLToken>("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);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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/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/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/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_fix.dart";
|
||||||
import "package:cw_custom_lints/print_verbose/print_verbose_rule.dart";
|
import "package:cw_custom_lints/print_verbose/print_verbose_rule.dart";
|
||||||
import "package:cw_custom_lints/restricted_imports/restricted_imports_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(HttpForceProxyRule());
|
||||||
registry.registerWarningRule(ModernButtonSemanticsRule());
|
registry.registerWarningRule(ModernButtonSemanticsRule());
|
||||||
registry.registerWarningRule(ModalTopBarSemanticsRule());
|
registry.registerWarningRule(ModalTopBarSemanticsRule());
|
||||||
|
registry.registerWarningRule(MoneyAmountToStringRule());
|
||||||
|
|
||||||
registry.registerFixForRule(PrintVerboseRule.code, ReplaceWithPrintV.new);
|
registry.registerFixForRule(PrintVerboseRule.code, ReplaceWithPrintV.new);
|
||||||
|
registry.registerFixForRule(MoneyAmountToStringRule.code, ReplaceWithMoneyToString.new);
|
||||||
|
registry.registerFixForRule(
|
||||||
|
MoneyAmountToStringRule.code,
|
||||||
|
ReplaceWithMoneyToStringInBaseUnit.new,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<void> compute(ChangeBuilder builder) async {
|
||||||
|
final invocation = node.thisOrAncestorOfType<MethodInvocation>();
|
||||||
|
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)";
|
||||||
|
}
|
||||||
@@ -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<void> {
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,8 +22,6 @@ migrate_working_dir/
|
|||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
|
||||||
/pubspec.lock
|
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.packages
|
.packages
|
||||||
|
|||||||
@@ -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"
|
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
@@ -22,8 +22,6 @@ migrate_working_dir/
|
|||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
|
||||||
/pubspec.lock
|
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.flutter-plugins
|
.flutter-plugins
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ dependencies:
|
|||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/blockchain_utils
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
ref: cake-update-v2
|
ref: 59fdf29d72068e0522a96a8953ed7272833a9f57
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -40,7 +40,7 @@ dependency_overrides:
|
|||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base
|
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
|
# For information on the generic Dart part of this file, see the
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
@@ -22,8 +22,6 @@ migrate_working_dir/
|
|||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
|
||||||
/pubspec.lock
|
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.packages
|
.packages
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
sources:
|
||||||
|
exclude:
|
||||||
|
- "**/.secrets.g.dart"
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
import 'package:cw_core/crypto_currency.dart';
|
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 {
|
class EVMChainTransactionCreationException implements Exception {
|
||||||
final String exceptionMessage;
|
final String exceptionMessage;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'dart:typed_data';
|
|||||||
import 'package:bip32/bip32.dart' as bip32;
|
import 'package:bip32/bip32.dart' as bip32;
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:cw_core/amount/money.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/crypto_currency.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/erc20_token.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_ledger_credentials.dart';
|
||||||
import 'package:cw_evm/hardware/evm_chain_trezor_credentials.dart';
|
import 'package:cw_evm/hardware/evm_chain_trezor_credentials.dart';
|
||||||
import 'package:hex/hex.dart';
|
import 'package:hex/hex.dart';
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:web3dart/crypto.dart';
|
import 'package:web3dart/crypto.dart';
|
||||||
@@ -109,10 +107,6 @@ abstract class EVMChainWalletBase
|
|||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory = setUpTransactionHistory(walletInfo, password, encryptionFileUtils);
|
transactionHistory = setUpTransactionHistory(walletInfo, password, encryptionFileUtils);
|
||||||
|
|
||||||
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
|
||||||
CakeHive.registerAdapter(Erc20TokenAdapter());
|
|
||||||
}
|
|
||||||
|
|
||||||
sharedPrefs.complete(SharedPreferences.getInstance());
|
sharedPrefs.complete(SharedPreferences.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,9 +115,7 @@ abstract class EVMChainWalletBase
|
|||||||
final String _password;
|
final String _password;
|
||||||
final EncryptionFileUtils encryptionFileUtils;
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
|
|
||||||
late final Box<Erc20Token> erc20TokensBox;
|
List<Erc20Token> _erc20Tokens = [];
|
||||||
|
|
||||||
late Box<Erc20Token> evmChainErc20TokensBox;
|
|
||||||
|
|
||||||
late final Credentials _evmChainPrivateKey;
|
late final Credentials _evmChainPrivateKey;
|
||||||
|
|
||||||
@@ -217,8 +209,8 @@ abstract class EVMChainWalletBase
|
|||||||
// Automatically connect to node for the selected chain
|
// Automatically connect to node for the selected chain
|
||||||
await connectToNode(node: node);
|
await connectToNode(node: node);
|
||||||
|
|
||||||
// Reload ERC20 tokens box for the new chain
|
// Reload ERC20 tokens for the new chain
|
||||||
await initErc20TokensBox();
|
await initErc20Tokens();
|
||||||
|
|
||||||
// Reload transaction history from the new chain's file
|
// Reload transaction history from the new chain's file
|
||||||
await transactionHistory.init();
|
await transactionHistory.init();
|
||||||
@@ -228,179 +220,52 @@ abstract class EVMChainWalletBase
|
|||||||
await startSync();
|
await startSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addInitialTokens() {
|
Future<void> addInitialTokens() async {
|
||||||
final initialErc20Tokens = EVMChainDefaultTokens.getDefaultTokensByChainId(selectedChainId);
|
final initialErc20Tokens = EVMChainDefaultTokens.getDefaultTokensByChainId(selectedChainId);
|
||||||
|
|
||||||
for (final token in initialErc20Tokens) {
|
for (final token in initialErc20Tokens) {
|
||||||
if (!evmChainErc20TokensBox.containsKey(token.contractAddress)) {
|
final existingToken = _findCachedToken(token.contractAddress);
|
||||||
evmChainErc20TokensBox.put(token.contractAddress, token);
|
|
||||||
} else {
|
final newToken = Erc20Token.copyWith(
|
||||||
// update existing token
|
token,
|
||||||
final existingToken = evmChainErc20TokensBox.get(token.contractAddress);
|
enabled: existingToken?.enabled ?? token.enabled,
|
||||||
evmChainErc20TokensBox.put(
|
walletName: walletInfo.name,
|
||||||
token.contractAddress,
|
chainId: selectedChainId,
|
||||||
Erc20Token.copyWith(token, enabled: existingToken!.enabled),
|
);
|
||||||
);
|
|
||||||
}
|
await newToken.save();
|
||||||
|
_upsertCachedToken(newToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> get getDefaultTokenContractAddresses =>
|
List<String> get getDefaultTokenContractAddresses =>
|
||||||
EVMChainDefaultTokens.getDefaultTokenAddresses(selectedChainId);
|
EVMChainDefaultTokens.getDefaultTokenAddresses(selectedChainId);
|
||||||
|
|
||||||
Future<void> initErc20TokensBox() async {
|
Future<void> initErc20Tokens() async {
|
||||||
// Migration for old WalletType.ethereum wallets:
|
_erc20Tokens = await Erc20Token.getAllForWallet(walletInfo.name, selectedChainId);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final chainId = selectedChainId;
|
await addInitialTokens();
|
||||||
|
|
||||||
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<Erc20Token>(boxName);
|
|
||||||
} else {
|
|
||||||
evmChainErc20TokensBox = await CakeHive.openBox<Erc20Token>(boxName);
|
|
||||||
}
|
|
||||||
|
|
||||||
await _normalizeEvmChainErc20TokensBoxKeys();
|
|
||||||
|
|
||||||
addInitialTokens();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ethereum-specific initialization with backward compatibility
|
Erc20Token? _findCachedToken(String contractAddress) {
|
||||||
Future<void> _initEthereumErc20TokensBox() async {
|
final lowerAddress = contractAddress.toLowerCase();
|
||||||
// Opens a box specific to this wallet
|
|
||||||
evmChainErc20TokensBox = await CakeHive.openBox<Erc20Token>(
|
|
||||||
"${walletInfo.name.replaceAll(" ", "_")}_${Erc20Token.ethereumBoxName}",
|
|
||||||
);
|
|
||||||
|
|
||||||
erc20TokensBox = await CakeHive.openBox<Erc20Token>(Erc20Token.boxName);
|
for (final token in _erc20Tokens) {
|
||||||
|
if (token.contractAddress.toLowerCase() == lowerAddress) return token;
|
||||||
if (erc20TokensBox.isEmpty) {
|
|
||||||
if (evmChainErc20TokensBox.isEmpty) addInitialTokens();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final allValues = erc20TokensBox.values.toList();
|
void _upsertCachedToken(Erc20Token token) {
|
||||||
|
final lowerAddress = token.contractAddress.toLowerCase();
|
||||||
|
|
||||||
// Clear and delete the old token box
|
_erc20Tokens.removeWhere((t) => t.contractAddress.toLowerCase() == lowerAddress);
|
||||||
await erc20TokensBox.clear();
|
_erc20Tokens.add(token);
|
||||||
await erc20TokensBox.deleteFromDisk();
|
|
||||||
|
|
||||||
// Add all the previous tokens with configs to the new box
|
|
||||||
await evmChainErc20TokensBox.addAll(allValues);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String getTransactionHistoryFileName() =>
|
String getTransactionHistoryFileName() =>
|
||||||
EVMChainUtils.getTransactionHistoryFileName(selectedChainId);
|
EVMChainUtils.getTransactionHistoryFileName(selectedChainId);
|
||||||
|
|
||||||
/// Ensures all ERC20 token entries use lowercase contract addresses as
|
|
||||||
/// their Hive keys to avoid duplicates caused by case differences.
|
|
||||||
Future<void> _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<String, Erc20Token> 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<bool> checkIfScanProviderIsEnabled() async {
|
Future<bool> checkIfScanProviderIsEnabled() async {
|
||||||
final key = EVMChainUtils.getScanProviderPreferenceKey(selectedChainId);
|
final key = EVMChainUtils.getScanProviderPreferenceKey(selectedChainId);
|
||||||
return (await sharedPrefs.future).getBool(key) ?? true;
|
return (await sharedPrefs.future).getBool(key) ?? true;
|
||||||
@@ -451,6 +316,8 @@ abstract class EVMChainWalletBase
|
|||||||
tag: token.tag ?? EVMChainUtils.getDefaultTokenTag(selectedChainId),
|
tag: token.tag ?? EVMChainUtils.getDefaultTokenTag(selectedChainId),
|
||||||
iconPath: iconPath,
|
iconPath: iconPath,
|
||||||
isPotentialScam: token.isPotentialScam,
|
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';
|
String idFor(String name, WalletType type) => '${walletTypeToString(type).toLowerCase()}_$name';
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
await initErc20TokensBox();
|
await initErc20Tokens();
|
||||||
|
|
||||||
await walletAddresses.init();
|
await walletAddresses.init();
|
||||||
await transactionHistory.init();
|
await transactionHistory.init();
|
||||||
@@ -669,8 +536,6 @@ abstract class EVMChainWalletBase
|
|||||||
|
|
||||||
Future<MoralisDiscoveryResult> discoverTokensFromMoralis() async {
|
Future<MoralisDiscoveryResult> discoverTokensFromMoralis() async {
|
||||||
try {
|
try {
|
||||||
if (!evmChainErc20TokensBox.isOpen) return MoralisDiscoveryResult.empty;
|
|
||||||
|
|
||||||
final address = walletAddresses.address;
|
final address = walletAddresses.address;
|
||||||
if (address.isEmpty) return MoralisDiscoveryResult.empty;
|
if (address.isEmpty) return MoralisDiscoveryResult.empty;
|
||||||
|
|
||||||
@@ -680,8 +545,7 @@ abstract class EVMChainWalletBase
|
|||||||
if (walletTokens.isEmpty) return MoralisDiscoveryResult.empty;
|
if (walletTokens.isEmpty) return MoralisDiscoveryResult.empty;
|
||||||
|
|
||||||
final existingTokenAddresses = {
|
final existingTokenAddresses = {
|
||||||
for (final token in evmChainErc20TokensBox.values)
|
for (final token in _erc20Tokens) token.contractAddress.toLowerCase(): token,
|
||||||
token.contractAddress.toLowerCase(): token,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
final whitelistedTokenAddresses =
|
final whitelistedTokenAddresses =
|
||||||
@@ -1419,32 +1283,21 @@ abstract class EVMChainWalletBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _fetchErc20Balances() async {
|
Future<void> _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
|
// 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
|
// This handles tokens from previous chains that might still be in the balance map
|
||||||
final tokensInBalance = balance.keys.whereType<Erc20Token>().toList();
|
final tokensInBalance = balance.keys.whereType<Erc20Token>().toList();
|
||||||
final tokensInBox = evmChainErc20TokensBox.values.toList();
|
final tokens = _erc20Tokens.toList();
|
||||||
final boxTokenAddresses = tokensInBox.map((t) => t.contractAddress.toLowerCase()).toSet();
|
final cachedTokenAddresses = tokens.map((t) => t.contractAddress.toLowerCase()).toSet();
|
||||||
|
|
||||||
for (var token in tokensInBalance) {
|
for (var token in tokensInBalance) {
|
||||||
// Remove token if it's not in the current box or doesn't match current chain
|
// Remove token if it's not in the current token list or doesn't match current chain
|
||||||
if (!boxTokenAddresses.contains(token.contractAddress.toLowerCase()) ||
|
if (!cachedTokenAddresses.contains(token.contractAddress.toLowerCase()) ||
|
||||||
!_isTokenMatchingChain(token)) {
|
!_isTokenMatchingChain(token)) {
|
||||||
balance.remove(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) {
|
for (var token in tokens) {
|
||||||
// Check if box is still open before operating on tokens
|
|
||||||
if (!evmChainErc20TokensBox.isOpen) break;
|
|
||||||
|
|
||||||
if (!_isTokenMatchingChain(token)) {
|
if (!_isTokenMatchingChain(token)) {
|
||||||
printV('NOTEE!!!: Token ${token.title} is not matching the currency ${currency.title}');
|
printV('NOTEE!!!: Token ${token.title} is not matching the currency ${currency.title}');
|
||||||
try {
|
try {
|
||||||
@@ -1532,15 +1385,7 @@ abstract class EVMChainWalletBase
|
|||||||
@override
|
@override
|
||||||
Future<void> updateTransactionsHistory() async => await _updateTransactions();
|
Future<void> updateTransactionsHistory() async => await _updateTransactions();
|
||||||
|
|
||||||
List<Erc20Token> get erc20Currencies {
|
List<Erc20Token> get erc20Currencies => _erc20Tokens.toList();
|
||||||
try {
|
|
||||||
if (!evmChainErc20TokensBox.isOpen) return [];
|
|
||||||
|
|
||||||
return evmChainErc20TokensBox.values.toList();
|
|
||||||
} catch (_) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> addErc20Token(Erc20Token token) async {
|
Future<void> addErc20Token(Erc20Token token) async {
|
||||||
final isSuspicious = isTokenPropertiesSuspicious(token);
|
final isSuspicious = isTokenPropertiesSuspicious(token);
|
||||||
@@ -1561,32 +1406,26 @@ abstract class EVMChainWalletBase
|
|||||||
final newToken = createNewErc20TokenObject(token, iconPath);
|
final newToken = createNewErc20TokenObject(token, iconPath);
|
||||||
|
|
||||||
if (newToken.enabled) {
|
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);
|
await newToken.save();
|
||||||
} on Exception catch (_) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
await evmChainErc20TokensBox.put(newToken.contractAddress, newToken);
|
await newToken.save();
|
||||||
balance.remove(newToken);
|
balance.remove(newToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_upsertCachedToken(newToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteErc20Token(Erc20Token token, {bool shouldUpdateBalance = true}) async {
|
Future<void> deleteErc20Token(Erc20Token token, {bool shouldUpdateBalance = true}) async {
|
||||||
// Check if box is open before trying to delete
|
try {
|
||||||
if (!evmChainErc20TokensBox.isOpen) {
|
await Erc20Token.deleteForWallet(walletInfo.name, selectedChainId, token.contractAddress);
|
||||||
balance.remove(token);
|
} catch (e) {
|
||||||
return;
|
printV('Error deleting token: $e');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
_erc20Tokens
|
||||||
await token.delete();
|
.removeWhere((t) => t.contractAddress.toLowerCase() == token.contractAddress.toLowerCase());
|
||||||
} catch (e) {
|
|
||||||
// Token might be from a closed box, just remove from balance
|
|
||||||
printV('Error deleting token from box: $e');
|
|
||||||
}
|
|
||||||
|
|
||||||
balance.remove(token);
|
balance.remove(token);
|
||||||
await removeTokenTransactionsInHistory(token);
|
await removeTokenTransactionsInHistory(token);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'dart:io';
|
import "dart:io";
|
||||||
|
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
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/pathForWallet.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
import 'package:cw_core/wallet_base.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:path/path.dart' as p;
|
||||||
import 'package:cw_evm/clients/evm_chain_client.dart';
|
import 'package:cw_evm/clients/evm_chain_client.dart';
|
||||||
import 'package:cw_evm/evm_chain_client_factory.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_registry.dart';
|
||||||
import 'package:cw_evm/evm_chain_wallet.dart';
|
import 'package:cw_evm/evm_chain_wallet.dart';
|
||||||
import 'package:cw_evm/evm_chain_wallet_creation_credentials.dart';
|
import 'package:cw_evm/evm_chain_wallet_creation_credentials.dart';
|
||||||
@@ -48,8 +50,8 @@ class EVMChainWalletService extends WalletService<
|
|||||||
@override
|
@override
|
||||||
WalletType getType() {
|
WalletType getType() {
|
||||||
throw UnsupportedError(
|
throw UnsupportedError(
|
||||||
'EVMChainWalletService is unified and does not have a single type. '
|
"EVMChainWalletService is unified and does not have a single type. "
|
||||||
'Use walletInfo.type instead.',
|
"Use walletInfo.type instead.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +61,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
Future<void> saveBackup(String name, {WalletInfo? walletInfo}) async {
|
Future<void> saveBackup(String name, {WalletInfo? walletInfo}) async {
|
||||||
final info = walletInfo ?? await _findWalletByName(name);
|
final info = walletInfo ?? await _findWalletByName(name);
|
||||||
if (info == null) {
|
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);
|
final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: info.type);
|
||||||
@@ -75,7 +77,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
Future<void> restoreWalletFilesFromBackup(String name) async {
|
Future<void> restoreWalletFilesFromBackup(String name) async {
|
||||||
final walletInfo = await _findWalletByName(name);
|
final walletInfo = await _findWalletByName(name);
|
||||||
if (walletInfo == null) {
|
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);
|
final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: walletInfo.type);
|
||||||
@@ -96,7 +98,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
// Get chainId from wallet type
|
// Get chainId from wallet type
|
||||||
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
|
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
|
||||||
if (chainConfig == null) {
|
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;
|
final initialChainId = chainConfig.chainId;
|
||||||
|
|
||||||
@@ -124,7 +126,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
wallet.addInitialTokens();
|
await wallet.addInitialTokens();
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
@@ -133,7 +135,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
Future<EVMChainWallet> openWallet(String name, String password) async {
|
Future<EVMChainWallet> openWallet(String name, String password) async {
|
||||||
final walletInfo = await _findWalletByName(name);
|
final walletInfo = await _findWalletByName(name);
|
||||||
if (walletInfo == null) {
|
if (walletInfo == null) {
|
||||||
throw Exception('Wallet not found');
|
throw Exception("Wallet not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -145,7 +147,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
wallet.addInitialTokens();
|
await wallet.addInitialTokens();
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
await saveBackup(name);
|
await saveBackup(name);
|
||||||
return wallet;
|
return wallet;
|
||||||
@@ -160,7 +162,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
wallet.addInitialTokens();
|
await wallet.addInitialTokens();
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
@@ -172,7 +174,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
|
|
||||||
final currentWalletInfo = await _findWalletByName(currentName);
|
final currentWalletInfo = await _findWalletByName(currentName);
|
||||||
if (currentWalletInfo == null) {
|
if (currentWalletInfo == null) {
|
||||||
throw Exception('Wallet not found');
|
throw Exception("Wallet not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
final type = currentWalletInfo.type;
|
final type = currentWalletInfo.type;
|
||||||
@@ -184,6 +186,16 @@ class EVMChainWalletService extends WalletService<
|
|||||||
currentWalletInfo.name = newName;
|
currentWalletInfo.name = newName;
|
||||||
await currentWalletInfo.save();
|
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));
|
final oldDir = Directory(p.join(await pathForWalletTypeDir(type: type), currentName));
|
||||||
if (oldDir.existsSync()) {
|
if (oldDir.existsSync()) {
|
||||||
try {
|
try {
|
||||||
@@ -199,12 +211,16 @@ class EVMChainWalletService extends WalletService<
|
|||||||
EVMChainRestoreWalletFromSeedCredentials credentials, {
|
EVMChainRestoreWalletFromSeedCredentials credentials, {
|
||||||
bool? isTestnet,
|
bool? isTestnet,
|
||||||
}) async {
|
}) async {
|
||||||
|
if (!bip39.validateMnemonic(credentials.mnemonic)) {
|
||||||
|
throw EVMChainMnemonicIsIncorrectException();
|
||||||
|
}
|
||||||
|
|
||||||
final walletInfo = credentials.walletInfo!;
|
final walletInfo = credentials.walletInfo!;
|
||||||
|
|
||||||
// Get chainId from wallet type
|
// Get chainId from wallet type
|
||||||
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
|
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
|
||||||
if (chainConfig == null) {
|
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;
|
final initialChainId = chainConfig.chainId;
|
||||||
|
|
||||||
@@ -230,7 +246,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
wallet.addInitialTokens();
|
await wallet.addInitialTokens();
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
@@ -245,7 +261,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
// Get chainId from wallet type
|
// Get chainId from wallet type
|
||||||
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
|
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
|
||||||
if (chainConfig == null) {
|
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;
|
final initialChainId = chainConfig.chainId;
|
||||||
|
|
||||||
@@ -270,7 +286,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
wallet.addInitialTokens();
|
await wallet.addInitialTokens();
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
@@ -284,7 +300,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
// Get chainId from wallet type
|
// Get chainId from wallet type
|
||||||
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
|
final chainConfig = _registry.getChainConfigByWalletType(walletInfo.type);
|
||||||
if (chainConfig == null) {
|
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;
|
final initialChainId = chainConfig.chainId;
|
||||||
|
|
||||||
@@ -308,7 +324,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
wallet.addInitialTokens();
|
await wallet.addInitialTokens();
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
@@ -327,11 +343,15 @@ class EVMChainWalletService extends WalletService<
|
|||||||
Future<void> remove(String wallet) async {
|
Future<void> remove(String wallet) async {
|
||||||
final walletInfo = await _findWalletByName(wallet);
|
final walletInfo = await _findWalletByName(wallet);
|
||||||
if (walletInfo == null) {
|
if (walletInfo == null) {
|
||||||
throw Exception('Wallet not found');
|
throw Exception("Wallet not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
File(await pathForWalletDir(name: wallet, type: walletInfo.type)).delete(recursive: true);
|
File(await pathForWalletDir(name: wallet, type: walletInfo.type)).delete(recursive: true);
|
||||||
await WalletInfo.delete(walletInfo);
|
await WalletInfo.delete(walletInfo);
|
||||||
|
final nameStillUsed = (await _findWalletByName(wallet)) != null;
|
||||||
|
if (!nameStillUsed) {
|
||||||
|
await Erc20Token.deleteAllForWallet(wallet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EVMChainWallet _createWalletInstance({
|
EVMChainWallet _createWalletInstance({
|
||||||
@@ -349,7 +369,7 @@ class EVMChainWalletService extends WalletService<
|
|||||||
final chainConfig = _registry.getChainConfigByWalletType(walletType);
|
final chainConfig = _registry.getChainConfigByWalletType(walletType);
|
||||||
|
|
||||||
if (chainConfig == null) {
|
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(
|
return EVMChainWallet(
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import 'package:cw_core/erc20_token.dart';
|
import "package:cw_evm/evm_chain_transaction_priority.dart";
|
||||||
import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
import "package:web3dart/web3dart.dart" show EtherAmount, EtherUnit;
|
||||||
import 'package:web3dart/web3dart.dart' show EtherAmount, EtherUnit;
|
|
||||||
|
|
||||||
/// Utility class for chain-specific EVM chain operations
|
/// Utility class for chain-specific EVM chain operations
|
||||||
class EVMChainUtils {
|
class EVMChainUtils {
|
||||||
static int getTotalPriorityFee(EVMChainTransactionPriority priority, int chainId) {
|
static int getTotalPriorityFee(EVMChainTransactionPriority priority, int chainId) => switch (chainId) {
|
||||||
return switch (chainId) {
|
|
||||||
1 => _ethereumPriorityFee(priority),
|
1 => _ethereumPriorityFee(priority),
|
||||||
137 => _polygonPriorityFee(priority),
|
137 => _polygonPriorityFee(priority),
|
||||||
8453 => _basePriorityFee(priority),
|
8453 => _basePriorityFee(priority),
|
||||||
@@ -13,14 +11,11 @@ class EVMChainUtils {
|
|||||||
42161 => 0, // Arbitrum doesn't use priority fees
|
42161 => 0, // Arbitrum doesn't use priority fees
|
||||||
_ => _ethereumPriorityFee(priority),
|
_ => _ethereumPriorityFee(priority),
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static bool hasPriorityFee(int chainId) {
|
static bool hasPriorityFee(int chainId) => switch (chainId) {
|
||||||
return switch (chainId) {
|
|
||||||
42161 => false, // Arbitrum doesn't use priority fees
|
42161 => false, // Arbitrum doesn't use priority fees
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static int computeBufferedMaxFeePerGasWei({
|
static int computeBufferedMaxFeePerGasWei({
|
||||||
required int? gasBaseFee,
|
required int? gasBaseFee,
|
||||||
@@ -38,78 +33,53 @@ class EVMChainUtils {
|
|||||||
return gasPrice + priorityFeeWei;
|
return gasPrice + priorityFeeWei;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getErc20TokensBoxName(String walletName, int chainId) {
|
static String getTransactionHistoryFileName(int chainId) => switch (chainId) {
|
||||||
final sanitizedName = walletName.replaceAll(" ", "_");
|
1 => "transactions.json", // Ethereum
|
||||||
|
137 => "polygon_transactions.json",
|
||||||
return switch (chainId) {
|
8453 => "base_transactions.json",
|
||||||
1 => "${sanitizedName}_${Erc20Token.ethereumBoxName}",
|
42161 => "arbitrum_transactions.json",
|
||||||
137 => "${sanitizedName}_${Erc20Token.polygonBoxName}",
|
56 => "bsc_transactions.json",
|
||||||
8453 => "${sanitizedName}_${Erc20Token.baseBoxName}",
|
_ => "transactions_$chainId.json", // Generic format for other chains
|
||||||
42161 => "${sanitizedName}_${Erc20Token.arbitrumBoxName}",
|
|
||||||
56 => "${sanitizedName}_${Erc20Token.bscBoxName}",
|
|
||||||
_ => "${sanitizedName}_${Erc20Token.ethereumBoxName}",
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
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
|
/// Get scan provider preference key for a wallet type
|
||||||
static String getScanProviderPreferenceKey(int chainId) {
|
static String getScanProviderPreferenceKey(int chainId) => switch (chainId) {
|
||||||
return switch (chainId) {
|
1 => "use_etherscan",
|
||||||
1 => 'use_etherscan',
|
137 => "use_polygonscan",
|
||||||
137 => 'use_polygonscan',
|
8453 => "use_basescan",
|
||||||
8453 => 'use_basescan',
|
42161 => "use_arbiscan",
|
||||||
42161 => 'use_arbiscan',
|
56 => "use_bscscan",
|
||||||
56 => 'use_bscscan',
|
_ => "use_etherscan",
|
||||||
_ => 'use_etherscan',
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static String getDefaultTokenTag(int chainId) {
|
static String getDefaultTokenTag(int chainId) => switch (chainId) {
|
||||||
return switch (chainId) {
|
1 => "ETH",
|
||||||
1 => 'ETH',
|
137 => "POL",
|
||||||
137 => 'POL',
|
8453 => "BASE",
|
||||||
8453 => 'BASE',
|
42161 => "ARB",
|
||||||
42161 => 'ARB',
|
56 => "BSC",
|
||||||
56 => 'BSC',
|
_ => "ETH",
|
||||||
_ => 'ETH',
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static String getFeeCurrency(int chainId) {
|
static String getFeeCurrency(int chainId) => switch (chainId) {
|
||||||
return switch (chainId) {
|
1 => "ETH",
|
||||||
1 => 'ETH',
|
137 => "POL",
|
||||||
137 => 'POL',
|
8453 => "ETH",
|
||||||
8453 => 'ETH',
|
42161 => "ETH",
|
||||||
42161 => 'ETH',
|
56 => "BNB",
|
||||||
56 => 'BNB',
|
_ => "ETH",
|
||||||
_ => 'ETH',
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static String getDefaultTokenSymbol(int chainId) {
|
static String getDefaultTokenSymbol(int chainId) => switch (chainId) {
|
||||||
return switch (chainId) {
|
1 => "ETH",
|
||||||
1 => 'ETH',
|
137 => "POL",
|
||||||
137 => 'POL',
|
8453 => "BASE",
|
||||||
8453 => 'BASE',
|
42161 => "ARBITRUM",
|
||||||
42161 => 'ARBITRUM',
|
56 => "BSC",
|
||||||
56 => 'BSC',
|
_ => "ETH",
|
||||||
_ => 'ETH',
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static int _ethereumPriorityFee(EVMChainTransactionPriority priority) {
|
static int _ethereumPriorityFee(EVMChainTransactionPriority priority) => EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
||||||
return EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Polygon priority fee calculation (minimum 25 gwei + additional based on priority)
|
// Polygon priority fee calculation (minimum 25 gwei + additional based on priority)
|
||||||
static int _polygonPriorityFee(EVMChainTransactionPriority priority) {
|
static int _polygonPriorityFee(EVMChainTransactionPriority priority) {
|
||||||
@@ -127,12 +97,10 @@ class EVMChainUtils {
|
|||||||
return minPriorityFeeWei + additionalPriorityFee;
|
return minPriorityFeeWei + additionalPriorityFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _basePriorityFee(EVMChainTransactionPriority priority) {
|
static int _basePriorityFee(EVMChainTransactionPriority priority) => switch (priority) {
|
||||||
return switch (priority) {
|
|
||||||
EVMChainTransactionPriority.fast => EtherAmount.fromInt(EtherUnit.mwei, 5).getInWei.toInt(),
|
EVMChainTransactionPriority.fast => EtherAmount.fromInt(EtherUnit.mwei, 5).getInWei.toInt(),
|
||||||
EVMChainTransactionPriority.medium => EtherAmount.fromInt(EtherUnit.mwei, 3).getInWei.toInt(),
|
EVMChainTransactionPriority.medium => EtherAmount.fromInt(EtherUnit.mwei, 3).getInWei.toInt(),
|
||||||
EVMChainTransactionPriority.slow => EtherAmount.fromInt(EtherUnit.mwei, 1).getInWei.toInt(),
|
EVMChainTransactionPriority.slow => EtherAmount.fromInt(EtherUnit.mwei, 1).getInWei.toInt(),
|
||||||
_ => EtherAmount.fromInt(EtherUnit.mwei, 1).getInWei.toInt(),
|
_ => EtherAmount.fromInt(EtherUnit.mwei, 1).getInWei.toInt(),
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
File diff suppressed because it is too large
Load Diff
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
@@ -22,8 +22,6 @@ migrate_working_dir/
|
|||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
|
||||||
/pubspec.lock
|
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.packages
|
.packages
|
||||||
|
|||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
sources:
|
||||||
|
exclude:
|
||||||
|
- "**/.secrets.g.dart"
|
||||||
@@ -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"
|
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../pubspec_overrides.yaml
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user