Merge branch 'main' of https://github.com/cake-tech/cake_wallet into mweb-bg-sync-2

This commit is contained in:
Matthew Fosse 2024-12-18 12:16:00 -05:00
commit a032d86653
325 changed files with 6634 additions and 2578 deletions

View file

@ -4,7 +4,7 @@ contact_links:
url: https://github.com/cake-tech/cake_wallet/discussions/new?category=feature-requests url: https://github.com/cake-tech/cake_wallet/discussions/new?category=feature-requests
about: Suggest an idea for Cake Wallet about: Suggest an idea for Cake Wallet
- name: Not sure where to start? - name: Not sure where to start?
url: https://guides.cakewallet.com url: https://docs.cakewallet.com
about: Start by reading checking out the guides! about: Start by reading checking out the guides!
- name: Need help? - name: Need help?
url: https://cakewallet.com/#contact url: https://cakewallet.com/#contact

View file

@ -0,0 +1,298 @@
name: Automated Integration Tests
on:
# pull_request:
# branches: [main, CW-659-Transaction-History-Automated-Tests]
workflow_dispatch:
inputs:
branch:
description: "Branch name to build"
required: true
default: "main"
jobs:
Automated_integration_test:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
api-level: [29]
# arch: [x86, x86_64]
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
PR_NUMBER: ${{ github.event.number }}
steps:
- name: is pr
if: github.event_name == 'pull_request'
run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV
- name: is not pr
if: github.event_name != 'pull_request'
run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENV
- name: Free Disk Space (Ubuntu)
uses: insightsengineering/disk-space-reclaimer@v1
with:
tools-cache: true
android: false
dotnet: true
haskell: true
large-packages: true
swap-storage: true
docker-images: true
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: "temurin"
java-version: "17"
- name: Configure placeholder git details
run: |
git config --global user.email "CI@cakewallet.com"
git config --global user.name "Cake Github Actions"
- name: Flutter action
uses: subosito/flutter-action@v1
with:
flutter-version: "3.24.0"
channel: stable
- name: Install package dependencies
run: |
sudo apt update
sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
- name: Execute Build and Setup Commands
run: |
sudo mkdir -p /opt/android
sudo chown $USER /opt/android
cd /opt/android
-y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install cargo-ndk
git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }}
cd cake_wallet/scripts/android/
./install_ndk.sh
source ./app_env.sh cakewallet
chmod +x pubspec_gen.sh
./app_config.sh
- name: Cache Externals
id: cache-externals
uses: actions/cache@v3
with:
path: |
/opt/android/cake_wallet/cw_haven/android/.cxx
/opt/android/cake_wallet/scripts/monero_c/release
key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }}
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
name: Generate Externals
run: |
cd /opt/android/cake_wallet/scripts/android/
source ./app_env.sh cakewallet
./build_monero_all.sh
- name: Install Flutter dependencies
run: |
cd /opt/android/cake_wallet
flutter pub get
- name: Install go and gomobile
run: |
# install go > 1.23:
wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
export PATH=$PATH:~/go/bin
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
- name: Build mwebd
run: |
# paths are reset after each step, so we need to set them again:
export PATH=$PATH:/usr/local/go/bin
export PATH=$PATH:~/go/bin
cd /opt/android/cake_wallet/scripts/android/
./build_mwebd.sh --dont-install
- name: Generate KeyStore
run: |
cd /opt/android/cake_wallet/android/app
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS
- name: Generate key properties
run: |
cd /opt/android/cake_wallet
flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS
- name: Generate localization
run: |
cd /opt/android/cake_wallet
flutter packages pub run tool/generate_localization.dart
- name: Build generated code
run: |
cd /opt/android/cake_wallet
./model_generator.sh
- name: Add secrets
run: |
cd /opt/android/cake_wallet
touch lib/.secrets.g.dart
touch cw_evm/lib/.secrets.g.dart
touch cw_solana/lib/.secrets.g.dart
touch cw_core/lib/.secrets.g.dart
touch cw_nano/lib/.secrets.g.dart
touch cw_tron/lib/.secrets.g.dart
echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart
echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart
echo "const quantexExchangeMarkup = '${{ secrets.QUANTEX_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart
echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart
echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
echo "const moneroTestWalletSeeds ='${{ secrets.MONERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const moneroLegacyTestWalletSeeds = '${{ secrets.MONERO_LEGACY_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const bitcoinTestWalletSeeds = '${{ secrets.BITCOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const ethereumTestWalletSeeds = '${{ secrets.ETHEREUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const litecoinTestWalletSeeds = '${{ secrets.LITECOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const bitcoinCashTestWalletSeeds = '${{ secrets.BITCOIN_CASH_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const polygonTestWalletSeeds = '${{ secrets.POLYGON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const solanaTestWalletSeeds = '${{ secrets.SOLANA_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const tronTestWalletSeeds = '${{ secrets.TRON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const nanoTestWalletSeeds = '${{ secrets.NANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const wowneroTestWalletSeeds = '${{ secrets.WOWNERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
echo "const moneroTestWalletReceiveAddress = '${{ secrets.MONERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const bitcoinTestWalletReceiveAddress = '${{ secrets.BITCOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const ethereumTestWalletReceiveAddress = '${{ secrets.ETHEREUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const litecoinTestWalletReceiveAddress = '${{ secrets.LITECOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const bitcoinCashTestWalletReceiveAddress = '${{ secrets.BITCOIN_CASH_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const polygonTestWalletReceiveAddress = '${{ secrets.POLYGON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const solanaTestWalletReceiveAddress = '${{ secrets.SOLANA_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const tronTestWalletReceiveAddress = '${{ secrets.TRON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const nanoTestWalletReceiveAddress = '${{ secrets.NANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const wowneroTestWalletReceiveAddress = '${{ secrets.WOWNERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
echo "const moneroTestWalletBlockHeight = '${{ secrets.MONERO_TEST_WALLET_BLOCK_HEIGHT }}';" >> lib/.secrets.g.dart
- name: Rename app
run: |
echo -e "id=com.cakewallet.test_${{ env.PR_NUMBER }}\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
- name: Build
run: |
cd /opt/android/cake_wallet
flutter build apk --release --split-per-abi
# - name: Rename apk file
# run: |
# cd /opt/android/cake_wallet/build/app/outputs/flutter-apk
# mkdir test-apk
# cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk
# cp app-x86_64-release.apk test-apk/${{env.BRANCH_NAME}}_x86.apk
# - name: Upload Artifact
# uses: kittaakos/upload-artifact-as-is@v0
# with:
# path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/
# - name: Send Test APK
# continue-on-error: true
# uses: adrey/slack-file-upload-action@1.0.5
# with:
# token: ${{ secrets.SLACK_APP_TOKEN }}
# path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/${{env.BRANCH_NAME}}.apk
# channel: ${{ secrets.SLACK_APK_CHANNEL }}
# title: "${{ env.BRANCH_NAME }}.apk"
# filename: ${{ env.BRANCH_NAME }}.apk
# initial_comment: ${{ github.event.head_commit.message }}
- name: 🦾 Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: 🦾 Cache gradle
uses: gradle/actions/setup-gradle@v3
- name: 🦾 Cache AVD
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ matrix.api-level }}
- name: 🦾 Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
force-avd-creation: false
# arch: ${{ matrix.arch }}
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
working-directory: /opt/android/cake_wallet
disable-animations: false
script: echo "Generated AVD snapshot for caching."
- name: 🚀 Integration tests on Android Emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
working-directory: /opt/android/cake_wallet
script: |
chmod a+rx integration_test_runner.sh
./integration_test_runner.sh

View file

@ -34,7 +34,7 @@ jobs:
- name: Flutter action - name: Flutter action
uses: subosito/flutter-action@v1 uses: subosito/flutter-action@v1
with: with:
flutter-version: "3.19.6" flutter-version: "3.24.4"
channel: stable channel: stable
- name: Install package dependencies - name: Install package dependencies
@ -62,6 +62,7 @@ jobs:
/opt/android/cake_wallet/cw_haven/android/.cxx /opt/android/cake_wallet/cw_haven/android/.cxx
/opt/android/cake_wallet/scripts/monero_c/release /opt/android/cake_wallet/scripts/monero_c/release
key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }} key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }}
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }} - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
name: Generate Externals name: Generate Externals
run: | run: |
@ -73,8 +74,8 @@ jobs:
id: cache-keystore id: cache-keystore
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: /opt/android/cake_wallet/android/app/key.jks path: /opt/android/cake_wallet/android/app
key: $STORE_PASS key: keystore
- if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }} - if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }}
name: Generate KeyStore name: Generate KeyStore

21
.github/workflows/no_print_in_dart.yaml vendored Normal file
View file

@ -0,0 +1,21 @@
name: No print statements in dart files
on:
pull_request:
branches: [main]
jobs:
PR_test_build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Check for print() statements in dart code (use printV() instead)
if: github.event_name == 'pull_request'
run: |
GIT_GREP_OUT="$(git grep ' print(' | (grep .dart: || test $? = 1) | (grep -v print_verbose.dart || test $? = 1) || true)"
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
echo "$GIT_GREP_OUT"
echo "There are .dart files which use print() statements"
echo "Please use printV from package: cw_core/utils/print_verbose.dart"
exit 1

View file

@ -53,7 +53,7 @@ jobs:
- name: Flutter action - name: Flutter action
uses: subosito/flutter-action@v1 uses: subosito/flutter-action@v1
with: with:
flutter-version: "3.19.6" flutter-version: "3.24.0"
channel: stable channel: stable
- name: Install package dependencies - name: Install package dependencies
@ -61,14 +61,32 @@ jobs:
sudo apt update sudo apt update
sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
- name: Execute Build and Setup Commands
- name: Clone Repo
run: | run: |
sudo mkdir -p /opt/android sudo mkdir -p /opt/android
sudo chown $USER /opt/android sudo chown $USER /opt/android
cd /opt/android
git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }}
# - name: Cache Keystore
# id: cache-keystore
# uses: actions/cache@v3
# with:
# path: /opt/android/cake_wallet/android/app
# key: keystore
#
# - if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }}
- name: Generate KeyStore
run: |
cd /opt/android/cake_wallet/android/app
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS
- name: Execute Build and Setup Commands
run: |
cd /opt/android cd /opt/android
-y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install cargo-ndk cargo install cargo-ndk
git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }}
cd cake_wallet/scripts/android/ cd cake_wallet/scripts/android/
./install_ndk.sh ./install_ndk.sh
source ./app_env.sh cakewallet source ./app_env.sh cakewallet
@ -115,28 +133,15 @@ jobs:
cd /opt/android/cake_wallet/scripts/android/ cd /opt/android/cake_wallet/scripts/android/
./build_mwebd.sh --dont-install ./build_mwebd.sh --dont-install
# - name: Cache Keystore
# id: cache-keystore
# uses: actions/cache@v3
# with:
# path: /opt/android/cake_wallet/android/app/key.jks
# key: $STORE_PASS
#
# - if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }}
- name: Generate KeyStore
run: |
cd /opt/android/cake_wallet/android/app
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS
- name: Generate key properties - name: Generate key properties
run: | run: |
cd /opt/android/cake_wallet cd /opt/android/cake_wallet
flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS
- name: Generate localization - name: Generate localization
run: | run: |
cd /opt/android/cake_wallet cd /opt/android/cake_wallet
flutter packages pub run tool/generate_localization.dart dart run tool/generate_localization.dart
- name: Build generated code - name: Build generated code
run: | run: |
@ -183,6 +188,7 @@ jobs:
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
@ -201,7 +207,7 @@ jobs:
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart
echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dar echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart
echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart

View file

@ -38,7 +38,7 @@ jobs:
- name: Flutter action - name: Flutter action
uses: subosito/flutter-action@v1 uses: subosito/flutter-action@v1
with: with:
flutter-version: "3.19.6" flutter-version: "3.24.0"
channel: stable channel: stable
- name: Install package dependencies - name: Install package dependencies
@ -111,7 +111,7 @@ jobs:
- name: Generate localization - name: Generate localization
run: | run: |
cd /opt/android/cake_wallet cd /opt/android/cake_wallet
flutter packages pub run tool/generate_localization.dart dart run tool/generate_localization.dart
- name: Build generated code - name: Build generated code
run: | run: |
@ -165,6 +165,7 @@ jobs:
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart

View file

@ -99,6 +99,17 @@ Cake Wallet includes support for several cryptocurrencies, including:
* F-Droid: https://fdroid.cakelabs.com * F-Droid: https://fdroid.cakelabs.com
* APK: https://github.com/cake-tech/cake_wallet/releases * APK: https://github.com/cake-tech/cake_wallet/releases
### APK Verification
APK releases on GitHub, Accrescent, and F-Droid use the same key. They can easily be verified using [apksigner](https://developer.android.com/tools/apksigner#options-verify) or [AppVerifier](https://github.com/soupslurpr/AppVerifier).
See below for Cake Wallet's SHA-256 signing certificate hash:
```
com.cakewallet.cake_wallet
C5:40:53:AB:0F:10:D9:54:17:62:A3:DA:76:65:AE:3D:BA:5E:7C:74:3A:B4:F1:08:A5:34:9D:62:AC:10:6E:F5
```
# Support # Support
We have 24/7 free support. Please contact support@cakewallet.com We have 24/7 free support. Please contact support@cakewallet.com

View file

@ -38,11 +38,14 @@ if (appPropertiesFile.exists()) {
android { android {
compileSdkVersion 34 compileSdkVersion 34
buildToolsVersion "34.0.0"
lintOptions { lintOptions {
disable 'InvalidPackage' disable 'InvalidPackage'
} }
namespace "com.cakewallet.cake_wallet"
defaultConfig { defaultConfig {
applicationId appProperties['id'] applicationId appProperties['id']
minSdkVersion 24 minSdkVersion 24
@ -80,7 +83,7 @@ android {
} }
} }
ndkVersion "25.1.8937393" ndkVersion "27.0.12077973"
} }
flutter { flutter {
@ -96,4 +99,4 @@ configurations {
implementation.exclude module:'proto-google-common-protos' implementation.exclude module:'proto-google-common-protos'
implementation.exclude module:'protolite-well-known-types' implementation.exclude module:'protolite-well-known-types'
implementation.exclude module:'protobuf-javalite' implementation.exclude module:'protobuf-javalite'
} }

View file

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.cakewallet.cake_wallet">
<!-- Flutter needs it to communicate with the running application <!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->

View file

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="__APP_PACKAGE__">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" /> <uses-permission android:name="android.permission.USE_FINGERPRINT" />

View file

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.cakewallet.cake_wallet">
<!-- Flutter needs it to communicate with the running application <!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->

View file

@ -1,12 +1,12 @@
buildscript { buildscript {
ext.kotlin_version = '1.8.21' ext.kotlin_version = '2.0.21'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.3.0' classpath 'com.android.tools.build:gradle:8.7.1'
classpath 'com.google.gms:google-services:4.3.8' classpath 'com.google.gms:google-services:4.3.8'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }

View file

@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx3072M org.gradle.jvmargs=-Xmx4096M
android.enableR8=true android.enableR8=true
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true

View file

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip

View file

@ -1,6 +1,3 @@
-
uri: electrum.cakewallet.com:50002
useSSL: true
- -
uri: btc-electrum.cakewallet.com:50002 uri: btc-electrum.cakewallet.com:50002
useSSL: true useSSL: true

View file

@ -6,5 +6,7 @@
uri: rpc.flashbots.net uri: rpc.flashbots.net
- -
uri: eth-mainnet.public.blastapi.io uri: eth-mainnet.public.blastapi.io
-
uri: eth.nownodes.io
- -
uri: ethereum.publicnode.com uri: ethereum.publicnode.com

BIN
assets/images/discord.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/images/discourse.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -2,6 +2,7 @@
uri: xmr-node.cakewallet.com:18081 uri: xmr-node.cakewallet.com:18081
is_default: true is_default: true
trusted: true trusted: true
useSSL: true
- -
uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081 uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081
is_default: false is_default: false

View file

@ -3,4 +3,6 @@
- -
uri: polygon-bor.publicnode.com uri: polygon-bor.publicnode.com
- -
uri: polygon.llamarpc.com uri: polygon.llamarpc.com
-
uri: matic.nownodes.io

View file

@ -1,10 +1,10 @@
- -
uri: rpc.ankr.com uri: rpc.ankr.com
is_default: true
useSSL: true useSSL: true
- -
uri: api.mainnet-beta.solana.com:443 uri: api.mainnet-beta.solana.com:443
useSSL: true useSSL: true
- -
uri: solana-rpc.publicnode.com:443 uri: solana-rpc.publicnode.com:443
useSSL: true useSSL: true
is_default: true

View file

@ -1,3 +1,3 @@
Add airgapped Monero wallet support (best used with our new offline app Cupcake) Support Monero Ledger
New Buy & Sell flow Bug fixes
Bug fixes New designs and better user experience

View file

@ -1,5 +1,5 @@
Add Litecoin Ledger support Support Monero Ledger
Add airgapped Monero wallet support (best used with our new offline app Cupcake) Prepare for Haven removal
MWEB fixes and enhancements Improve Ethereum and Polygon sending process
New Buy & Sell flow Bug fixes
Bug fixes New designs and better user experience

View file

@ -4,9 +4,8 @@
useSSL: true useSSL: true
- -
uri: api.trongrid.io uri: api.trongrid.io
is_default: false is_default: true
useSSL: true useSSL: true
- -
uri: trx.nownodes.io uri: trx.nownodes.io
is_default: true
useSSL: true useSSL: true

View file

@ -120,7 +120,7 @@ Install Flutter package dependencies with this command:
Your CakeWallet binary will be built with some specific keys for iterate with 3rd party services. You may generate these secret keys placeholders with the following command: Your CakeWallet binary will be built with some specific keys for iterate with 3rd party services. You may generate these secret keys placeholders with the following command:
`$ flutter packages pub run tool/generate_new_secrets.dart` `$ dart run tool/generate_new_secrets.dart`
We will generate mobx models for the project. We will generate mobx models for the project.
@ -128,7 +128,7 @@ We will generate mobx models for the project.
Then we need to generate localization files. Then we need to generate localization files.
`$ flutter packages pub run tool/generate_localization.dart` `$ dart run tool/generate_localization.dart`
### 5. Build! ### 5. Build!

View file

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
set -x -e
IOS="ios" IOS="ios"
ANDROID="android" ANDROID="android"
MACOS="macos" MACOS="macos"
@ -36,6 +36,6 @@ fi
source ./app_env.sh cakewallet source ./app_env.sh cakewallet
./app_config.sh ./app_config.sh
cd ../.. && flutter pub get cd ../.. && flutter pub get
flutter packages pub run tool/generate_localization.dart dart run tool/generate_localization.dart
./model_generator.sh #./model_generator.sh
#cd macos && pod install #cd macos && pod install

View file

@ -6,6 +6,7 @@ import 'package:cw_bitcoin/utils.dart';
import 'package:cw_core/hardware/hardware_account_data.dart'; import 'package:cw_core/hardware/hardware_account_data.dart';
import 'package:ledger_bitcoin/ledger_bitcoin.dart'; import 'package:ledger_bitcoin/ledger_bitcoin.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:cw_core/utils/print_verbose.dart';
class BitcoinHardwareWalletService { class BitcoinHardwareWalletService {
BitcoinHardwareWalletService(this.ledgerConnection); BitcoinHardwareWalletService(this.ledgerConnection);

View file

@ -106,6 +106,15 @@ class BitcoinWalletService extends WalletService<
final walletInfo = walletInfoSource.values final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!; .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key); await walletInfoSource.delete(walletInfo.key);
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where(
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList();
final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList();
if (keysToDelete.isNotEmpty) {
await unspentCoinsInfoSource.deleteAll(keysToDelete);
}
} }
@override @override

View file

@ -4,6 +4,7 @@ import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
@ -117,17 +118,17 @@ class ElectrumClient {
_parseResponse(message); _parseResponse(message);
} }
} catch (e) { } catch (e) {
print("socket.listen: $e"); printV("socket.listen: $e");
} }
}, },
onError: (Object error) { onError: (Object error) {
final errorMsg = error.toString(); final errorMsg = error.toString();
print(errorMsg); printV(errorMsg);
unterminatedString = ''; unterminatedString = '';
socket = null; socket = null;
}, },
onDone: () { onDone: () {
print("SOCKET CLOSED!!!!!"); printV("SOCKET CLOSED!!!!!");
unterminatedString = ''; unterminatedString = '';
try { try {
if (host == socket?.address.host || socket == null) { if (host == socket?.address.host || socket == null) {
@ -136,7 +137,7 @@ class ElectrumClient {
socket = null; socket = null;
} }
} catch (e) { } catch (e) {
print("onDone: $e"); printV("onDone: $e");
} }
}, },
cancelOnError: true, cancelOnError: true,
@ -181,7 +182,7 @@ class ElectrumClient {
unterminatedString = ''; unterminatedString = '';
} }
} catch (e) { } catch (e) {
print("parse $e"); printV("parse $e");
} }
} }
@ -234,21 +235,21 @@ class ElectrumClient {
return []; return [];
}); });
Future<List<Map<String, dynamic>>> getListUnspent(String scriptHash) => Future<List<Map<String, dynamic>>> getListUnspent(String scriptHash) async {
call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]) final result = await call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]);
.then((dynamic result) {
if (result is List) {
return result.map((dynamic val) {
if (val is Map<String, dynamic>) {
return val;
}
return <String, dynamic>{}; if (result is List) {
}).toList(); return result.map((dynamic val) {
if (val is Map<String, dynamic>) {
return val;
} }
return []; return <String, dynamic>{};
}); }).toList();
}
return [];
}
Future<List<Map<String, dynamic>>> getMempool(String scriptHash) => Future<List<Map<String, dynamic>>> getMempool(String scriptHash) =>
call(method: 'blockchain.scripthash.get_mempool', params: [scriptHash]) call(method: 'blockchain.scripthash.get_mempool', params: [scriptHash])
@ -403,7 +404,7 @@ class ElectrumClient {
} on RequestFailedTimeoutException catch (_) { } on RequestFailedTimeoutException catch (_) {
return null; return null;
} catch (e) { } catch (e) {
print("getCurrentBlockChainTip: ${e.toString()}"); printV("getCurrentBlockChainTip: ${e.toString()}");
return null; return null;
} }
} }
@ -434,7 +435,7 @@ class ElectrumClient {
return subscription; return subscription;
} catch (e) { } catch (e) {
print("subscribe $e"); printV("subscribe $e");
return null; return null;
} }
} }
@ -473,7 +474,7 @@ class ElectrumClient {
return completer.future; return completer.future;
} catch (e) { } catch (e) {
print("callWithTimeout $e"); printV("callWithTimeout $e");
rethrow; rethrow;
} }
} }

View file

@ -5,6 +5,7 @@ import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/utils/file.dart'; import 'package:cw_core/utils/file.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_history.dart';
@ -30,7 +31,10 @@ abstract class ElectrumTransactionHistoryBase
String _password; String _password;
int _height; int _height;
Future<void> init() async => await _load(); Future<void> init() async {
clear();
await _load();
}
@override @override
void addOne(ElectrumTransactionInfo transaction) => transactions[transaction.id] = transaction; void addOne(ElectrumTransactionInfo transaction) => transactions[transaction.id] = transaction;
@ -51,7 +55,7 @@ abstract class ElectrumTransactionHistoryBase
final data = json.encode({'height': _height, 'transactions': txjson}); final data = json.encode({'height': _height, 'transactions': txjson});
await encryptionFileUtils.write(path: path, password: _password, data: data); await encryptionFileUtils.write(path: path, password: _password, data: data);
} catch (e) { } catch (e) {
print('Error while save bitcoin transaction history: ${e.toString()}'); printV('Error while save bitcoin transaction history: ${e.toString()}');
} }
} }
@ -88,7 +92,7 @@ abstract class ElectrumTransactionHistoryBase
_height = content['height'] as int; _height = content['height'] as int;
} catch (e) { } catch (e) {
print(e); printV(e);
} }
} }

View file

@ -4,6 +4,8 @@ import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/litecoin_wallet_addresses.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/litecoin_wallet.dart'; import 'package:cw_bitcoin/litecoin_wallet.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -304,6 +306,7 @@ abstract class ElectrumWalletBase
Future<void> init() async { Future<void> init() async {
await walletAddresses.init(); await walletAddresses.init();
await transactionHistory.init(); await transactionHistory.init();
await cleanUpDuplicateUnspentCoins();
await save(); await save();
_autoSaveTimer = _autoSaveTimer =
@ -479,8 +482,8 @@ abstract class ElectrumWalletBase
syncStatus = SyncedSyncStatus(); syncStatus = SyncedSyncStatus();
} }
} catch (e, stacktrace) { } catch (e, stacktrace) {
print(stacktrace); printV(stacktrace);
print("startSync $e"); printV("startSync $e");
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
} }
} }
@ -500,10 +503,11 @@ abstract class ElectrumWalletBase
@action @action
Future<void> updateFeeRates() async { Future<void> updateFeeRates() async {
if (await checkIfMempoolAPIIsEnabled()) { if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
try { try {
final response = final response = await http
await http.get(Uri.parse("http://mempool.cakewallet.com:8999/api/v1/fees/recommended")); .get(Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
.timeout(Duration(seconds: 5));
final result = json.decode(response.body) as Map<String, dynamic>; final result = json.decode(response.body) as Map<String, dynamic>;
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0; final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
@ -518,7 +522,7 @@ abstract class ElectrumWalletBase
_feeRates = [slowFee, mediumFee, fastFee]; _feeRates = [slowFee, mediumFee, fastFee];
return; return;
} catch (e) { } catch (e) {
print(e); printV(e);
} }
} }
@ -609,8 +613,8 @@ abstract class ElectrumWalletBase
} }
} }
} catch (e, stacktrace) { } catch (e, stacktrace) {
print(stacktrace); printV(stacktrace);
print("connectToNode $e"); printV("connectToNode $e");
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
} }
} }
@ -1118,6 +1122,7 @@ abstract class ElectrumWalletBase
)..addListener((transaction) async { )..addListener((transaction) async {
transactionHistory.addOne(transaction); transactionHistory.addOne(transaction);
await updateBalance(); await updateBalance();
await updateAllUnspents();
}); });
} }
@ -1210,6 +1215,7 @@ abstract class ElectrumWalletBase
.removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash)); .removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash));
await updateBalance(); await updateBalance();
await updateAllUnspents();
}); });
} catch (e) { } catch (e) {
throw e; throw e;
@ -1365,7 +1371,7 @@ abstract class ElectrumWalletBase
} }
@override @override
Future<void> close({required bool shouldCleanup}) async { Future<void> close({bool shouldCleanup = false}) async {
try { try {
await _receiveStream?.cancel(); await _receiveStream?.cancel();
await electrumClient.close(); await electrumClient.close();
@ -1402,9 +1408,11 @@ abstract class ElectrumWalletBase
unspentCoins = updatedUnspentCoins; unspentCoins = updatedUnspentCoins;
if (unspentCoinsInfo.length != updatedUnspentCoins.length) { final currentWalletUnspentCoins =
unspentCoinsInfo.values.where((element) => element.walletId == id);
if (currentWalletUnspentCoins.length != updatedUnspentCoins.length) {
unspentCoins.forEach((coin) => addCoinInfo(coin)); unspentCoins.forEach((coin) => addCoinInfo(coin));
return;
} }
await updateCoins(unspentCoins); await updateCoins(unspentCoins);
@ -1430,6 +1438,7 @@ abstract class ElectrumWalletBase
coin.isFrozen = coinInfo.isFrozen; coin.isFrozen = coinInfo.isFrozen;
coin.isSending = coinInfo.isSending; coin.isSending = coinInfo.isSending;
coin.note = coinInfo.note; coin.note = coinInfo.note;
if (coin.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord) if (coin.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord)
coin.bitcoinAddressRecord.balance += coinInfo.value; coin.bitcoinAddressRecord.balance += coinInfo.value;
} else { } else {
@ -1467,47 +1476,70 @@ abstract class ElectrumWalletBase
@action @action
Future<void> addCoinInfo(BitcoinUnspent coin) async { Future<void> addCoinInfo(BitcoinUnspent coin) async {
final newInfo = UnspentCoinsInfo( // Check if the coin is already in the unspentCoinsInfo for the wallet
walletId: id, final existingCoinInfo = unspentCoinsInfo.values
hash: coin.hash, .firstWhereOrNull((element) => element.walletId == walletInfo.id && element == coin);
isFrozen: coin.isFrozen,
isSending: coin.isSending,
noteRaw: coin.note,
address: coin.bitcoinAddressRecord.address,
value: coin.value,
vout: coin.vout,
isChange: coin.isChange,
isSilentPayment: coin is BitcoinSilentPaymentsUnspent,
);
await unspentCoinsInfo.add(newInfo); if (existingCoinInfo == null) {
final newInfo = UnspentCoinsInfo(
walletId: id,
hash: coin.hash,
isFrozen: coin.isFrozen,
isSending: coin.isSending,
noteRaw: coin.note,
address: coin.bitcoinAddressRecord.address,
value: coin.value,
vout: coin.vout,
isChange: coin.isChange,
isSilentPayment: coin is BitcoinSilentPaymentsUnspent,
);
await unspentCoinsInfo.add(newInfo);
}
} }
Future<void> _refreshUnspentCoinsInfo() async { Future<void> _refreshUnspentCoinsInfo() async {
try { try {
final List<dynamic> keys = <dynamic>[]; final List<dynamic> keys = [];
final currentWalletUnspentCoins = final currentWalletUnspentCoins =
unspentCoinsInfo.values.where((element) => element.walletId.contains(id)); unspentCoinsInfo.values.where((record) => record.walletId == id);
if (currentWalletUnspentCoins.isNotEmpty) { for (final element in currentWalletUnspentCoins) {
currentWalletUnspentCoins.forEach((element) { if (RegexUtils.addressTypeFromStr(element.address, network) is MwebAddress) continue;
final existUnspentCoins = unspentCoins
.where((coin) => element.hash.contains(coin.hash) && element.vout == coin.vout);
if (existUnspentCoins.isEmpty) { final existUnspentCoins = unspentCoins.where((coin) => element == coin);
keys.add(element.key);
} if (existUnspentCoins.isEmpty) {
}); keys.add(element.key);
}
} }
if (keys.isNotEmpty) { if (keys.isNotEmpty) {
await unspentCoinsInfo.deleteAll(keys); await unspentCoinsInfo.deleteAll(keys);
} }
} catch (e) { } catch (e) {
print("refreshUnspentCoinsInfo $e"); printV("refreshUnspentCoinsInfo $e");
} }
} }
Future<void> cleanUpDuplicateUnspentCoins() async {
final currentWalletUnspentCoins =
unspentCoinsInfo.values.where((element) => element.walletId == id);
final Map<String, UnspentCoinsInfo> uniqueUnspentCoins = {};
final List<dynamic> duplicateKeys = [];
for (final unspentCoin in currentWalletUnspentCoins) {
final key = '${unspentCoin.hash}:${unspentCoin.vout}';
if (!uniqueUnspentCoins.containsKey(key)) {
uniqueUnspentCoins[key] = unspentCoin;
} else {
duplicateKeys.add(unspentCoin.key);
}
}
if (duplicateKeys.isNotEmpty) await unspentCoinsInfo.deleteAll(duplicateKeys);
}
int transactionVSize(String transactionHex) => BtcTransaction.fromRaw(transactionHex).getVSize(); int transactionVSize(String transactionHex) => BtcTransaction.fromRaw(transactionHex).getVSize();
Future<String?> canReplaceByFee(ElectrumTransactionInfo tx) async { Future<String?> canReplaceByFee(ElectrumTransactionInfo tx) async {
@ -1525,14 +1557,22 @@ abstract class ElectrumWalletBase
final bundle = await getTransactionExpanded(hash: txId); final bundle = await getTransactionExpanded(hash: txId);
final outputs = bundle.originalTransaction.outputs; final outputs = bundle.originalTransaction.outputs;
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden); final ownAddresses = walletAddresses.allAddresses.map((addr) => addr.address).toSet();
// look for a change address in the outputs final receiverAmount = outputs
final changeOutput = outputs.firstWhereOrNull((output) => changeAddresses.any( .where((output) =>
(element) => element.address == addressFromOutputScript(output.scriptPubKey, network))); !ownAddresses.contains(addressFromOutputScript(output.scriptPubKey, network)))
.fold<int>(0, (sum, output) => sum + output.amount.toInt());
var allInputsAmount = 0; if (receiverAmount == 0) {
throw Exception("Receiver output not found.");
}
final availableInputs = unspentCoins.where((utxo) => utxo.isSending && !utxo.isFrozen).toList();
int totalBalance = availableInputs.fold<int>(
0, (previousValue, element) => previousValue + element.value.toInt());
int allInputsAmount = 0;
for (int i = 0; i < bundle.originalTransaction.inputs.length; i++) { for (int i = 0; i < bundle.originalTransaction.inputs.length; i++) {
final input = bundle.originalTransaction.inputs[i]; final input = bundle.originalTransaction.inputs[i];
final inputTransaction = bundle.ins[i]; final inputTransaction = bundle.ins[i];
@ -1543,12 +1583,10 @@ abstract class ElectrumWalletBase
int totalOutAmount = bundle.originalTransaction.outputs int totalOutAmount = bundle.originalTransaction.outputs
.fold<int>(0, (previousValue, element) => previousValue + element.amount.toInt()); .fold<int>(0, (previousValue, element) => previousValue + element.amount.toInt());
var currentFee = allInputsAmount - totalOutAmount; var currentFee = allInputsAmount - totalOutAmount;
int remainingFee = (newFee - currentFee > 0) ? newFee - currentFee : newFee; int remainingFee = (newFee - currentFee > 0) ? newFee - currentFee : newFee;
return totalBalance - receiverAmount - remainingFee >= _dustAmount;
return changeOutput != null && changeOutput.amount.toInt() - remainingFee >= 0;
} }
Future<PendingBitcoinTransaction> replaceByFee(String hash, int newFee) async { Future<PendingBitcoinTransaction> replaceByFee(String hash, int newFee) async {
@ -1556,12 +1594,13 @@ abstract class ElectrumWalletBase
final bundle = await getTransactionExpanded(hash: hash); final bundle = await getTransactionExpanded(hash: hash);
final utxos = <UtxoWithAddress>[]; final utxos = <UtxoWithAddress>[];
final outputs = <BitcoinOutput>[];
List<ECPrivate> privateKeys = []; List<ECPrivate> privateKeys = [];
var allInputsAmount = 0; var allInputsAmount = 0;
String? memo; String? memo;
// Add inputs // Add original inputs
for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) { for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) {
final input = bundle.originalTransaction.inputs[i]; final input = bundle.originalTransaction.inputs[i];
final inputTransaction = bundle.ins[i]; final inputTransaction = bundle.ins[i];
@ -1572,7 +1611,6 @@ abstract class ElectrumWalletBase
final addressRecord = final addressRecord =
walletAddresses.allAddresses.firstWhere((element) => element.address == address); walletAddresses.allAddresses.firstWhere((element) => element.address == address);
final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network); final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network);
final privkey = generateECPrivate( final privkey = generateECPrivate(
hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd,
@ -1595,10 +1633,8 @@ abstract class ElectrumWalletBase
); );
} }
// Create a list of available outputs // Add original outputs
final outputs = <BitcoinOutput>[];
for (final out in bundle.originalTransaction.outputs) { for (final out in bundle.originalTransaction.outputs) {
// Check if the script contains OP_RETURN
final script = out.scriptPubKey.script; final script = out.scriptPubKey.script;
if (script.contains('OP_RETURN') && memo == null) { if (script.contains('OP_RETURN') && memo == null) {
final index = script.indexOf('OP_RETURN'); final index = script.indexOf('OP_RETURN');
@ -1628,17 +1664,95 @@ abstract class ElectrumWalletBase
throw Exception("New fee must be higher than the current fee."); throw Exception("New fee must be higher than the current fee.");
} }
// Deduct Remaining Fee from Main Outputs // Deduct fee from change outputs first, if possible
if (remainingFee > 0) { if (remainingFee > 0) {
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden);
for (int i = outputs.length - 1; i >= 0; i--) { for (int i = outputs.length - 1; i >= 0; i--) {
int outputAmount = outputs[i].value.toInt(); final output = outputs[i];
final isChange = changeAddresses
.any((element) => element.address == output.address.toAddress(network));
if (isChange) {
int outputAmount = output.value.toInt();
if (outputAmount > _dustAmount) {
int deduction = (outputAmount - _dustAmount >= remainingFee)
? remainingFee
: outputAmount - _dustAmount;
outputs[i] = BitcoinOutput(
address: output.address, value: BigInt.from(outputAmount - deduction));
remainingFee -= deduction;
if (remainingFee <= 0) break;
}
}
}
}
// If still not enough, add UTXOs until the fee is covered
if (remainingFee > 0) {
final unusedUtxos = unspentCoins
.where((utxo) => utxo.isSending && !utxo.isFrozen && utxo.confirmations! > 0)
.toList();
for (final utxo in unusedUtxos) {
final address = RegexUtils.addressTypeFromStr(utxo.address, network);
final privkey = generateECPrivate(
hd: utxo.bitcoinAddressRecord.isHidden
? walletAddresses.sideHd
: walletAddresses.mainHd,
index: utxo.bitcoinAddressRecord.index,
network: network,
);
privateKeys.add(privkey);
utxos.add(UtxoWithAddress(
utxo: BitcoinUtxo(
txHash: utxo.hash,
value: BigInt.from(utxo.value),
vout: utxo.vout,
scriptType: _getScriptType(address)),
ownerDetails:
UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: address),
));
allInputsAmount += utxo.value;
remainingFee -= utxo.value;
if (remainingFee < 0) {
final changeOutput = outputs.firstWhereOrNull((output) => walletAddresses.allAddresses
.any((addr) => addr.address == output.address.toAddress(network)));
if (changeOutput != null) {
final newValue = changeOutput.value.toInt() + (-remainingFee);
outputs[outputs.indexOf(changeOutput)] =
BitcoinOutput(address: changeOutput.address, value: BigInt.from(newValue));
} else {
final changeAddress = await walletAddresses.getChangeAddress();
outputs.add(BitcoinOutput(
address: RegexUtils.addressTypeFromStr(changeAddress.address, network),
value: BigInt.from(-remainingFee)));
}
remainingFee = 0;
break;
}
if (remainingFee <= 0) break;
}
}
// Deduct from the receiver's output if remaining fee is still greater than 0
if (remainingFee > 0) {
for (int i = 0; i < outputs.length; i++) {
final output = outputs[i];
int outputAmount = output.value.toInt();
if (outputAmount > _dustAmount) { if (outputAmount > _dustAmount) {
int deduction = (outputAmount - _dustAmount >= remainingFee) int deduction = (outputAmount - _dustAmount >= remainingFee)
? remainingFee ? remainingFee
: outputAmount - _dustAmount; : outputAmount - _dustAmount;
outputs[i] = BitcoinOutput( outputs[i] = BitcoinOutput(
address: outputs[i].address, value: BigInt.from(outputAmount - deduction)); address: output.address, value: BigInt.from(outputAmount - deduction));
remainingFee -= deduction; remainingFee -= deduction;
if (remainingFee <= 0) break; if (remainingFee <= 0) break;
@ -1677,7 +1791,6 @@ abstract class ElectrumWalletBase
final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) { final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) {
final key = final key =
privateKeys.firstWhereOrNull((element) => element.getPublic().toHex() == publicKey); privateKeys.firstWhereOrNull((element) => element.getPublic().toHex() == publicKey);
if (key == null) { if (key == null) {
throw Exception("Cannot find private key"); throw Exception("Cannot find private key");
} }
@ -1708,6 +1821,7 @@ abstract class ElectrumWalletBase
}); });
transactionHistory.addOne(transaction); transactionHistory.addOne(transaction);
await updateBalance(); await updateBalance();
await updateAllUnspents();
}); });
} catch (e) { } catch (e) {
throw e; throw e;
@ -1729,7 +1843,7 @@ abstract class ElectrumWalletBase
try { try {
final blockHash = await http.get( final blockHash = await http.get(
Uri.parse( Uri.parse(
"http://mempool.cakewallet.com:8999/api/v1/block-height/$height", "https://mempool.cakewallet.com/api/v1/block-height/$height",
), ),
); );
@ -1738,7 +1852,7 @@ abstract class ElectrumWalletBase
jsonDecode(blockHash.body) != null) { jsonDecode(blockHash.body) != null) {
final blockResponse = await http.get( final blockResponse = await http.get(
Uri.parse( Uri.parse(
"http://mempool.cakewallet.com:8999/api/v1/block/${blockHash.body}", "https://mempool.cakewallet.com/api/v1/block/${blockHash.body}",
), ),
); );
if (blockResponse.statusCode == 200 && if (blockResponse.statusCode == 200 &&
@ -1849,7 +1963,7 @@ abstract class ElectrumWalletBase
return historiesWithDetails; return historiesWithDetails;
} catch (e) { } catch (e) {
print("fetchTransactions $e"); printV("fetchTransactions $e");
return {}; return {};
} }
} }
@ -1973,7 +2087,7 @@ abstract class ElectrumWalletBase
} }
Future<void> updateTransactions() async { Future<void> updateTransactions() async {
print("updateTransactions() called!"); printV("updateTransactions() called!");
try { try {
if (_isTransactionUpdating) { if (_isTransactionUpdating) {
return; return;
@ -2005,8 +2119,8 @@ abstract class ElectrumWalletBase
walletAddresses.updateReceiveAddresses(); walletAddresses.updateReceiveAddresses();
_isTransactionUpdating = false; _isTransactionUpdating = false;
} catch (e, stacktrace) { } catch (e, stacktrace) {
print(stacktrace); printV(stacktrace);
print(e); printV(e);
_isTransactionUpdating = false; _isTransactionUpdating = false;
} }
} }
@ -2024,13 +2138,13 @@ abstract class ElectrumWalletBase
try { try {
await _scripthashesUpdateSubject[sh]?.close(); await _scripthashesUpdateSubject[sh]?.close();
} catch (e) { } catch (e) {
print("failed to close: $e"); printV("failed to close: $e");
} }
} }
try { try {
_scripthashesUpdateSubject[sh] = await electrumClient.scripthashUpdate(sh); _scripthashesUpdateSubject[sh] = await electrumClient.scripthashUpdate(sh);
} catch (e) { } catch (e) {
print("failed scripthashUpdate: $e"); printV("failed scripthashUpdate: $e");
} }
_scripthashesUpdateSubject[sh]?.listen((event) async { _scripthashesUpdateSubject[sh]?.listen((event) async {
try { try {
@ -2040,7 +2154,7 @@ abstract class ElectrumWalletBase
await _fetchAddressHistory(address, await getCurrentChainTip()); await _fetchAddressHistory(address, await getCurrentChainTip());
} catch (e, s) { } catch (e, s) {
print("sub error: $e"); printV("sub error: $e");
_onError?.call(FlutterErrorDetails( _onError?.call(FlutterErrorDetails(
exception: e, exception: e,
stack: s, stack: s,
@ -2048,7 +2162,7 @@ abstract class ElectrumWalletBase
)); ));
} }
}, onError: (e, s) { }, onError: (e, s) {
print("sub_listen error: $e $s"); printV("sub_listen error: $e $s");
}); });
})); }));
} }
@ -2100,7 +2214,7 @@ abstract class ElectrumWalletBase
if (balances.isNotEmpty && balances.first['confirmed'] == null) { if (balances.isNotEmpty && balances.first['confirmed'] == null) {
// if we got null balance responses from the server, set our connection status to lost and return our last known balance: // if we got null balance responses from the server, set our connection status to lost and return our last known balance:
print("got null balance responses from the server, setting connection status to lost"); printV("got null balance responses from the server, setting connection status to lost");
syncStatus = LostConnectionSyncStatus(); syncStatus = LostConnectionSyncStatus();
return balance[currency] ?? ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0); return balance[currency] ?? ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
} }
@ -2127,7 +2241,7 @@ abstract class ElectrumWalletBase
} }
Future<void> updateBalance() async { Future<void> updateBalance() async {
print("updateBalance() called!"); printV("updateBalance() called!");
balance[currency] = await fetchBalances(); balance[currency] = await fetchBalances();
await save(); await save();
} }
@ -2267,7 +2381,7 @@ abstract class ElectrumWalletBase
} }
void _syncStatusReaction(SyncStatus syncStatus) async { void _syncStatusReaction(SyncStatus syncStatus) async {
print("SYNC_STATUS_CHANGE: ${syncStatus}"); printV("SYNC_STATUS_CHANGE: ${syncStatus}");
if (syncStatus is SyncingSyncStatus) { if (syncStatus is SyncingSyncStatus) {
return; return;
} }

View file

@ -3,6 +3,8 @@ import 'dart:io' show Platform;
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
@ -193,7 +195,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
receiveAddresses.remove(addressRecord); receiveAddresses.remove(addressRecord);
receiveAddresses.insert(0, addressRecord); receiveAddresses.insert(0, addressRecord);
} catch (e) { } catch (e) {
print("ElectrumWalletAddressBase: set address ($addr): $e"); printV("ElectrumWalletAddressBase: set address ($addr): $e");
} }
} }
@ -483,7 +485,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
await saveAddressesInBox(); await saveAddressesInBox();
} catch (e) { } catch (e) {
print("updateAddresses $e"); printV("updateAddresses $e");
} }
} }

View file

@ -9,6 +9,7 @@ import 'package:crypto/crypto.dart';
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/mweb_utxo.dart'; import 'package:cw_core/mweb_utxo.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
import 'package:cw_mweb/mwebd.pbgrpc.dart'; import 'package:cw_mweb/mwebd.pbgrpc.dart';
import 'package:fixnum/fixnum.dart'; import 'package:fixnum/fixnum.dart';
@ -283,7 +284,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
Future<void> waitForMwebAddresses() async { Future<void> waitForMwebAddresses() async {
print("waitForMwebAddresses() called!"); printV("waitForMwebAddresses() called!");
// ensure that we have the full 1000 mweb addresses generated before continuing: // ensure that we have the full 1000 mweb addresses generated before continuing:
// should no longer be needed, but leaving here just in case // should no longer be needed, but leaving here just in case
await (walletAddresses as LitecoinWalletAddresses).ensureMwebAddressUpToIndexExists(1020); await (walletAddresses as LitecoinWalletAddresses).ensureMwebAddressUpToIndexExists(1020);
@ -302,8 +303,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
@action @action
@override @override
Future<void> startSync() async { Future<void> startSync() async {
print("startSync() called!"); printV("startSync() called!");
print("STARTING SYNC - MWEB ENABLED: $mwebEnabled"); printV("STARTING SYNC - MWEB ENABLED: $mwebEnabled");
if (!mwebEnabled) { if (!mwebEnabled) {
try { try {
// in case we're switching from a litecoin wallet that had mweb enabled // in case we're switching from a litecoin wallet that had mweb enabled
@ -317,33 +318,33 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
return; return;
} }
print("STARTING SYNC - MWEB ENABLED: $mwebEnabled"); printV("STARTING SYNC - MWEB ENABLED: $mwebEnabled");
_syncTimer?.cancel(); _syncTimer?.cancel();
try { try {
mwebSyncStatus = SyncronizingSyncStatus(); mwebSyncStatus = SyncronizingSyncStatus();
try { try {
await subscribeForUpdates(); await subscribeForUpdates();
} catch (e) { } catch (e) {
print("failed to subcribe for updates: $e"); printV("failed to subcribe for updates: $e");
} }
updateFeeRates(); updateFeeRates();
_feeRatesTimer?.cancel(); _feeRatesTimer?.cancel();
_feeRatesTimer = _feeRatesTimer =
Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates()); Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates());
print("START SYNC FUNCS"); printV("START SYNC FUNCS");
await waitForMwebAddresses(); await waitForMwebAddresses();
await processMwebUtxos(); await processMwebUtxos();
await updateTransactions(); await updateTransactions();
await updateUnspent(); await updateUnspent();
await updateBalance(); await updateBalance();
print("DONE SYNC FUNCS"); } catch (e) {
} catch (e, s) { printV("failed to start mweb sync: $e");
print("mweb sync failed: $e $s"); syncStatus = FailedSyncStatus();
mwebSyncStatus = FailedSyncStatus(error: "mweb sync failed: $e");
return; return;
} }
_syncTimer?.cancel();
_syncTimer = Timer.periodic(const Duration(milliseconds: 3000), (timer) async { _syncTimer = Timer.periodic(const Duration(milliseconds: 3000), (timer) async {
if (mwebSyncStatus is FailedSyncStatus) { if (mwebSyncStatus is FailedSyncStatus) {
_syncTimer?.cancel(); _syncTimer?.cancel();
@ -401,7 +402,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
for (var coin in tx.unspents!) { for (var coin in tx.unspents!) {
final utxo = mwebUtxosBox.get(coin.address); final utxo = mwebUtxosBox.get(coin.address);
if (utxo != null) { if (utxo != null) {
print("deleting utxo ${coin.address} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); printV("deleting utxo ${coin.address} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
await mwebUtxosBox.delete(coin.address); await mwebUtxosBox.delete(coin.address);
} }
} }
@ -428,7 +429,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
return; return;
} }
} catch (e) { } catch (e) {
print("error syncing: $e"); printV("error syncing: $e");
mwebSyncStatus = FailedSyncStatus(error: e.toString()); mwebSyncStatus = FailedSyncStatus(error: e.toString());
} }
}); });
@ -437,12 +438,13 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
@action @action
@override @override
Future<void> stopSync() async { Future<void> stopSync() async {
print("stopSync() called!"); printV("stopSync() called!");
_syncTimer?.cancel(); _syncTimer?.cancel();
_utxoStream?.cancel(); _utxoStream?.cancel();
_feeRatesTimer?.cancel(); _feeRatesTimer?.cancel();
await CwMweb.stop(); await CwMweb.stop();
await super.stopSync(); await super.stopSync();
printV("stopped syncing!");
} }
Future<void> initMwebUtxosBox() async { Future<void> initMwebUtxosBox() async {
@ -514,7 +516,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
Future<void> handleIncoming(MwebUtxo utxo) async { Future<void> handleIncoming(MwebUtxo utxo) async {
print("handleIncoming() called!"); printV("handleIncoming() called!");
final status = await CwMweb.status(StatusRequest()); final status = await CwMweb.status(StatusRequest());
var date = DateTime.now(); var date = DateTime.now();
var confirmations = 0; var confirmations = 0;
@ -559,7 +561,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
final addressRecord = walletAddresses.allAddresses final addressRecord = walletAddresses.allAddresses
.firstWhereOrNull((addressRecord) => addressRecord.address == utxo.address); .firstWhereOrNull((addressRecord) => addressRecord.address == utxo.address);
if (addressRecord == null) { if (addressRecord == null) {
print("we don't have this address in the wallet! ${utxo.address}"); printV("we don't have this address in the wallet! ${utxo.address}");
return; return;
} }
@ -580,13 +582,13 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
Future<void> processMwebUtxos() async { Future<void> processMwebUtxos() async {
print("processMwebUtxos() called!"); printV("processMwebUtxos() called!");
if (!mwebEnabled) { if (!mwebEnabled) {
return; return;
} }
int restoreHeight = walletInfo.restoreHeight; int restoreHeight = walletInfo.restoreHeight;
print("SCANNING FROM HEIGHT: $restoreHeight"); printV("SCANNING FROM HEIGHT: $restoreHeight");
final req = UtxosRequest(scanSecret: scanSecret, fromHeight: restoreHeight); final req = UtxosRequest(scanSecret: scanSecret, fromHeight: restoreHeight);
// process new utxos as they come in: // process new utxos as they come in:
@ -621,7 +623,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
// but do update the utxo height if it's somehow different: // but do update the utxo height if it's somehow different:
final existingUtxo = mwebUtxosBox.get(utxo.outputId); final existingUtxo = mwebUtxosBox.get(utxo.outputId);
if (existingUtxo!.height != utxo.height) { if (existingUtxo!.height != utxo.height) {
print( printV(
"updating utxo height for $utxo.outputId: ${existingUtxo.height} -> ${utxo.height}"); "updating utxo height for $utxo.outputId: ${existingUtxo.height} -> ${utxo.height}");
existingUtxo.height = utxo.height; existingUtxo.height = utxo.height;
await mwebUtxosBox.put(utxo.outputId, existingUtxo); await mwebUtxosBox.put(utxo.outputId, existingUtxo);
@ -644,7 +646,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
await handleIncoming(utxo); await handleIncoming(utxo);
}, },
onError: (error) { onError: (error) {
print("error in utxo stream: $error"); printV("error in utxo stream: $error");
mwebSyncStatus = FailedSyncStatus(error: error.toString()); mwebSyncStatus = FailedSyncStatus(error: error.toString());
}, },
cancelOnError: true, cancelOnError: true,
@ -652,7 +654,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
Future<void> deleteSpentUtxos() async { Future<void> deleteSpentUtxos() async {
print("deleteSpentUtxos() called!"); printV("deleteSpentUtxos() called!");
final chainHeight = await electrumClient.getCurrentBlockChainTip(); final chainHeight = await electrumClient.getCurrentBlockChainTip();
final status = await CwMweb.status(StatusRequest()); final status = await CwMweb.status(StatusRequest());
if (chainHeight == null || status.blockHeaderHeight != chainHeight) return; if (chainHeight == null || status.blockHeaderHeight != chainHeight) return;
@ -676,7 +678,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
Future<void> checkMwebUtxosSpent() async { Future<void> checkMwebUtxosSpent() async {
print("checkMwebUtxosSpent() called!"); printV("checkMwebUtxosSpent() called!");
if (!mwebEnabled) { if (!mwebEnabled) {
return; return;
} }
@ -757,6 +759,13 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
if (!mwebEnabled) return false; if (!mwebEnabled) return false;
if (!tx.isPending) return false; if (!tx.isPending) return false;
final isMwebTx = (tx.inputAddresses?.any((addr) => addr.contains("mweb")) ?? false) ||
(tx.outputAddresses?.any((addr) => addr.contains("mweb")) ?? false);
if (!isMwebTx) {
return false;
}
final outputId = <String>[], target = <String>{}; final outputId = <String>[], target = <String>{};
final isHash = RegExp(r'^[a-f0-9]{64}$').hasMatch; final isHash = RegExp(r'^[a-f0-9]{64}$').hasMatch;
final spendingOutputIds = tx.inputAddresses?.where(isHash) ?? []; final spendingOutputIds = tx.inputAddresses?.where(isHash) ?? [];
@ -791,7 +800,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
Future<void> updateUnspent() async { Future<void> updateUnspent() async {
print("updateUnspent() called!"); printV("updateUnspent() called!");
await checkMwebUtxosSpent(); await checkMwebUtxosSpent();
await updateAllUnspents(); await updateAllUnspents();
} }
@ -822,7 +831,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
.firstWhereOrNull((addressRecord) => addressRecord.address == utxo.address); .firstWhereOrNull((addressRecord) => addressRecord.address == utxo.address);
if (addressRecord == null) { if (addressRecord == null) {
print("utxo contains an address that is not in the wallet: ${utxo.address}"); printV("utxo contains an address that is not in the wallet: ${utxo.address}");
return; return;
} }
final unspent = BitcoinUnspent( final unspent = BitcoinUnspent(
@ -863,7 +872,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
mwebUtxosBox.values.forEach((utxo) { mwebUtxosBox.values.forEach((utxo) {
bool isConfirmed = utxo.height > 0; bool isConfirmed = utxo.height > 0;
print( printV(
"utxo: ${isConfirmed ? "confirmed" : "unconfirmed"} ${utxo.spent ? "spent" : "unspent"} ${utxo.outputId} ${utxo.height} ${utxo.value}"); "utxo: ${isConfirmed ? "confirmed" : "unconfirmed"} ${utxo.spent ? "spent" : "unspent"} ${utxo.outputId} ${utxo.height} ${utxo.value}");
if (isConfirmed) { if (isConfirmed) {
@ -1001,7 +1010,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
final sum1 = _sumOutputAmounts(outputs.map((e) => e.toOutput).toList()) + fee; final sum1 = _sumOutputAmounts(outputs.map((e) => e.toOutput).toList()) + fee;
final sum2 = utxos.sumOfUtxosValue(); final sum2 = utxos.sumOfUtxosValue();
if (sum1 != sum2) { if (sum1 != sum2) {
print("@@@@@ WE HAD TO ADJUST THE FEE! @@@@@@@@"); printV("@@@@@ WE HAD TO ADJUST THE FEE! @@@@@@@@");
final diff = sum2 - sum1; final diff = sum2 - sum1;
// add the difference to the fee (abs value): // add the difference to the fee (abs value):
fee += diff.abs(); fee += diff.abs();
@ -1166,7 +1175,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
addressRecord.balance -= utxo.value.toInt(); addressRecord.balance -= utxo.value.toInt();
}); });
transaction.inputAddresses?.addAll(addresses); transaction.inputAddresses?.addAll(addresses);
print("isPegIn: $isPegIn, isPegOut: $isPegOut"); printV("isPegIn: $isPegIn, isPegOut: $isPegOut");
transaction.additionalInfo["isPegIn"] = isPegIn; transaction.additionalInfo["isPegIn"] = isPegIn;
transaction.additionalInfo["isPegOut"] = isPegOut; transaction.additionalInfo["isPegOut"] = isPegOut;
transactionHistory.addOne(transaction); transactionHistory.addOne(transaction);
@ -1174,10 +1183,10 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
await updateBalance(); await updateBalance();
}); });
} catch (e, s) { } catch (e, s) {
print(e); printV(e);
print(s); printV(s);
if (e.toString().contains("commit failed")) { if (e.toString().contains("commit failed")) {
print(e); printV(e);
throw Exception("Transaction commit failed (no peers responded), please try again."); throw Exception("Transaction commit failed (no peers responded), please try again.");
} }
rethrow; rethrow;
@ -1190,7 +1199,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
@override @override
Future<void> close({required bool shouldCleanup}) async { Future<void> close({bool shouldCleanup = false}) async {
_utxoStream?.cancel(); _utxoStream?.cancel();
_feeRatesTimer?.cancel(); _feeRatesTimer?.cancel();
_syncTimer?.cancel(); _syncTimer?.cancel();

View file

@ -9,6 +9,7 @@ import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_bitcoin/utils.dart'; import 'package:cw_bitcoin/utils.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_mweb/cw_mweb.dart'; import 'package:cw_mweb/cw_mweb.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -35,7 +36,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
for (int i = 0; i < mwebAddresses.length; i++) { for (int i = 0; i < mwebAddresses.length; i++) {
mwebAddrs.add(mwebAddresses[i].address); mwebAddrs.add(mwebAddresses[i].address);
} }
print("initialized with ${mwebAddrs.length} mweb addresses"); printV("initialized with ${mwebAddrs.length} mweb addresses");
} }
final Bip32Slip10Secp256k1? mwebHd; final Bip32Slip10Secp256k1? mwebHd;
@ -73,25 +74,25 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
} }
while (generating) { while (generating) {
print("generating....."); printV("generating.....");
// this function was called multiple times in multiple places: // this function was called multiple times in multiple places:
await Future.delayed(const Duration(milliseconds: 100)); await Future.delayed(const Duration(milliseconds: 100));
} }
print("Generating MWEB addresses up to index $index"); printV("Generating MWEB addresses up to index $index");
generating = true; generating = true;
try { try {
while (mwebAddrs.length <= (index + 1)) { while (mwebAddrs.length <= (index + 1)) {
final addresses = final addresses =
await CwMweb.addresses(scan, spend, mwebAddrs.length, mwebAddrs.length + 50); await CwMweb.addresses(scan, spend, mwebAddrs.length, mwebAddrs.length + 50);
print("generated up to index ${mwebAddrs.length}"); printV("generated up to index ${mwebAddrs.length}");
// sleep for a bit to avoid making the main thread unresponsive: // sleep for a bit to avoid making the main thread unresponsive:
await Future.delayed(Duration(milliseconds: 200)); await Future.delayed(Duration(milliseconds: 200));
mwebAddrs.addAll(addresses!); mwebAddrs.addAll(addresses!);
} }
} catch (_) {} } catch (_) {}
generating = false; generating = false;
print("Done generating MWEB addresses len: ${mwebAddrs.length}"); printV("Done generating MWEB addresses len: ${mwebAddrs.length}");
// ensure mweb addresses are up to date: // ensure mweb addresses are up to date:
// This is the Case if the Litecoin Wallet is a hardware Wallet // This is the Case if the Litecoin Wallet is a hardware Wallet
@ -109,7 +110,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
)) ))
.toList(); .toList();
addMwebAddresses(addressRecords); addMwebAddresses(addressRecords);
print("set ${addressRecords.length} mweb addresses"); printV("set ${addressRecords.length} mweb addresses");
} }
} }

View file

@ -126,6 +126,15 @@ class LitecoinWalletService extends WalletService<
mwebdLogs.deleteSync(); mwebdLogs.deleteSync();
} }
} }
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where(
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList();
final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList();
if (keysToDelete.isNotEmpty) {
await unspentCoinsInfoSource.deleteAll(keysToDelete);
}
} }
@override @override

View file

@ -2,6 +2,7 @@ import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:convert/convert.dart'; import 'package:convert/convert.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:ledger_bitcoin/psbt.dart'; import 'package:ledger_bitcoin/psbt.dart';
class PSBTTransactionBuild { class PSBTTransactionBuild {
@ -16,6 +17,10 @@ class PSBTTransactionBuild {
for (var i = 0; i < inputs.length; i++) { for (var i = 0; i < inputs.length; i++) {
final input = inputs[i]; final input = inputs[i];
printV(input.utxo.isP2tr());
printV(input.utxo.isSegwit());
printV(input.utxo.isP2shSegwit());
psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList())); psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList()));
psbt.setInputOutputIndex(i, input.utxo.vout); psbt.setInputOutputIndex(i, input.utxo.vout);
psbt.setInputSequence(i, enableRBF ? 0x1 : 0xffffffff); psbt.setInputSequence(i, enableRBF ? 0x1 : 0xffffffff);

View file

@ -29,10 +29,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.6.0"
asn1lib: asn1lib:
dependency: transitive dependency: transitive
description: description:
@ -145,10 +145,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.1" version: "4.0.2"
build_resolvers: build_resolvers:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -161,10 +161,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.9" version: "2.4.13"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
@ -250,18 +250,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.6"
cryptography: cryptography:
dependency: "direct main" dependency: "direct main"
description: description:
@ -360,10 +360,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: fixnum name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -431,10 +431,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: graphs name: graphs
sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
grpc: grpc:
dependency: "direct main" dependency: "direct main"
description: description:
@ -503,10 +503,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -535,26 +535,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.0" version: "10.0.5"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.5"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.1"
ledger_bitcoin: ledger_bitcoin:
dependency: "direct main" dependency: "direct main"
description: description:
@ -577,7 +577,7 @@ packages:
description: description:
path: "packages/ledger-litecoin" path: "packages/ledger-litecoin"
ref: HEAD ref: HEAD
resolved-ref: "07cd61ef76a2a017b6d5ef233396740163265457" resolved-ref: "3dee36713e6ebec9dceb59b9ccae7f243a53ea9e"
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins" url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
source: git source: git
version: "0.0.2" version: "0.0.2"
@ -593,10 +593,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.3.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -609,26 +609,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.0" version: "0.11.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.15.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.6" version: "2.0.0"
mobx: mobx:
dependency: "direct main" dependency: "direct main"
description: description:
@ -681,10 +681,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.4" version: "2.2.12"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
@ -729,10 +729,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.5" version: "3.1.6"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -809,18 +809,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences name: shared_preferences
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.3" version: "2.3.2"
shared_preferences_android: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.3.3"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
@ -849,10 +849,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2" sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.2"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
@ -873,10 +873,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -967,10 +967,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.7.2"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -991,10 +991,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.4.0"
universal_ble: universal_ble:
dependency: transitive dependency: transitive
description: description:
@ -1031,10 +1031,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "14.2.4"
watcher: watcher:
dependency: "direct overridden" dependency: "direct overridden"
description: description:
@ -1047,18 +1047,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "1.1.0"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
url: "https://pub.dev"
source: hosted
version: "0.1.6"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.5" version: "3.0.1"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@ -1092,5 +1100,5 @@ packages:
source: hosted source: hosted
version: "2.2.1" version: "2.2.1"
sdks: sdks:
dart: ">=3.3.0 <4.0.0" dart: ">=3.5.0 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.24.0"

View file

@ -16,7 +16,7 @@ dependencies:
http: ^1.1.0 http: ^1.1.0
mobx: ^2.0.7+4 mobx: ^2.0.7+4
flutter_mobx: ^2.0.6+1 flutter_mobx: ^2.0.6+1
intl: ^0.18.0 intl: ^0.19.0
shared_preferences: ^2.0.15 shared_preferences: ^2.0.15
cw_core: cw_core:
path: ../cw_core path: ../cw_core

View file

@ -85,6 +85,15 @@ class BitcoinCashWalletService extends WalletService<
final walletInfo = walletInfoSource.values final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!; .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key); await walletInfoSource.delete(walletInfo.key);
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where(
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList();
final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList();
if (keysToDelete.isNotEmpty) {
await unspentCoinsInfoSource.deleteAll(keysToDelete);
}
} }
@override @override

View file

@ -1,3 +1,4 @@
import 'package:cw_core/utils/print_verbose.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
const MethodChannel _channel = MethodChannel('com.cake_wallet/native_utils'); const MethodChannel _channel = MethodChannel('com.cake_wallet/native_utils');
@ -6,17 +7,17 @@ Future<void> requestDisableBatteryOptimization() async {
try { try {
await _channel.invokeMethod('disableBatteryOptimization'); await _channel.invokeMethod('disableBatteryOptimization');
} on PlatformException catch (e) { } on PlatformException catch (e) {
print("Failed to disable battery optimization: '${e.message}'."); printV("Failed to disable battery optimization: '${e.message}'.");
} }
} }
Future<bool> isBatteryOptimizationDisabled() async { Future<bool> isBatteryOptimizationDisabled() async {
try { try {
final bool isDisabled = await _channel.invokeMethod('isBatteryOptimizationDisabled') as bool; final bool isDisabled = await _channel.invokeMethod('isBatteryOptimizationDisabled') as bool;
print('It\'s actually disabled? $isDisabled'); printV('It\'s actually disabled? $isDisabled');
return isDisabled; return isDisabled;
} on PlatformException catch (e) { } on PlatformException catch (e) {
print("Failed to check battery optimization status: '${e.message}'."); printV("Failed to check battery optimization status: '${e.message}'.");
return false; return false;
} }
} }

View file

@ -1,3 +1,4 @@
import 'package:cw_core/utils/print_verbose.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -152,7 +153,7 @@ int getMoneroHeigthByDate({required DateTime date}) {
height = startHeight + daysHeight - heightPerDay; height = startHeight + daysHeight - heightPerDay;
} }
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
return height; return height;
@ -270,7 +271,7 @@ const bitcoinDates = {
Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async { Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async {
final response = await http.get( final response = await http.get(
Uri.parse( Uri.parse(
"http://mempool.cakewallet.com:8999/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}", "https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}",
), ),
); );

View file

@ -7,7 +7,7 @@ enum DeviceConnectionType {
static List<DeviceConnectionType> supportedConnectionTypes(WalletType walletType, static List<DeviceConnectionType> supportedConnectionTypes(WalletType walletType,
[bool isIOS = false]) { [bool isIOS = false]) {
switch (walletType) { switch (walletType) {
// case WalletType.monero: case WalletType.monero:
case WalletType.bitcoin: case WalletType.bitcoin:
case WalletType.litecoin: case WalletType.litecoin:
case WalletType.ethereum: case WalletType.ethereum:

View file

@ -18,4 +18,5 @@ const SPL_TOKEN_TYPE_ID = 16;
const DERIVATION_INFO_TYPE_ID = 17; const DERIVATION_INFO_TYPE_ID = 17;
const TRON_TOKEN_TYPE_ID = 18; const TRON_TOKEN_TYPE_ID = 18;
const HARDWARE_WALLET_TYPE_TYPE_ID = 19; const HARDWARE_WALLET_TYPE_TYPE_ID = 19;
const MWEB_UTXO_TYPE_ID = 20; const MWEB_UTXO_TYPE_ID = 20;
const HAVEN_SEED_STORE_TYPE_ID = 21;

View file

@ -3,8 +3,8 @@ import 'package:cw_core/monero_amount_format.dart';
class MoneroBalance extends Balance { class MoneroBalance extends Balance {
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0}) MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
: formattedFullBalance = moneroAmountToString(amount: fullBalance), : formattedFullBalance = moneroAmountToString(amount: frozenBalance + fullBalance),
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance - frozenBalance), formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
formattedLockedBalance = formattedLockedBalance =
moneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance), moneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
super(unlockedBalance, fullBalance); super(unlockedBalance, fullBalance);

View file

@ -203,9 +203,30 @@ class Node extends HiveObject with Keyable {
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: json.encode(body), body: json.encode(body),
); );
client.close(); client.close();
if ((
response.body.contains("400 Bad Request") // Some other generic error
|| response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|| response.headers["location"] != null // Generic reverse proxy
|| response.body.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
) && !(useSSL??false)
) {
final oldUseSSL = useSSL;
useSSL = true;
try {
final ret = await requestMoneroNode();
if (ret == true) {
await save();
return ret;
}
useSSL = oldUseSSL;
} catch (e) {
useSSL = oldUseSSL;
}
}
final resBody = json.decode(response.body) as Map<String, dynamic>; final resBody = json.decode(response.body) as Map<String, dynamic>;
return !(resBody['result']['offline'] as bool); return !(resBody['result']['offline'] as bool);
} catch (_) { } catch (_) {

View file

@ -1,10 +1,11 @@
import 'package:cw_core/hive_type_ids.dart'; import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/unspent_comparable_mixin.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
part 'unspent_coins_info.g.dart'; part 'unspent_coins_info.g.dart';
@HiveType(typeId: UnspentCoinsInfo.typeId) @HiveType(typeId: UnspentCoinsInfo.typeId)
class UnspentCoinsInfo extends HiveObject { class UnspentCoinsInfo extends HiveObject with UnspentComparable {
UnspentCoinsInfo({ UnspentCoinsInfo({
required this.walletId, required this.walletId,
required this.hash, required this.hash,

View file

@ -0,0 +1,27 @@
mixin UnspentComparable {
String get address;
String get hash;
int get value;
int get vout;
String? get keyImage;
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is UnspentComparable &&
other.hash == hash &&
other.address == address &&
other.value == value &&
other.vout == vout &&
other.keyImage == keyImage;
}
@override
int get hashCode {
return Object.hash(address, hash, value, vout, keyImage);
}
}

View file

@ -1,4 +1,6 @@
class Unspent { import 'package:cw_core/unspent_comparable_mixin.dart';
class Unspent with UnspentComparable {
Unspent(this.address, this.hash, this.value, this.vout, this.keyImage) Unspent(this.address, this.hash, this.value, this.vout, this.keyImage)
: isSending = true, : isSending = true,
isFrozen = false, isFrozen = false,

View file

@ -0,0 +1,84 @@
void printV(dynamic content) {
CustomTrace programInfo = CustomTrace(StackTrace.current);
print("${programInfo.fileName}#${programInfo.lineNumber}:${programInfo.columnNumber} ${programInfo.callerFunctionName}: $content");
}
// https://stackoverflow.com/a/59386101
class CustomTrace {
final StackTrace _trace;
String? fileName;
String? functionName;
String? callerFunctionName;
int? lineNumber;
int? columnNumber;
CustomTrace(this._trace) {
try {
_parseTrace();
} catch (e) {
print("Unable to parse trace (printV): $e");
}
}
String _getFunctionNameFromFrame(String frame) {
/* Just giving another nickname to the frame */
var currentTrace = frame;
/* To get rid off the #number thing, get the index of the first whitespace */
var indexOfWhiteSpace = currentTrace.indexOf(' ');
/* Create a substring from the first whitespace index till the end of the string */
var subStr = currentTrace.substring(indexOfWhiteSpace);
/* Grab the function name using reg expr */
var indexOfFunction = subStr.indexOf(RegExp(r'[A-Za-z0-9_]'));
/* Create a new substring from the function name index till the end of string */
subStr = subStr.substring(indexOfFunction);
indexOfWhiteSpace = subStr.indexOf(RegExp(r'[ .]'));
/* Create a new substring from start to the first index of a whitespace. This substring gives us the function name */
subStr = subStr.substring(0, indexOfWhiteSpace);
return subStr;
}
void _parseTrace() {
/* The trace comes with multiple lines of strings, (each line is also known as a frame), so split the trace's string by lines to get all the frames */
var frames = this._trace.toString().split("\n");
/* The first frame is the current function */
this.functionName = _getFunctionNameFromFrame(frames[0]);
/* The second frame is the caller function */
this.callerFunctionName = _getFunctionNameFromFrame(frames[1]);
/* The first frame has all the information we need */
var traceString = frames[1];
/* Search through the string and find the index of the file name by looking for the '.dart' regex */
var indexOfFileName = traceString.indexOf(RegExp(r'[/A-Za-z_]+.dart'), 1); // 1 to offest and not print the printV function name
var fileInfo = traceString.substring(indexOfFileName);
var listOfInfos = fileInfo.split(":");
/* Splitting fileInfo by the character ":" separates the file name, the line number and the column counter nicely.
Example: main.dart:5:12
To get the file name, we split with ":" and get the first index
To get the line number, we would have to get the second index
To get the column number, we would have to get the third index
*/
try {
this.fileName = listOfInfos[0];
this.lineNumber = int.tryParse(listOfInfos[1]);
var columnStr = listOfInfos[2];
columnStr = columnStr.replaceFirst(")", "");
this.columnNumber = int.tryParse(columnStr);
} catch (e) {
}
}
}

View file

@ -1,4 +1,5 @@
import 'package:cw_core/address_info.dart'; import 'package:cw_core/address_info.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
@ -71,7 +72,7 @@ abstract class WalletAddresses {
await walletInfo.save(); await walletInfo.save();
} }
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }

View file

@ -83,7 +83,7 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
Future<void> rescan({required int height}); Future<void> rescan({required int height});
Future<void> close({required bool shouldCleanup}); Future<void> close({bool shouldCleanup = false});
Future<void> changePassword(String password); Future<void> changePassword(String password);

View file

@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
const MethodChannel _channel = MethodChannel('com.cake_wallet/native_utils'); const MethodChannel _channel = MethodChannel('com.cake_wallet/native_utils');
@ -14,9 +15,9 @@ Future<void> setDefaultMinimumWindowSize() async {
) as bool; ) as bool;
if (!result) { if (!result) {
print("Failed to set minimum window size."); printV("Failed to set minimum window size.");
} }
} on PlatformException catch (e) { } on PlatformException catch (e) {
print("Failed to set minimum window size: '${e.message}'."); printV("Failed to set minimum window size: '${e.message}'.");
} }
} }

View file

@ -5,34 +5,39 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: _fe_analyzer_shared name: _fe_analyzer_shared
sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "64.0.0" version: "72.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.2"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.0" version: "6.7.0"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.6.0"
asn1lib: asn1lib:
dependency: transitive dependency: transitive
description: description:
name: asn1lib name: asn1lib
sha256: "21afe4333076c02877d14f4a89df111e658a6d466cbfc802eb705eb91bd5adfd" sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.0" version: "1.5.5"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -69,10 +74,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.1" version: "4.0.2"
build_resolvers: build_resolvers:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -85,18 +90,18 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.8" version: "2.4.13"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.2.11" version: "7.3.2"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
@ -109,10 +114,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: built_value name: built_value
sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309 sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.8.1" version: "8.9.2"
cake_backup: cake_backup:
dependency: "direct main" dependency: "direct main"
description: description:
@ -166,42 +171,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.6"
cryptography: cryptography:
dependency: transitive dependency: transitive
description: description:
name: cryptography name: cryptography
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35 sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.7.0"
cupertino_icons: cupertino_icons:
dependency: transitive dependency: transitive
description: description:
name: cupertino_icons name: cupertino_icons
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.6" version: "1.0.8"
dart_style: dart_style:
dependency: transitive dependency: transitive
description: description:
name: dart_style name: dart_style
sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.4" version: "2.3.7"
encrypt: encrypt:
dependency: "direct main" dependency: "direct main"
description: description:
@ -222,26 +227,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.3"
file: file:
dependency: "direct main" dependency: "direct main"
description: description:
name: file name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.0.1"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
name: fixnum name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -251,10 +256,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_mobx name: flutter_mobx
sha256: "4a5d062ff85ed3759f4aac6410ff0ffae32e324b2e71ca722ae1b37b32e865f4" sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0+2" version: "2.2.1+1"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -264,10 +269,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: frontend_server_client name: frontend_server_client
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "4.0.0"
glob: glob:
dependency: transitive dependency: transitive
description: description:
@ -280,10 +285,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: graphs name: graphs
sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
hive: hive:
dependency: transitive dependency: transitive
description: description:
@ -304,10 +309,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.2.2"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -328,10 +333,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -352,42 +357,50 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: json_annotation name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.8.1" version: "4.9.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.0" version: "10.0.5"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.5"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.1"
logging: logging:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.3.0"
macros:
dependency: transitive
description:
name: macros
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
url: "https://pub.dev"
source: hosted
version: "0.1.2-main.4"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -400,42 +413,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.0" version: "0.11.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.15.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0"
mobx: mobx:
dependency: "direct main" dependency: "direct main"
description: description:
name: mobx name: mobx
sha256: "74ee54012dc7c1b3276eaa960a600a7418ef5f9997565deb8fca1fd88fb36b78" sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0+1" version: "2.3.3+2"
mobx_codegen: mobx_codegen:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: mobx_codegen name: mobx_codegen
sha256: b26c7f9c20b38f0ea572c1ed3f29d8e027cb265538bbd1aed3ec198642cfca42 sha256: "8e0d8653a0c720ad933cd8358f6f89f740ce89203657c13f25bea772ef1fff7c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.6.0+1" version: "2.6.1"
nested: nested:
dependency: transitive dependency: transitive
description: description:
@ -464,26 +477,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.4"
path_provider_android: path_provider_android:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.2.12"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.0"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@ -504,18 +517,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.3.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.4" version: "3.1.6"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -528,10 +541,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: pointycastle
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.7.4" version: "3.9.1"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -544,10 +557,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: provider name: provider
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.1" version: "6.1.2"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
@ -560,10 +573,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: pubspec_parse name: pubspec_parse
sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.3" version: "1.3.0"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
@ -576,10 +589,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -589,10 +602,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: socks5_proxy name: socks5_proxy
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a" sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.6"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -661,10 +674,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.7.2"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -685,10 +698,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.4.0"
unorm_dart: unorm_dart:
dependency: "direct main" dependency: "direct main"
description: description:
@ -709,10 +722,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "14.2.4"
watcher: watcher:
dependency: "direct overridden" dependency: "direct overridden"
description: description:
@ -721,30 +734,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
url: "https://pub.dev"
source: hosted
version: "0.1.6"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.0" version: "3.0.1"
win32:
dependency: transitive
description:
name: win32
sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
url: "https://pub.dev"
source: hosted
version: "5.0.9"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.1.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
@ -754,5 +775,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.2.0-0 <4.0.0" dart: ">=3.5.0 <4.0.0"
flutter: ">=3.10.0" flutter: ">=3.24.0"

View file

@ -17,7 +17,7 @@ dependencies:
path_provider: ^2.0.11 path_provider: ^2.0.11
mobx: ^2.0.7+4 mobx: ^2.0.7+4
flutter_mobx: ^2.0.6+1 flutter_mobx: ^2.0.6+1
intl: ^0.18.0 intl: ^0.19.0
encrypt: ^5.0.1 encrypt: ^5.0.1
cake_backup: cake_backup:
git: git:

View file

@ -36,7 +36,18 @@ abstract class EVMChainClient {
bool connect(Node node) { bool connect(Node node) {
try { try {
_client = Web3Client(node.uri.toString(), httpClient); Uri? rpcUri;
bool isModifiedNodeUri = false;
if (node.uriRaw == 'eth.nownodes.io' || node.uriRaw == 'matic.nownodes.io') {
isModifiedNodeUri = true;
String nowNodeApiKey = secrets.nowNodesApiKey;
rpcUri = Uri.https(node.uriRaw, '/$nowNodeApiKey');
}
_client =
Web3Client(isModifiedNodeUri ? rpcUri!.toString() : node.uri.toString(), httpClient);
return true; return true;
} catch (e) { } catch (e) {
@ -83,23 +94,20 @@ abstract class EVMChainClient {
} }
} }
Future<int> getEstimatedGas({ Future<int> getEstimatedGasUnitsForTransaction({
String? contractAddress,
required EthereumAddress toAddress, required EthereumAddress toAddress,
required EthereumAddress senderAddress, required EthereumAddress senderAddress,
required EtherAmount value, required EtherAmount value,
String? contractAddress,
EtherAmount? gasPrice, EtherAmount? gasPrice,
// EtherAmount? maxFeePerGas, EtherAmount? maxFeePerGas,
// EtherAmount? maxPriorityFeePerGas,
}) async { }) async {
try { try {
if (contractAddress == null) { if (contractAddress == null) {
final estimatedGas = await _client!.estimateGas( final estimatedGas = await _client!.estimateGas(
sender: senderAddress, sender: senderAddress,
gasPrice: gasPrice,
to: toAddress, to: toAddress,
value: value, value: value,
// maxPriorityFeePerGas: maxPriorityFeePerGas,
// maxFeePerGas: maxFeePerGas, // maxFeePerGas: maxFeePerGas,
); );
@ -133,7 +141,9 @@ abstract class EVMChainClient {
required Credentials privateKey, required Credentials privateKey,
required String toAddress, required String toAddress,
required BigInt amount, required BigInt amount,
required BigInt gas, required BigInt gasFee,
required int estimatedGasUnits,
required int maxFeePerGas,
required EVMChainTransactionPriority priority, required EVMChainTransactionPriority priority,
required CryptoCurrency currency, required CryptoCurrency currency,
required int exponent, required int exponent,
@ -152,6 +162,8 @@ abstract class EVMChainClient {
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip), maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
amount: isNativeToken ? EtherAmount.inWei(amount) : EtherAmount.zero(), amount: isNativeToken ? EtherAmount.inWei(amount) : EtherAmount.zero(),
data: data != null ? hexToBytes(data) : null, data: data != null ? hexToBytes(data) : null,
maxGas: estimatedGasUnits,
maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
); );
Uint8List signedTransaction; Uint8List signedTransaction;
@ -180,7 +192,7 @@ abstract class EVMChainClient {
return PendingEVMChainTransaction( return PendingEVMChainTransaction(
signedTransaction: signedTransaction, signedTransaction: signedTransaction,
amount: amount.toString(), amount: amount.toString(),
fee: gas, fee: gasFee,
sendTransaction: _sendTransaction, sendTransaction: _sendTransaction,
exponent: exponent, exponent: exponent,
); );
@ -191,7 +203,10 @@ abstract class EVMChainClient {
required EthereumAddress to, required EthereumAddress to,
required EtherAmount amount, required EtherAmount amount,
EtherAmount? maxPriorityFeePerGas, EtherAmount? maxPriorityFeePerGas,
EtherAmount? gasPrice,
EtherAmount? maxFeePerGas,
Uint8List? data, Uint8List? data,
int? maxGas,
}) { }) {
return Transaction( return Transaction(
from: from, from: from,
@ -199,6 +214,9 @@ abstract class EVMChainClient {
maxPriorityFeePerGas: maxPriorityFeePerGas, maxPriorityFeePerGas: maxPriorityFeePerGas,
value: amount, value: amount,
data: data, data: data,
maxGas: maxGas,
gasPrice: gasPrice,
maxFeePerGas: maxFeePerGas,
); );
} }

View file

@ -34,7 +34,10 @@ abstract class EVMChainTransactionHistoryBase
//! Common methods across all child classes //! Common methods across all child classes
Future<void> init() async => await _load(); Future<void> init() async {
clear();
await _load();
}
@override @override
Future<void> save() async { Future<void> save() async {

View file

@ -14,6 +14,7 @@ import 'package:cw_core/pathForWallet.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/sync_status.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
@ -200,7 +201,7 @@ abstract class EVMChainWalletBase
} else { } else {
// MaxFeePerGas with gasPrice; // MaxFeePerGas with gasPrice;
maxFeePerGas = gasPrice; maxFeePerGas = gasPrice;
debugPrint('MaxFeePerGas with gasPrice: $maxFeePerGas'); printV('MaxFeePerGas with gasPrice: $maxFeePerGas');
} }
final totalGasFee = estimatedGasUnits * maxFeePerGas; final totalGasFee = estimatedGasUnits * maxFeePerGas;
@ -220,7 +221,7 @@ abstract class EVMChainWalletBase
/// - The exact amount the user wants to send, /// - The exact amount the user wants to send,
/// - The addressHex for the receiving wallet, /// - The addressHex for the receiving wallet,
/// - A contract address which would be essential in determining if to calcualate the estimate for ERC20 or native ETH /// - A contract address which would be essential in determining if to calcualate the estimate for ERC20 or native ETH
Future<int> calculateActualEstimatedFeeForCreateTransaction({ Future<GasParamsHandler> calculateActualEstimatedFeeForCreateTransaction({
required amount, required amount,
required String? contractAddress, required String? contractAddress,
required String receivingAddressHex, required String receivingAddressHex,
@ -239,22 +240,27 @@ abstract class EVMChainWalletBase
maxFeePerGas = gasPrice; maxFeePerGas = gasPrice;
} }
final estimatedGas = await _client.getEstimatedGas( final estimatedGas = await _client.getEstimatedGasUnitsForTransaction(
contractAddress: contractAddress, contractAddress: contractAddress,
senderAddress: _evmChainPrivateKey.address, senderAddress: _evmChainPrivateKey.address,
value: EtherAmount.fromBigInt(EtherUnit.wei, amount!), value: EtherAmount.fromBigInt(EtherUnit.wei, amount!),
gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice), gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice),
toAddress: EthereumAddress.fromHex(receivingAddressHex), toAddress: EthereumAddress.fromHex(receivingAddressHex),
// maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas), maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
// maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
); );
final totalGasFee = estimatedGas * maxFeePerGas; final totalGasFee = estimatedGas * maxFeePerGas;
return totalGasFee;
return GasParamsHandler(
estimatedGasUnits: estimatedGas,
estimatedGasFee: totalGasFee,
maxFeePerGas: maxFeePerGas,
gasPrice: gasPrice,
);
} }
return 0; return GasParamsHandler.zero();
} catch (e) { } catch (e) {
return 0; return GasParamsHandler.zero();
} }
} }
@ -264,7 +270,7 @@ abstract class EVMChainWalletBase
} }
@override @override
Future<void> close({required bool shouldCleanup}) async { Future<void> close({bool shouldCleanup = false}) async {
_client.stop(); _client.stop();
_transactionsUpdateTimer?.cancel(); _transactionsUpdateTimer?.cancel();
_updateFeesTimer?.cancel(); _updateFeesTimer?.cancel();
@ -317,7 +323,7 @@ abstract class EVMChainWalletBase
gasPrice = await _client.getGasUnitPrice(); gasPrice = await _client.getGasUnitPrice();
estimatedGasUnits = await _client.getEstimatedGas( estimatedGasUnits = await _client.getEstimatedGasUnitsForTransaction(
senderAddress: _evmChainPrivateKey.address, senderAddress: _evmChainPrivateKey.address,
toAddress: _evmChainPrivateKey.address, toAddress: _evmChainPrivateKey.address,
gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice), gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice),
@ -348,6 +354,8 @@ abstract class EVMChainWalletBase
int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18; int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
num amountToEVMChainMultiplier = pow(10, exponent); num amountToEVMChainMultiplier = pow(10, exponent);
String? contractAddress; String? contractAddress;
int estimatedGasUnitsForTransaction = 0;
int maxFeePerGasForTransaction = 0;
String toAddress = _credentials.outputs.first.isParsedAddress String toAddress = _credentials.outputs.first.isParsedAddress
? _credentials.outputs.first.extractedAddress! ? _credentials.outputs.first.extractedAddress!
: _credentials.outputs.first.address; : _credentials.outputs.first.address;
@ -366,14 +374,16 @@ abstract class EVMChainWalletBase
outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0))); outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
totalAmount = BigInt.from(totalOriginalAmount * amountToEVMChainMultiplier); totalAmount = BigInt.from(totalOriginalAmount * amountToEVMChainMultiplier);
final estimateFees = await calculateActualEstimatedFeeForCreateTransaction( final gasFeesModel = await calculateActualEstimatedFeeForCreateTransaction(
amount: totalAmount, amount: totalAmount,
receivingAddressHex: toAddress, receivingAddressHex: toAddress,
priority: _credentials.priority!, priority: _credentials.priority!,
contractAddress: contractAddress, contractAddress: contractAddress,
); );
estimatedFeesForTransaction = BigInt.from(estimateFees); estimatedFeesForTransaction = BigInt.from(gasFeesModel.estimatedGasFee);
estimatedGasUnitsForTransaction = gasFeesModel.estimatedGasUnits;
maxFeePerGasForTransaction = gasFeesModel.maxFeePerGas;
if (erc20Balance.balance < totalAmount) { if (erc20Balance.balance < totalAmount) {
throw EVMChainTransactionCreationException(transactionCurrency); throw EVMChainTransactionCreationException(transactionCurrency);
@ -391,14 +401,16 @@ abstract class EVMChainWalletBase
totalAmount = erc20Balance.balance; totalAmount = erc20Balance.balance;
} }
final estimateFees = await calculateActualEstimatedFeeForCreateTransaction( final gasFeesModel = await calculateActualEstimatedFeeForCreateTransaction(
amount: totalAmount, amount: totalAmount,
receivingAddressHex: toAddress, receivingAddressHex: toAddress,
priority: _credentials.priority!, priority: _credentials.priority!,
contractAddress: contractAddress, contractAddress: contractAddress,
); );
estimatedFeesForTransaction = BigInt.from(estimateFees); estimatedFeesForTransaction = BigInt.from(gasFeesModel.estimatedGasFee);
estimatedGasUnitsForTransaction = gasFeesModel.estimatedGasUnits;
maxFeePerGasForTransaction = gasFeesModel.maxFeePerGas;
if (output.sendAll && transactionCurrency is! Erc20Token) { if (output.sendAll && transactionCurrency is! Erc20Token) {
totalAmount = (erc20Balance.balance - estimatedFeesForTransaction); totalAmount = (erc20Balance.balance - estimatedFeesForTransaction);
@ -419,12 +431,14 @@ abstract class EVMChainWalletBase
} }
final pendingEVMChainTransaction = await _client.signTransaction( final pendingEVMChainTransaction = await _client.signTransaction(
estimatedGasUnits: estimatedGasUnitsForTransaction,
privateKey: _evmChainPrivateKey, privateKey: _evmChainPrivateKey,
toAddress: toAddress, toAddress: toAddress,
amount: totalAmount, amount: totalAmount,
gas: estimatedFeesForTransaction, gasFee: estimatedFeesForTransaction,
priority: _credentials.priority!, priority: _credentials.priority!,
currency: transactionCurrency, currency: transactionCurrency,
maxFeePerGas: maxFeePerGasForTransaction,
exponent: exponent, exponent: exponent,
contractAddress: contractAddress:
transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null, transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null,
@ -727,3 +741,25 @@ abstract class EVMChainWalletBase
@override @override
final String? passphrase; final String? passphrase;
} }
class GasParamsHandler {
final int estimatedGasUnits;
final int estimatedGasFee;
final int maxFeePerGas;
final int gasPrice;
GasParamsHandler(
{required this.estimatedGasUnits,
required this.estimatedGasFee,
required this.maxFeePerGas,
required this.gasPrice});
static GasParamsHandler zero() {
return GasParamsHandler(
estimatedGasUnits: 0,
estimatedGasFee: 0,
maxFeePerGas: 0,
gasPrice: 0,
);
}
}

View file

@ -3,6 +3,7 @@ import 'dart:typed_data';
import 'package:cw_core/hardware/device_not_connected_exception.dart' import 'package:cw_core/hardware/device_not_connected_exception.dart'
as exception; as exception;
import 'package:cw_core/utils/print_verbose.dart';
import 'package:ledger_ethereum/ledger_ethereum.dart'; import 'package:ledger_ethereum/ledger_ethereum.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:web3dart/crypto.dart'; import 'package:web3dart/crypto.dart';
@ -96,7 +97,7 @@ class EvmLedgerCredentials extends CredentialsWithKnownAddress {
await ethereumLedgerApp!.getAndProvideERC20TokenInformation( await ethereumLedgerApp!.getAndProvideERC20TokenInformation(
erc20ContractAddress: erc20ContractAddress, chainId: chainId); erc20ContractAddress: erc20ContractAddress, chainId: chainId);
} catch (e) { } catch (e) {
print(e); printV(e);
rethrow; rethrow;
// if (e.errorCode != -28672) rethrow; // if (e.errorCode != -28672) rethrow;
} }

View file

@ -2,14 +2,14 @@ group 'com.cakewallet.cw_haven'
version '1.0-SNAPSHOT' version '1.0-SNAPSHOT'
buildscript { buildscript {
ext.kotlin_version = '1.7.10' ext.kotlin_version = '2.0.21'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.3.0' classpath 'com.android.tools.build:gradle:8.7.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
@ -25,8 +25,20 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 28 compileSdkVersion 33
if (project.android.hasProperty("namespace")) {
namespace 'com.cakewallet.cw_haven'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
} }

View file

@ -1,3 +1,4 @@
import 'package:cw_core/utils/print_verbose.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_core/account.dart'; import 'package:cw_core/account.dart';
import 'package:cw_core/account_list.dart'; import 'package:cw_core/account_list.dart';
@ -77,7 +78,7 @@ abstract class HavenAccountListBase extends AccountList<Account> with Store {
_isRefreshing = false; _isRefreshing = false;
} catch (e) { } catch (e) {
_isRefreshing = false; _isRefreshing = false;
print(e); printV(e);
rethrow; rethrow;
} }
} }

View file

@ -1,3 +1,4 @@
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_haven/api/structs/subaddress_row.dart'; import 'package:cw_haven/api/structs/subaddress_row.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -79,7 +80,7 @@ abstract class HavenSubaddressListBase with Store {
_isRefreshing = false; _isRefreshing = false;
} on PlatformException catch (e) { } on PlatformException catch (e) {
_isRefreshing = false; _isRefreshing = false;
print(e); printV(e);
rethrow; rethrow;
} }
} }

View file

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_haven/haven_transaction_creation_credentials.dart'; import 'package:cw_haven/haven_transaction_creation_credentials.dart';
import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_haven/haven_transaction_creation_exception.dart'; import 'package:cw_haven/haven_transaction_creation_exception.dart';
@ -107,7 +108,7 @@ abstract class HavenWalletBase
Future<void>? updateBalance() => null; Future<void>? updateBalance() => null;
@override @override
Future<void> close({required bool shouldCleanup}) async { Future<void> close({bool shouldCleanup = false}) async {
_listener?.stop(); _listener?.stop();
_onAccountChangeReaction?.reaction.dispose(); _onAccountChangeReaction?.reaction.dispose();
_autoSaveTimer?.cancel(); _autoSaveTimer?.cancel();
@ -130,7 +131,7 @@ abstract class HavenWalletBase
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();
} catch (e) { } catch (e) {
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
print(e); printV(e);
} }
} }
@ -147,7 +148,7 @@ abstract class HavenWalletBase
_listener?.start(); _listener?.start();
} catch (e) { } catch (e) {
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
print(e); printV(e);
rethrow; rethrow;
} }
} }
@ -324,7 +325,7 @@ abstract class HavenWalletBase
await transactionHistory.save(); await transactionHistory.save();
_isTransactionUpdating = false; _isTransactionUpdating = false;
} catch (e) { } catch (e) {
print(e); printV(e);
_isTransactionUpdating = false; _isTransactionUpdating = false;
} }
} }
@ -403,7 +404,7 @@ abstract class HavenWalletBase
syncStatus = SyncingSyncStatus(blocksLeft, ptc); syncStatus = SyncingSyncStatus(blocksLeft, ptc);
} }
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }
@ -413,7 +414,7 @@ abstract class HavenWalletBase
_askForUpdateBalance(); _askForUpdateBalance();
await Future<void>.delayed(Duration(seconds: 1)); await Future<void>.delayed(Duration(seconds: 1));
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }

View file

@ -1,3 +1,4 @@
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_addresses_with_account.dart'; import 'package:cw_core/wallet_addresses_with_account.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/account.dart'; import 'package:cw_core/account.dart';
@ -60,7 +61,7 @@ abstract class HavenWalletAddressesBase extends WalletAddressesWithAccount<Accou
await saveAddressesInBox(); await saveAddressesInBox();
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }

View file

@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/monero_wallet_utils.dart'; import 'package:cw_core/monero_wallet_utils.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@ -81,7 +82,7 @@ class HavenWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('HavenWalletsManager Error: ${e.toString()}'); printV('HavenWalletsManager Error: ${e.toString()}');
rethrow; rethrow;
} }
} }
@ -93,7 +94,7 @@ class HavenWalletService extends WalletService<
return haven_wallet_manager.isWalletExist(path: path); return haven_wallet_manager.isWalletExist(path: path);
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('HavenWalletsManager Error: $e'); printV('HavenWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
@ -197,7 +198,7 @@ class HavenWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('HavenWalletsManager Error: $e'); printV('HavenWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
@ -218,7 +219,7 @@ class HavenWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('HavenWalletsManager Error: $e'); printV('HavenWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
@ -252,7 +253,7 @@ class HavenWalletService extends WalletService<
newFile.writeAsBytesSync(file.readAsBytesSync()); newFile.writeAsBytesSync(file.readAsBytesSync());
}); });
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }
} }

View file

@ -21,18 +21,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.6.0"
asn1lib: asn1lib:
dependency: transitive dependency: transitive
description: description:
name: asn1lib name: asn1lib
sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039 sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.5.5"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -53,10 +53,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build name: build
sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.4.1"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
@ -69,10 +69,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "4.0.2"
build_resolvers: build_resolvers:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -85,18 +85,18 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.9" version: "2.4.13"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.2.7" version: "7.2.10"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
@ -109,10 +109,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: built_value name: built_value
sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725" sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.4.3" version: "8.9.2"
cake_backup: cake_backup:
dependency: transitive dependency: transitive
description: description:
@ -134,10 +134,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: checked_yaml name: checked_yaml
sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.2" version: "2.0.3"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -150,10 +150,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: code_builder name: code_builder
sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.4.0" version: "4.10.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
@ -166,34 +166,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.0.6"
cryptography: cryptography:
dependency: transitive dependency: transitive
description: description:
name: cryptography name: cryptography
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35 sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.7.0"
cupertino_icons: cupertino_icons:
dependency: transitive dependency: transitive
description: description:
name: cupertino_icons name: cupertino_icons
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.6" version: "1.0.8"
cw_core: cw_core:
dependency: "direct main" dependency: "direct main"
description: description:
@ -213,10 +213,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: encrypt name: encrypt
sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb" sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.1" version: "5.0.3"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -229,26 +229,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: ffi name: ffi
sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.1.3"
file: file:
dependency: transitive dependency: transitive
description: description:
name: file name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.0.1"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
name: fixnum name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -258,10 +258,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_mobx name: flutter_mobx
sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e" sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.6+5" version: "2.2.1+1"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -271,10 +271,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: frontend_server_client name: frontend_server_client
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "4.0.0"
glob: glob:
dependency: transitive dependency: transitive
description: description:
@ -287,10 +287,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: graphs name: graphs
sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.3.2"
hive: hive:
dependency: transitive dependency: transitive
description: description:
@ -311,10 +311,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.2.2"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -335,10 +335,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -359,42 +359,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: json_annotation name: json_annotation
sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.8.0" version: "4.9.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.0" version: "10.0.5"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.5"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.1"
logging: logging:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.3.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -407,42 +407,50 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.0" version: "0.11.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.15.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0"
mobx: mobx:
dependency: "direct main" dependency: "direct main"
description: description:
name: mobx name: mobx
sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.3+1" version: "2.3.3+2"
mobx_codegen: mobx_codegen:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: mobx_codegen name: mobx_codegen
sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181" sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.3.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
@ -463,26 +471,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.4"
path_provider_android: path_provider_android:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.2.12"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.4.0"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@ -495,42 +503,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.3.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.0" version: "3.1.6"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.3" version: "2.1.8"
pointycastle: pointycastle:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: pointycastle
sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.6.2" version: "3.9.1"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -539,38 +547,46 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.1" version: "1.5.1"
provider:
dependency: transitive
description:
name: provider
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
name: pub_semver name: pub_semver
sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.3" version: "2.1.4"
pubspec_parse: pubspec_parse:
dependency: transitive dependency: transitive
description: description:
name: pubspec_parse name: pubspec_parse
sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
name: shelf name: shelf
sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.1"
shelf_web_socket: shelf_web_socket:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.3" version: "2.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -580,10 +596,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: socks5_proxy name: socks5_proxy
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a" sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.6"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -652,10 +668,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.7.2"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -676,10 +692,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.4.0"
unorm_dart: unorm_dart:
dependency: transitive dependency: transitive
description: description:
@ -700,10 +716,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "14.2.4"
watcher: watcher:
dependency: "direct overridden" dependency: "direct overridden"
description: description:
@ -712,38 +728,46 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
url: "https://pub.dev"
source: hosted
version: "0.1.6"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "3.0.1"
win32:
dependency: transitive
description:
name: win32
sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
url: "https://pub.dev"
source: hosted
version: "3.1.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.1.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
name: yaml name: yaml
sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.2"
sdks: sdks:
dart: ">=3.2.0-0 <4.0.0" dart: ">=3.5.0 <4.0.0"
flutter: ">=3.7.0" flutter: ">=3.24.0"

View file

@ -17,7 +17,7 @@ dependencies:
path_provider: ^2.0.11 path_provider: ^2.0.11
mobx: ^2.0.7+4 mobx: ^2.0.7+4
flutter_mobx: ^2.0.6+1 flutter_mobx: ^2.0.6+1
intl: ^0.18.0 intl: ^0.19.0
cw_core: cw_core:
path: ../cw_core path: ../cw_core

View file

@ -12,6 +12,18 @@ int countOfCoins() => monero.Coins_count(coins!);
monero.CoinsInfo getCoin(int index) => monero.Coins_coin(coins!, index); monero.CoinsInfo getCoin(int index) => monero.Coins_coin(coins!, index);
int? getCoinByKeyImage(String keyImage) {
final count = countOfCoins();
for (int i = 0; i < count; i++) {
final coin = getCoin(i);
final coinAddress = monero.CoinsInfo_keyImage(coin);
if (keyImage == coinAddress) {
return i;
}
}
return null;
}
void freezeCoin(int index) => monero.Coins_setFrozen(coins!, index: index); void freezeCoin(int index) => monero.Coins_setFrozen(coins!, index: index);
void thawCoin(int index) => monero.Coins_thaw(coins!, index: index); void thawCoin(int index) => monero.Coins_thaw(coins!, index: index);

View file

@ -6,6 +6,7 @@ import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
import 'package:cw_monero/api/monero_output.dart'; import 'package:cw_monero/api/monero_output.dart';
import 'package:cw_monero/api/structs/pending_transaction.dart'; import 'package:cw_monero/api/structs/pending_transaction.dart';
import 'package:cw_monero/api/wallet.dart'; import 'package:cw_monero/api/wallet.dart';
import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
import 'package:monero/src/generated_bindings_monero.g.dart' as monero_gen; import 'package:monero/src/generated_bindings_monero.g.dart' as monero_gen;
@ -17,7 +18,7 @@ String getTxKey(String txId) {
final status = monero.Wallet_status(wptr!); final status = monero.Wallet_status(wptr!);
if (status != 0) { if (status != 0) {
final error = monero.Wallet_errorString(wptr!); final error = monero.Wallet_errorString(wptr!);
return txId+"_"+error; return "";
} }
return txKey; return txKey;
} }
@ -91,12 +92,23 @@ Future<PendingTransactionDescription> createTransactionSync(
List<String> preferredInputs = const []}) async { List<String> preferredInputs = const []}) async {
final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount); final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount);
final address_ = address.toNativeUtf8();
final paymentId_ = paymentId.toNativeUtf8();
final preferredInputs_ = preferredInputs.join(monero.defaultSeparatorStr).toNativeUtf8();
final waddr = wptr!.address; final waddr = wptr!.address;
// force reconnection in case the os killed the connection?
// fixes failed to get block height error.
Isolate.run(() async {
monero.Wallet_synchronized(Pointer.fromAddress(waddr));
});
final address_ = address.toNativeUtf8();
final paymentId_ = paymentId.toNativeUtf8();
if (preferredInputs.isEmpty) {
throw MoneroTransactionCreationException("No inputs provided, transaction cannot be constructed");
}
final preferredInputs_ = preferredInputs.join(monero.defaultSeparatorStr).toNativeUtf8();
final addraddr = address_.address; final addraddr = address_.address;
final paymentIdAddr = paymentId_.address; final paymentIdAddr = paymentId_.address;
final preferredInputsAddr = preferredInputs_.address; final preferredInputsAddr = preferredInputs_.address;
@ -159,8 +171,8 @@ PendingTransactionDescription createTransactionMultDestSync(
final dstAddrs = outputs.map((e) => e.address).toList(); final dstAddrs = outputs.map((e) => e.address).toList();
final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList(); final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList();
// print("multDest: dstAddrs: $dstAddrs"); // printV("multDest: dstAddrs: $dstAddrs");
// print("multDest: amounts: $amounts"); // printV("multDest: amounts: $amounts");
final txptr = monero.Wallet_createTransactionMultDest( final txptr = monero.Wallet_createTransactionMultDest(
wptr!, wptr!,
@ -188,19 +200,35 @@ String? commitTransactionFromPointerAddress({required int address, required bool
commitTransaction(transactionPointer: monero.PendingTransaction.fromAddress(address), useUR: useUR); commitTransaction(transactionPointer: monero.PendingTransaction.fromAddress(address), useUR: useUR);
String? commitTransaction({required monero.PendingTransaction transactionPointer, required bool useUR}) { String? commitTransaction({required monero.PendingTransaction transactionPointer, required bool useUR}) {
final transactionPointerAddress = transactionPointer.address;
final txCommit = useUR final txCommit = useUR
? monero.PendingTransaction_commitUR(transactionPointer, 120) ? monero.PendingTransaction_commitUR(transactionPointer, 120)
: monero.PendingTransaction_commit(transactionPointer, filename: '', overwrite: false); : Isolate.run(() {
monero.PendingTransaction_commit(
Pointer.fromAddress(transactionPointerAddress),
filename: '',
overwrite: false,
);
});
final String? error = (() { String? error = (() {
final status = monero.PendingTransaction_status(transactionPointer.cast()); final status = monero.PendingTransaction_status(transactionPointer.cast());
if (status == 0) { if (status == 0) {
return null; return null;
} }
return monero.Wallet_errorString(wptr!); return monero.PendingTransaction_errorString(transactionPointer.cast());
})(); })();
if (error == null) {
error = (() {
final status = monero.Wallet_status(wptr!);
if (status == 0) {
return null;
}
return monero.Wallet_errorString(wptr!);
})();
if (error != null) { }
if (error != null && error != "no tx keys found for this txid") {
throw CreationTransactionException(message: error); throw CreationTransactionException(message: error);
} }
if (useUR) { if (useUR) {
@ -348,16 +376,7 @@ class Transaction {
confirmations = monero.TransactionInfo_confirmations(txInfo), confirmations = monero.TransactionInfo_confirmations(txInfo),
fee = monero.TransactionInfo_fee(txInfo), fee = monero.TransactionInfo_fee(txInfo),
description = monero.TransactionInfo_description(txInfo), description = monero.TransactionInfo_description(txInfo),
key = getTxKey(txInfo); key = getTxKey(monero.TransactionInfo_hash(txInfo));
static String getTxKey(monero.TransactionInfo txInfo) {
final txKey = monero.Wallet_getTxKey(wptr!, txid: monero.TransactionInfo_hash(txInfo));
final status = monero.Wallet_status(wptr!);
if (status != 0) {
return "";
}
return txKey;
}
Transaction.dummy({ Transaction.dummy({
required this.displayLabel, required this.displayLabel,

View file

@ -2,15 +2,17 @@ import 'dart:async';
import 'dart:ffi'; import 'dart:ffi';
import 'dart:isolate'; import 'dart:isolate';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart'; import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
import 'package:flutter/foundation.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
int getSyncingHeight() { int getSyncingHeight() {
// final height = monero.MONERO_cw_WalletListener_height(getWlptr()); // final height = monero.MONERO_cw_WalletListener_height(getWlptr());
final h2 = monero.Wallet_blockChainHeight(wptr!); final h2 = monero.Wallet_blockChainHeight(wptr!);
// print("height: $height / $h2"); // printV("height: $height / $h2");
return h2; return h2;
} }
@ -69,9 +71,9 @@ String getSeedLegacy(String? language) {
Map<int, Map<int, Map<int, String>>> addressCache = {}; Map<int, Map<int, Map<int, String>>> addressCache = {};
String getAddress({int accountIndex = 0, int addressIndex = 0}) { String getAddress({int accountIndex = 0, int addressIndex = 0}) {
// print("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}"); // printV("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}");
while (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) { while (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) {
print("adding subaddress"); printV("adding subaddress");
monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex); monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex);
} }
addressCache[wptr!.address] ??= {}; addressCache[wptr!.address] ??= {};
@ -100,7 +102,7 @@ Future<bool> setupNodeSync(
bool useSSL = false, bool useSSL = false,
bool isLightWallet = false, bool isLightWallet = false,
String? socksProxyAddress}) async { String? socksProxyAddress}) async {
print(''' printV('''
{ {
wptr!, wptr!,
daemonAddress: $address, daemonAddress: $address,
@ -119,16 +121,24 @@ Future<bool> setupNodeSync(
daemonUsername: login ?? '', daemonUsername: login ?? '',
daemonPassword: password ?? ''); daemonPassword: password ?? '');
}); });
// monero.Wallet_init3(wptr!, argv0: '', defaultLogBaseName: 'moneroc', console: true, logPath: '');
final status = monero.Wallet_status(wptr!); final status = monero.Wallet_status(wptr!);
if (status != 0) { if (status != 0) {
final error = monero.Wallet_errorString(wptr!); final error = monero.Wallet_errorString(wptr!);
print("error: $error"); printV("error: $error");
throw SetupWalletException(message: error); throw SetupWalletException(message: error);
} }
if (kDebugMode) {
monero.Wallet_init3(
wptr!, argv0: '',
defaultLogBaseName: 'moneroc',
console: true,
logPath: '',
);
}
return status == 0; return status == 0;
} }
@ -150,14 +160,15 @@ final storeMutex = Mutex();
int lastStorePointer = 0; int lastStorePointer = 0;
int lastStoreHeight = 0; int lastStoreHeight = 0;
void storeSync() async { void storeSync({bool force = false}) async {
final addr = wptr!.address; final addr = wptr!.address;
final synchronized = await Isolate.run(() { final synchronized = await Isolate.run(() {
return monero.Wallet_synchronized(Pointer.fromAddress(addr)); return monero.Wallet_synchronized(Pointer.fromAddress(addr));
}); });
if (lastStorePointer == wptr!.address && if (lastStorePointer == wptr!.address &&
lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) && lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) &&
!synchronized) { !synchronized &&
!force) {
return; return;
} }
lastStorePointer = wptr!.address; lastStorePointer = wptr!.address;

View file

@ -2,6 +2,7 @@ import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart'; import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart';
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart'; import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
@ -50,9 +51,9 @@ final monero.WalletManager wmPtr = Pointer.fromAddress((() {
// than plugging gdb in. Especially on windows/android. // than plugging gdb in. Especially on windows/android.
monero.printStarts = false; monero.printStarts = false;
_wmPtr ??= monero.WalletManagerFactory_getWalletManager(); _wmPtr ??= monero.WalletManagerFactory_getWalletManager();
print("ptr: $_wmPtr"); printV("ptr: $_wmPtr");
} catch (e) { } catch (e) {
print(e); printV(e);
rethrow; rethrow;
} }
return _wmPtr!.address; return _wmPtr!.address;
@ -81,6 +82,7 @@ void createWalletSync(
wptr = newWptr; wptr = newWptr;
monero.Wallet_store(wptr!, path: path); monero.Wallet_store(wptr!, path: path);
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
// is the line below needed? // is the line below needed?
// setupNodeSync(address: "node.moneroworld.com:18089"); // setupNodeSync(address: "node.moneroworld.com:18089");
@ -116,6 +118,7 @@ void restoreWalletFromSeedSync(
wptr = newWptr; wptr = newWptr;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
} }
void restoreWalletFromKeysSync( void restoreWalletFromKeysSync(
@ -183,6 +186,7 @@ void restoreWalletFromKeysSync(
wptr = newWptr; wptr = newWptr;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
} }
void restoreWalletFromSpendKeySync( void restoreWalletFromSpendKeySync(
@ -220,7 +224,7 @@ void restoreWalletFromSpendKeySync(
if (status != 0) { if (status != 0) {
final err = monero.Wallet_errorString(newWptr); final err = monero.Wallet_errorString(newWptr);
print("err: $err"); printV("err: $err");
throw WalletRestoreFromKeysException(message: err); throw WalletRestoreFromKeysException(message: err);
} }
@ -231,6 +235,7 @@ void restoreWalletFromSpendKeySync(
storeSync(); storeSync();
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
} }
String _lastOpenedWallet = ""; String _lastOpenedWallet = "";
@ -260,7 +265,7 @@ Future<void> restoreWalletFromHardwareWallet(
throw WalletRestoreFromSeedException(message: error); throw WalletRestoreFromSeedException(message: error);
} }
wptr = newWptr; wptr = newWptr;
_lastOpenedWallet = path;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
} }
@ -286,8 +291,23 @@ Future<void> loadWallet(
/// 0: Software Wallet /// 0: Software Wallet
/// 1: Ledger /// 1: Ledger
/// 2: Trezor /// 2: Trezor
final deviceType = monero.WalletManager_queryWalletDevice(wmPtr, late final deviceType;
keysFileName: "$path.keys", password: password, kdfRounds: 1);
if (Platform.isAndroid || Platform.isIOS) {
deviceType = monero.WalletManager_queryWalletDevice(
wmPtr,
keysFileName: "$path.keys",
password: password,
kdfRounds: 1,
);
final status = monero.WalletManager_errorString(wmPtr);
if (status != "") {
printV("loadWallet:"+status);
throw WalletOpeningException(message: status);
}
} else {
deviceType = 0;
}
if (deviceType == 1) { if (deviceType == 1) {
final dummyWPtr = wptr ?? final dummyWPtr = wptr ??
@ -304,15 +324,15 @@ Future<void> loadWallet(
final newWptr = Pointer<Void>.fromAddress(newWptrAddr); final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
_lastOpenedWallet = path;
final status = monero.Wallet_status(newWptr); final status = monero.Wallet_status(newWptr);
if (status != 0) { if (status != 0) {
final err = monero.Wallet_errorString(newWptr); final err = monero.Wallet_errorString(newWptr);
print(err); printV("loadWallet:"+err);
throw WalletOpeningException(message: err); throw WalletOpeningException(message: err);
} }
wptr = newWptr; wptr = newWptr;
_lastOpenedWallet = path;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
} }
} }

View file

@ -2,11 +2,12 @@ import 'dart:async';
import 'dart:ffi'; import 'dart:ffi';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus_dart.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus_dart.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
// import 'package:polyseed/polyseed.dart';
LedgerConnection? gLedger; LedgerConnection? gLedger;
@ -28,9 +29,16 @@ void enableLedgerExchange(monero.wallet ptr, LedgerConnection connection) {
ptr, emptyPointer.cast<UnsignedChar>(), 0); ptr, emptyPointer.cast<UnsignedChar>(), 0);
malloc.free(emptyPointer); malloc.free(emptyPointer);
// print("> ${ledgerRequest.toHexString()}"); _logLedgerCommand(ledgerRequest, false);
final response = await exchange(connection, ledgerRequest); final response = await exchange(connection, ledgerRequest);
// print("< ${response.toHexString()}"); _logLedgerCommand(response, true);
if (ListEquality().equals(response, [0x55, 0x15])) {
await connection.disconnect();
// // TODO: Show POPUP pls unlock your device
// await Future.delayed(Duration(seconds: 15));
// response = await exchange(connection, ledgerRequest);
}
final Pointer<Uint8> result = malloc<Uint8>(response.length); final Pointer<Uint8> result = malloc<Uint8>(response.length);
for (var i = 0; i < response.length; i++) { for (var i = 0; i < response.length; i++) {
@ -82,3 +90,59 @@ class ExchangeOperation extends LedgerRawOperation<Uint8List> {
@override @override
Future<List<Uint8List>> write(ByteDataWriter writer) async => [inputData]; Future<List<Uint8List>> write(ByteDataWriter writer) async => [inputData];
} }
const _ledgerMoneroCommands = {
0x00: "INS_NONE",
0x02: "INS_RESET",
0x20: "INS_GET_KEY",
0x21: "INS_DISPLAY_ADDRESS",
0x22: "INS_PUT_KEY",
0x24: "INS_GET_CHACHA8_PREKEY",
0x26: "INS_VERIFY_KEY",
0x28: "INS_MANAGE_SEEDWORDS",
0x30: "INS_SECRET_KEY_TO_PUBLIC_KEY",
0x32: "INS_GEN_KEY_DERIVATION",
0x34: "INS_DERIVATION_TO_SCALAR",
0x36: "INS_DERIVE_PUBLIC_KEY",
0x38: "INS_DERIVE_SECRET_KEY",
0x3A: "INS_GEN_KEY_IMAGE",
0x3B: "INS_DERIVE_VIEW_TAG",
0x3C: "INS_SECRET_KEY_ADD",
0x3E: "INS_SECRET_KEY_SUB",
0x40: "INS_GENERATE_KEYPAIR",
0x42: "INS_SECRET_SCAL_MUL_KEY",
0x44: "INS_SECRET_SCAL_MUL_BASE",
0x46: "INS_DERIVE_SUBADDRESS_PUBLIC_KEY",
0x48: "INS_GET_SUBADDRESS",
0x4A: "INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY",
0x4C: "INS_GET_SUBADDRESS_SECRET_KEY",
0x70: "INS_OPEN_TX",
0x72: "INS_SET_SIGNATURE_MODE",
0x74: "INS_GET_ADDITIONAL_KEY",
0x76: "INS_STEALTH",
0x77: "INS_GEN_COMMITMENT_MASK",
0x78: "INS_BLIND",
0x7A: "INS_UNBLIND",
0x7B: "INS_GEN_TXOUT_KEYS",
0x7D: "INS_PREFIX_HASH",
0x7C: "INS_VALIDATE",
0x7E: "INS_MLSAG",
0x7F: "INS_CLSAG",
0x80: "INS_CLOSE_TX",
0xA0: "INS_GET_TX_PROOF",
0xC0: "INS_GET_RESPONSE"
};
void _logLedgerCommand(Uint8List command, [bool isResponse = true]) {
String toHexString(Uint8List data) =>
data.map((e) => e.toRadixString(16).padLeft(2, '0')).join();
if (isResponse) {
printV("< ${toHexString(command)}");
} else {
printV(
"> ${_ledgerMoneroCommands[command[1]]} ${toHexString(command.sublist(2))}");
}
}

View file

@ -1,4 +1,5 @@
import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_core/account.dart'; import 'package:cw_core/account.dart';
import 'package:cw_monero/api/account_list.dart' as account_list; import 'package:cw_monero/api/account_list.dart' as account_list;
@ -74,7 +75,7 @@ abstract class MoneroAccountListBase with Store {
_isRefreshing = false; _isRefreshing = false;
} catch (e) { } catch (e) {
_isRefreshing = false; _isRefreshing = false;
print(e); printV(e);
rethrow; rethrow;
} }
} }

View file

@ -1,4 +1,5 @@
import 'package:cw_core/subaddress.dart'; import 'package:cw_core/subaddress.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/coins_info.dart'; import 'package:cw_monero/api/coins_info.dart';
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list; import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
import 'package:cw_monero/api/wallet.dart'; import 'package:cw_monero/api/wallet.dart';
@ -87,7 +88,7 @@ abstract class MoneroSubaddressListBase with Store {
_isRefreshing = false; _isRefreshing = false;
} on PlatformException catch (e) { } on PlatformException catch (e) {
_isRefreshing = false; _isRefreshing = false;
print(e); printV(e);
rethrow; rethrow;
} }
} }

View file

@ -1,10 +1,33 @@
import 'package:cw_core/unspent_transaction_output.dart'; import 'package:cw_core/unspent_transaction_output.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/coins_info.dart';
import 'package:monero/monero.dart' as monero;
class MoneroUnspent extends Unspent { class MoneroUnspent extends Unspent {
MoneroUnspent( MoneroUnspent(
String address, String hash, String keyImage, int value, bool isFrozen, this.isUnlocked) String address, String hash, String keyImage, int value, bool isFrozen, this.isUnlocked)
: super(address, hash, value, 0, keyImage) { : super(address, hash, value, 0, keyImage) {
this.isFrozen = isFrozen; }
@override
set isFrozen(bool freeze) {
printV("set isFrozen: $freeze ($keyImage): $freeze");
final coinId = getCoinByKeyImage(keyImage!);
if (coinId == null) throw Exception("Unable to find a coin for address $address");
if (freeze) {
freezeCoin(coinId);
} else {
thawCoin(coinId);
}
}
@override
bool get isFrozen {
printV("get isFrozen");
final coinId = getCoinByKeyImage(keyImage!);
if (coinId == null) throw Exception("Unable to find a coin for address $address");
final coin = getCoin(coinId);
return monero.CoinsInfo_frozen(coin);
} }
final bool isUnlocked; final bool isUnlocked;

View file

@ -17,6 +17,7 @@ import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_direction.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/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
@ -167,7 +168,7 @@ abstract class MoneroWalletBase
Future<void>? updateBalance() => null; Future<void>? updateBalance() => null;
@override @override
Future<void> close({required bool shouldCleanup}) async { Future<void> close({bool shouldCleanup = false}) async {
_listener?.stop(); _listener?.stop();
_onAccountChangeReaction?.reaction.dispose(); _onAccountChangeReaction?.reaction.dispose();
_onTxHistoryChangeReaction?.reaction.dispose(); _onTxHistoryChangeReaction?.reaction.dispose();
@ -191,7 +192,7 @@ abstract class MoneroWalletBase
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();
} catch (e) { } catch (e) {
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
print(e); printV(e);
} }
} }
@ -222,7 +223,7 @@ abstract class MoneroWalletBase
_listener?.start(); _listener?.start();
} catch (e) { } catch (e) {
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
print(e); printV(e);
rethrow; rethrow;
} }
} }
@ -306,9 +307,8 @@ abstract class MoneroWalletBase
throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.'); throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.');
} }
if (!spendAllCoins && (allInputsAmount < totalAmount + estimatedFee)) { if (inputs.isEmpty) MoneroTransactionCreationException(
throw MoneroTransactionNoInputsException(inputs.length); 'No inputs selected');
}
final moneroOutputs = outputs.map((output) { final moneroOutputs = outputs.map((output) {
final outputAddress = output.isParsedAddress ? output.extractedAddress : output.address; final outputAddress = output.isParsedAddress ? output.extractedAddress : output.address;
@ -328,29 +328,29 @@ abstract class MoneroWalletBase
final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
final formattedAmount = output.sendAll ? null : output.formattedCryptoAmount; final formattedAmount = output.sendAll ? null : output.formattedCryptoAmount;
if ((formattedAmount != null && unlockedBalance < formattedAmount) || // if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
(formattedAmount == null && unlockedBalance <= 0)) { // (formattedAmount == null && unlockedBalance <= 0)) {
final formattedBalance = moneroAmountToString(amount: unlockedBalance); // final formattedBalance = moneroAmountToString(amount: unlockedBalance);
//
// throw MoneroTransactionCreationException(
// 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
// }
throw MoneroTransactionCreationException( final estimatedFee =
'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); calculateEstimatedFee(_credentials.priority, formattedAmount);
} if (inputs.isEmpty) MoneroTransactionCreationException(
'No inputs selected');
final estimatedFee = calculateEstimatedFee(_credentials.priority, formattedAmount); pendingTransactionDescription =
if (!spendAllCoins && await transaction_history.createTransaction(
((formattedAmount != null && allInputsAmount < (formattedAmount + estimatedFee)) || address: address!,
formattedAmount == null)) { amount: amount,
throw MoneroTransactionNoInputsException(inputs.length); priorityRaw: _credentials.priority.serialize(),
} accountIndex: walletAddresses.account!.id,
preferredInputs: inputs);
pendingTransactionDescription = await transaction_history.createTransaction(
address: address!,
amount: amount,
priorityRaw: _credentials.priority.serialize(),
accountIndex: walletAddresses.account!.id,
preferredInputs: inputs);
} }
// final status = monero.PendingTransaction_status(pendingTransactionDescription);
return PendingMoneroTransaction(pendingTransactionDescription); return PendingMoneroTransaction(pendingTransactionDescription);
} }
@ -391,8 +391,8 @@ abstract class MoneroWalletBase
try { try {
await backupWalletFiles(name); await backupWalletFiles(name);
} catch (e) { } catch (e) {
print("¯\\_(ツ)_/¯"); printV("¯\\_(ツ)_/¯");
print(e); printV(e);
} }
} }
@ -401,7 +401,7 @@ abstract class MoneroWalletBase
final currentWalletDirPath = await pathForWalletDir(name: name, type: type); final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) { if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) {
// NOTE: this is realistically only required on windows. // NOTE: this is realistically only required on windows.
print("closing wallet"); printV("closing wallet");
final wmaddr = wmPtr.address; final wmaddr = wmPtr.address;
final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address; final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address;
await Isolate.run(() { await Isolate.run(() {
@ -409,7 +409,7 @@ abstract class MoneroWalletBase
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true); Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
}); });
openedWalletsByPath.remove("$currentWalletDirPath/$name"); openedWalletsByPath.remove("$currentWalletDirPath/$name");
print("wallet closed"); printV("wallet closed");
} }
try { try {
// -- rename the waller folder -- // -- rename the waller folder --
@ -498,7 +498,7 @@ abstract class MoneroWalletBase
for (var i = 0; i < coinCount; i++) { for (var i = 0; i < coinCount; i++) {
final coin = getCoin(i); final coin = getCoin(i);
final coinSpent = monero.CoinsInfo_spent(coin); final coinSpent = monero.CoinsInfo_spent(coin);
if (coinSpent == false) { if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) {
final unspent = MoneroUnspent( final unspent = MoneroUnspent(
monero.CoinsInfo_address(coin), monero.CoinsInfo_address(coin),
monero.CoinsInfo_hash(coin), monero.CoinsInfo_hash(coin),
@ -542,7 +542,7 @@ abstract class MoneroWalletBase
await _refreshUnspentCoinsInfo(); await _refreshUnspentCoinsInfo();
_askForUpdateBalance(); _askForUpdateBalance();
} catch (e, s) { } catch (e, s) {
print(e.toString()); printV(e.toString());
onError?.call(FlutterErrorDetails( onError?.call(FlutterErrorDetails(
exception: e, exception: e,
stack: s, stack: s,
@ -589,7 +589,7 @@ abstract class MoneroWalletBase
await unspentCoinsInfo.deleteAll(keys); await unspentCoinsInfo.deleteAll(keys);
} }
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }
@ -621,7 +621,7 @@ abstract class MoneroWalletBase
await transactionHistory.save(); await transactionHistory.save();
_isTransactionUpdating = false; _isTransactionUpdating = false;
} catch (e) { } catch (e) {
print(e); printV(e);
_isTransactionUpdating = false; _isTransactionUpdating = false;
} }
} }
@ -708,9 +708,9 @@ abstract class MoneroWalletBase
void _askForUpdateBalance() { void _askForUpdateBalance() {
final unlockedBalance = _getUnlockedBalance(); final unlockedBalance = _getUnlockedBalance();
final fullBalance = _getFullBalance(); final fullBalance = monero_wallet.getFullBalance(
accountIndex: walletAddresses.account!.id);
final frozenBalance = _getFrozenBalance(); final frozenBalance = _getFrozenBalance();
if (balance[currency]!.fullBalance != fullBalance || if (balance[currency]!.fullBalance != fullBalance ||
balance[currency]!.unlockedBalance != unlockedBalance || balance[currency]!.unlockedBalance != unlockedBalance ||
balance[currency]!.frozenBalance != frozenBalance) { balance[currency]!.frozenBalance != frozenBalance) {
@ -730,10 +730,10 @@ abstract class MoneroWalletBase
var frozenBalance = 0; var frozenBalance = 0;
for (var coin in unspentCoinsInfo.values.where((element) => for (var coin in unspentCoinsInfo.values.where((element) =>
element.walletId == id && element.accountIndex == walletAddresses.account!.id)) { element.walletId == id &&
if (coin.isFrozen) frozenBalance += coin.value; element.accountIndex == walletAddresses.account!.id)) {
if (coin.isFrozen && !coin.isSending) frozenBalance += coin.value;
} }
return frozenBalance; return frozenBalance;
} }
@ -763,7 +763,7 @@ abstract class MoneroWalletBase
syncStatus = SyncingSyncStatus(blocksLeft, ptc); syncStatus = SyncingSyncStatus(blocksLeft, ptc);
} }
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }
@ -773,7 +773,7 @@ abstract class MoneroWalletBase
_askForUpdateBalance(); _askForUpdateBalance();
await Future<void>.delayed(Duration(seconds: 1)); await Future<void>.delayed(Duration(seconds: 1));
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }

View file

@ -1,6 +1,7 @@
import 'package:cw_core/account.dart'; import 'package:cw_core/account.dart';
import 'package:cw_core/address_info.dart'; import 'package:cw_core/address_info.dart';
import 'package:cw_core/subaddress.dart'; import 'package:cw_core/subaddress.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list; import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
@ -96,7 +97,7 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
await saveAddressesInBox(); await saveAddressesInBox();
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }

View file

@ -1,23 +1,26 @@
import 'dart:ffi'; import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'package:cw_core/get_height_by_date.dart';
import 'package:cw_core/monero_wallet_utils.dart'; import 'package:cw_core/monero_wallet_utils.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.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/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cw_core/get_height_by_date.dart';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager; import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
import 'package:cw_monero/api/wallet_manager.dart'; import 'package:cw_monero/api/wallet_manager.dart';
import 'package:cw_monero/ledger.dart'; import 'package:cw_monero/ledger.dart';
import 'package:cw_monero/monero_wallet.dart'; import 'package:cw_monero/monero_wallet.dart';
import 'package:collection/collection.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:polyseed/polyseed.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
import 'package:polyseed/polyseed.dart';
class MoneroNewWalletCredentials extends WalletCredentials { class MoneroNewWalletCredentials extends WalletCredentials {
MoneroNewWalletCredentials( MoneroNewWalletCredentials(
@ -110,7 +113,7 @@ class MoneroWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: ${e.toString()}'); printV('MoneroWalletsManager Error: ${e.toString()}');
rethrow; rethrow;
} }
} }
@ -122,7 +125,7 @@ class MoneroWalletService extends WalletService<
return monero_wallet_manager.isWalletExist(path: path); return monero_wallet_manager.isWalletExist(path: path);
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); printV('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
@ -132,14 +135,12 @@ class MoneroWalletService extends WalletService<
try { try {
final path = await pathForWallet(name: name, type: getType()); final path = await pathForWallet(name: name, type: getType());
if (walletFilesExist(path)) { if (walletFilesExist(path)) await repairOldAndroidWallet(name);
await repairOldAndroidWallet(name);
}
await monero_wallet_manager await monero_wallet_manager
.openWalletAsync({'path': path, 'password': password}); .openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values.firstWhere( final walletInfo = walletInfoSource.values
(info) => info.id == WalletBase.idFor(name, getType())); .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
final wallet = MoneroWallet( final wallet = MoneroWallet(
walletInfo: walletInfo, walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource, unspentCoinsInfo: unspentCoinsInfoSource,
@ -168,7 +169,7 @@ class MoneroWalletService extends WalletService<
} }
await restoreOrResetWalletFiles(name); await restoreOrResetWalletFiles(name);
return openWallet(name, password, retryOnFailure: false); return await openWallet(name, password, retryOnFailure: false);
} }
} }
@ -177,7 +178,7 @@ class MoneroWalletService extends WalletService<
final path = await pathForWalletDir(name: wallet, type: getType()); final path = await pathForWalletDir(name: wallet, type: getType());
if (openedWalletsByPath["$path/$wallet"] != null) { if (openedWalletsByPath["$path/$wallet"] != null) {
// NOTE: this is realistically only required on windows. // NOTE: this is realistically only required on windows.
print("closing wallet"); printV("closing wallet");
final wmaddr = wmPtr.address; final wmaddr = wmPtr.address;
final waddr = openedWalletsByPath["$path/$wallet"]!.address; final waddr = openedWalletsByPath["$path/$wallet"]!.address;
// await Isolate.run(() { // await Isolate.run(() {
@ -185,7 +186,7 @@ class MoneroWalletService extends WalletService<
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), false); Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), false);
// }); // });
openedWalletsByPath.remove("$path/$wallet"); openedWalletsByPath.remove("$path/$wallet");
print("wallet closed"); printV("wallet closed");
} }
final file = Directory(path); final file = Directory(path);
@ -203,7 +204,7 @@ class MoneroWalletService extends WalletService<
@override @override
Future<void> rename(String currentName, String password, String newName) async { Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhere( final currentWalletInfo = walletInfoSource.values.firstWhere(
(info) => info.id == WalletBase.idFor(currentName, getType())); (info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWallet = MoneroWallet( final currentWallet = MoneroWallet(
walletInfo: currentWalletInfo, walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource, unspentCoinsInfo: unspentCoinsInfoSource,
@ -241,7 +242,7 @@ class MoneroWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); printV('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
@ -254,14 +255,14 @@ class MoneroWalletService extends WalletService<
final password = credentials.password; final password = credentials.password;
final height = credentials.height; final height = credentials.height;
if (wptr == null ) monero_wallet_manager.createWalletPointer(); if (wptr == null) monero_wallet_manager.createWalletPointer();
enableLedgerExchange(wptr!, credentials.ledgerConnection); enableLedgerExchange(wptr!, credentials.ledgerConnection);
await monero_wallet_manager.restoreWalletFromHardwareWallet( await monero_wallet_manager.restoreWalletFromHardwareWallet(
path: path, path: path,
password: password!, password: password!,
restoreHeight: height!, restoreHeight: height!,
deviceName: 'Ledger'); deviceName: 'Ledger');
final wallet = MoneroWallet( final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!, walletInfo: credentials.walletInfo!,
@ -272,13 +273,14 @@ class MoneroWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); printV('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
@override @override
Future<MoneroWallet> restoreFromSeed(MoneroRestoreWalletFromSeedCredentials credentials, Future<MoneroWallet> restoreFromSeed(
MoneroRestoreWalletFromSeedCredentials credentials,
{bool? isTestnet}) async { {bool? isTestnet}) async {
// Restore from Polyseed // Restore from Polyseed
if (Polyseed.isValidSeed(credentials.mnemonic)) { if (Polyseed.isValidSeed(credentials.mnemonic)) {
@ -301,7 +303,7 @@ class MoneroWalletService extends WalletService<
return wallet; return wallet;
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); printV('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
@ -312,13 +314,14 @@ class MoneroWalletService extends WalletService<
final path = await pathForWallet(name: credentials.name, type: getType()); final path = await pathForWallet(name: credentials.name, type: getType());
final polyseedCoin = PolyseedCoin.POLYSEED_MONERO; final polyseedCoin = PolyseedCoin.POLYSEED_MONERO;
final lang = PolyseedLang.getByPhrase(credentials.mnemonic); final lang = PolyseedLang.getByPhrase(credentials.mnemonic);
final polyseed = Polyseed.decode(credentials.mnemonic, lang, polyseedCoin); final polyseed =
Polyseed.decode(credentials.mnemonic, lang, polyseedCoin);
return _restoreFromPolyseed( return _restoreFromPolyseed(
path, credentials.password!, polyseed, credentials.walletInfo!, lang); path, credentials.password!, polyseed, credentials.walletInfo!, lang);
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e'); printV('MoneroWalletsManager Error: $e');
rethrow; rethrow;
} }
} }
@ -354,24 +357,18 @@ class MoneroWalletService extends WalletService<
Future<void> repairOldAndroidWallet(String name) async { Future<void> repairOldAndroidWallet(String name) async {
try { try {
if (!Platform.isAndroid) { if (!Platform.isAndroid) return;
return;
}
final oldAndroidWalletDirPath = await outdatedAndroidPathForWalletDir(name: name); final oldAndroidWalletDirPath = await outdatedAndroidPathForWalletDir(name: name);
final dir = Directory(oldAndroidWalletDirPath); final dir = Directory(oldAndroidWalletDirPath);
if (!dir.existsSync()) { if (!dir.existsSync()) return;
return;
}
final newWalletDirPath = await pathForWalletDir(name: name, type: getType()); final newWalletDirPath = await pathForWalletDir(name: name, type: getType());
dir.listSync().forEach((f) { dir.listSync().forEach((f) {
final file = File(f.path); final file = File(f.path);
final name = f.path final name = f.path.split('/').last;
.split('/')
.last;
final newPath = newWalletDirPath + '/$name'; final newPath = newWalletDirPath + '/$name';
final newFile = File(newPath); final newFile = File(newPath);
@ -381,7 +378,7 @@ class MoneroWalletService extends WalletService<
newFile.writeAsBytesSync(file.readAsBytesSync()); newFile.writeAsBytesSync(file.readAsBytesSync());
}); });
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }
@ -390,9 +387,7 @@ class MoneroWalletService extends WalletService<
try { try {
final path = await pathForWallet(name: name, type: getType()); final path = await pathForWallet(name: name, type: getType());
if (walletFilesExist(path)) { if (walletFilesExist(path)) await repairOldAndroidWallet(name);
await repairOldAndroidWallet(name);
}
await monero_wallet_manager.openWalletAsync({'path': path, 'password': password}); await monero_wallet_manager.openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values final walletInfo = walletInfoSource.values
@ -411,8 +406,10 @@ class MoneroWalletService extends WalletService<
@override @override
bool requireHardwareWalletConnection(String name) { bool requireHardwareWalletConnection(String name) {
final walletInfo = walletInfoSource.values return walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(name, getType())); .firstWhereOrNull(
return walletInfo.isHardwareWallet; (info) => info.id == WalletBase.idFor(name, getType()))
?.isHardwareWallet ??
false;
} }
} }

View file

@ -6,6 +6,7 @@ import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/amount_converter.dart'; import 'package:cw_core/amount_converter.dart';
import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/pending_transaction.dart';
import 'package:cw_monero/api/wallet.dart';
class DoubleSpendException implements Exception { class DoubleSpendException implements Exception {
DoubleSpendException(); DoubleSpendException();
@ -53,6 +54,7 @@ class PendingMoneroTransaction with PendingTransaction {
rethrow; rethrow;
} }
storeSync(force: true);
} }
@override @override

View file

@ -0,0 +1 @@
/Users/omarhatem/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/

View file

@ -21,10 +21,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.6.0"
asn1lib: asn1lib:
dependency: transitive dependency: transitive
description: description:
@ -77,10 +77,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.1" version: "4.0.2"
build_resolvers: build_resolvers:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -93,10 +93,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.9" version: "2.4.13"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
@ -174,18 +174,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.6"
cryptography: cryptography:
dependency: transitive dependency: transitive
description: description:
@ -253,18 +253,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: file name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.0.1"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
name: fixnum name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -311,10 +311,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: graphs name: graphs
sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
hashlib: hashlib:
dependency: transitive dependency: transitive
description: description:
@ -375,10 +375,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -407,26 +407,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.0" version: "10.0.5"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.5"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.1"
ledger_flutter_plus: ledger_flutter_plus:
dependency: "direct main" dependency: "direct main"
description: description:
@ -447,10 +447,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.3.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -463,26 +463,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.0" version: "0.11.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.15.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.6" version: "2.0.0"
mobx: mobx:
dependency: "direct main" dependency: "direct main"
description: description:
@ -503,8 +503,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "impls/monero.dart" path: "impls/monero.dart"
ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 ref: af5277f96073917185864d3596e82b67bee54e78
resolved-ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 resolved-ref: af5277f96073917185864d3596e82b67bee54e78
url: "https://github.com/mrcyjanek/monero_c" url: "https://github.com/mrcyjanek/monero_c"
source: git source: git
version: "0.0.0" version: "0.0.0"
@ -552,10 +552,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.4" version: "2.2.12"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
@ -600,10 +600,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.5" version: "3.1.6"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -680,10 +680,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -765,10 +765,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.7.2"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -789,10 +789,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.4.0"
universal_ble: universal_ble:
dependency: transitive dependency: transitive
description: description:
@ -829,10 +829,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "14.2.4"
watcher: watcher:
dependency: "direct overridden" dependency: "direct overridden"
description: description:
@ -845,18 +845,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "1.1.0"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
url: "https://pub.dev"
source: hosted
version: "0.1.6"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.5" version: "3.0.1"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@ -882,5 +890,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.3.0 <4.0.0" dart: ">=3.5.0 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.24.0"

View file

@ -17,7 +17,7 @@ dependencies:
path_provider: ^2.0.11 path_provider: ^2.0.11
mobx: ^2.0.7+4 mobx: ^2.0.7+4
flutter_mobx: ^2.0.6+1 flutter_mobx: ^2.0.6+1
intl: ^0.18.0 intl: ^0.19.0
encrypt: ^5.0.1 encrypt: ^5.0.1
polyseed: ^0.0.6 polyseed: ^0.0.6
cw_core: cw_core:
@ -25,7 +25,7 @@ dependencies:
monero: monero:
git: git:
url: https://github.com/mrcyjanek/monero_c url: https://github.com/mrcyjanek/monero_c
ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 ref: af5277f96073917185864d3596e82b67bee54e78
# ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash # ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash
path: impls/monero.dart path: impls/monero.dart
mutex: ^3.1.0 mutex: ^3.1.0

View file

@ -2,14 +2,14 @@ group 'com.cakewallet.mweb'
version '1.0-SNAPSHOT' version '1.0-SNAPSHOT'
buildscript { buildscript {
ext.kotlin_version = '1.7.10' ext.kotlin_version = '2.0.21'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.3.0' classpath 'com.android.tools.build:gradle:8.7.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
@ -33,15 +33,19 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 31 compileSdkVersion 33
if (project.android.hasProperty("namespace")) {
namespace 'com.cakewallet.mweb'
}
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_17
} }
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' jvmTarget = '17'
} }
sourceSets { sourceSets {

View file

@ -1 +1,3 @@
rootProject.name = 'cw_mweb' rootProject.name = 'cw_mweb'
id "com.android.application" version "8.3.2" apply false
id "org.jetbrains.kotlin.android" version "2.0.20" apply false

View file

@ -4,6 +4,7 @@ import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:grpc/grpc.dart'; import 'package:grpc/grpc.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'cw_mweb_platform_interface.dart'; import 'cw_mweb_platform_interface.dart';
@ -39,18 +40,18 @@ class CwMweb {
final fileStream = file.openRead(lastLength, currentLength); final fileStream = file.openRead(lastLength, currentLength);
final newLines = await fileStream.transform(utf8.decoder).join(); final newLines = await fileStream.transform(utf8.decoder).join();
lastLength = currentLength; lastLength = currentLength;
log(newLines); printV(newLines);
} }
} on GrpcError catch (e) { } on GrpcError catch (e) {
log('Caught grpc error: ${e.message}'); printV('Caught grpc error: ${e.message}');
} catch (e) { } catch (e) {
log('The mwebd debug log probably is not initialized yet.'); printV('The mwebd debug log probably is not initialized yet.');
} }
}); });
} }
static Future<void> _initializeClient() async { static Future<void> _initializeClient() async {
print("_initializeClient() called!"); printV("_initializeClient() called!");
final appDir = await getApplicationSupportDirectory(); final appDir = await getApplicationSupportDirectory();
const ltcNodeUri = "ltc-electrum.cakewallet.com:9333"; const ltcNodeUri = "ltc-electrum.cakewallet.com:9333";
@ -61,14 +62,14 @@ class CwMweb {
if (_port == null || _port == 0) { if (_port == null || _port == 0) {
throw Exception("Failed to start server"); throw Exception("Failed to start server");
} }
log("Attempting to connect to server on port: $_port"); printV("Attempting to connect to server on port: $_port");
// wait for the server to finish starting up before we try to connect to it: // wait for the server to finish starting up before we try to connect to it:
await Future.delayed(const Duration(seconds: 8)); await Future.delayed(const Duration(seconds: 8));
_clientChannel = ClientChannel('127.0.0.1', port: _port!, channelShutdownHandler: () { _clientChannel = ClientChannel('127.0.0.1', port: _port!, channelShutdownHandler: () {
_rpcClient = null; _rpcClient = null;
log("Channel is shutting down!"); printV("Channel is shutting down!");
}, },
options: const ChannelOptions( options: const ChannelOptions(
credentials: ChannelCredentials.insecure(), credentials: ChannelCredentials.insecure(),
@ -90,14 +91,14 @@ class CwMweb {
} }
return _rpcClient!; return _rpcClient!;
} on GrpcError catch (e) { } on GrpcError catch (e) {
log("Attempt $i failed: $e"); printV("Attempt $i failed: $e");
log('Caught grpc error: ${e.message}'); printV('Caught grpc error: ${e.message}');
_rpcClient = null; _rpcClient = null;
// necessary if the database isn't open: // necessary if the database isn't open:
await stop(); await stop();
await Future.delayed(const Duration(seconds: 3)); await Future.delayed(const Duration(seconds: 3));
} catch (e) { } catch (e) {
log("Attempt $i failed: $e"); printV("Attempt $i failed: $e");
_rpcClient = null; _rpcClient = null;
await stop(); await stop();
await Future.delayed(const Duration(seconds: 3)); await Future.delayed(const Duration(seconds: 3));
@ -111,9 +112,9 @@ class CwMweb {
await CwMwebPlatform.instance.stop(); await CwMwebPlatform.instance.stop();
await cleanup(); await cleanup();
} on GrpcError catch (e) { } on GrpcError catch (e) {
log('Caught grpc error: ${e.message}'); printV('Caught grpc error: ${e.message}');
} catch (e) { } catch (e) {
log("Error stopping server: $e"); printV("Error stopping server: $e");
} }
} }
@ -123,9 +124,9 @@ class CwMweb {
?.split(',') ?.split(',')
.first; .first;
} on GrpcError catch (e) { } on GrpcError catch (e) {
log('Caught grpc error: ${e.message}'); printV('Caught grpc error: ${e.message}');
} catch (e) { } catch (e) {
log("Error getting address: $e"); printV("Error getting address: $e");
} }
return null; return null;
} }
@ -159,9 +160,9 @@ class CwMweb {
_rpcClient = await stub(); _rpcClient = await stub();
return await _rpcClient!.spent(request, options: CallOptions(timeout: TIMEOUT_DURATION)); return await _rpcClient!.spent(request, options: CallOptions(timeout: TIMEOUT_DURATION));
} on GrpcError catch (e) { } on GrpcError catch (e) {
log('Caught grpc error: ${e.message}'); printV('Caught grpc error: ${e.message}');
} catch (e) { } catch (e) {
log("Error getting spent: $e"); printV("Error getting spent: $e");
} }
return SpentResponse(); return SpentResponse();
} }
@ -172,9 +173,9 @@ class CwMweb {
_rpcClient = await stub(); _rpcClient = await stub();
return await _rpcClient!.status(request, options: CallOptions(timeout: TIMEOUT_DURATION)); return await _rpcClient!.status(request, options: CallOptions(timeout: TIMEOUT_DURATION));
} on GrpcError catch (e) { } on GrpcError catch (e) {
log('Caught grpc error: ${e.message}'); printV('Caught grpc error: ${e.message}');
} catch (e) { } catch (e) {
log("Error getting status: $e"); printV("Error getting status: $e");
} }
return StatusResponse(); return StatusResponse();
} }
@ -185,9 +186,9 @@ class CwMweb {
_rpcClient = await stub(); _rpcClient = await stub();
return await _rpcClient!.create(request, options: CallOptions(timeout: TIMEOUT_DURATION)); return await _rpcClient!.create(request, options: CallOptions(timeout: TIMEOUT_DURATION));
} on GrpcError catch (e) { } on GrpcError catch (e) {
log('Caught grpc error: ${e.message}'); printV('Caught grpc error: ${e.message}');
} catch (e) { } catch (e) {
log("Error getting create: $e"); printV("Error getting create: $e");
} }
return CreateResponse(); return CreateResponse();
} }
@ -201,9 +202,9 @@ class CwMweb {
log("got utxo stream"); log("got utxo stream");
return resp; return resp;
} on GrpcError catch (e) { } on GrpcError catch (e) {
log('Caught grpc error: ${e.message}'); printV('Caught grpc error: ${e.message}');
} catch (e) { } catch (e) {
log("Error getting utxos: $e"); printV("Error getting utxos: $e");
} }
return null; return null;
} }
@ -217,7 +218,7 @@ class CwMweb {
log('Caught grpc error: ${e.message}'); log('Caught grpc error: ${e.message}');
throw "error from broadcast mweb: $e"; throw "error from broadcast mweb: $e";
} catch (e) { } catch (e) {
log("Error getting create: $e"); printV("Error getting utxos: $e");
rethrow; rethrow;
} }
} }

View file

@ -13,6 +13,8 @@ dependencies:
grpc: ^3.2.4 grpc: ^3.2.4
path_provider: ^2.1.2 path_provider: ^2.1.2
plugin_platform_interface: ^2.0.2 plugin_platform_interface: ^2.0.2
cw_core:
path: ../cw_core
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:cw_core/nano_account_info_response.dart'; import 'package:cw_core/nano_account_info_response.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_nano/nano_block_info_response.dart'; import 'package:cw_nano/nano_block_info_response.dart';
import 'package:cw_core/n2_node.dart'; import 'package:cw_core/n2_node.dart';
import 'package:cw_nano/nano_balance.dart'; import 'package:cw_nano/nano_balance.dart';
@ -106,7 +107,7 @@ class NanoClient {
final data = await jsonDecode(response.body); final data = await jsonDecode(response.body);
return AccountInfoResponse.fromJson(data as Map<String, dynamic>); return AccountInfoResponse.fromJson(data as Map<String, dynamic>);
} catch (e) { } catch (e) {
print("error while getting account info $e"); printV("error while getting account info $e");
return null; return null;
} }
} }
@ -127,7 +128,7 @@ class NanoClient {
final data = await jsonDecode(response.body); final data = await jsonDecode(response.body);
return BlockContentsResponse.fromJson(data["contents"] as Map<String, dynamic>); return BlockContentsResponse.fromJson(data["contents"] as Map<String, dynamic>);
} catch (e) { } catch (e) {
print("error while getting block info $e"); printV("error while getting block info $e");
return null; return null;
} }
} }
@ -508,7 +509,7 @@ class NanoClient {
.map<NanoTransactionModel>((transaction) => NanoTransactionModel.fromJson(transaction)) .map<NanoTransactionModel>((transaction) => NanoTransactionModel.fromJson(transaction))
.toList(); .toList();
} catch (e) { } catch (e) {
print(e); printV(e);
return []; return [];
} }
} }

View file

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:core'; import 'dart:core';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/encryption_file_utils.dart'; import 'package:cw_core/encryption_file_utils.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -27,7 +28,10 @@ abstract class NanoTransactionHistoryBase extends TransactionHistoryBase<NanoTra
final EncryptionFileUtils encryptionFileUtils; final EncryptionFileUtils encryptionFileUtils;
String _password; String _password;
Future<void> init() async => await _load(); Future<void> init() async {
clear();
await _load();
}
@override @override
Future<void> save() async { Future<void> save() async {
@ -37,7 +41,7 @@ abstract class NanoTransactionHistoryBase extends TransactionHistoryBase<NanoTra
final data = json.encode({'transactions': transactions}); final data = json.encode({'transactions': transactions});
await encryptionFileUtils.write(path: path, password: _password, data: data); await encryptionFileUtils.write(path: path, password: _password, data: data);
} catch (e) { } catch (e) {
print('Error while save nano transaction history: ${e.toString()}'); printV('Error while save nano transaction history: ${e.toString()}');
} }
} }
@ -72,7 +76,7 @@ abstract class NanoTransactionHistoryBase extends TransactionHistoryBase<NanoTra
} }
}); });
} catch (e) { } catch (e) {
print(e); printV(e);
} }
} }

View file

@ -15,6 +15,7 @@ import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_keys_file.dart'; import 'package:cw_core/wallet_keys_file.dart';
@ -149,7 +150,7 @@ abstract class NanoWalletBase
Future<void> changePassword(String password) => throw UnimplementedError("changePassword"); Future<void> changePassword(String password) => throw UnimplementedError("changePassword");
@override @override
Future<void> close({required bool shouldCleanup}) async { Future<void> close({bool shouldCleanup = false}) async {
_client.stop(); _client.stop();
_receiveTimer?.cancel(); _receiveTimer?.cancel();
} }
@ -170,12 +171,12 @@ abstract class NanoWalletBase
await _updateRep(); await _updateRep();
await _receiveAll(); await _receiveAll();
} catch (e) { } catch (e) {
print(e); printV(e);
} }
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();
} catch (e) { } catch (e) {
print(e); printV(e);
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
} }
} }
@ -367,7 +368,7 @@ abstract class NanoWalletBase
syncStatus = SyncedSyncStatus(); syncStatus = SyncedSyncStatus();
} catch (e) { } catch (e) {
print(e); printV(e);
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
rethrow; rethrow;
} }
@ -444,7 +445,7 @@ abstract class NanoWalletBase
try { try {
balance[currency] = await _client.getBalance(_publicAddress!); balance[currency] = await _client.getBalance(_publicAddress!);
} catch (e) { } catch (e) {
print("Failed to get balance $e"); printV("Failed to get balance $e");
// if we don't have a balance, we should at least create one, since it's a late binding // if we don't have a balance, we should at least create one, since it's a late binding
// otherwise, it's better to just leave it as whatever it was before: // otherwise, it's better to just leave it as whatever it was before:
if (balance[currency] == null) { if (balance[currency] == null) {

View file

@ -1,4 +1,5 @@
import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/nano_account.dart'; import 'package:cw_core/nano_account.dart';
@ -47,7 +48,7 @@ abstract class NanoWalletAddressesBase extends WalletAddresses with Store {
addressesMap[address] = ''; addressesMap[address] = '';
await saveAddressesInBox(); await saveAddressesInBox();
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }
} }

View file

@ -21,18 +21,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.6.0"
asn1lib: asn1lib:
dependency: transitive dependency: transitive
description: description:
name: asn1lib name: asn1lib
sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda" sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.3" version: "1.5.5"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -77,10 +77,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build name: build
sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.4.1"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
@ -93,10 +93,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.1" version: "4.0.2"
build_resolvers: build_resolvers:
dependency: transitive dependency: transitive
description: description:
@ -109,10 +109,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.9" version: "2.4.13"
build_runner_core: build_runner_core:
dependency: "direct overridden" dependency: "direct overridden"
description: description:
@ -190,18 +190,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.6"
cryptography: cryptography:
dependency: transitive dependency: transitive
description: description:
@ -245,18 +245,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: ed25519_hd_key name: ed25519_hd_key
sha256: c5c9f11a03f5789bf9dcd9ae88d641571c802640851f1cacdb13123f171b3a26 sha256: "31e191ec97492873067e46dc9cc0c7d55170559c83a478400feffa0627acaccf"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.3.0"
encrypt: encrypt:
dependency: transitive dependency: transitive
description: description:
name: encrypt name: encrypt
sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb" sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.1" version: "5.0.3"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -269,26 +269,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.3"
file: file:
dependency: transitive dependency: transitive
description: description:
name: file name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.0.1"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
name: fixnum name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
fixnum_nanodart: fixnum_nanodart:
dependency: transitive dependency: transitive
description: description:
@ -306,10 +306,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: flutter_mobx name: flutter_mobx
sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e" sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.6+5" version: "2.2.1+1"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -324,10 +324,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: frontend_server_client name: frontend_server_client
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "4.0.0"
glob: glob:
dependency: transitive dependency: transitive
description: description:
@ -340,10 +340,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: graphs name: graphs
sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
hex: hex:
dependency: "direct main" dependency: "direct main"
description: description:
@ -372,10 +372,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.2.2"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -396,10 +396,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -420,34 +420,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: json_annotation name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.8.1" version: "4.9.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.0" version: "10.0.5"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.5"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.1"
libcrypto: libcrypto:
dependency: "direct main" dependency: "direct main"
description: description:
@ -460,10 +460,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.3.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -476,26 +476,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.0" version: "0.11.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.15.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0"
mobx: mobx:
dependency: "direct main" dependency: "direct main"
description: description:
@ -529,6 +529,14 @@ packages:
url: "https://github.com/perishllc/nanoutil.git" url: "https://github.com/perishllc/nanoutil.git"
source: git source: git
version: "1.0.3" version: "1.0.3"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
@ -549,26 +557,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider name: path_provider
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.4"
path_provider_android: path_provider_android:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.2.12"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.4.0"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@ -581,34 +589,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.3.0"
pinenacl: pinenacl:
dependency: transitive dependency: transitive
description: description:
name: pinenacl name: pinenacl
sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327" sha256: "57e907beaacbc3c024a098910b6240758e899674de07d6949a67b52fd984cbdf"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "0.6.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.0" version: "3.1.6"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -621,10 +629,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.7.3" version: "3.9.1"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -633,6 +641,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.1" version: "1.5.1"
provider:
dependency: transitive
description:
name: provider
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
@ -645,50 +661,50 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: pubspec_parse name: pubspec_parse
sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.3" version: "1.3.0"
rational: rational:
dependency: transitive dependency: transitive
description: description:
name: rational name: rational
sha256: ba58e9e18df9abde280e8b10051e4bce85091e41e8e7e411b6cde2e738d357cf sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.2.3"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences name: shared_preferences
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.3.2"
shared_preferences_android: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.3.3"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833" sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.5.3"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_linux name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.1"
shared_preferences_platform_interface: shared_preferences_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -701,18 +717,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.4.2"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_windows name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.1"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
@ -725,10 +741,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -738,10 +754,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: socks5_proxy name: socks5_proxy
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a" sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.6"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -810,10 +826,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.7.2"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -834,10 +850,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.4.0"
unorm_dart: unorm_dart:
dependency: transitive dependency: transitive
description: description:
@ -858,10 +874,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "14.2.4"
watcher: watcher:
dependency: "direct overridden" dependency: "direct overridden"
description: description:
@ -870,30 +886,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
url: "https://pub.dev"
source: hosted
version: "0.1.6"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.0" version: "3.0.1"
win32:
dependency: transitive
description:
name: win32
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
url: "https://pub.dev"
source: hosted
version: "5.5.0"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.1.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
@ -903,5 +927,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.3.0 <4.0.0" dart: ">=3.5.0 <4.0.0"
flutter: ">=3.16.6" flutter: ">=3.24.0"

View file

@ -14,11 +14,19 @@ class PolygonClient extends EVMChainClient {
required EtherAmount amount, required EtherAmount amount,
EtherAmount? maxPriorityFeePerGas, EtherAmount? maxPriorityFeePerGas,
Uint8List? data, Uint8List? data,
int? maxGas,
EtherAmount? gasPrice,
EtherAmount? maxFeePerGas,
}) { }) {
return Transaction( return Transaction(
from: from, from: from,
to: to, to: to,
value: amount, value: amount,
// data: data,
maxGas: maxGas,
// gasPrice: gasPrice,
// maxFeePerGas: maxFeePerGas,
// maxPriorityFeePerGas: maxPriorityFeePerGas,
); );
} }

View file

@ -25,7 +25,20 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 30 compileSdkVersion 33
if (project.android.hasProperty("namespace")) {
namespace 'com.cakewallet.cw_shared_external'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'

View file

@ -1,11 +1,13 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:math'; import 'dart:math' as math;
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_solana/pending_solana_transaction.dart'; import 'package:cw_solana/pending_solana_transaction.dart';
import 'package:cw_solana/solana_balance.dart'; import 'package:cw_solana/solana_balance.dart';
import 'package:cw_solana/solana_exceptions.dart';
import 'package:cw_solana/solana_transaction_model.dart'; import 'package:cw_solana/solana_transaction_model.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:solana/dto.dart'; import 'package:solana/dto.dart';
@ -179,7 +181,7 @@ class SolanaWalletClient {
bool isOutgoingTx = transfer.source == publicKey.toBase58(); bool isOutgoingTx = transfer.source == publicKey.toBase58();
double amount = (double.tryParse(transfer.amount) ?? 0.0) / double amount = (double.tryParse(transfer.amount) ?? 0.0) /
pow(10, splTokenDecimal ?? 9); math.pow(10, splTokenDecimal ?? 9);
transactions.add( transactions.add(
SolanaTransactionModel( SolanaTransactionModel(
@ -275,6 +277,7 @@ class SolanaWalletClient {
required String destinationAddress, required String destinationAddress,
required Ed25519HDKeyPair ownerKeypair, required Ed25519HDKeyPair ownerKeypair,
required bool isSendAll, required bool isSendAll,
required double solBalance,
String? tokenMint, String? tokenMint,
List<String> references = const [], List<String> references = const [],
}) async { }) async {
@ -289,6 +292,7 @@ class SolanaWalletClient {
ownerKeypair: ownerKeypair, ownerKeypair: ownerKeypair,
commitment: commitment, commitment: commitment,
isSendAll: isSendAll, isSendAll: isSendAll,
solBalance: solBalance,
); );
return pendingNativeTokenTransaction; return pendingNativeTokenTransaction;
} else { } else {
@ -300,6 +304,7 @@ class SolanaWalletClient {
destinationAddress: destinationAddress, destinationAddress: destinationAddress,
ownerKeypair: ownerKeypair, ownerKeypair: ownerKeypair,
commitment: commitment, commitment: commitment,
solBalance: solBalance,
); );
return pendingSPLTokenTransaction; return pendingSPLTokenTransaction;
} }
@ -352,6 +357,23 @@ class SolanaWalletClient {
return fee; return fee;
} }
Future<bool> hasSufficientFundsLeftForRent({
required double inputAmount,
required double solBalance,
required double fee,
}) async {
final rent =
await _client!.getMinimumBalanceForMintRentExemption(commitment: Commitment.confirmed);
final rentInSol = (rent / lamportsPerSol).toDouble();
final remnant = solBalance - (inputAmount + fee);
if (remnant > rentInSol) return true;
return false;
}
Future<PendingSolanaTransaction> _signNativeTokenTransaction({ Future<PendingSolanaTransaction> _signNativeTokenTransaction({
required String tokenTitle, required String tokenTitle,
required int tokenDecimals, required int tokenDecimals,
@ -360,6 +382,7 @@ class SolanaWalletClient {
required Ed25519HDKeyPair ownerKeypair, required Ed25519HDKeyPair ownerKeypair,
required Commitment commitment, required Commitment commitment,
required bool isSendAll, required bool isSendAll,
required double solBalance,
}) async { }) async {
// Convert SOL to lamport // Convert SOL to lamport
int lamports = (inputAmount * lamportsPerSol).toInt(); int lamports = (inputAmount * lamportsPerSol).toInt();
@ -377,6 +400,16 @@ class SolanaWalletClient {
commitment, commitment,
); );
bool hasSufficientFundsLeft = await hasSufficientFundsLeftForRent(
inputAmount: inputAmount,
fee: fee,
solBalance: solBalance,
);
if (!hasSufficientFundsLeft) {
throw SolanaSignNativeTokenTransactionRentException();
}
SignedTx signedTx; SignedTx signedTx;
if (isSendAll) { if (isSendAll) {
final feeInLamports = (fee * lamportsPerSol).toInt(); final feeInLamports = (fee * lamportsPerSol).toInt();
@ -424,6 +457,7 @@ class SolanaWalletClient {
required String destinationAddress, required String destinationAddress,
required Ed25519HDKeyPair ownerKeypair, required Ed25519HDKeyPair ownerKeypair,
required Commitment commitment, required Commitment commitment,
required double solBalance,
}) async { }) async {
final destinationOwner = Ed25519HDPublicKey.fromBase58(destinationAddress); final destinationOwner = Ed25519HDPublicKey.fromBase58(destinationAddress);
final mint = Ed25519HDPublicKey.fromBase58(tokenMint); final mint = Ed25519HDPublicKey.fromBase58(tokenMint);
@ -446,7 +480,7 @@ class SolanaWalletClient {
// Throw an appropriate exception if the sender has no associated // Throw an appropriate exception if the sender has no associated
// token account // token account
if (associatedSenderAccount == null) { if (associatedSenderAccount == null) {
throw NoAssociatedTokenAccountException(ownerKeypair.address, mint.toBase58()); throw SolanaNoAssociatedTokenAccountException(ownerKeypair.address, mint.toBase58());
} }
try { try {
@ -456,11 +490,11 @@ class SolanaWalletClient {
funder: ownerKeypair, funder: ownerKeypair,
); );
} catch (e) { } catch (e) {
throw Exception('Insufficient SOL balance to complete this transaction: ${e.toString()}'); throw SolanaCreateAssociatedTokenAccountException(e.toString());
} }
// Input by the user // Input by the user
final amount = (inputAmount * pow(10, tokenDecimals)).toInt(); final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt();
final instruction = TokenInstruction.transfer( final instruction = TokenInstruction.transfer(
source: Ed25519HDPublicKey.fromBase58(associatedSenderAccount.pubkey), source: Ed25519HDPublicKey.fromBase58(associatedSenderAccount.pubkey),
@ -482,6 +516,16 @@ class SolanaWalletClient {
commitment, commitment,
); );
bool hasSufficientFundsLeft = await hasSufficientFundsLeftForRent(
inputAmount: inputAmount,
fee: fee,
solBalance: solBalance,
);
if (!hasSufficientFundsLeft) {
throw SolanaSignSPLTokenTransactionRentException();
}
final signedTx = await _signTransactionInternal( final signedTx = await _signTransactionInternal(
message: message, message: message,
signers: signers, signers: signers,
@ -529,7 +573,7 @@ class SolanaWalletClient {
return signature; return signature;
} catch (e) { } catch (e) {
print('Error while sending transaction: ${e.toString()}'); printV('Error while sending transaction: ${e.toString()}');
throw Exception(e); throw Exception(e);
} }
} }
@ -546,7 +590,7 @@ class SolanaWalletClient {
return null; return null;
} }
} catch (e) { } catch (e) {
print('Error occurred while fetching token image: \n${e.toString()}'); printV('Error occurred while fetching token image: \n${e.toString()}');
return null; return null;
} }
} }

View file

@ -19,3 +19,20 @@ class SolanaTransactionWrongBalanceException implements Exception {
@override @override
String toString() => exceptionMessage; String toString() => exceptionMessage;
} }
class SolanaSignNativeTokenTransactionRentException implements Exception {}
class SolanaCreateAssociatedTokenAccountException implements Exception {
final String exceptionMessage;
SolanaCreateAssociatedTokenAccountException(this.exceptionMessage);
}
class SolanaSignSPLTokenTransactionRentException implements Exception {}
class SolanaNoAssociatedTokenAccountException implements Exception {
const SolanaNoAssociatedTokenAccountException(this.account, this.mint);
final String account;
final String mint;
}

View file

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:core'; import 'dart:core';
import 'package:cw_core/encryption_file_utils.dart'; import 'package:cw_core/encryption_file_utils.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/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_solana/solana_transaction_info.dart'; import 'package:cw_solana/solana_transaction_info.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -25,7 +26,10 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<Solan
final EncryptionFileUtils encryptionFileUtils; final EncryptionFileUtils encryptionFileUtils;
String _password; String _password;
Future<void> init() async => await _load(); Future<void> init() async {
clear();
await _load();
}
@override @override
Future<void> save() async { Future<void> save() async {
@ -36,8 +40,8 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<Solan
final data = json.encode({'transactions': transactionMaps}); final data = json.encode({'transactions': transactionMaps});
await encryptionFileUtils.write(path: path, password: _password, data: data); await encryptionFileUtils.write(path: path, password: _password, data: data);
} catch (e, s) { } catch (e, s) {
print('Error while saving solana transaction history: ${e.toString()}'); printV('Error while saving solana transaction history: ${e.toString()}');
print(s); printV(s);
} }
} }
@ -72,7 +76,7 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<Solan
} }
}); });
} catch (e) { } catch (e) {
print(e); printV(e);
} }
} }

View file

@ -11,6 +11,7 @@ import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
@ -179,7 +180,7 @@ abstract class SolanaWalletBase
Future<void> changePassword(String password) => throw UnimplementedError("changePassword"); Future<void> changePassword(String password) => throw UnimplementedError("changePassword");
@override @override
Future<void> close({required bool shouldCleanup}) async { Future<void> close({bool shouldCleanup = false}) async {
_client.stop(); _client.stop();
_transactionsUpdateTimer?.cancel(); _transactionsUpdateTimer?.cancel();
} }
@ -227,6 +228,8 @@ abstract class SolanaWalletBase
final walletBalanceForCurrency = balance[transactionCurrency]!.balance; final walletBalanceForCurrency = balance[transactionCurrency]!.balance;
final solBalance = balance[CryptoCurrency.sol]!.balance;
double totalAmount = 0.0; double totalAmount = 0.0;
bool isSendAll = false; bool isSendAll = false;
@ -278,6 +281,7 @@ abstract class SolanaWalletBase
? solCredentials.outputs.first.extractedAddress! ? solCredentials.outputs.first.extractedAddress!
: solCredentials.outputs.first.address, : solCredentials.outputs.first.address,
isSendAll: isSendAll, isSendAll: isSendAll,
solBalance: solBalance,
); );
return pendingSolanaTransaction; return pendingSolanaTransaction;
@ -454,7 +458,7 @@ abstract class SolanaWalletBase
SolanaBalance(0.0); SolanaBalance(0.0);
balance[token] = tokenBalance; balance[token] = tokenBalance;
} catch (e) { } catch (e) {
print('Error fetching spl token (${token.symbol}) balance ${e.toString()}'); printV('Error fetching spl token (${token.symbol}) balance ${e.toString()}');
} }
} else { } else {
balance.remove(token); balance.remove(token);

View file

@ -1,3 +1,4 @@
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -30,7 +31,7 @@ abstract class SolanaWalletAddressesBase extends WalletAddresses with Store {
addressesMap[address] = ''; addressesMap[address] = '';
await saveAddressesInBox(); await saveAddressesInBox();
} catch (e) { } catch (e) {
print(e.toString()); printV(e.toString());
} }
} }
} }

View file

@ -25,7 +25,10 @@ abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTra
final WalletInfo walletInfo; final WalletInfo walletInfo;
final EncryptionFileUtils encryptionFileUtils; final EncryptionFileUtils encryptionFileUtils;
Future<void> init() async => await _load(); Future<void> init() async {
clear();
await _load();
}
@override @override
Future<void> save() async { Future<void> save() async {

View file

@ -217,7 +217,7 @@ abstract class TronWalletBase
Future<void> changePassword(String password) => throw UnimplementedError("changePassword"); Future<void> changePassword(String password) => throw UnimplementedError("changePassword");
@override @override
Future<void> close({required bool shouldCleanup}) async => _transactionsUpdateTimer?.cancel(); Future<void> close({bool shouldCleanup = false}) async => _transactionsUpdateTimer?.cancel();
@action @action
@override @override

Some files were not shown because too many files have changed in this diff Show more