mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-16 17:27:37 +00:00
CW-676 Add Linux scripts to build monero_c for linux platform (#1527)
* Revert "Revert btc address types"
This reverts commit a49e57e3
* Re-add Bitcoin Address types
Fix conflicts with main
* fix: label issues, clear spent utxo
* chore: deps
* fix: build
* fix: missing types
* feat: new electrs API & changes, fixes for last block scanning
* Update Monero
* not sure why it's failing
* Enable Exolix
Improve service updates indicator
New versions
* Add exolix Api token to limits api
* Ignore reporting network issues
* Change default bitcoin node
* Merge main and update linux version
* Update app version [skip ci]
* New versions
* Fix conflicts and update linux version
* minor fix
* feat: Scan Silent Payments homepage toggle
* chore: build configure
* feat: generic fixes, testnet UI improvements, useSSL on bitcoin nodes
* fix: invalid Object in sendData
* feat: improve addresses page & address book displays
* feat: silent payments labeled addresses disclaimer
* fix: missing i18n
* chore: print
* feat: single block scan, rescan by date working for btc mainnet
* feat: new cake features page replace market page, move sp scan toggle, auto switch node pop up alert
* feat: delete silent addresses
* fix: red dot in non ssl nodes
* fix: inconsistent connection states, fix tx history
* fix: tx & balance displays, cpfp sending
* feat: new rust lib
* chore: node path
* fix: check node based on network
* fix: missing txcount from addresses
* style: padding in feature page cards
* fix: restore not getting all wallet addresses by type
* fix: auto switch node broken
* fix: silent payment txs not being restored
* update linux version
* feat: change scanning to subscription model, sync improvements
* fix: scan re-subscription
* fix: default nodes
* fix: improve scanning by date, fix single block scan
* refactor: common function for input tx selection
* various fixes for build issues
* initial monero.dart implementation
* ...
* multiple wallets
new lib
minor fixes
* other fixes from monero.dart and monero_c
* fix: nodes & build
* update build scripts
fix polyseed
* remove unnecessary code
* Add windows app, build scripts and build guide for it.
* Minor fix in generated monero configs
* Merge and fix main
* fix: send all with multiple outs
* add missing monero_c command
* add android build script
* update version
* Merge and fix main
* undo android ndk removal
* Fix modified exception_handler.dart
* Temporarily remove haven
* fix build issues
* fix pr script
* Fixes for build monero.dart (monero_c) for windows.
* monero build script
* wip: ios build script
* refactor: unchanged file
* Added build guides for iOS and macOS. Replaced nproc call on macOS. Added macOS configuration for configure_cake_wallet.sh script.
* Update monero.dart and monero_c versions.
* Add missed windows build scripts
* Update the application configuration for windows build script.
* Update cw_monero pubspec lock file for monero.dart
* Update pr_test_build.yml
* chore: upgrade
* chore: merge changes
* refactor: unchanged files [skip ci]
* Fix conflicts with main
* fix for multiple wallets
* update app version [skip ci]
* Add tron to windows application configuration.
* Add macOS option for description message in configure_cake_wallet.sh
* fix missing encryption utils in hardware wallet functions [skip ci]
* fix conflicts
* Include missed monero dll for windows.
* reformatting [skip ci]
* fix conflicts with main
* Disable haven configuration for iOS as default. Add ability to configure cakewallet for iOS with for configuration script. Remove cw_shared configuration for cw_monero.
* fix: scan fixes, add date, allow sending while scanning
* add missing nano secrets file [skip ci]
* ios library
* don't pull prebuilds android
* Add auto generation of manifest file for android project even for iOS, macOS, Windows.
* remove tron
* feat: sync fixes, sp settings
* feat: fix resyncing
* store crash fix
* make init async so it won't lag
disable print starts
* fix monero_c build issues
* libstdc++
* merge main and update version
* Fix MacOS saving wallet file issue
Fix Secure Storage issue (somehow)
* update pubspec.lock
* fix build script
* Use dylib as iOS framework. Use custom path for loading of iOS framework for monero.dart. Add script for generate iOS framework for monero wallet.
* fix: date from height logic, status disconnected & chain tip get
* fix: params
* feat: electrum migration if using cake electrum
* fix nodes
update versions
* re-enable tron
* update sp_scanner to work on iOS [skip ci]
* bump monero_c hash
* bump monero_c commit
* bump moneroc version
* bump monero_c commit
* Add ability to build monero wallet lib as universal lib. Update macOS build guide. Change default arch for macOS project to .
* fix: wrong socket for old electrum nodes
* update version
* Fix unchecked wallet type call
* get App Dir correctly in default_settings_migration.dart
* handle previous issue with fetching linux documents directory [skip ci]
* backup fix
* fix NTFS issues
* Add Tron
Update Linux version
* Close the wallet when the wallet gets changed
* fix: double balance
* feat: node domain
* fix: menu name
* bump monero_c commit
* fix: update tip on set scanning
* fix: connection switching back and forth
* feat: check if node is electrs, and supports sp
* chore: fix build
* minor enhancements
* fixes and enhancements
* solve conflicts with main
* Only stop wallet on rename and delete
* fix: status toggle
* minor enhancement
* Monero.com fixes
* bump monero_c commit
* update sp_scanner to include windows and linux
* merge main
* Update macOS build guide. Change brew dependencies for build unbound locally.
* fix: Tron file write, build scripts
* - merge linux with Monero Dart
- Temporarily disable Monero
* fix other issues with linux
* linux ci
fix build script
* Update pr_test_build_linux.yml
install required packages
* add linux desktop dependencies
* don't use apk in linux build releases
* don't copy the file to test-apk
* fix linux runtime issues
* remove libc++_shared.so
* fix issues with linux
* prepare both android and linux (because otherwise it will fail)
* ci script updates
* run apt update
* bump image to ubuntu 22.04
note: remember to put it down later
* bump python version
* remove some dependencies
* remove unused import
* add missing dependencies
* fix dependencies
* some fixes
* remove print [skip ci]
* Add back RunnerBase.entitlements
minor fixes [skip ci]
* fix memory leak / infinite recurrsion when opening xmr wallet
* url_launcher_linux: 3.1.1 # https://github.com/flutter/flutter/issues/153083
* fix conflicts with main
* handle walletKeysFile with encryptionUtils
* update app version [skip ci]
* add wownero [skip ci]
---------
Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
Co-authored-by: Rafael Saes <git@rafael.saes.dev>
Co-authored-by: M <m@cakewallet.com>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
This commit is contained in:
parent
3b635218a5
commit
1ce60d62b3
178 changed files with 3955 additions and 563 deletions
2
.github/workflows/cache_dependencies.yml
vendored
2
.github/workflows/cache_dependencies.yml
vendored
|
@ -25,7 +25,7 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: "11.x"
|
java-version: "17.x"
|
||||||
- name: Configure placeholder git details
|
- name: Configure placeholder git details
|
||||||
run: |
|
run: |
|
||||||
git config --global user.email "CI@cakewallet.com"
|
git config --global user.email "CI@cakewallet.com"
|
||||||
|
|
|
@ -53,7 +53,9 @@ jobs:
|
||||||
channel: stable
|
channel: stable
|
||||||
|
|
||||||
- name: Install package dependencies
|
- name: Install package dependencies
|
||||||
run: sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
|
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
|
- name: Execute Build and Setup Commands
|
||||||
run: |
|
run: |
|
186
.github/workflows/pr_test_build_linux.yml
vendored
Normal file
186
.github/workflows/pr_test_build_linux.yml
vendored
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
name: PR Test Build linux
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: "Branch name to build"
|
||||||
|
required: true
|
||||||
|
default: "main"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
PR_test_build:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
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_ENVg
|
||||||
|
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: "17.x"
|
||||||
|
- 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.19.6"
|
||||||
|
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-is-python3 libtool libtinfo5 cmake clang
|
||||||
|
|
||||||
|
- name: Install desktop dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y ninja-build libgtk-3-dev gperf
|
||||||
|
- 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 scripts && ./gen_android_manifest.sh && cd ..
|
||||||
|
cd cake_wallet/scripts/android/
|
||||||
|
source ./app_env.sh cakewallet
|
||||||
|
./app_config.sh
|
||||||
|
cd ../../..
|
||||||
|
cd cake_wallet/scripts/linux/
|
||||||
|
source ./app_env.sh cakewallet
|
||||||
|
./app_config.sh
|
||||||
|
cd ../../..
|
||||||
|
|
||||||
|
- 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: linux-${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh') }}
|
||||||
|
|
||||||
|
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
|
||||||
|
name: Generate Externals
|
||||||
|
run: |
|
||||||
|
cd /opt/android/cake_wallet/scripts/linux/
|
||||||
|
source ./app_env.sh cakewallet
|
||||||
|
./build_monero_all.sh
|
||||||
|
|
||||||
|
- name: Install Flutter dependencies
|
||||||
|
run: |
|
||||||
|
cd /opt/android/cake_wallet
|
||||||
|
flutter pub get
|
||||||
|
|
||||||
|
- 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 }}';" >> 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
|
||||||
|
|
||||||
|
- 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 linux --release
|
||||||
|
|
||||||
|
- name: Prepare release zip file
|
||||||
|
run: |
|
||||||
|
cd /opt/android/cake_wallet/build/linux/x64/release
|
||||||
|
zip -r ${{env.BRANCH_NAME}}.zip bundle
|
||||||
|
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: kittaakos/upload-artifact-as-is@v0
|
||||||
|
with:
|
||||||
|
path: /opt/android/cake_wallet/build/linux/x64/release/${{env.BRANCH_NAME}}.zip
|
||||||
|
|
||||||
|
- 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/linux/x64/release/${{env.BRANCH_NAME}}.zip
|
||||||
|
channel: ${{ secrets.SLACK_APK_CHANNEL }}
|
||||||
|
title: "${{ env.BRANCH_NAME }}_linux.zip"
|
||||||
|
filename: ${{ env.BRANCH_NAME }}_linux.zip
|
||||||
|
initial_comment: ${{ github.event.head_commit.message }}
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -160,6 +160,8 @@ macos/Runner/Release.entitlements
|
||||||
macos/Runner/Runner.entitlements
|
macos/Runner/Runner.entitlements
|
||||||
lib/core/secure_storage.dart
|
lib/core/secure_storage.dart
|
||||||
|
|
||||||
|
lib/core/secure_storage.dart
|
||||||
|
|
||||||
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
|
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
|
||||||
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
|
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
|
||||||
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
|
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
|
||||||
|
|
|
@ -18,6 +18,12 @@ migration:
|
||||||
- platform: windows
|
- platform: windows
|
||||||
create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
|
create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
|
||||||
base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
|
base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
|
||||||
|
- platform: macos
|
||||||
|
create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
|
||||||
|
base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
|
||||||
|
- platform: linux
|
||||||
|
create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
|
||||||
|
base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|
176
build-guide-linux.md
Normal file
176
build-guide-linux.md
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
# Building CakeWallet for Linux
|
||||||
|
|
||||||
|
## Requirements and Setup
|
||||||
|
|
||||||
|
The following are the system requirements to build CakeWallet for your Linux device.
|
||||||
|
|
||||||
|
```
|
||||||
|
Ubuntu >= 16.04
|
||||||
|
Flutter 3.10.x
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building CakeWallet on Linux
|
||||||
|
|
||||||
|
These steps will help you configure and execute a build of CakeWallet from its source code.
|
||||||
|
|
||||||
|
### 1. Installing Package Dependencies
|
||||||
|
|
||||||
|
CakeWallet requires some packages to be install on your build system. You may easily install them on your build system with the following command:
|
||||||
|
|
||||||
|
`$ sudo apt install build-essential cmake pkg-config git curl autoconf libtool`
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
>
|
||||||
|
> ### Check gcc version
|
||||||
|
>
|
||||||
|
> It is needed to use gcc 10 or 9 to successfully link dependencies with flutter.\
|
||||||
|
> To check what gcc version you are using:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> $ gcc --version
|
||||||
|
> $ g++ --version
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> If you are using gcc version newer than 10, then you need to downgrade to version 10.4.0:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> $ sudo apt install gcc-10 g++-10
|
||||||
|
> $ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
|
||||||
|
> $ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
|
||||||
|
> ```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> Alternatively, you can use the [nix-shell](https://nixos.org/) with the `gcc10.nix` file\
|
||||||
|
> present on `scripts/linux` like so:
|
||||||
|
> ```bash
|
||||||
|
> $ nix-shell gcc10.nix
|
||||||
|
> ```
|
||||||
|
> This will get you in a nix environment with all the required dependencies that you can use to build the software from,\
|
||||||
|
> and it works in any linux distro.
|
||||||
|
|
||||||
|
### 2. Installing Flutter
|
||||||
|
|
||||||
|
Need to install flutter. For this please check section [How to install flutter on Linux](https://docs.flutter.dev/get-started/install/linux).
|
||||||
|
|
||||||
|
### 3. Verify Installations
|
||||||
|
|
||||||
|
Verify that the Flutter have been correctly installed on your system with the following command:
|
||||||
|
|
||||||
|
`$ flutter doctor`
|
||||||
|
|
||||||
|
The output of this command will appear like this, indicating successful installations. If there are problems with your installation, they **must** be corrected before proceeding.
|
||||||
|
|
||||||
|
```
|
||||||
|
Doctor summary (to see all details, run flutter doctor -v):
|
||||||
|
[✓] Flutter (Channel stable, 3.10.x, on Linux, locale en_US.UTF-8)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Acquiring the CakeWallet Source Code
|
||||||
|
|
||||||
|
Download CakeWallet source code
|
||||||
|
|
||||||
|
`$ git clone https://github.com/cake-tech/cake_wallet.git --branch linux/password-direct-input`
|
||||||
|
|
||||||
|
Proceed into the source code before proceeding with the next steps:
|
||||||
|
|
||||||
|
`$ cd cake_wallet/scripts/linux/`
|
||||||
|
|
||||||
|
To configure some project properties run:
|
||||||
|
|
||||||
|
`$ ./cakewallet.sh`
|
||||||
|
|
||||||
|
Build the Monero libraries and their dependencies:
|
||||||
|
|
||||||
|
`$ ./build_all.sh`
|
||||||
|
|
||||||
|
Now the dependencies need to be copied into the CakeWallet project with this command:
|
||||||
|
|
||||||
|
`$ ./setup.sh`
|
||||||
|
|
||||||
|
It is now time to change back to the base directory of the CakeWallet source code:
|
||||||
|
|
||||||
|
`$ cd ../../`
|
||||||
|
|
||||||
|
Install Flutter package dependencies with this command:
|
||||||
|
|
||||||
|
`$ flutter pub get`
|
||||||
|
|
||||||
|
> #### If you will get an error like:
|
||||||
|
>
|
||||||
|
> ```
|
||||||
|
> The plugin `cw_shared_external` requires your app to be migrated to the Android embedding v2. Follow the steps on the migration doc above and re-run
|
||||||
|
> this command.
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Then need to config Android project settings. For this open `scripts/android` (`$ cd scripts/android`) directory and run followed commands:
|
||||||
|
>
|
||||||
|
> ```
|
||||||
|
> $ source ./app_env.sh cakewallet
|
||||||
|
> $ ./app_config.sh
|
||||||
|
> $ cd ../..
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Then re-configure Linux project again. For this open `scripts/linux` (`$cd scripts/linux`) directory and run:
|
||||||
|
> `$ ./cakewallet.sh`
|
||||||
|
> and back to project root directory:
|
||||||
|
> `$ cd ../..`
|
||||||
|
> and fetch dependecies again
|
||||||
|
> `$ flutter pub get`
|
||||||
|
|
||||||
|
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`
|
||||||
|
|
||||||
|
We will generate mobx models for the project.
|
||||||
|
|
||||||
|
`$ ./model_generator.sh`
|
||||||
|
|
||||||
|
Then we need to generate localization files.
|
||||||
|
|
||||||
|
`$ flutter packages pub run tool/generate_localization.dart`
|
||||||
|
|
||||||
|
### 5. Build!
|
||||||
|
|
||||||
|
`$ flutter build linux --release`
|
||||||
|
|
||||||
|
Path to executable file will be:
|
||||||
|
|
||||||
|
`build/linux/x64/release/bundle/cake_wallet`
|
||||||
|
|
||||||
|
> ### Troubleshooting
|
||||||
|
>
|
||||||
|
> If you got an error while building the application with `$ flutter build linux --release` command, add `-v` argument to the command (`$ flutter build linux -v --release`) to get details.\
|
||||||
|
> If you got in flutter build logs: undefined reference to `hid_free_enumeration`, or another error with undefined reference to `hid_*`, then rebuild monero lib without hidapi lib. Check does exists `libhidapi-dev` in your scope and remove it from your scope for build without it.
|
||||||
|
|
||||||
|
# Flatpak
|
||||||
|
|
||||||
|
For package the built application into flatpak you need fistly to install `flatpak` and `flatpak-builder`:
|
||||||
|
|
||||||
|
`$ sudo apt install flatpak flatpak-builder`
|
||||||
|
|
||||||
|
Then need to [add flathub](https://flatpak.org/setup/Ubuntu) (or just `$ flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo`). Then need to install freedesktop runtime and sdk:
|
||||||
|
|
||||||
|
`$ flatpak install flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08`
|
||||||
|
|
||||||
|
To build with using of `flatpak-build` directory run next:
|
||||||
|
|
||||||
|
`$ flatpak-builder --force-clean flatpak-build com.cakewallet.CakeWallet.yml`
|
||||||
|
|
||||||
|
And then export bundle:
|
||||||
|
|
||||||
|
`$ flatpak build-export export flatpak-build`
|
||||||
|
|
||||||
|
`$ flatpak build-bundle export cake_wallet.flatpak com.cakewallet.CakeWallet`
|
||||||
|
|
||||||
|
Result file: `cake_wallet.flatpak` should be generated in current directory.
|
||||||
|
|
||||||
|
For install generated flatpak file use:
|
||||||
|
|
||||||
|
`$ flatpak --user install cake_wallet.flatpak`
|
||||||
|
|
||||||
|
For run the installed application run:
|
||||||
|
|
||||||
|
`$ flatpak run com.cakewallet.CakeWallet`
|
||||||
|
|
||||||
|
Copyright (c) 2023 Cake Technologies LLC.
|
35
com.cakewallet.CakeWallet.yml
Normal file
35
com.cakewallet.CakeWallet.yml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
app-id: com.cakewallet.CakeWallet
|
||||||
|
runtime: org.freedesktop.Platform
|
||||||
|
runtime-version: '22.08'
|
||||||
|
sdk: org.freedesktop.Sdk
|
||||||
|
command: cake_wallet
|
||||||
|
separate-locales: false
|
||||||
|
finish-args:
|
||||||
|
- --share=ipc
|
||||||
|
- --socket=fallback-x11
|
||||||
|
- --socket=wayland
|
||||||
|
- --device=dri
|
||||||
|
- --socket=pulseaudio
|
||||||
|
- --share=network
|
||||||
|
- --filesystem=home
|
||||||
|
modules:
|
||||||
|
- name: cake_wallet
|
||||||
|
buildsystem: simple
|
||||||
|
only-arches:
|
||||||
|
- x86_64
|
||||||
|
build-commands:
|
||||||
|
- "cp -R bundle /app/cake_wallet"
|
||||||
|
- "chmod +x /app/cake_wallet/cake_wallet"
|
||||||
|
- "mkdir -p /app/bin"
|
||||||
|
- "ln -s /app/cake_wallet/cake_wallet /app/bin/cake_wallet"
|
||||||
|
- "mkdir -p /app/share/icons/hicolor/scalable/apps"
|
||||||
|
- "cp cakewallet_icon_180.png /app/share/icons/hicolor/scalable/apps/com.cakewallet.CakeWallet.png"
|
||||||
|
- "mkdir -p /app/share/applications"
|
||||||
|
- "cp com.cakewallet.CakeWallet.desktop /app/share/applications"
|
||||||
|
sources:
|
||||||
|
- type: dir
|
||||||
|
path: build/linux/x64/release
|
||||||
|
- type: file
|
||||||
|
path: assets/images/cakewallet_icon_180.png
|
||||||
|
- type: file
|
||||||
|
path: linux/com.cakewallet.CakeWallet.desktop
|
|
@ -3,12 +3,13 @@
|
||||||
IOS="ios"
|
IOS="ios"
|
||||||
ANDROID="android"
|
ANDROID="android"
|
||||||
MACOS="macos"
|
MACOS="macos"
|
||||||
|
LINUX="linux"
|
||||||
|
|
||||||
PLATFORMS=($IOS $ANDROID $MACOS)
|
PLATFORMS=($IOS $ANDROID $MACOS $LINUX)
|
||||||
PLATFORM=$1
|
PLATFORM=$1
|
||||||
|
|
||||||
if ! [[ " ${PLATFORMS[*]} " =~ " ${PLATFORM} " ]]; then
|
if ! [[ " ${PLATFORMS[*]} " =~ " ${PLATFORM} " ]]; then
|
||||||
echo "specify platform: ./configure_cake_wallet.sh ios|android|macos"
|
echo "specify platform: ./configure_cake_wallet.sh ios|android|macos|linux"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -27,9 +28,14 @@ if [ "$PLATFORM" == "$ANDROID" ]; then
|
||||||
cd scripts/android
|
cd scripts/android
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$PLATFORM" == "$LINUX" ]; then
|
||||||
|
echo "Configuring for linux"
|
||||||
|
cd scripts/linux
|
||||||
|
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
|
flutter packages pub run tool/generate_localization.dart
|
||||||
./model_generator.sh
|
./model_generator.sh
|
||||||
#cd macos && pod install
|
#cd macos && pod install
|
|
@ -5,9 +5,10 @@ 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/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
||||||
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
|
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
|
||||||
|
@ -30,6 +31,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
Uint8List? seedBytes,
|
Uint8List? seedBytes,
|
||||||
String? mnemonic,
|
String? mnemonic,
|
||||||
String? xpub,
|
String? xpub,
|
||||||
|
@ -58,6 +60,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
currency:
|
currency:
|
||||||
networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
|
networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
|
@ -90,6 +93,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
String? passphrase,
|
String? passphrase,
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
BasedUtxoNetwork? network,
|
BasedUtxoNetwork? network,
|
||||||
|
@ -124,6 +128,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialSilentAddresses: initialSilentAddresses,
|
initialSilentAddresses: initialSilentAddresses,
|
||||||
initialSilentAddressIndex: initialSilentAddressIndex,
|
initialSilentAddressIndex: initialSilentAddressIndex,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
|
@ -137,6 +142,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required String password,
|
required String password,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
required bool alwaysScan,
|
required bool alwaysScan,
|
||||||
}) async {
|
}) async {
|
||||||
final network = walletInfo.network != null
|
final network = walletInfo.network != null
|
||||||
|
@ -148,7 +154,13 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
ElectrumWalletSnapshot? snp = null;
|
ElectrumWalletSnapshot? snp = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, network);
|
snp = await ElectrumWalletSnapshot.load(
|
||||||
|
encryptionFileUtils,
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
network,
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!hasKeysFile) rethrow;
|
if (!hasKeysFile) rethrow;
|
||||||
}
|
}
|
||||||
|
@ -156,10 +168,18 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
final WalletKeysData keysData;
|
final WalletKeysData keysData;
|
||||||
// Migrate wallet from the old scheme to then new .keys file scheme
|
// Migrate wallet from the old scheme to then new .keys file scheme
|
||||||
if (!hasKeysFile) {
|
if (!hasKeysFile) {
|
||||||
keysData =
|
keysData = WalletKeysData(
|
||||||
WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
|
mnemonic: snp!.mnemonic,
|
||||||
|
xPub: snp.xpub,
|
||||||
|
passphrase: snp.passphrase,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
|
keysData = await WalletKeysFile.readKeysFile(
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
walletInfo.derivationInfo ??= DerivationInfo();
|
walletInfo.derivationInfo ??= DerivationInfo();
|
||||||
|
@ -198,6 +218,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialSilentAddresses: snp?.silentAddresses,
|
initialSilentAddresses: snp?.silentAddresses,
|
||||||
initialSilentAddressIndex: snp?.silentAddressIndex ?? 0,
|
initialSilentAddressIndex: snp?.silentAddressIndex ?? 0,
|
||||||
initialBalance: snp?.balance,
|
initialBalance: snp?.balance,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
initialRegularAddressIndex: snp?.regularAddressIndex,
|
initialRegularAddressIndex: snp?.regularAddressIndex,
|
||||||
initialChangeAddressIndex: snp?.changeAddressIndex,
|
initialChangeAddressIndex: snp?.changeAddressIndex,
|
||||||
|
|
|
@ -6,11 +6,13 @@ class BitcoinNewWalletCredentials extends WalletCredentials {
|
||||||
BitcoinNewWalletCredentials(
|
BitcoinNewWalletCredentials(
|
||||||
{required String name,
|
{required String name,
|
||||||
WalletInfo? walletInfo,
|
WalletInfo? walletInfo,
|
||||||
|
String? password,
|
||||||
DerivationType? derivationType,
|
DerivationType? derivationType,
|
||||||
String? derivationPath})
|
String? derivationPath})
|
||||||
: super(
|
: super(
|
||||||
name: name,
|
name: name,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
password: password,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
@ -19,11 +20,12 @@ class BitcoinWalletService extends WalletService<
|
||||||
BitcoinRestoreWalletFromSeedCredentials,
|
BitcoinRestoreWalletFromSeedCredentials,
|
||||||
BitcoinRestoreWalletFromWIFCredentials,
|
BitcoinRestoreWalletFromWIFCredentials,
|
||||||
BitcoinRestoreWalletFromHardware> {
|
BitcoinRestoreWalletFromHardware> {
|
||||||
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.alwaysScan);
|
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.alwaysScan, this.isDirect);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||||
final bool alwaysScan;
|
final bool alwaysScan;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletType getType() => WalletType.bitcoin;
|
WalletType getType() => WalletType.bitcoin;
|
||||||
|
@ -40,6 +42,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
network: network,
|
network: network,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
|
@ -63,6 +66,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
saveBackup(name);
|
saveBackup(name);
|
||||||
|
@ -75,6 +79,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -99,6 +104,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
walletInfo: currentWalletInfo,
|
walletInfo: currentWalletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
|
@ -125,6 +131,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
networkParam: network,
|
networkParam: network,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -153,6 +160,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
network: network,
|
network: network,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
|
||||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
@ -6,6 +7,8 @@ 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/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_bitcoin/electrum_transaction_info.dart';
|
||||||
|
|
||||||
part 'electrum_transaction_history.g.dart';
|
part 'electrum_transaction_history.g.dart';
|
||||||
|
|
||||||
|
@ -15,13 +18,15 @@ class ElectrumTransactionHistory = ElectrumTransactionHistoryBase with _$Electru
|
||||||
|
|
||||||
abstract class ElectrumTransactionHistoryBase
|
abstract class ElectrumTransactionHistoryBase
|
||||||
extends TransactionHistoryBase<ElectrumTransactionInfo> with Store {
|
extends TransactionHistoryBase<ElectrumTransactionInfo> with Store {
|
||||||
ElectrumTransactionHistoryBase({required this.walletInfo, required String password})
|
ElectrumTransactionHistoryBase(
|
||||||
|
{required this.walletInfo, required String password, required this.encryptionFileUtils})
|
||||||
: _password = password,
|
: _password = password,
|
||||||
_height = 0 {
|
_height = 0 {
|
||||||
transactions = ObservableMap<String, ElectrumTransactionInfo>();
|
transactions = ObservableMap<String, ElectrumTransactionInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletInfo walletInfo;
|
final WalletInfo walletInfo;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
String _password;
|
String _password;
|
||||||
int _height;
|
int _height;
|
||||||
|
|
||||||
|
@ -44,7 +49,7 @@ abstract class ElectrumTransactionHistoryBase
|
||||||
txjson[tx.key] = tx.value.toJson();
|
txjson[tx.key] = tx.value.toJson();
|
||||||
}
|
}
|
||||||
final data = json.encode({'height': _height, 'transactions': txjson});
|
final data = json.encode({'height': _height, 'transactions': txjson});
|
||||||
await writeData(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()}');
|
print('Error while save bitcoin transaction history: ${e.toString()}');
|
||||||
}
|
}
|
||||||
|
@ -58,7 +63,7 @@ abstract class ElectrumTransactionHistoryBase
|
||||||
Future<Map<String, dynamic>> _read() async {
|
Future<Map<String, dynamic>> _read() async {
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final content = await read(path: path, password: _password);
|
final content = await encryptionFileUtils.read(path: path, password: _password);
|
||||||
return json.decode(content) as Map<String, dynamic>;
|
return json.decode(content) as Map<String, dynamic>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:isolate';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:cw_bitcoin/address_from_output.dart';
|
import 'package:cw_bitcoin/address_from_output.dart';
|
||||||
|
@ -32,7 +33,6 @@ 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/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_core/utils/file.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';
|
||||||
|
@ -58,6 +58,7 @@ abstract class ElectrumWalletBase
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required this.network,
|
required this.network,
|
||||||
|
required this.encryptionFileUtils,
|
||||||
String? xpub,
|
String? xpub,
|
||||||
String? mnemonic,
|
String? mnemonic,
|
||||||
Uint8List? seedBytes,
|
Uint8List? seedBytes,
|
||||||
|
@ -92,7 +93,11 @@ abstract class ElectrumWalletBase
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.electrumClient = electrumClient ?? ElectrumClient();
|
this.electrumClient = electrumClient ?? ElectrumClient();
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory = ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
|
transactionHistory = ElectrumTransactionHistory(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
password: password,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
|
);
|
||||||
|
|
||||||
reaction((_) => syncStatus, _syncStatusReaction);
|
reaction((_) => syncStatus, _syncStatusReaction);
|
||||||
}
|
}
|
||||||
|
@ -127,6 +132,8 @@ abstract class ElectrumWalletBase
|
||||||
final String? _mnemonic;
|
final String? _mnemonic;
|
||||||
|
|
||||||
Bip32Slip10Secp256k1 get hd => accountHD.childKey(Bip32KeyIndex(0));
|
Bip32Slip10Secp256k1 get hd => accountHD.childKey(Bip32KeyIndex(0));
|
||||||
|
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
final String? passphrase;
|
final String? passphrase;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -167,6 +174,9 @@ abstract class ElectrumWalletBase
|
||||||
WalletKeysData get walletKeysData =>
|
WalletKeysData get walletKeysData =>
|
||||||
WalletKeysData(mnemonic: _mnemonic, xPub: xpub, passphrase: passphrase);
|
WalletKeysData(mnemonic: _mnemonic, xPub: xpub, passphrase: passphrase);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get password => _password;
|
||||||
|
|
||||||
BasedUtxoNetwork network;
|
BasedUtxoNetwork network;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -455,7 +465,6 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
node!.isElectrs = false;
|
node!.isElectrs = false;
|
||||||
node!.save();
|
node!.save();
|
||||||
return node!.isElectrs!;
|
return node!.isElectrs!;
|
||||||
|
@ -1130,12 +1139,12 @@ abstract class ElectrumWalletBase
|
||||||
@override
|
@override
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
||||||
await saveKeysFile(_password);
|
await saveKeysFile(_password, encryptionFileUtils);
|
||||||
saveKeysFile(_password, true);
|
saveKeysFile(_password, encryptionFileUtils, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
final path = await makePath();
|
final path = await makePath();
|
||||||
await write(path: path, password: _password, data: toJSON());
|
await encryptionFileUtils.write(path: path, password: _password, data: toJSON());
|
||||||
await transactionHistory.save();
|
await transactionHistory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2258,4 +2267,3 @@ class UtxoDetails {
|
||||||
required this.spendsUnconfirmedTX,
|
required this.spendsUnconfirmedTX,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -51,9 +52,9 @@ class ElectrumWalletSnapshot {
|
||||||
String? derivationPath;
|
String? derivationPath;
|
||||||
|
|
||||||
static Future<ElectrumWalletSnapshot> load(
|
static Future<ElectrumWalletSnapshot> load(
|
||||||
String name, WalletType type, String password, BasedUtxoNetwork network) async {
|
EncryptionFileUtils encryptionFileUtils, String name, WalletType type, String password, BasedUtxoNetwork network) async {
|
||||||
final path = await pathForWallet(name: name, type: type);
|
final path = await pathForWallet(name: name, type: type);
|
||||||
final jsonSource = await read(path: path, password: password);
|
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
|
||||||
final data = json.decode(jsonSource) as Map;
|
final data = json.decode(jsonSource) as Map;
|
||||||
final addressesTmp = data['addresses'] as List? ?? <Object>[];
|
final addressesTmp = data['addresses'] as List? ?? <Object>[];
|
||||||
final mnemonic = data['mnemonic'] as String?;
|
final mnemonic = data['mnemonic'] as String?;
|
||||||
|
|
|
@ -4,13 +4,14 @@ 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/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
||||||
import 'package:cw_bitcoin/litecoin_wallet_addresses.dart';
|
import 'package:cw_bitcoin/litecoin_wallet_addresses.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.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';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -28,6 +29,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required Uint8List seedBytes,
|
required Uint8List seedBytes,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
ElectrumBalance? initialBalance,
|
ElectrumBalance? initialBalance,
|
||||||
|
@ -42,6 +44,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
currency: CryptoCurrency.ltc) {
|
currency: CryptoCurrency.ltc) {
|
||||||
walletAddresses = LitecoinWalletAddresses(
|
walletAddresses = LitecoinWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
|
@ -62,6 +65,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
String? passphrase,
|
String? passphrase,
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
|
@ -89,6 +93,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
|
@ -96,19 +101,24 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LitecoinWallet> open({
|
static Future<LitecoinWallet> open(
|
||||||
required String name,
|
{required String name,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required String password,
|
required String password,
|
||||||
}) async {
|
required EncryptionFileUtils encryptionFileUtils}) async {
|
||||||
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
||||||
|
|
||||||
ElectrumWalletSnapshot? snp = null;
|
ElectrumWalletSnapshot? snp = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
snp = await ElectrumWalletSnapshot.load(
|
snp = await ElectrumWalletSnapshot.load(
|
||||||
name, walletInfo.type, password, LitecoinNetwork.mainnet);
|
encryptionFileUtils,
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
LitecoinNetwork.mainnet,
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!hasKeysFile) rethrow;
|
if (!hasKeysFile) rethrow;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +129,12 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
keysData =
|
keysData =
|
||||||
WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
|
WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
|
||||||
} else {
|
} else {
|
||||||
keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
|
keysData = await WalletKeysFile.readKeysFile(
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return LitecoinWallet(
|
return LitecoinWallet(
|
||||||
|
@ -130,6 +145,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialAddresses: snp?.addresses,
|
initialAddresses: snp?.addresses,
|
||||||
initialBalance: snp?.balance,
|
initialBalance: snp?.balance,
|
||||||
seedBytes: await mnemonicToSeedBytes(keysData.mnemonic!),
|
seedBytes: await mnemonicToSeedBytes(keysData.mnemonic!),
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
initialRegularAddressIndex: snp?.regularAddressIndex,
|
initialRegularAddressIndex: snp?.regularAddressIndex,
|
||||||
initialChangeAddressIndex: snp?.changeAddressIndex,
|
initialChangeAddressIndex: snp?.changeAddressIndex,
|
||||||
addressPageType: snp?.addressPageType,
|
addressPageType: snp?.addressPageType,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
@ -16,11 +17,13 @@ import 'package:bip39/bip39.dart' as bip39;
|
||||||
class LitecoinWalletService extends WalletService<
|
class LitecoinWalletService extends WalletService<
|
||||||
BitcoinNewWalletCredentials,
|
BitcoinNewWalletCredentials,
|
||||||
BitcoinRestoreWalletFromSeedCredentials,
|
BitcoinRestoreWalletFromSeedCredentials,
|
||||||
BitcoinRestoreWalletFromWIFCredentials,BitcoinNewWalletCredentials> {
|
BitcoinRestoreWalletFromWIFCredentials,
|
||||||
LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
BitcoinNewWalletCredentials> {
|
||||||
|
LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletType getType() => WalletType.litecoin;
|
WalletType getType() => WalletType.litecoin;
|
||||||
|
@ -32,8 +35,9 @@ class LitecoinWalletService extends WalletService<
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
passphrase: credentials.passphrase,
|
passphrase: credentials.passphrase,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
|
@ -46,21 +50,29 @@ class LitecoinWalletService extends WalletService<
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LitecoinWallet> openWallet(String name, String password) async {
|
Future<LitecoinWallet> openWallet(String name, String password) async {
|
||||||
final walletInfo = walletInfoSource.values.firstWhereOrNull(
|
final walletInfo = walletInfoSource.values
|
||||||
(info) => info.id == WalletBase.idFor(name, getType()))!;
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final wallet = await LitecoinWalletBase.open(
|
final wallet = await LitecoinWalletBase.open(
|
||||||
password: password, name: name, walletInfo: walletInfo,
|
password: password,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
name: name,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
saveBackup(name);
|
saveBackup(name);
|
||||||
return wallet;
|
return wallet;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
await restoreWalletFilesFromBackup(name);
|
await restoreWalletFilesFromBackup(name);
|
||||||
final wallet = await LitecoinWalletBase.open(
|
final wallet = await LitecoinWalletBase.open(
|
||||||
password: password, name: name, walletInfo: walletInfo,
|
password: password,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
name: name,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
@ -68,22 +80,23 @@ class LitecoinWalletService extends WalletService<
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> remove(String wallet) async {
|
Future<void> remove(String wallet) async {
|
||||||
File(await pathForWalletDir(name: wallet, type: getType()))
|
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
|
||||||
.delete(recursive: true);
|
final walletInfo = walletInfoSource.values
|
||||||
final walletInfo = walletInfoSource.values.firstWhereOrNull(
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
||||||
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
|
||||||
await walletInfoSource.delete(walletInfo.key);
|
await walletInfoSource.delete(walletInfo.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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.firstWhereOrNull(
|
final currentWalletInfo = walletInfoSource.values
|
||||||
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
|
||||||
final currentWallet = await LitecoinWalletBase.open(
|
final currentWallet = await LitecoinWalletBase.open(
|
||||||
password: password,
|
password: password,
|
||||||
name: currentName,
|
name: currentName,
|
||||||
walletInfo: currentWalletInfo,
|
walletInfo: currentWalletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
await saveBackup(newName);
|
await saveBackup(newName);
|
||||||
|
@ -97,17 +110,18 @@ class LitecoinWalletService extends WalletService<
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LitecoinWallet> restoreFromHardwareWallet(BitcoinNewWalletCredentials credentials) {
|
Future<LitecoinWallet> restoreFromHardwareWallet(BitcoinNewWalletCredentials credentials) {
|
||||||
throw UnimplementedError("Restoring a Litecoin wallet from a hardware wallet is not yet supported!");
|
throw UnimplementedError(
|
||||||
|
"Restoring a Litecoin wallet from a hardware wallet is not yet supported!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LitecoinWallet> restoreFromKeys(
|
Future<LitecoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials,
|
||||||
BitcoinRestoreWalletFromWIFCredentials credentials, {bool? isTestnet}) async =>
|
{bool? isTestnet}) async =>
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LitecoinWallet> restoreFromSeed(
|
Future<LitecoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
|
||||||
BitcoinRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
|
{bool? isTestnet}) async {
|
||||||
if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) {
|
if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) {
|
||||||
throw LitecoinMnemonicIsIncorrectException();
|
throw LitecoinMnemonicIsIncorrectException();
|
||||||
}
|
}
|
||||||
|
@ -117,7 +131,9 @@ class LitecoinWalletService extends WalletService<
|
||||||
passphrase: credentials.passphrase,
|
passphrase: credentials.passphrase,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
return wallet;
|
return wallet;
|
||||||
|
|
|
@ -164,6 +164,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.9.2"
|
version: "8.9.2"
|
||||||
|
cake_backup:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: main
|
||||||
|
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
||||||
|
url: "https://github.com/cake-tech/cake_backup.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.0+1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -236,6 +245,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.7.0"
|
version: "2.7.0"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
cw_core:
|
cw_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -837,6 +854,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:bitbox/bitbox.dart' as bitbox;
|
import 'package:bitbox/bitbox.dart' as bitbox;
|
||||||
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_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
|
@ -28,6 +29,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required Uint8List seedBytes,
|
required Uint8List seedBytes,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
BitcoinAddressType? addressPageType,
|
BitcoinAddressType? addressPageType,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
ElectrumBalance? initialBalance,
|
ElectrumBalance? initialBalance,
|
||||||
|
@ -42,7 +44,8 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
currency: CryptoCurrency.bch) {
|
currency: CryptoCurrency.bch,
|
||||||
|
encryptionFileUtils: encryptionFileUtils) {
|
||||||
walletAddresses = BitcoinCashWalletAddresses(
|
walletAddresses = BitcoinCashWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
|
@ -63,6 +66,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
ElectrumBalance? initialBalance,
|
ElectrumBalance? initialBalance,
|
||||||
|
@ -76,6 +80,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: await MnemonicBip39.toSeed(mnemonic),
|
seedBytes: await MnemonicBip39.toSeed(mnemonic),
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
addressPageType: P2pkhAddressType.p2pkh,
|
addressPageType: P2pkhAddressType.p2pkh,
|
||||||
|
@ -87,6 +92,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required String password,
|
required String password,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
}) async {
|
}) async {
|
||||||
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
||||||
|
|
||||||
|
@ -94,7 +100,12 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
snp = await ElectrumWalletSnapshot.load(
|
snp = await ElectrumWalletSnapshot.load(
|
||||||
name, walletInfo.type, password, BitcoinCashNetwork.mainnet);
|
encryptionFileUtils,
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
BitcoinCashNetwork.mainnet,
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!hasKeysFile) rethrow;
|
if (!hasKeysFile) rethrow;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +116,12 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
keysData =
|
keysData =
|
||||||
WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
|
WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
|
||||||
} else {
|
} else {
|
||||||
keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
|
keysData = await WalletKeysFile.readKeysFile(
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BitcoinCashWallet(
|
return BitcoinCashWallet(
|
||||||
|
@ -135,6 +151,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
}).toList(),
|
}).toList(),
|
||||||
initialBalance: snp?.balance,
|
initialBalance: snp?.balance,
|
||||||
seedBytes: await MnemonicBip39.toSeed(keysData.mnemonic!),
|
seedBytes: await MnemonicBip39.toSeed(keysData.mnemonic!),
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
initialRegularAddressIndex: snp?.regularAddressIndex,
|
initialRegularAddressIndex: snp?.regularAddressIndex,
|
||||||
initialChangeAddressIndex: snp?.changeAddressIndex,
|
initialChangeAddressIndex: snp?.changeAddressIndex,
|
||||||
addressPageType: P2pkhAddressType.p2pkh,
|
addressPageType: P2pkhAddressType.p2pkh,
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
class BitcoinCashNewWalletCredentials extends WalletCredentials {
|
class BitcoinCashNewWalletCredentials extends WalletCredentials {
|
||||||
BitcoinCashNewWalletCredentials({required String name, WalletInfo? walletInfo})
|
BitcoinCashNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
|
||||||
: super(name: name, walletInfo: walletInfo);
|
: super(name: name, walletInfo: walletInfo, password: password);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitcoinCashRestoreWalletFromSeedCredentials extends WalletCredentials {
|
class BitcoinCashRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:bip39/bip39.dart';
|
import 'package:bip39/bip39.dart';
|
||||||
import 'package:cw_bitcoin_cash/cw_bitcoin_cash.dart';
|
import 'package:cw_bitcoin_cash/cw_bitcoin_cash.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/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
@ -16,10 +17,11 @@ class BitcoinCashWalletService extends WalletService<
|
||||||
BitcoinCashRestoreWalletFromSeedCredentials,
|
BitcoinCashRestoreWalletFromSeedCredentials,
|
||||||
BitcoinCashRestoreWalletFromWIFCredentials,
|
BitcoinCashRestoreWalletFromWIFCredentials,
|
||||||
BitcoinCashNewWalletCredentials> {
|
BitcoinCashNewWalletCredentials> {
|
||||||
BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletType getType() => WalletType.bitcoinCash;
|
WalletType getType() => WalletType.bitcoinCash;
|
||||||
|
@ -36,8 +38,9 @@ class BitcoinCashWalletService extends WalletService<
|
||||||
mnemonic: await MnemonicBip39.generate(strength: strength),
|
mnemonic: await MnemonicBip39.generate(strength: strength),
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
|
@ -54,7 +57,9 @@ class BitcoinCashWalletService extends WalletService<
|
||||||
password: password,
|
password: password,
|
||||||
name: name,
|
name: name,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
saveBackup(name);
|
saveBackup(name);
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -64,7 +69,9 @@ class BitcoinCashWalletService extends WalletService<
|
||||||
password: password,
|
password: password,
|
||||||
name: name,
|
name: name,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +93,8 @@ class BitcoinCashWalletService extends WalletService<
|
||||||
password: password,
|
password: password,
|
||||||
name: currentName,
|
name: currentName,
|
||||||
walletInfo: currentWalletInfo,
|
walletInfo: currentWalletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
await saveBackup(newName);
|
await saveBackup(newName);
|
||||||
|
@ -121,7 +129,8 @@ class BitcoinCashWalletService extends WalletService<
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
return wallet;
|
return wallet;
|
||||||
|
|
42
cw_core/lib/encryption_file_utils.dart
Normal file
42
cw_core/lib/encryption_file_utils.dart
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:cw_core/utils/file.dart' as file;
|
||||||
|
import 'package:cake_backup/backup.dart' as cwb;
|
||||||
|
|
||||||
|
EncryptionFileUtils encryptionFileUtilsFor(bool direct)
|
||||||
|
=> direct
|
||||||
|
? XChaCha20EncryptionFileUtils()
|
||||||
|
: Salsa20EncryhptionFileUtils();
|
||||||
|
|
||||||
|
abstract class EncryptionFileUtils {
|
||||||
|
Future<void> write({required String path, required String password, required String data});
|
||||||
|
Future<String> read({required String path, required String password});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Salsa20EncryhptionFileUtils extends EncryptionFileUtils {
|
||||||
|
// Requires legacy complex key + iv as password
|
||||||
|
@override
|
||||||
|
Future<void> write({required String path, required String password, required String data}) async
|
||||||
|
=> await file.write(path: path, password: password, data: data);
|
||||||
|
|
||||||
|
// Requires legacy complex key + iv as password
|
||||||
|
@override
|
||||||
|
Future<String> read({required String path, required String password}) async
|
||||||
|
=> await file.read(path: path, password: password);
|
||||||
|
}
|
||||||
|
|
||||||
|
class XChaCha20EncryptionFileUtils extends EncryptionFileUtils {
|
||||||
|
@override
|
||||||
|
Future<void> write({required String path, required String password, required String data}) async {
|
||||||
|
final encrypted = await cwb.encrypt(password, Uint8List.fromList(data.codeUnits));
|
||||||
|
await File(path).writeAsBytes(encrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> read({required String path, required String password}) async {
|
||||||
|
final file = File(path);
|
||||||
|
final encrypted = await file.readAsBytes();
|
||||||
|
final bytes = await cwb.decrypt(password, encrypted);
|
||||||
|
return String.fromCharCodes(bytes);
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,8 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
|
||||||
|
|
||||||
Future<void> changePassword(String password);
|
Future<void> changePassword(String password);
|
||||||
|
|
||||||
|
String get password;
|
||||||
|
|
||||||
Future<void>? updateBalance();
|
Future<void>? updateBalance();
|
||||||
|
|
||||||
void setExceptionHandler(void Function(FlutterErrorDetails) onError) => null;
|
void setExceptionHandler(void Function(FlutterErrorDetails) onError) => null;
|
||||||
|
|
|
@ -3,10 +3,10 @@ import 'dart:developer' as dev;
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.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/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cw_core/utils/file.dart';
|
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
@ -20,28 +20,32 @@ mixin WalletKeysFile<BalanceType extends Balance, HistoryType extends Transactio
|
||||||
|
|
||||||
Future<String> makeKeysFilePath() async => "${await makePath()}.keys";
|
Future<String> makeKeysFilePath() async => "${await makePath()}.keys";
|
||||||
|
|
||||||
Future<void> saveKeysFile(String password, [bool isBackup = false]) async {
|
Future<void> saveKeysFile(String password, EncryptionFileUtils encryptionFileUtils,
|
||||||
|
[bool isBackup = false]) async {
|
||||||
try {
|
try {
|
||||||
final rootPath = await makeKeysFilePath();
|
final rootPath = await makeKeysFilePath();
|
||||||
final path = "$rootPath${isBackup ? ".backup" : ""}";
|
final path = "$rootPath${isBackup ? ".backup" : ""}";
|
||||||
dev.log("Saving .keys file '$path'");
|
dev.log("Saving .keys file '$path'");
|
||||||
await write(path: path, password: password, data: walletKeysData.toJSON());
|
await encryptionFileUtils.write(
|
||||||
|
path: path, password: password, data: walletKeysData.toJSON());
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> createKeysFile(
|
static Future<void> createKeysFile(String name, WalletType type, String password,
|
||||||
String name, WalletType type, String password, WalletKeysData walletKeysData,
|
WalletKeysData walletKeysData, EncryptionFileUtils encryptionFileUtils,
|
||||||
[bool withBackup = true]) async {
|
[bool withBackup = true]) async {
|
||||||
try {
|
try {
|
||||||
final rootPath = await pathForWallet(name: name, type: type);
|
final rootPath = await pathForWallet(name: name, type: type);
|
||||||
final path = "$rootPath.keys";
|
final path = "$rootPath.keys";
|
||||||
|
|
||||||
dev.log("Saving .keys file '$path'");
|
dev.log("Saving .keys file '$path'");
|
||||||
await write(path: path, password: password, data: walletKeysData.toJSON());
|
await encryptionFileUtils.write(
|
||||||
|
path: path, password: password, data: walletKeysData.toJSON());
|
||||||
|
|
||||||
if (withBackup) {
|
if (withBackup) {
|
||||||
dev.log("Saving .keys.backup file '$path.backup'");
|
dev.log("Saving .keys.backup file '$path.backup'");
|
||||||
await write(path: "$path.backup", password: password, data: walletKeysData.toJSON());
|
await encryptionFileUtils.write(
|
||||||
|
path: "$path.backup", password: password, data: walletKeysData.toJSON());
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
@ -55,14 +59,19 @@ mixin WalletKeysFile<BalanceType extends Balance, HistoryType extends Transactio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<WalletKeysData> readKeysFile(String name, WalletType type, String password) async {
|
static Future<WalletKeysData> readKeysFile(
|
||||||
|
String name,
|
||||||
|
WalletType type,
|
||||||
|
String password,
|
||||||
|
EncryptionFileUtils encryptionFileUtils,
|
||||||
|
) async {
|
||||||
final path = await pathForWallet(name: name, type: type);
|
final path = await pathForWallet(name: name, type: type);
|
||||||
|
|
||||||
var readPath = "$path.keys";
|
var readPath = "$path.keys";
|
||||||
try {
|
try {
|
||||||
if (!File(readPath).existsSync()) throw Exception("No .keys file found for $name $type");
|
if (!File(readPath).existsSync()) throw Exception("No .keys file found for $name $type");
|
||||||
|
|
||||||
final jsonSource = await read(path: readPath, password: password);
|
final jsonSource = await encryptionFileUtils.read(path: readPath, password: password);
|
||||||
final data = json.decode(jsonSource) as Map<String, dynamic>;
|
final data = json.decode(jsonSource) as Map<String, dynamic>;
|
||||||
return WalletKeysData.fromJSON(data);
|
return WalletKeysData.fromJSON(data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -72,12 +81,12 @@ mixin WalletKeysFile<BalanceType extends Balance, HistoryType extends Transactio
|
||||||
if (!File(readPath).existsSync())
|
if (!File(readPath).existsSync())
|
||||||
throw Exception("No .keys nor a .keys.backup file found for $name $type");
|
throw Exception("No .keys nor a .keys.backup file found for $name $type");
|
||||||
|
|
||||||
final jsonSource = await read(path: readPath, password: password);
|
final jsonSource = await encryptionFileUtils.read(path: readPath, password: password);
|
||||||
final data = json.decode(jsonSource) as Map<String, dynamic>;
|
final data = json.decode(jsonSource) as Map<String, dynamic>;
|
||||||
final keysData = WalletKeysData.fromJSON(data);
|
final keysData = WalletKeysData.fromJSON(data);
|
||||||
|
|
||||||
dev.log("Restoring .keys from .keys.backup");
|
dev.log("Restoring .keys from .keys.backup");
|
||||||
createKeysFile(name, type, password, keysData, false);
|
createKeysFile(name, type, password, keysData, encryptionFileUtils, false);
|
||||||
return keysData;
|
return keysData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.8.1"
|
version: "8.8.1"
|
||||||
|
cake_backup:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: main
|
||||||
|
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
||||||
|
url: "https://github.com/cake-tech/cake_backup.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.0+1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -169,6 +178,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.3"
|
||||||
|
cryptography:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cryptography
|
||||||
|
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -648,6 +673,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -19,6 +19,11 @@ dependencies:
|
||||||
flutter_mobx: ^2.0.6+1
|
flutter_mobx: ^2.0.6+1
|
||||||
intl: ^0.18.0
|
intl: ^0.18.0
|
||||||
encrypt: ^5.0.1
|
encrypt: ^5.0.1
|
||||||
|
cake_backup:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/cake_backup.git
|
||||||
|
ref: main
|
||||||
|
version: 1.0.0
|
||||||
socks5_proxy: ^1.0.4
|
socks5_proxy: ^1.0.4
|
||||||
unorm_dart: ^0.3.0
|
unorm_dart: ^0.3.0
|
||||||
# tor:
|
# tor:
|
||||||
|
|
|
@ -7,6 +7,7 @@ class EthereumTransactionHistory extends EVMChainTransactionHistory {
|
||||||
EthereumTransactionHistory({
|
EthereumTransactionHistory({
|
||||||
required super.walletInfo,
|
required super.walletInfo,
|
||||||
required super.password,
|
required super.password,
|
||||||
|
required super.encryptionFileUtils,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:cw_core/cake_hive.dart';
|
import 'package:cw_core/cake_hive.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/erc20_token.dart';
|
import 'package:cw_core/erc20_token.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
|
@ -16,7 +17,6 @@ import 'package:cw_evm/evm_chain_transaction_info.dart';
|
||||||
import 'package:cw_evm/evm_chain_transaction_model.dart';
|
import 'package:cw_evm/evm_chain_transaction_model.dart';
|
||||||
import 'package:cw_evm/evm_chain_wallet.dart';
|
import 'package:cw_evm/evm_chain_wallet.dart';
|
||||||
import 'package:cw_evm/evm_erc20_balance.dart';
|
import 'package:cw_evm/evm_erc20_balance.dart';
|
||||||
import 'package:cw_evm/file.dart';
|
|
||||||
|
|
||||||
class EthereumWallet extends EVMChainWallet {
|
class EthereumWallet extends EVMChainWallet {
|
||||||
EthereumWallet({
|
EthereumWallet({
|
||||||
|
@ -26,6 +26,7 @@ class EthereumWallet extends EVMChainWallet {
|
||||||
super.mnemonic,
|
super.mnemonic,
|
||||||
super.initialBalance,
|
super.initialBalance,
|
||||||
super.privateKey,
|
super.privateKey,
|
||||||
|
required super.encryptionFileUtils,
|
||||||
}) : super(nativeCurrency: CryptoCurrency.eth);
|
}) : super(nativeCurrency: CryptoCurrency.eth);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -117,18 +118,24 @@ class EthereumWallet extends EVMChainWallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
EVMChainTransactionHistory setUpTransactionHistory(WalletInfo walletInfo, String password) {
|
EVMChainTransactionHistory setUpTransactionHistory(
|
||||||
return EthereumTransactionHistory(walletInfo: walletInfo, password: password);
|
WalletInfo walletInfo, String password, EncryptionFileUtils encryptionFileUtils) {
|
||||||
|
return EthereumTransactionHistory(
|
||||||
|
walletInfo: walletInfo, password: password, encryptionFileUtils: encryptionFileUtils);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<EthereumWallet> open(
|
static Future<EthereumWallet> open({
|
||||||
{required String name, required String password, required WalletInfo walletInfo}) async {
|
required String name,
|
||||||
|
required String password,
|
||||||
|
required WalletInfo walletInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
|
}) async {
|
||||||
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
||||||
final path = await pathForWallet(name: name, type: walletInfo.type);
|
final path = await pathForWallet(name: name, type: walletInfo.type);
|
||||||
|
|
||||||
Map<String, dynamic>? data;
|
Map<String, dynamic>? data;
|
||||||
try {
|
try {
|
||||||
final jsonSource = await read(path: path, password: password);
|
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
|
||||||
|
|
||||||
data = json.decode(jsonSource) as Map<String, dynamic>;
|
data = json.decode(jsonSource) as Map<String, dynamic>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -146,7 +153,12 @@ class EthereumWallet extends EVMChainWallet {
|
||||||
|
|
||||||
keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
|
keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
|
||||||
} else {
|
} else {
|
||||||
keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
|
keysData = await WalletKeysFile.readKeysFile(
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EthereumWallet(
|
return EthereumWallet(
|
||||||
|
@ -156,6 +168,7 @@ class EthereumWallet extends EVMChainWallet {
|
||||||
privateKey: keysData.privateKey,
|
privateKey: keysData.privateKey,
|
||||||
initialBalance: balance,
|
initialBalance: balance,
|
||||||
client: EthereumClient(),
|
client: EthereumClient(),
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/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_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -9,7 +10,7 @@ import 'package:cw_evm/evm_chain_wallet_creation_credentials.dart';
|
||||||
import 'package:cw_evm/evm_chain_wallet_service.dart';
|
import 'package:cw_evm/evm_chain_wallet_service.dart';
|
||||||
|
|
||||||
class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
||||||
EthereumWalletService(super.walletInfoSource, {required this.client});
|
EthereumWalletService(super.walletInfoSource, super.isDirect, {required this.client});
|
||||||
|
|
||||||
late EthereumClient client;
|
late EthereumClient client;
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
client: client,
|
client: client,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -46,6 +48,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -59,6 +62,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
|
@ -71,7 +75,11 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
||||||
final currentWalletInfo = walletInfoSource.values
|
final currentWalletInfo = walletInfoSource.values
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
final currentWallet = await EthereumWallet.open(
|
final currentWallet = await EthereumWallet.open(
|
||||||
password: password, name: currentName, walletInfo: currentWalletInfo);
|
password: password,
|
||||||
|
name: currentName,
|
||||||
|
walletInfo: currentWalletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
await saveBackup(newName);
|
await saveBackup(newName);
|
||||||
|
@ -97,6 +105,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
client: client,
|
client: client,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -114,6 +123,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
||||||
privateKey: credentials.privateKey,
|
privateKey: credentials.privateKey,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
client: client,
|
client: client,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -135,6 +145,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
client: client,
|
client: client,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_evm/evm_chain_transaction_info.dart';
|
import 'package:cw_evm/evm_chain_transaction_info.dart';
|
||||||
import 'package:cw_evm/file.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';
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ abstract class EVMChainTransactionHistory = EVMChainTransactionHistoryBase
|
||||||
|
|
||||||
abstract class EVMChainTransactionHistoryBase
|
abstract class EVMChainTransactionHistoryBase
|
||||||
extends TransactionHistoryBase<EVMChainTransactionInfo> with Store {
|
extends TransactionHistoryBase<EVMChainTransactionInfo> with Store {
|
||||||
EVMChainTransactionHistoryBase({required this.walletInfo, required String password})
|
EVMChainTransactionHistoryBase(
|
||||||
|
{required this.walletInfo, required String password, required this.encryptionFileUtils})
|
||||||
: _password = password {
|
: _password = password {
|
||||||
transactions = ObservableMap<String, EVMChainTransactionInfo>();
|
transactions = ObservableMap<String, EVMChainTransactionInfo>();
|
||||||
}
|
}
|
||||||
|
@ -23,6 +24,7 @@ abstract class EVMChainTransactionHistoryBase
|
||||||
String _password;
|
String _password;
|
||||||
|
|
||||||
final WalletInfo walletInfo;
|
final WalletInfo walletInfo;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
|
|
||||||
//! Method to be overridden by all child classes
|
//! Method to be overridden by all child classes
|
||||||
|
|
||||||
|
@ -41,7 +43,7 @@ abstract class EVMChainTransactionHistoryBase
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
String path = '$dirPath/$transactionsHistoryFileNameForWallet';
|
String path = '$dirPath/$transactionsHistoryFileNameForWallet';
|
||||||
final data = json.encode({'transactions': transactions});
|
final data = json.encode({'transactions': transactions});
|
||||||
await writeData(path: path, password: _password, data: data);
|
await encryptionFileUtils.write(path: path, password: _password, data: data);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
log('Error while saving ${walletInfo.type.name} transaction history: ${e.toString()}');
|
log('Error while saving ${walletInfo.type.name} transaction history: ${e.toString()}');
|
||||||
log(s.toString());
|
log(s.toString());
|
||||||
|
@ -59,7 +61,7 @@ abstract class EVMChainTransactionHistoryBase
|
||||||
final transactionsHistoryFileNameForWallet = getTransactionHistoryFileName();
|
final transactionsHistoryFileNameForWallet = getTransactionHistoryFileName();
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
String path = '$dirPath/$transactionsHistoryFileNameForWallet';
|
String path = '$dirPath/$transactionsHistoryFileNameForWallet';
|
||||||
final content = await read(path: path, password: _password);
|
final content = await encryptionFileUtils.read(path: path, password: _password);
|
||||||
if (content.isEmpty) {
|
if (content.isEmpty) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:bip32/bip32.dart' as bip32;
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:cw_core/cake_hive.dart';
|
import 'package:cw_core/cake_hive.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/erc20_token.dart';
|
import 'package:cw_core/erc20_token.dart';
|
||||||
import 'package:cw_core/node.dart';
|
import 'package:cw_core/node.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
@ -27,7 +28,6 @@ import 'package:cw_evm/evm_chain_transaction_model.dart';
|
||||||
import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
||||||
import 'package:cw_evm/evm_chain_wallet_addresses.dart';
|
import 'package:cw_evm/evm_chain_wallet_addresses.dart';
|
||||||
import 'package:cw_evm/evm_ledger_credentials.dart';
|
import 'package:cw_evm/evm_ledger_credentials.dart';
|
||||||
import 'package:cw_evm/file.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hex/hex.dart';
|
import 'package:hex/hex.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
@ -68,6 +68,7 @@ abstract class EVMChainWalletBase
|
||||||
String? privateKey,
|
String? privateKey,
|
||||||
required String password,
|
required String password,
|
||||||
EVMChainERC20Balance? initialBalance,
|
EVMChainERC20Balance? initialBalance,
|
||||||
|
required this.encryptionFileUtils,
|
||||||
}) : syncStatus = const NotConnectedSyncStatus(),
|
}) : syncStatus = const NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_mnemonic = mnemonic,
|
_mnemonic = mnemonic,
|
||||||
|
@ -83,7 +84,7 @@ abstract class EVMChainWalletBase
|
||||||
),
|
),
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory = setUpTransactionHistory(walletInfo, password);
|
transactionHistory = setUpTransactionHistory(walletInfo, password, encryptionFileUtils);
|
||||||
|
|
||||||
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
||||||
CakeHive.registerAdapter(Erc20TokenAdapter());
|
CakeHive.registerAdapter(Erc20TokenAdapter());
|
||||||
|
@ -95,6 +96,7 @@ abstract class EVMChainWalletBase
|
||||||
final String? _mnemonic;
|
final String? _mnemonic;
|
||||||
final String? _hexPrivateKey;
|
final String? _hexPrivateKey;
|
||||||
final String _password;
|
final String _password;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
|
|
||||||
late final Box<Erc20Token> erc20TokensBox;
|
late final Box<Erc20Token> erc20TokensBox;
|
||||||
|
|
||||||
|
@ -149,7 +151,11 @@ abstract class EVMChainWalletBase
|
||||||
|
|
||||||
Erc20Token createNewErc20TokenObject(Erc20Token token, String? iconPath);
|
Erc20Token createNewErc20TokenObject(Erc20Token token, String? iconPath);
|
||||||
|
|
||||||
EVMChainTransactionHistory setUpTransactionHistory(WalletInfo walletInfo, String password);
|
EVMChainTransactionHistory setUpTransactionHistory(
|
||||||
|
WalletInfo walletInfo,
|
||||||
|
String password,
|
||||||
|
EncryptionFileUtils encryptionFileUtils,
|
||||||
|
);
|
||||||
|
|
||||||
//! Common Methods across child classes
|
//! Common Methods across child classes
|
||||||
|
|
||||||
|
@ -510,13 +516,13 @@ abstract class EVMChainWalletBase
|
||||||
@override
|
@override
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
||||||
await saveKeysFile(_password);
|
await saveKeysFile(_password, encryptionFileUtils);
|
||||||
saveKeysFile(_password, true);
|
saveKeysFile(_password, encryptionFileUtils, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
await walletAddresses.updateAddressesInBox();
|
await walletAddresses.updateAddressesInBox();
|
||||||
final path = await makePath();
|
final path = await makePath();
|
||||||
await write(path: path, password: _password, data: toJSON());
|
await encryptionFileUtils.write(path: path, password: _password, data: toJSON());
|
||||||
await transactionHistory.save();
|
await transactionHistory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,4 +696,7 @@ abstract class EVMChainWalletBase
|
||||||
bytesToHex(await _evmChainPrivateKey.signPersonalMessage(ascii.encode(message)));
|
bytesToHex(await _evmChainPrivateKey.signPersonalMessage(ascii.encode(message)));
|
||||||
|
|
||||||
Web3Client? getWeb3Client() => _client.getWeb3Client();
|
Web3Client? getWeb3Client() => _client.getWeb3Client();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get password => _password;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
class EVMChainNewWalletCredentials extends WalletCredentials {
|
class EVMChainNewWalletCredentials extends WalletCredentials {
|
||||||
EVMChainNewWalletCredentials({required String name, WalletInfo? walletInfo})
|
EVMChainNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
|
||||||
: super(name: name, walletInfo: walletInfo);
|
: super(name: name, walletInfo: walletInfo, password: password);
|
||||||
}
|
}
|
||||||
|
|
||||||
class EVMChainRestoreWalletFromSeedCredentials extends WalletCredentials {
|
class EVMChainRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
|
|
@ -15,9 +15,10 @@ abstract class EVMChainWalletService<T extends EVMChainWallet> extends WalletSer
|
||||||
EVMChainRestoreWalletFromSeedCredentials,
|
EVMChainRestoreWalletFromSeedCredentials,
|
||||||
EVMChainRestoreWalletFromPrivateKey,
|
EVMChainRestoreWalletFromPrivateKey,
|
||||||
EVMChainRestoreWalletFromHardware> {
|
EVMChainRestoreWalletFromHardware> {
|
||||||
EVMChainWalletService(this.walletInfoSource);
|
EVMChainWalletService(this.walletInfoSource, this.isDirect);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletType getType();
|
WalletType getType();
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:cw_core/key.dart';
|
|
||||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
|
||||||
|
|
||||||
Future<void> write(
|
|
||||||
{required String path,
|
|
||||||
required String password,
|
|
||||||
required String data}) async {
|
|
||||||
final keys = extractKeys(password);
|
|
||||||
final key = encrypt.Key.fromBase64(keys.first);
|
|
||||||
final iv = encrypt.IV.fromBase64(keys.last);
|
|
||||||
final encrypted = await encode(key: key, iv: iv, data: data);
|
|
||||||
final f = File(path);
|
|
||||||
f.writeAsStringSync(encrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> writeData(
|
|
||||||
{required String path,
|
|
||||||
required String password,
|
|
||||||
required String data}) async {
|
|
||||||
final keys = extractKeys(password);
|
|
||||||
final key = encrypt.Key.fromBase64(keys.first);
|
|
||||||
final iv = encrypt.IV.fromBase64(keys.last);
|
|
||||||
final encrypted = await encode(key: key, iv: iv, data: data);
|
|
||||||
final f = File(path);
|
|
||||||
f.writeAsStringSync(encrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> read({required String path, required String password}) async {
|
|
||||||
final file = File(path);
|
|
||||||
|
|
||||||
if (!file.existsSync()) {
|
|
||||||
file.createSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
final encrypted = file.readAsStringSync();
|
|
||||||
|
|
||||||
return decode(password: password, data: encrypted);
|
|
||||||
}
|
|
|
@ -20,6 +20,7 @@ dependencies:
|
||||||
hive: ^2.2.3
|
hive: ^2.2.3
|
||||||
collection: ^1.17.1
|
collection: ^1.17.1
|
||||||
shared_preferences: ^2.0.15
|
shared_preferences: ^2.0.15
|
||||||
|
mobx: ^2.0.7+4
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter: ^1.0.1
|
||||||
|
|
|
@ -38,9 +38,10 @@ class HavenWallet = HavenWalletBase with _$HavenWallet;
|
||||||
|
|
||||||
abstract class HavenWalletBase
|
abstract class HavenWalletBase
|
||||||
extends WalletBase<MoneroBalance, HavenTransactionHistory, HavenTransactionInfo> with Store {
|
extends WalletBase<MoneroBalance, HavenTransactionHistory, HavenTransactionInfo> with Store {
|
||||||
HavenWalletBase({required WalletInfo walletInfo})
|
HavenWalletBase({required WalletInfo walletInfo, String? password})
|
||||||
: balance = ObservableMap.of(getHavenBalance(accountIndex: 0)),
|
: balance = ObservableMap.of(getHavenBalance(accountIndex: 0)),
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
|
_password = password ?? '',
|
||||||
_hasSyncAfterStartup = false,
|
_hasSyncAfterStartup = false,
|
||||||
walletAddresses = HavenWalletAddresses(walletInfo),
|
walletAddresses = HavenWalletAddresses(walletInfo),
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
|
@ -56,6 +57,7 @@ abstract class HavenWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int _autoSaveInterval = 30;
|
static const int _autoSaveInterval = 30;
|
||||||
|
final String _password;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
HavenWalletAddresses walletAddresses;
|
HavenWalletAddresses walletAddresses;
|
||||||
|
@ -414,4 +416,7 @@ abstract class HavenWalletBase
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get password => _password;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.4.3"
|
version: "8.4.3"
|
||||||
|
cake_backup:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: main
|
||||||
|
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
||||||
|
url: "https://github.com/cake-tech/cake_backup.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.0+1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -169,6 +178,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
|
cryptography:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cryptography
|
||||||
|
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
cw_core:
|
cw_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -639,6 +664,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -18,6 +18,9 @@ migration:
|
||||||
- platform: macos
|
- platform: macos
|
||||||
create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
|
create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
|
||||||
base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
|
base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
|
||||||
|
- platform: linux
|
||||||
|
create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
|
||||||
|
base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|
1
cw_monero/example/linux/.gitignore
vendored
Normal file
1
cw_monero/example/linux/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
flutter/ephemeral
|
138
cw_monero/example/linux/CMakeLists.txt
Normal file
138
cw_monero/example/linux/CMakeLists.txt
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
# Project-level configuration.
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(runner LANGUAGES CXX)
|
||||||
|
|
||||||
|
# The name of the executable created for the application. Change this to change
|
||||||
|
# the on-disk name of your application.
|
||||||
|
set(BINARY_NAME "cw_monero_example")
|
||||||
|
# The unique GTK application identifier for this application. See:
|
||||||
|
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||||
|
set(APPLICATION_ID "com.cakewallet.cw_monero")
|
||||||
|
|
||||||
|
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||||
|
# versions of CMake.
|
||||||
|
cmake_policy(SET CMP0063 NEW)
|
||||||
|
|
||||||
|
# Load bundled libraries from the lib/ directory relative to the binary.
|
||||||
|
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
|
||||||
|
|
||||||
|
# Root filesystem for cross-building.
|
||||||
|
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
|
||||||
|
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
|
||||||
|
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Define build configuration options.
|
||||||
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
|
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
||||||
|
STRING "Flutter build mode" FORCE)
|
||||||
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||||
|
"Debug" "Profile" "Release")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Compilation settings that should be applied to most targets.
|
||||||
|
#
|
||||||
|
# Be cautious about adding new options here, as plugins use this function by
|
||||||
|
# default. In most cases, you should add new options to specific targets instead
|
||||||
|
# of modifying this function.
|
||||||
|
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||||
|
target_compile_features(${TARGET} PUBLIC cxx_std_14)
|
||||||
|
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
|
||||||
|
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
||||||
|
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Flutter library and tool build rules.
|
||||||
|
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||||
|
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||||
|
|
||||||
|
# System-level dependencies.
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||||
|
|
||||||
|
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
|
||||||
|
|
||||||
|
# Define the application target. To change its name, change BINARY_NAME above,
|
||||||
|
# not the value here, or `flutter run` will no longer work.
|
||||||
|
#
|
||||||
|
# Any new source files that you add to the application should be added here.
|
||||||
|
add_executable(${BINARY_NAME}
|
||||||
|
"main.cc"
|
||||||
|
"my_application.cc"
|
||||||
|
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Apply the standard set of build settings. This can be removed for applications
|
||||||
|
# that need different build settings.
|
||||||
|
apply_standard_settings(${BINARY_NAME})
|
||||||
|
|
||||||
|
# Add dependency libraries. Add any application-specific dependencies here.
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
||||||
|
|
||||||
|
# Run the Flutter tool portions of the build. This must not be removed.
|
||||||
|
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||||
|
|
||||||
|
# Only the install-generated bundle's copy of the executable will launch
|
||||||
|
# correctly, since the resources must in the right relative locations. To avoid
|
||||||
|
# people trying to run the unbundled copy, put it in a subdirectory instead of
|
||||||
|
# the default top-level location.
|
||||||
|
set_target_properties(${BINARY_NAME}
|
||||||
|
PROPERTIES
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generated plugin build rules, which manage building the plugins and adding
|
||||||
|
# them to the application.
|
||||||
|
include(flutter/generated_plugins.cmake)
|
||||||
|
|
||||||
|
|
||||||
|
# === Installation ===
|
||||||
|
# By default, "installing" just makes a relocatable bundle in the build
|
||||||
|
# directory.
|
||||||
|
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
|
||||||
|
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||||
|
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Start with a clean build bundle directory every time.
|
||||||
|
install(CODE "
|
||||||
|
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
|
||||||
|
" COMPONENT Runtime)
|
||||||
|
|
||||||
|
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
||||||
|
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||||
|
|
||||||
|
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||||
|
install(FILES "${bundled_library}"
|
||||||
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
endforeach(bundled_library)
|
||||||
|
|
||||||
|
# Fully re-copy the assets directory on each build to avoid having stale files
|
||||||
|
# from a previous install.
|
||||||
|
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
||||||
|
install(CODE "
|
||||||
|
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
||||||
|
" COMPONENT Runtime)
|
||||||
|
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
|
||||||
|
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
|
||||||
|
|
||||||
|
# Install the AOT library on non-Debug builds only.
|
||||||
|
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||||
|
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
endif()
|
88
cw_monero/example/linux/flutter/CMakeLists.txt
Normal file
88
cw_monero/example/linux/flutter/CMakeLists.txt
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
# This file controls Flutter-level build steps. It should not be edited.
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
|
||||||
|
|
||||||
|
# Configuration provided via flutter tool.
|
||||||
|
include(${EPHEMERAL_DIR}/generated_config.cmake)
|
||||||
|
|
||||||
|
# TODO: Move the rest of this into files in ephemeral. See
|
||||||
|
# https://github.com/flutter/flutter/issues/57146.
|
||||||
|
|
||||||
|
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
|
||||||
|
# which isn't available in 3.10.
|
||||||
|
function(list_prepend LIST_NAME PREFIX)
|
||||||
|
set(NEW_LIST "")
|
||||||
|
foreach(element ${${LIST_NAME}})
|
||||||
|
list(APPEND NEW_LIST "${PREFIX}${element}")
|
||||||
|
endforeach(element)
|
||||||
|
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# === Flutter Library ===
|
||||||
|
# System-level dependencies.
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||||
|
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||||
|
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
|
||||||
|
|
||||||
|
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
|
||||||
|
|
||||||
|
# Published to parent scope for install step.
|
||||||
|
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
|
||||||
|
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
|
||||||
|
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
|
||||||
|
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
|
||||||
|
|
||||||
|
list(APPEND FLUTTER_LIBRARY_HEADERS
|
||||||
|
"fl_basic_message_channel.h"
|
||||||
|
"fl_binary_codec.h"
|
||||||
|
"fl_binary_messenger.h"
|
||||||
|
"fl_dart_project.h"
|
||||||
|
"fl_engine.h"
|
||||||
|
"fl_json_message_codec.h"
|
||||||
|
"fl_json_method_codec.h"
|
||||||
|
"fl_message_codec.h"
|
||||||
|
"fl_method_call.h"
|
||||||
|
"fl_method_channel.h"
|
||||||
|
"fl_method_codec.h"
|
||||||
|
"fl_method_response.h"
|
||||||
|
"fl_plugin_registrar.h"
|
||||||
|
"fl_plugin_registry.h"
|
||||||
|
"fl_standard_message_codec.h"
|
||||||
|
"fl_standard_method_codec.h"
|
||||||
|
"fl_string_codec.h"
|
||||||
|
"fl_value.h"
|
||||||
|
"fl_view.h"
|
||||||
|
"flutter_linux.h"
|
||||||
|
)
|
||||||
|
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
|
||||||
|
add_library(flutter INTERFACE)
|
||||||
|
target_include_directories(flutter INTERFACE
|
||||||
|
"${EPHEMERAL_DIR}"
|
||||||
|
)
|
||||||
|
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
|
||||||
|
target_link_libraries(flutter INTERFACE
|
||||||
|
PkgConfig::GTK
|
||||||
|
PkgConfig::GLIB
|
||||||
|
PkgConfig::GIO
|
||||||
|
)
|
||||||
|
add_dependencies(flutter flutter_assemble)
|
||||||
|
|
||||||
|
# === Flutter tool backend ===
|
||||||
|
# _phony_ is a non-existent file to force this command to run every time,
|
||||||
|
# since currently there's no way to get a full input/output list from the
|
||||||
|
# flutter tool.
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/_phony_
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
|
${FLUTTER_TOOL_ENVIRONMENT}
|
||||||
|
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
|
||||||
|
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
add_custom_target(flutter_assemble DEPENDS
|
||||||
|
"${FLUTTER_LIBRARY}"
|
||||||
|
${FLUTTER_LIBRARY_HEADERS}
|
||||||
|
)
|
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <cw_monero/cw_monero_plugin.h>
|
||||||
|
|
||||||
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) cw_monero_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "CwMoneroPlugin");
|
||||||
|
cw_monero_plugin_register_with_registrar(cw_monero_registrar);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||||
|
#define GENERATED_PLUGIN_REGISTRANT_
|
||||||
|
|
||||||
|
#include <flutter_linux/flutter_linux.h>
|
||||||
|
|
||||||
|
// Registers Flutter plugins.
|
||||||
|
void fl_register_plugins(FlPluginRegistry* registry);
|
||||||
|
|
||||||
|
#endif // GENERATED_PLUGIN_REGISTRANT_
|
24
cw_monero/example/linux/flutter/generated_plugins.cmake
Normal file
24
cw_monero/example/linux/flutter/generated_plugins.cmake
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#
|
||||||
|
# Generated file, do not edit.
|
||||||
|
#
|
||||||
|
|
||||||
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
cw_monero
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
)
|
||||||
|
|
||||||
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|
||||||
|
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
||||||
|
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
|
||||||
|
endforeach(plugin)
|
||||||
|
|
||||||
|
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
|
||||||
|
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
|
||||||
|
endforeach(ffi_plugin)
|
6
cw_monero/example/linux/main.cc
Normal file
6
cw_monero/example/linux/main.cc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include "my_application.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
g_autoptr(MyApplication) app = my_application_new();
|
||||||
|
return g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
|
}
|
104
cw_monero/example/linux/my_application.cc
Normal file
104
cw_monero/example/linux/my_application.cc
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include "my_application.h"
|
||||||
|
|
||||||
|
#include <flutter_linux/flutter_linux.h>
|
||||||
|
#ifdef GDK_WINDOWING_X11
|
||||||
|
#include <gdk/gdkx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "flutter/generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
struct _MyApplication {
|
||||||
|
GtkApplication parent_instance;
|
||||||
|
char** dart_entrypoint_arguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
|
// Implements GApplication::activate.
|
||||||
|
static void my_application_activate(GApplication* application) {
|
||||||
|
MyApplication* self = MY_APPLICATION(application);
|
||||||
|
GtkWindow* window =
|
||||||
|
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||||
|
|
||||||
|
// Use a header bar when running in GNOME as this is the common style used
|
||||||
|
// by applications and is the setup most users will be using (e.g. Ubuntu
|
||||||
|
// desktop).
|
||||||
|
// If running on X and not using GNOME then just use a traditional title bar
|
||||||
|
// in case the window manager does more exotic layout, e.g. tiling.
|
||||||
|
// If running on Wayland assume the header bar will work (may need changing
|
||||||
|
// if future cases occur).
|
||||||
|
gboolean use_header_bar = TRUE;
|
||||||
|
#ifdef GDK_WINDOWING_X11
|
||||||
|
GdkScreen* screen = gtk_window_get_screen(window);
|
||||||
|
if (GDK_IS_X11_SCREEN(screen)) {
|
||||||
|
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
|
||||||
|
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
|
||||||
|
use_header_bar = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (use_header_bar) {
|
||||||
|
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
||||||
|
gtk_widget_show(GTK_WIDGET(header_bar));
|
||||||
|
gtk_header_bar_set_title(header_bar, "cw_monero_example");
|
||||||
|
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
||||||
|
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
||||||
|
} else {
|
||||||
|
gtk_window_set_title(window, "cw_monero_example");
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_window_set_default_size(window, 1280, 720);
|
||||||
|
gtk_widget_show(GTK_WIDGET(window));
|
||||||
|
|
||||||
|
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
||||||
|
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
|
||||||
|
|
||||||
|
FlView* view = fl_view_new(project);
|
||||||
|
gtk_widget_show(GTK_WIDGET(view));
|
||||||
|
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
|
||||||
|
|
||||||
|
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
||||||
|
|
||||||
|
gtk_widget_grab_focus(GTK_WIDGET(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements GApplication::local_command_line.
|
||||||
|
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
|
||||||
|
MyApplication* self = MY_APPLICATION(application);
|
||||||
|
// Strip out the first argument as it is the binary name.
|
||||||
|
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
|
||||||
|
|
||||||
|
g_autoptr(GError) error = nullptr;
|
||||||
|
if (!g_application_register(application, nullptr, &error)) {
|
||||||
|
g_warning("Failed to register: %s", error->message);
|
||||||
|
*exit_status = 1;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_application_activate(application);
|
||||||
|
*exit_status = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements GObject::dispose.
|
||||||
|
static void my_application_dispose(GObject* object) {
|
||||||
|
MyApplication* self = MY_APPLICATION(object);
|
||||||
|
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
|
||||||
|
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void my_application_class_init(MyApplicationClass* klass) {
|
||||||
|
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
|
||||||
|
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
|
||||||
|
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void my_application_init(MyApplication* self) {}
|
||||||
|
|
||||||
|
MyApplication* my_application_new() {
|
||||||
|
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||||
|
"application-id", APPLICATION_ID,
|
||||||
|
"flags", G_APPLICATION_NON_UNIQUE,
|
||||||
|
nullptr));
|
||||||
|
}
|
18
cw_monero/example/linux/my_application.h
Normal file
18
cw_monero/example/linux/my_application.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef FLUTTER_MY_APPLICATION_H_
|
||||||
|
#define FLUTTER_MY_APPLICATION_H_
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
|
||||||
|
GtkApplication)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* my_application_new:
|
||||||
|
*
|
||||||
|
* Creates a new Flutter-based application.
|
||||||
|
*
|
||||||
|
* Returns: a new #MyApplication.
|
||||||
|
*/
|
||||||
|
MyApplication* my_application_new();
|
||||||
|
|
||||||
|
#endif // FLUTTER_MY_APPLICATION_H_
|
|
@ -34,7 +34,6 @@ List<monero.SubaddressAccountRow> getAllAccount() {
|
||||||
// final size = monero.Wallet_numSubaddressAccounts(wptr!);
|
// final size = monero.Wallet_numSubaddressAccounts(wptr!);
|
||||||
refreshAccounts();
|
refreshAccounts();
|
||||||
int size = monero.SubaddressAccount_getAll_size(subaddressAccount!);
|
int size = monero.SubaddressAccount_getAll_size(subaddressAccount!);
|
||||||
print("size: $size");
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
monero.Wallet_addSubaddressAccount(wptr!);
|
monero.Wallet_addSubaddressAccount(wptr!);
|
||||||
return getAllAccount();
|
return getAllAccount();
|
||||||
|
|
|
@ -7,6 +7,8 @@ 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';
|
||||||
import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart';
|
import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart';
|
||||||
import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart';
|
import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart';
|
||||||
|
import 'package:cw_monero/api/wallet.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:cw_monero/api/transaction_history.dart';
|
import 'package:cw_monero/api/transaction_history.dart';
|
||||||
import 'package:cw_monero/api/wallet.dart';
|
import 'package:cw_monero/api/wallet.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
|
@ -3,6 +3,8 @@ import 'dart:ffi';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:isolate';
|
import 'dart:isolate';
|
||||||
|
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cw_core/account.dart';
|
import 'package:cw_core/account.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/monero_amount_format.dart';
|
import 'package:cw_core/monero_amount_format.dart';
|
||||||
|
@ -50,7 +52,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
|
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
|
||||||
MoneroWalletBase(
|
MoneroWalletBase(
|
||||||
{required WalletInfo walletInfo,
|
{required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo})
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required String password})
|
||||||
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
|
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
|
||||||
CryptoCurrency.xmr: MoneroBalance(
|
CryptoCurrency.xmr: MoneroBalance(
|
||||||
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
|
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
|
||||||
|
@ -59,6 +62,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
_hasSyncAfterStartup = false,
|
_hasSyncAfterStartup = false,
|
||||||
isEnabledAutoGenerateSubaddress = false,
|
isEnabledAutoGenerateSubaddress = false,
|
||||||
|
_password = password,
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
unspentCoins = [],
|
unspentCoins = [],
|
||||||
this.unspentCoinsInfo = unspentCoinsInfo,
|
this.unspentCoinsInfo = unspentCoinsInfo,
|
||||||
|
@ -111,6 +115,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
String get seed => monero_wallet.getSeed();
|
String get seed => monero_wallet.getSeed();
|
||||||
String seedLegacy(String? language) => monero_wallet.getSeedLegacy(language);
|
String seedLegacy(String? language) => monero_wallet.getSeedLegacy(language);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get password => _password;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MoneroWalletKeys get keys => MoneroWalletKeys(
|
MoneroWalletKeys get keys => MoneroWalletKeys(
|
||||||
privateSpendKey: monero_wallet.getSecretSpendKey(),
|
privateSpendKey: monero_wallet.getSecretSpendKey(),
|
||||||
|
@ -127,6 +134,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
bool _hasSyncAfterStartup;
|
bool _hasSyncAfterStartup;
|
||||||
Timer? _autoSaveTimer;
|
Timer? _autoSaveTimer;
|
||||||
List<MoneroUnspent> unspentCoins;
|
List<MoneroUnspent> unspentCoins;
|
||||||
|
String _password;
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
await walletAddresses.init();
|
await walletAddresses.init();
|
||||||
|
|
|
@ -93,7 +93,9 @@ class MoneroWalletService extends WalletService<
|
||||||
await monero_wallet_manager.createWallet(
|
await monero_wallet_manager.createWallet(
|
||||||
path: path, password: credentials.password!, language: credentials.language);
|
path: path, password: credentials.password!, language: credentials.language);
|
||||||
final wallet = MoneroWallet(
|
final wallet = MoneroWallet(
|
||||||
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
walletInfo: credentials.walletInfo!,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
password: credentials.password!);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -126,10 +128,14 @@ class MoneroWalletService extends WalletService<
|
||||||
await repairOldAndroidWallet(name);
|
await repairOldAndroidWallet(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
await monero_wallet_manager.openWalletAsync({'path': path, 'password': password});
|
await monero_wallet_manager
|
||||||
final walletInfo = walletInfoSource.values
|
.openWalletAsync({'path': path, 'password': password});
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
final walletInfo = walletInfoSource.values.firstWhere(
|
||||||
wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
(info) => info.id == WalletBase.idFor(name, getType()));
|
||||||
|
final wallet = MoneroWallet(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
password: password);
|
||||||
final isValid = wallet.walletAddresses.validate();
|
final isValid = wallet.walletAddresses.validate();
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
|
@ -162,15 +168,22 @@ class MoneroWalletService extends WalletService<
|
||||||
final bool invalidSignature = e.toString().contains('invalid signature') ||
|
final bool invalidSignature = e.toString().contains('invalid signature') ||
|
||||||
(e is WalletOpeningException && e.message.contains('invalid signature'));
|
(e is WalletOpeningException && e.message.contains('invalid signature'));
|
||||||
|
|
||||||
|
final bool invalidPassword = e.toString().contains('invalid password') ||
|
||||||
|
(e is WalletOpeningException && e.message.contains('invalid password'));
|
||||||
|
|
||||||
if (!isBadAlloc &&
|
if (!isBadAlloc &&
|
||||||
!doesNotCorrespond &&
|
!doesNotCorrespond &&
|
||||||
!isMissingCacheFilesIOS &&
|
!isMissingCacheFilesIOS &&
|
||||||
!isMissingCacheFilesAndroid &&
|
!isMissingCacheFilesAndroid &&
|
||||||
!invalidSignature &&
|
!invalidSignature &&
|
||||||
|
!invalidPassword &&
|
||||||
wallet != null &&
|
wallet != null &&
|
||||||
wallet.onError != null) {
|
wallet.onError != null) {
|
||||||
wallet.onError!(FlutterErrorDetails(exception: e, stack: s));
|
wallet.onError!(FlutterErrorDetails(exception: e, stack: s));
|
||||||
}
|
}
|
||||||
|
if (invalidPassword) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
|
||||||
await restoreOrResetWalletFiles(name);
|
await restoreOrResetWalletFiles(name);
|
||||||
return openWallet(name, password);
|
return openWallet(name, password);
|
||||||
|
@ -206,11 +219,15 @@ class MoneroWalletService extends WalletService<
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> rename(String currentName, String password, String newName) async {
|
Future<void> rename(
|
||||||
final currentWalletInfo = walletInfoSource.values
|
String currentName, String password, String newName) async {
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
final currentWalletInfo = walletInfoSource.values.firstWhere(
|
||||||
final currentWallet =
|
(info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
MoneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
final currentWallet = MoneroWallet(
|
||||||
|
walletInfo: currentWalletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
password: password,
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
|
|
||||||
|
@ -235,7 +252,9 @@ class MoneroWalletService extends WalletService<
|
||||||
viewKey: credentials.viewKey,
|
viewKey: credentials.viewKey,
|
||||||
spendKey: credentials.spendKey);
|
spendKey: credentials.spendKey);
|
||||||
final wallet = MoneroWallet(
|
final wallet = MoneroWallet(
|
||||||
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
walletInfo: credentials.walletInfo!,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
password: credentials.password!);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -268,7 +287,9 @@ class MoneroWalletService extends WalletService<
|
||||||
seed: credentials.mnemonic,
|
seed: credentials.mnemonic,
|
||||||
restoreHeight: credentials.height!);
|
restoreHeight: credentials.height!);
|
||||||
final wallet = MoneroWallet(
|
final wallet = MoneroWallet(
|
||||||
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
walletInfo: credentials.walletInfo!,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
password: credentials.password!);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -315,7 +336,11 @@ class MoneroWalletService extends WalletService<
|
||||||
restoreHeight: height,
|
restoreHeight: height,
|
||||||
spendKey: spendKey);
|
spendKey: spendKey);
|
||||||
|
|
||||||
final wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
final wallet = MoneroWallet(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
password: password,
|
||||||
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -364,7 +389,11 @@ class MoneroWalletService extends WalletService<
|
||||||
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
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
||||||
final wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
final wallet = MoneroWallet(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
password: password,
|
||||||
|
);
|
||||||
return wallet.seed;
|
return wallet.seed;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// if the file couldn't be opened or read
|
// if the file couldn't be opened or read
|
||||||
|
|
270
cw_monero/linux/CMakeLists.txt
Normal file
270
cw_monero/linux/CMakeLists.txt
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
# The Flutter tooling requires that developers have CMake 3.10 or later
|
||||||
|
# installed. You should not increase this version, as doing so will cause
|
||||||
|
# the plugin to fail to compile for some customers of the plugin.
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
# Project-level configuration.
|
||||||
|
set(PROJECT_NAME "cw_monero")
|
||||||
|
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||||
|
|
||||||
|
# This value is used when generating builds using this plugin, so it must
|
||||||
|
# not be changed.
|
||||||
|
set(PLUGIN_NAME "cw_monero_plugin")
|
||||||
|
|
||||||
|
# Define the plugin library target. Its name must not be changed (see comment
|
||||||
|
# on PLUGIN_NAME above).
|
||||||
|
#
|
||||||
|
# Any new source files that you add to the plugin should be added here.
|
||||||
|
add_library(${PLUGIN_NAME} SHARED
|
||||||
|
"cw_monero_plugin.cc"
|
||||||
|
"../ios/Classes/monero_api.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Apply a standard set of build settings that are configured in the
|
||||||
|
# application-level CMakeLists.txt. This can be removed for plugins that want
|
||||||
|
# full control over build settings.
|
||||||
|
apply_standard_settings(${PLUGIN_NAME})
|
||||||
|
|
||||||
|
# Symbols are hidden by default to reduce the chance of accidental conflicts
|
||||||
|
# between plugins. This should not be removed; any symbols that should be
|
||||||
|
# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro.
|
||||||
|
set_target_properties(${PLUGIN_NAME} PROPERTIES
|
||||||
|
CXX_VISIBILITY_PRESET hidden)
|
||||||
|
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
||||||
|
|
||||||
|
# Source include directories and library dependencies. Add any plugin-specific
|
||||||
|
# dependencies here.
|
||||||
|
target_include_directories(${PLUGIN_NAME} INTERFACE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
|
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
|
||||||
|
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK)
|
||||||
|
target_link_libraries(${PLUGIN_NAME} PUBLIC cw_monero)
|
||||||
|
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||||
|
# This list could contain prebuilt libraries, or libraries created by an
|
||||||
|
# external build triggered from this build file.
|
||||||
|
set(cw_monero_bundled_libraries
|
||||||
|
""
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library( cw_monero
|
||||||
|
STATIC
|
||||||
|
../ios/Classes/monero_api.cpp)
|
||||||
|
|
||||||
|
set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../cw_shared_external/ios/External/linux)
|
||||||
|
|
||||||
|
############
|
||||||
|
# libsodium
|
||||||
|
############
|
||||||
|
|
||||||
|
add_library(sodium STATIC IMPORTED)
|
||||||
|
set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libsodium.a)
|
||||||
|
|
||||||
|
############
|
||||||
|
# OpenSSL
|
||||||
|
############
|
||||||
|
|
||||||
|
add_library(crypto STATIC IMPORTED)
|
||||||
|
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libcrypto.a)
|
||||||
|
|
||||||
|
add_library(ssl STATIC IMPORTED)
|
||||||
|
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libssl.a)
|
||||||
|
|
||||||
|
############
|
||||||
|
# Boost
|
||||||
|
############
|
||||||
|
|
||||||
|
add_library(boost_chrono STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_chrono.a)
|
||||||
|
|
||||||
|
add_library(boost_date_time STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_date_time.a)
|
||||||
|
|
||||||
|
add_library(boost_filesystem STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_filesystem.a)
|
||||||
|
|
||||||
|
add_library(boost_program_options STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_program_options.a)
|
||||||
|
|
||||||
|
add_library(boost_regex STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_regex.a)
|
||||||
|
|
||||||
|
add_library(boost_serialization STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_serialization.a)
|
||||||
|
|
||||||
|
add_library(boost_system STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_system.a)
|
||||||
|
|
||||||
|
add_library(boost_thread STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_thread.a)
|
||||||
|
|
||||||
|
add_library(boost_wserialization STATIC IMPORTED)
|
||||||
|
set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libboost_wserialization.a)
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Monero
|
||||||
|
#############
|
||||||
|
|
||||||
|
|
||||||
|
add_library(wallet STATIC IMPORTED)
|
||||||
|
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libwallet.a)
|
||||||
|
|
||||||
|
add_library(wallet_api STATIC IMPORTED)
|
||||||
|
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libwallet_api.a)
|
||||||
|
|
||||||
|
add_library(cryptonote_core STATIC IMPORTED)
|
||||||
|
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libcryptonote_core.a)
|
||||||
|
|
||||||
|
add_library(cryptonote_basic STATIC IMPORTED)
|
||||||
|
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libcryptonote_basic.a)
|
||||||
|
|
||||||
|
add_library(cryptonote_format_utils_basic STATIC IMPORTED)
|
||||||
|
set_target_properties(cryptonote_format_utils_basic PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libcryptonote_format_utils_basic.a)
|
||||||
|
|
||||||
|
add_library(mnemonics STATIC IMPORTED)
|
||||||
|
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libmnemonics.a)
|
||||||
|
|
||||||
|
add_library(common STATIC IMPORTED)
|
||||||
|
set_target_properties(common PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libcommon.a)
|
||||||
|
|
||||||
|
add_library(cncrypto STATIC IMPORTED)
|
||||||
|
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libcncrypto.a)
|
||||||
|
|
||||||
|
add_library(ringct STATIC IMPORTED)
|
||||||
|
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libringct.a)
|
||||||
|
|
||||||
|
add_library(ringct_basic STATIC IMPORTED)
|
||||||
|
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libringct_basic.a)
|
||||||
|
|
||||||
|
add_library(blockchain_db STATIC IMPORTED)
|
||||||
|
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libblockchain_db.a)
|
||||||
|
|
||||||
|
add_library(lmdb STATIC IMPORTED)
|
||||||
|
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/liblmdb.a)
|
||||||
|
|
||||||
|
add_library(easylogging STATIC IMPORTED)
|
||||||
|
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libeasylogging.a)
|
||||||
|
|
||||||
|
add_library(epee STATIC IMPORTED)
|
||||||
|
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libepee.a)
|
||||||
|
|
||||||
|
add_library(blocks STATIC IMPORTED)
|
||||||
|
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libblocks.a)
|
||||||
|
|
||||||
|
add_library(checkpoints STATIC IMPORTED)
|
||||||
|
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libcheckpoints.a)
|
||||||
|
|
||||||
|
add_library(device STATIC IMPORTED)
|
||||||
|
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libdevice.a)
|
||||||
|
|
||||||
|
add_library(device_trezor STATIC IMPORTED)
|
||||||
|
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libdevice_trezor.a)
|
||||||
|
|
||||||
|
add_library(multisig STATIC IMPORTED)
|
||||||
|
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libmultisig.a)
|
||||||
|
|
||||||
|
add_library(version STATIC IMPORTED)
|
||||||
|
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libversion.a)
|
||||||
|
|
||||||
|
add_library(net STATIC IMPORTED)
|
||||||
|
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libnet.a)
|
||||||
|
|
||||||
|
add_library(hardforks STATIC IMPORTED)
|
||||||
|
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libhardforks.a)
|
||||||
|
|
||||||
|
add_library(randomx STATIC IMPORTED)
|
||||||
|
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/librandomx.a)
|
||||||
|
|
||||||
|
add_library(rpc_base STATIC IMPORTED)
|
||||||
|
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/librpc_base.a)
|
||||||
|
|
||||||
|
add_library(wallet-crypto STATIC IMPORTED)
|
||||||
|
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/monero/libwallet-crypto.a)
|
||||||
|
|
||||||
|
add_library(unbound STATIC IMPORTED)
|
||||||
|
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/lib/libunbound.a)
|
||||||
|
|
||||||
|
include_directories( ${EXTERNAL_LIBS_DIR}/include )
|
||||||
|
|
||||||
|
target_link_libraries( cw_monero
|
||||||
|
|
||||||
|
wallet_api
|
||||||
|
wallet
|
||||||
|
cryptonote_core
|
||||||
|
cryptonote_basic
|
||||||
|
cryptonote_format_utils_basic
|
||||||
|
mnemonics
|
||||||
|
ringct
|
||||||
|
ringct_basic
|
||||||
|
net
|
||||||
|
common
|
||||||
|
cncrypto
|
||||||
|
blockchain_db
|
||||||
|
lmdb
|
||||||
|
easylogging
|
||||||
|
unbound
|
||||||
|
epee
|
||||||
|
blocks
|
||||||
|
checkpoints
|
||||||
|
device
|
||||||
|
device_trezor
|
||||||
|
multisig
|
||||||
|
version
|
||||||
|
randomx
|
||||||
|
hardforks
|
||||||
|
rpc_base
|
||||||
|
wallet-crypto
|
||||||
|
|
||||||
|
boost_chrono
|
||||||
|
boost_date_time
|
||||||
|
boost_filesystem
|
||||||
|
boost_program_options
|
||||||
|
boost_regex
|
||||||
|
boost_serialization
|
||||||
|
boost_system
|
||||||
|
boost_thread
|
||||||
|
boost_wserialization
|
||||||
|
|
||||||
|
ssl
|
||||||
|
crypto
|
||||||
|
|
||||||
|
sodium
|
||||||
|
)
|
70
cw_monero/linux/cw_monero_plugin.cc
Normal file
70
cw_monero/linux/cw_monero_plugin.cc
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#include "include/cw_monero/cw_monero_plugin.h"
|
||||||
|
|
||||||
|
#include <flutter_linux/flutter_linux.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#define CW_MONERO_PLUGIN(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj), cw_monero_plugin_get_type(), \
|
||||||
|
CwMoneroPlugin))
|
||||||
|
|
||||||
|
struct _CwMoneroPlugin {
|
||||||
|
GObject parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(CwMoneroPlugin, cw_monero_plugin, g_object_get_type())
|
||||||
|
|
||||||
|
// Called when a method call is received from Flutter.
|
||||||
|
static void cw_monero_plugin_handle_method_call(
|
||||||
|
CwMoneroPlugin* self,
|
||||||
|
FlMethodCall* method_call) {
|
||||||
|
g_autoptr(FlMethodResponse) response = nullptr;
|
||||||
|
|
||||||
|
const gchar* method = fl_method_call_get_name(method_call);
|
||||||
|
|
||||||
|
if (strcmp(method, "getPlatformVersion") == 0) {
|
||||||
|
struct utsname uname_data = {};
|
||||||
|
uname(&uname_data);
|
||||||
|
g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version);
|
||||||
|
g_autoptr(FlValue) result = fl_value_new_string(version);
|
||||||
|
response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
|
||||||
|
} else {
|
||||||
|
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
|
||||||
|
}
|
||||||
|
|
||||||
|
fl_method_call_respond(method_call, response, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cw_monero_plugin_dispose(GObject* object) {
|
||||||
|
G_OBJECT_CLASS(cw_monero_plugin_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cw_monero_plugin_class_init(CwMoneroPluginClass* klass) {
|
||||||
|
G_OBJECT_CLASS(klass)->dispose = cw_monero_plugin_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cw_monero_plugin_init(CwMoneroPlugin* self) {}
|
||||||
|
|
||||||
|
static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call,
|
||||||
|
gpointer user_data) {
|
||||||
|
CwMoneroPlugin* plugin = CW_MONERO_PLUGIN(user_data);
|
||||||
|
cw_monero_plugin_handle_method_call(plugin, method_call);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cw_monero_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
|
||||||
|
CwMoneroPlugin* plugin = CW_MONERO_PLUGIN(
|
||||||
|
g_object_new(cw_monero_plugin_get_type(), nullptr));
|
||||||
|
|
||||||
|
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||||
|
g_autoptr(FlMethodChannel) channel =
|
||||||
|
fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),
|
||||||
|
"cw_monero",
|
||||||
|
FL_METHOD_CODEC(codec));
|
||||||
|
fl_method_channel_set_method_call_handler(channel, method_call_cb,
|
||||||
|
g_object_ref(plugin),
|
||||||
|
g_object_unref);
|
||||||
|
|
||||||
|
g_object_unref(plugin);
|
||||||
|
}
|
11
cw_monero/linux/flutter/generated_plugin_registrant.cc
Normal file
11
cw_monero/linux/flutter/generated_plugin_registrant.cc
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
|
||||||
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
}
|
15
cw_monero/linux/flutter/generated_plugin_registrant.h
Normal file
15
cw_monero/linux/flutter/generated_plugin_registrant.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||||
|
#define GENERATED_PLUGIN_REGISTRANT_
|
||||||
|
|
||||||
|
#include <flutter_linux/flutter_linux.h>
|
||||||
|
|
||||||
|
// Registers Flutter plugins.
|
||||||
|
void fl_register_plugins(FlPluginRegistry* registry);
|
||||||
|
|
||||||
|
#endif // GENERATED_PLUGIN_REGISTRANT_
|
23
cw_monero/linux/flutter/generated_plugins.cmake
Normal file
23
cw_monero/linux/flutter/generated_plugins.cmake
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#
|
||||||
|
# Generated file, do not edit.
|
||||||
|
#
|
||||||
|
|
||||||
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
)
|
||||||
|
|
||||||
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|
||||||
|
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
||||||
|
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
|
||||||
|
endforeach(plugin)
|
||||||
|
|
||||||
|
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
|
||||||
|
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
|
||||||
|
endforeach(ffi_plugin)
|
26
cw_monero/linux/include/cw_monero/cw_monero_plugin.h
Normal file
26
cw_monero/linux/include/cw_monero/cw_monero_plugin.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef FLUTTER_PLUGIN_CW_MONERO_PLUGIN_H_
|
||||||
|
#define FLUTTER_PLUGIN_CW_MONERO_PLUGIN_H_
|
||||||
|
|
||||||
|
#include <flutter_linux/flutter_linux.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef FLUTTER_PLUGIN_IMPL
|
||||||
|
#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
#define FLUTTER_PLUGIN_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _CwMoneroPlugin CwMoneroPlugin;
|
||||||
|
typedef struct {
|
||||||
|
GObjectClass parent_class;
|
||||||
|
} CwMoneroPluginClass;
|
||||||
|
|
||||||
|
FLUTTER_PLUGIN_EXPORT GType cw_monero_plugin_get_type();
|
||||||
|
|
||||||
|
FLUTTER_PLUGIN_EXPORT void cw_monero_plugin_register_with_registrar(
|
||||||
|
FlPluginRegistrar* registrar);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif // FLUTTER_PLUGIN_CW_MONERO_PLUGIN_H_
|
|
@ -113,6 +113,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.9.2"
|
version: "8.9.2"
|
||||||
|
cake_backup:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: main
|
||||||
|
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
||||||
|
url: "https://github.com/cake-tech/cake_backup.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.0+1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -169,6 +178,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.3"
|
||||||
|
cryptography:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cryptography
|
||||||
|
sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.7.0"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
cw_core:
|
cw_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -342,10 +367,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: js
|
name: js
|
||||||
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.1"
|
version: "0.6.7"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -696,6 +721,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:cw_core/key.dart';
|
|
||||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
|
||||||
|
|
||||||
Future<void> write(
|
|
||||||
{required String path,
|
|
||||||
required String password,
|
|
||||||
required String data}) async {
|
|
||||||
final keys = extractKeys(password);
|
|
||||||
final key = encrypt.Key.fromBase64(keys.first);
|
|
||||||
final iv = encrypt.IV.fromBase64(keys.last);
|
|
||||||
final encrypted = await encode(key: key, iv: iv, data: data);
|
|
||||||
final f = File(path);
|
|
||||||
f.writeAsStringSync(encrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> writeData(
|
|
||||||
{required String path,
|
|
||||||
required String password,
|
|
||||||
required String data}) async {
|
|
||||||
final keys = extractKeys(password);
|
|
||||||
final key = encrypt.Key.fromBase64(keys.first);
|
|
||||||
final iv = encrypt.IV.fromBase64(keys.last);
|
|
||||||
final encrypted = await encode(key: key, iv: iv, data: data);
|
|
||||||
final f = File(path);
|
|
||||||
f.writeAsStringSync(encrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> read({required String path, required String password}) async {
|
|
||||||
final file = File(path);
|
|
||||||
|
|
||||||
if (!file.existsSync()) {
|
|
||||||
file.createSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
final encrypted = file.readAsStringSync();
|
|
||||||
|
|
||||||
return decode(password: password, data: encrypted);
|
|
||||||
}
|
|
|
@ -2,24 +2,29 @@ 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/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_nano/file.dart';
|
import 'package:cw_core/encryption_file_utils.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';
|
||||||
import 'package:cw_nano/nano_transaction_info.dart';
|
import 'package:cw_nano/nano_transaction_info.dart';
|
||||||
|
|
||||||
part 'nano_transaction_history.g.dart';
|
part 'nano_transaction_history.g.dart';
|
||||||
|
|
||||||
const transactionsHistoryFileName = 'transactions.json';
|
const transactionsHistoryFileName = 'transactions.json';
|
||||||
|
|
||||||
class NanoTransactionHistory = NanoTransactionHistoryBase with _$NanoTransactionHistory;
|
class NanoTransactionHistory = NanoTransactionHistoryBase with _$NanoTransactionHistory;
|
||||||
|
|
||||||
abstract class NanoTransactionHistoryBase
|
abstract class NanoTransactionHistoryBase extends TransactionHistoryBase<NanoTransactionInfo>
|
||||||
extends TransactionHistoryBase<NanoTransactionInfo> with Store {
|
with Store {
|
||||||
NanoTransactionHistoryBase({required this.walletInfo, required String password})
|
NanoTransactionHistoryBase({
|
||||||
: _password = password {
|
required this.walletInfo,
|
||||||
|
required String password,
|
||||||
|
required this.encryptionFileUtils,
|
||||||
|
}) : _password = password {
|
||||||
transactions = ObservableMap<String, NanoTransactionInfo>();
|
transactions = ObservableMap<String, NanoTransactionInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletInfo walletInfo;
|
final WalletInfo walletInfo;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
String _password;
|
String _password;
|
||||||
|
|
||||||
Future<void> init() async => await _load();
|
Future<void> init() async => await _load();
|
||||||
|
@ -30,7 +35,7 @@ abstract class NanoTransactionHistoryBase
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final data = json.encode({'transactions': transactions});
|
final data = json.encode({'transactions': transactions});
|
||||||
await writeData(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()}');
|
print('Error while save nano transaction history: ${e.toString()}');
|
||||||
}
|
}
|
||||||
|
@ -46,7 +51,10 @@ abstract class NanoTransactionHistoryBase
|
||||||
Future<Map<String, dynamic>> _read() async {
|
Future<Map<String, dynamic>> _read() async {
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final content = await read(path: path, password: _password);
|
final content = await encryptionFileUtils.read(path: path, password: _password);
|
||||||
|
if (content.isEmpty) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
return json.decode(content) as Map<String, dynamic>;
|
return json.decode(content) as Map<String, dynamic>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:io';
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:cw_core/cake_hive.dart';
|
import 'package:cw_core/cake_hive.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/n2_node.dart';
|
import 'package:cw_core/n2_node.dart';
|
||||||
import 'package:cw_core/nano_account.dart';
|
import 'package:cw_core/nano_account.dart';
|
||||||
import 'package:cw_core/nano_account_info_response.dart';
|
import 'package:cw_core/nano_account_info_response.dart';
|
||||||
|
@ -17,7 +18,6 @@ import 'package:cw_core/transaction_priority.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';
|
||||||
import 'package:cw_nano/file.dart';
|
|
||||||
import 'package:cw_nano/nano_balance.dart';
|
import 'package:cw_nano/nano_balance.dart';
|
||||||
import 'package:cw_nano/nano_client.dart';
|
import 'package:cw_nano/nano_client.dart';
|
||||||
import 'package:cw_nano/nano_transaction_credentials.dart';
|
import 'package:cw_nano/nano_transaction_credentials.dart';
|
||||||
|
@ -42,11 +42,13 @@ abstract class NanoWalletBase
|
||||||
required String mnemonic,
|
required String mnemonic,
|
||||||
required String password,
|
required String password,
|
||||||
NanoBalance? initialBalance,
|
NanoBalance? initialBalance,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
}) : syncStatus = NotConnectedSyncStatus(),
|
}) : syncStatus = NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_mnemonic = mnemonic,
|
_mnemonic = mnemonic,
|
||||||
_derivationType = walletInfo.derivationInfo!.derivationType!,
|
_derivationType = walletInfo.derivationInfo!.derivationType!,
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
|
_encryptionFileUtils = encryptionFileUtils,
|
||||||
_client = NanoClient(),
|
_client = NanoClient(),
|
||||||
walletAddresses = NanoWalletAddresses(walletInfo),
|
walletAddresses = NanoWalletAddresses(walletInfo),
|
||||||
balance = ObservableMap<CryptoCurrency, NanoBalance>.of({
|
balance = ObservableMap<CryptoCurrency, NanoBalance>.of({
|
||||||
|
@ -55,7 +57,11 @@ abstract class NanoWalletBase
|
||||||
}),
|
}),
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory = NanoTransactionHistory(walletInfo: walletInfo, password: password);
|
transactionHistory = NanoTransactionHistory(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
password: password,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
|
);
|
||||||
if (!CakeHive.isAdapterRegistered(NanoAccount.typeId)) {
|
if (!CakeHive.isAdapterRegistered(NanoAccount.typeId)) {
|
||||||
CakeHive.registerAdapter(NanoAccountAdapter());
|
CakeHive.registerAdapter(NanoAccountAdapter());
|
||||||
}
|
}
|
||||||
|
@ -65,6 +71,8 @@ abstract class NanoWalletBase
|
||||||
final String _password;
|
final String _password;
|
||||||
DerivationType _derivationType;
|
DerivationType _derivationType;
|
||||||
|
|
||||||
|
final EncryptionFileUtils _encryptionFileUtils;
|
||||||
|
|
||||||
String? _privateKey;
|
String? _privateKey;
|
||||||
String? _publicAddress;
|
String? _publicAddress;
|
||||||
String? _hexSeed;
|
String? _hexSeed;
|
||||||
|
@ -89,6 +97,9 @@ abstract class NanoWalletBase
|
||||||
@observable
|
@observable
|
||||||
late ObservableMap<CryptoCurrency, NanoBalance> balance;
|
late ObservableMap<CryptoCurrency, NanoBalance> balance;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get password => _password;
|
||||||
|
|
||||||
static const int POLL_INTERVAL_SECONDS = 10;
|
static const int POLL_INTERVAL_SECONDS = 10;
|
||||||
|
|
||||||
// initialize the different forms of private / public key we'll need:
|
// initialize the different forms of private / public key we'll need:
|
||||||
|
@ -308,13 +319,13 @@ abstract class NanoWalletBase
|
||||||
@override
|
@override
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
||||||
await saveKeysFile(_password);
|
await saveKeysFile(_password, _encryptionFileUtils);
|
||||||
saveKeysFile(_password, true);
|
saveKeysFile(_password, _encryptionFileUtils, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
await walletAddresses.updateAddressesInBox();
|
await walletAddresses.updateAddressesInBox();
|
||||||
final path = await makePath();
|
final path = await makePath();
|
||||||
await write(path: path, password: _password, data: toJSON());
|
await _encryptionFileUtils.write(path: path, password: _password, data: toJSON());
|
||||||
await transactionHistory.save();
|
await transactionHistory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,13 +384,14 @@ abstract class NanoWalletBase
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
}) async {
|
}) async {
|
||||||
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
||||||
final path = await pathForWallet(name: name, type: walletInfo.type);
|
final path = await pathForWallet(name: name, type: walletInfo.type);
|
||||||
|
|
||||||
Map<String, dynamic>? data = null;
|
Map<String, dynamic>? data = null;
|
||||||
try {
|
try {
|
||||||
final jsonSource = await read(path: path, password: password);
|
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
|
||||||
|
|
||||||
data = json.decode(jsonSource) as Map<String, dynamic>;
|
data = json.decode(jsonSource) as Map<String, dynamic>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -400,7 +412,12 @@ abstract class NanoWalletBase
|
||||||
keysData = WalletKeysData(
|
keysData = WalletKeysData(
|
||||||
mnemonic: isHexSeed ? null : mnemonic, altMnemonic: isHexSeed ? mnemonic : null);
|
mnemonic: isHexSeed ? null : mnemonic, altMnemonic: isHexSeed ? mnemonic : null);
|
||||||
} else {
|
} else {
|
||||||
keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
|
keysData = await WalletKeysFile.readKeysFile(
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivationType derivationType = DerivationType.nano;
|
DerivationType derivationType = DerivationType.nano;
|
||||||
|
@ -416,6 +433,7 @@ abstract class NanoWalletBase
|
||||||
password: password,
|
password: password,
|
||||||
mnemonic: keysData.mnemonic!,
|
mnemonic: keysData.mnemonic!,
|
||||||
initialBalance: balance,
|
initialBalance: balance,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
);
|
);
|
||||||
// init() should always be run after this!
|
// init() should always be run after this!
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.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_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
@ -15,9 +16,10 @@ import 'package:nanoutil/nanoutil.dart';
|
||||||
|
|
||||||
class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
NanoRestoreWalletFromSeedCredentials, NanoRestoreWalletFromKeysCredentials, NanoNewWalletCredentials> {
|
NanoRestoreWalletFromSeedCredentials, NanoRestoreWalletFromKeysCredentials, NanoNewWalletCredentials> {
|
||||||
NanoWalletService(this.walletInfoSource);
|
NanoWalletService(this.walletInfoSource, this.isDirect);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
static bool walletFilesExist(String path) =>
|
static bool walletFilesExist(String path) =>
|
||||||
!File(path).existsSync() && !File('$path.keys').existsSync();
|
!File(path).existsSync() && !File('$path.keys').existsSync();
|
||||||
|
@ -38,6 +40,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -65,8 +68,12 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
|
|
||||||
String randomWords =
|
String randomWords =
|
||||||
(List<String>.from(nm.NanoMnemomics.WORDLIST)..shuffle()).take(24).join(' ');
|
(List<String>.from(nm.NanoMnemomics.WORDLIST)..shuffle()).take(24).join(' ');
|
||||||
final currentWallet =
|
final currentWallet = NanoWallet(
|
||||||
NanoWallet(walletInfo: currentWalletInfo, password: password, mnemonic: randomWords);
|
walletInfo: currentWalletInfo,
|
||||||
|
password: password,
|
||||||
|
mnemonic: randomWords,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
await saveBackup(newName);
|
await saveBackup(newName);
|
||||||
|
@ -103,6 +110,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
mnemonic: mnemonic ?? credentials.seedKey,
|
mnemonic: mnemonic ?? credentials.seedKey,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
|
@ -139,6 +147,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -160,6 +169,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -172,6 +182,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
|
@ -137,6 +137,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.9.2"
|
version: "8.9.2"
|
||||||
|
cake_backup:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: main
|
||||||
|
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
||||||
|
url: "https://github.com/cake-tech/cake_backup.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.0+1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -193,6 +202,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.3"
|
||||||
|
cryptography:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cryptography
|
||||||
|
sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.7.0"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
cw_core:
|
cw_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -797,6 +822,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -8,6 +8,7 @@ class PolygonTransactionHistory extends EVMChainTransactionHistory {
|
||||||
PolygonTransactionHistory({
|
PolygonTransactionHistory({
|
||||||
required super.walletInfo,
|
required super.walletInfo,
|
||||||
required super.password,
|
required super.password,
|
||||||
|
required super.encryptionFileUtils,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:cw_core/cake_hive.dart';
|
import 'package:cw_core/cake_hive.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/erc20_token.dart';
|
import 'package:cw_core/erc20_token.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
|
@ -12,7 +13,6 @@ import 'package:cw_evm/evm_chain_transaction_info.dart';
|
||||||
import 'package:cw_evm/evm_chain_transaction_model.dart';
|
import 'package:cw_evm/evm_chain_transaction_model.dart';
|
||||||
import 'package:cw_evm/evm_chain_wallet.dart';
|
import 'package:cw_evm/evm_chain_wallet.dart';
|
||||||
import 'package:cw_evm/evm_erc20_balance.dart';
|
import 'package:cw_evm/evm_erc20_balance.dart';
|
||||||
import 'package:cw_evm/file.dart';
|
|
||||||
import 'package:cw_polygon/default_polygon_erc20_tokens.dart';
|
import 'package:cw_polygon/default_polygon_erc20_tokens.dart';
|
||||||
import 'package:cw_polygon/polygon_client.dart';
|
import 'package:cw_polygon/polygon_client.dart';
|
||||||
import 'package:cw_polygon/polygon_transaction_history.dart';
|
import 'package:cw_polygon/polygon_transaction_history.dart';
|
||||||
|
@ -26,6 +26,7 @@ class PolygonWallet extends EVMChainWallet {
|
||||||
super.initialBalance,
|
super.initialBalance,
|
||||||
super.privateKey,
|
super.privateKey,
|
||||||
required super.client,
|
required super.client,
|
||||||
|
required super.encryptionFileUtils,
|
||||||
}) : super(nativeCurrency: CryptoCurrency.maticpoly);
|
}) : super(nativeCurrency: CryptoCurrency.maticpoly);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -92,18 +93,27 @@ class PolygonWallet extends EVMChainWallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
EVMChainTransactionHistory setUpTransactionHistory(WalletInfo walletInfo, String password) {
|
EVMChainTransactionHistory setUpTransactionHistory(
|
||||||
return PolygonTransactionHistory(walletInfo: walletInfo, password: password);
|
WalletInfo walletInfo, String password, EncryptionFileUtils encryptionFileUtils) {
|
||||||
|
return PolygonTransactionHistory(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
password: password,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<PolygonWallet> open(
|
static Future<PolygonWallet> open({
|
||||||
{required String name, required String password, required WalletInfo walletInfo}) async {
|
required String name,
|
||||||
|
required String password,
|
||||||
|
required WalletInfo walletInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
|
}) async {
|
||||||
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
||||||
final path = await pathForWallet(name: name, type: walletInfo.type);
|
final path = await pathForWallet(name: name, type: walletInfo.type);
|
||||||
|
|
||||||
Map<String, dynamic>? data;
|
Map<String, dynamic>? data;
|
||||||
try {
|
try {
|
||||||
final jsonSource = await read(path: path, password: password);
|
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
|
||||||
|
|
||||||
data = json.decode(jsonSource) as Map<String, dynamic>;
|
data = json.decode(jsonSource) as Map<String, dynamic>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -121,7 +131,12 @@ class PolygonWallet extends EVMChainWallet {
|
||||||
|
|
||||||
keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
|
keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
|
||||||
} else {
|
} else {
|
||||||
keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
|
keysData = await WalletKeysFile.readKeysFile(
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PolygonWallet(
|
return PolygonWallet(
|
||||||
|
@ -131,6 +146,7 @@ class PolygonWallet extends EVMChainWallet {
|
||||||
privateKey: keysData.privateKey,
|
privateKey: keysData.privateKey,
|
||||||
initialBalance: balance,
|
initialBalance: balance,
|
||||||
client: PolygonClient(),
|
client: PolygonClient(),
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/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_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -10,7 +11,7 @@ import 'package:cw_polygon/polygon_wallet.dart';
|
||||||
|
|
||||||
class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
||||||
PolygonWalletService(
|
PolygonWalletService(
|
||||||
super.walletInfoSource, {
|
super.walletInfoSource, super.isDirect, {
|
||||||
required this.client,
|
required this.client,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
client: client,
|
client: client,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -48,6 +50,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -61,6 +64,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -77,6 +81,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
||||||
privateKey: credentials.privateKey,
|
privateKey: credentials.privateKey,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
client: client,
|
client: client,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -99,6 +104,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
client: client,
|
client: client,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -120,6 +126,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
client: client,
|
client: client,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -134,7 +141,11 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
|
||||||
final currentWalletInfo = walletInfoSource.values
|
final currentWalletInfo = walletInfoSource.values
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
final currentWallet = await PolygonWallet.open(
|
final currentWallet = await PolygonWallet.open(
|
||||||
password: password, name: currentName, walletInfo: currentWalletInfo);
|
password: password,
|
||||||
|
name: currentName,
|
||||||
|
walletInfo: currentWalletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
await saveBackup(newName);
|
await saveBackup(newName);
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:cw_core/key.dart';
|
|
||||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
|
||||||
|
|
||||||
Future<void> write(
|
|
||||||
{required String path,
|
|
||||||
required String password,
|
|
||||||
required String data}) async {
|
|
||||||
final keys = extractKeys(password);
|
|
||||||
final key = encrypt.Key.fromBase64(keys.first);
|
|
||||||
final iv = encrypt.IV.fromBase64(keys.last);
|
|
||||||
final encrypted = await encode(key: key, iv: iv, data: data);
|
|
||||||
final f = File(path);
|
|
||||||
f.writeAsStringSync(encrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> writeData(
|
|
||||||
{required String path,
|
|
||||||
required String password,
|
|
||||||
required String data}) async {
|
|
||||||
final keys = extractKeys(password);
|
|
||||||
final key = encrypt.Key.fromBase64(keys.first);
|
|
||||||
final iv = encrypt.IV.fromBase64(keys.last);
|
|
||||||
final encrypted = await encode(key: key, iv: iv, data: data);
|
|
||||||
final f = File(path);
|
|
||||||
f.writeAsStringSync(encrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> read({required String path, required String password}) async {
|
|
||||||
final file = File(path);
|
|
||||||
|
|
||||||
if (!file.existsSync()) {
|
|
||||||
file.createSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
final encrypted = file.readAsStringSync();
|
|
||||||
|
|
||||||
return decode(password: password, data: encrypted);
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_solana/file.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';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
|
@ -15,12 +15,14 @@ class SolanaTransactionHistory = SolanaTransactionHistoryBase with _$SolanaTrans
|
||||||
|
|
||||||
abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<SolanaTransactionInfo>
|
abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<SolanaTransactionInfo>
|
||||||
with Store {
|
with Store {
|
||||||
SolanaTransactionHistoryBase({required this.walletInfo, required String password})
|
SolanaTransactionHistoryBase(
|
||||||
|
{required this.walletInfo, required String password, required this.encryptionFileUtils})
|
||||||
: _password = password {
|
: _password = password {
|
||||||
transactions = ObservableMap<String, SolanaTransactionInfo>();
|
transactions = ObservableMap<String, SolanaTransactionInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletInfo walletInfo;
|
final WalletInfo walletInfo;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
String _password;
|
String _password;
|
||||||
|
|
||||||
Future<void> init() async => await _load();
|
Future<void> init() async => await _load();
|
||||||
|
@ -32,7 +34,7 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<Solan
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson()));
|
final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson()));
|
||||||
final data = json.encode({'transactions': transactionMaps});
|
final data = json.encode({'transactions': transactionMaps});
|
||||||
await writeData(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()}');
|
print('Error while saving solana transaction history: ${e.toString()}');
|
||||||
print(s);
|
print(s);
|
||||||
|
@ -49,7 +51,7 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<Solan
|
||||||
Future<Map<String, dynamic>> _read() async {
|
Future<Map<String, dynamic>> _read() async {
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final content = await read(path: path, password: _password);
|
final content = await encryptionFileUtils.read(path: path, password: _password);
|
||||||
if (content.isEmpty) {
|
if (content.isEmpty) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:cw_core/cake_hive.dart';
|
import 'package:cw_core/cake_hive.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/node.dart';
|
import 'package:cw_core/node.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/pending_transaction.dart';
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
|
@ -15,7 +16,6 @@ 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';
|
||||||
import 'package:cw_solana/default_spl_tokens.dart';
|
import 'package:cw_solana/default_spl_tokens.dart';
|
||||||
import 'package:cw_solana/file.dart';
|
|
||||||
import 'package:cw_solana/solana_balance.dart';
|
import 'package:cw_solana/solana_balance.dart';
|
||||||
import 'package:cw_solana/solana_client.dart';
|
import 'package:cw_solana/solana_client.dart';
|
||||||
import 'package:cw_solana/solana_exceptions.dart';
|
import 'package:cw_solana/solana_exceptions.dart';
|
||||||
|
@ -46,6 +46,7 @@ abstract class SolanaWalletBase
|
||||||
String? privateKey,
|
String? privateKey,
|
||||||
required String password,
|
required String password,
|
||||||
SolanaBalance? initialBalance,
|
SolanaBalance? initialBalance,
|
||||||
|
required this.encryptionFileUtils,
|
||||||
}) : syncStatus = const NotConnectedSyncStatus(),
|
}) : syncStatus = const NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_mnemonic = mnemonic,
|
_mnemonic = mnemonic,
|
||||||
|
@ -56,7 +57,11 @@ abstract class SolanaWalletBase
|
||||||
{CryptoCurrency.sol: initialBalance ?? SolanaBalance(BigInt.zero.toDouble())}),
|
{CryptoCurrency.sol: initialBalance ?? SolanaBalance(BigInt.zero.toDouble())}),
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory = SolanaTransactionHistory(walletInfo: walletInfo, password: password);
|
transactionHistory = SolanaTransactionHistory(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
password: password,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
|
);
|
||||||
|
|
||||||
if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
|
if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
|
||||||
CakeHive.registerAdapter(SPLTokenAdapter());
|
CakeHive.registerAdapter(SPLTokenAdapter());
|
||||||
|
@ -68,6 +73,7 @@ abstract class SolanaWalletBase
|
||||||
final String _password;
|
final String _password;
|
||||||
final String? _mnemonic;
|
final String? _mnemonic;
|
||||||
final String? _hexPrivateKey;
|
final String? _hexPrivateKey;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
|
|
||||||
// The Solana WalletPair
|
// The Solana WalletPair
|
||||||
Ed25519HDKeyPair? _walletKeyPair;
|
Ed25519HDKeyPair? _walletKeyPair;
|
||||||
|
@ -77,7 +83,7 @@ abstract class SolanaWalletBase
|
||||||
// To access the privateKey bytes.
|
// To access the privateKey bytes.
|
||||||
Ed25519HDKeyPairData? _keyPairData;
|
Ed25519HDKeyPairData? _keyPairData;
|
||||||
|
|
||||||
late SolanaWalletClient _client;
|
late final SolanaWalletClient _client;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
double? estimatedFee;
|
double? estimatedFee;
|
||||||
|
@ -97,7 +103,7 @@ abstract class SolanaWalletBase
|
||||||
@observable
|
@observable
|
||||||
late ObservableMap<CryptoCurrency, SolanaBalance> balance;
|
late ObservableMap<CryptoCurrency, SolanaBalance> balance;
|
||||||
|
|
||||||
Completer<SharedPreferences> _sharedPrefs = Completer();
|
final Completer<SharedPreferences> _sharedPrefs = Completer();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Ed25519HDKeyPairData get keys {
|
Ed25519HDKeyPairData get keys {
|
||||||
|
@ -343,13 +349,13 @@ abstract class SolanaWalletBase
|
||||||
@override
|
@override
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
||||||
await saveKeysFile(_password);
|
await saveKeysFile(_password, encryptionFileUtils);
|
||||||
saveKeysFile(_password, true);
|
saveKeysFile(_password, encryptionFileUtils, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
await walletAddresses.updateAddressesInBox();
|
await walletAddresses.updateAddressesInBox();
|
||||||
final path = await makePath();
|
final path = await makePath();
|
||||||
await write(path: path, password: _password, data: toJSON());
|
await encryptionFileUtils.write(path: path, password: _password, data: toJSON());
|
||||||
await transactionHistory.save();
|
await transactionHistory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,13 +388,14 @@ abstract class SolanaWalletBase
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
}) async {
|
}) async {
|
||||||
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
||||||
final path = await pathForWallet(name: name, type: walletInfo.type);
|
final path = await pathForWallet(name: name, type: walletInfo.type);
|
||||||
|
|
||||||
Map<String, dynamic>? data;
|
Map<String, dynamic>? data;
|
||||||
try {
|
try {
|
||||||
final jsonSource = await read(path: path, password: password);
|
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
|
||||||
|
|
||||||
data = json.decode(jsonSource) as Map<String, dynamic>;
|
data = json.decode(jsonSource) as Map<String, dynamic>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -405,7 +412,12 @@ abstract class SolanaWalletBase
|
||||||
|
|
||||||
keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
|
keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
|
||||||
} else {
|
} else {
|
||||||
keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
|
keysData = await WalletKeysFile.readKeysFile(
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SolanaWallet(
|
return SolanaWallet(
|
||||||
|
@ -414,6 +426,7 @@ abstract class SolanaWalletBase
|
||||||
mnemonic: keysData.mnemonic,
|
mnemonic: keysData.mnemonic,
|
||||||
privateKey: keysData.privateKey,
|
privateKey: keysData.privateKey,
|
||||||
initialBalance: balance,
|
initialBalance: balance,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,4 +585,7 @@ abstract class SolanaWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
SolanaClient? get solanaClient => _client.getSolanaClient;
|
SolanaClient? get solanaClient => _client.getSolanaClient;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get password => _password;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
class SolanaNewWalletCredentials extends WalletCredentials {
|
class SolanaNewWalletCredentials extends WalletCredentials {
|
||||||
SolanaNewWalletCredentials({required String name, WalletInfo? walletInfo})
|
SolanaNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
|
||||||
: super(name: name, walletInfo: walletInfo);
|
: super(name: name, walletInfo: walletInfo, password: password);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SolanaRestoreWalletFromSeedCredentials extends WalletCredentials {
|
class SolanaRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.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';
|
||||||
|
@ -17,9 +18,10 @@ import 'package:hive/hive.dart';
|
||||||
|
|
||||||
class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
|
class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
|
||||||
SolanaRestoreWalletFromSeedCredentials, SolanaRestoreWalletFromPrivateKey, SolanaNewWalletCredentials> {
|
SolanaRestoreWalletFromSeedCredentials, SolanaRestoreWalletFromPrivateKey, SolanaNewWalletCredentials> {
|
||||||
SolanaWalletService(this.walletInfoSource);
|
SolanaWalletService(this.walletInfoSource, this.isDirect);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<SolanaWallet> create(SolanaNewWalletCredentials credentials, {bool? isTestnet}) async {
|
Future<SolanaWallet> create(SolanaNewWalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
|
@ -31,6 +33,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -56,6 +59,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -69,6 +73,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -92,6 +97,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
privateKey: credentials.privateKey,
|
privateKey: credentials.privateKey,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -112,6 +118,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -126,7 +133,11 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
|
||||||
final currentWalletInfo = walletInfoSource.values
|
final currentWalletInfo = walletInfoSource.values
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
final currentWallet = await SolanaWalletBase.open(
|
final currentWallet = await SolanaWalletBase.open(
|
||||||
password: password, name: currentName, walletInfo: currentWalletInfo);
|
password: password,
|
||||||
|
name: currentName,
|
||||||
|
walletInfo: currentWalletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
await saveBackup(newName);
|
await saveBackup(newName);
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:cw_core/key.dart';
|
|
||||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
|
||||||
|
|
||||||
Future<void> write(
|
|
||||||
{required String path,
|
|
||||||
required String password,
|
|
||||||
required String data}) async {
|
|
||||||
final keys = extractKeys(password);
|
|
||||||
final key = encrypt.Key.fromBase64(keys.first);
|
|
||||||
final iv = encrypt.IV.fromBase64(keys.last);
|
|
||||||
final encrypted = await encode(key: key, iv: iv, data: data);
|
|
||||||
final f = File(path);
|
|
||||||
f.writeAsStringSync(encrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> writeData(
|
|
||||||
{required String path,
|
|
||||||
required String password,
|
|
||||||
required String data}) async {
|
|
||||||
final keys = extractKeys(password);
|
|
||||||
final key = encrypt.Key.fromBase64(keys.first);
|
|
||||||
final iv = encrypt.IV.fromBase64(keys.last);
|
|
||||||
final encrypted = await encode(key: key, iv: iv, data: data);
|
|
||||||
final f = File(path);
|
|
||||||
f.writeAsStringSync(encrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> read({required String path, required String password}) async {
|
|
||||||
final file = File(path);
|
|
||||||
|
|
||||||
if (!file.existsSync()) {
|
|
||||||
file.createSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
final encrypted = file.readAsStringSync();
|
|
||||||
|
|
||||||
return decode(password: password, data: encrypted);
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ import 'dart:core';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_evm/file.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_tron/tron_transaction_info.dart';
|
import 'package:cw_tron/tron_transaction_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';
|
||||||
|
@ -14,7 +14,8 @@ class TronTransactionHistory = TronTransactionHistoryBase with _$TronTransaction
|
||||||
|
|
||||||
abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTransactionInfo>
|
abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTransactionInfo>
|
||||||
with Store {
|
with Store {
|
||||||
TronTransactionHistoryBase({required this.walletInfo, required String password})
|
TronTransactionHistoryBase(
|
||||||
|
{required this.walletInfo, required String password, required this.encryptionFileUtils})
|
||||||
: _password = password {
|
: _password = password {
|
||||||
transactions = ObservableMap<String, TronTransactionInfo>();
|
transactions = ObservableMap<String, TronTransactionInfo>();
|
||||||
}
|
}
|
||||||
|
@ -22,6 +23,7 @@ abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTra
|
||||||
String _password;
|
String _password;
|
||||||
|
|
||||||
final WalletInfo walletInfo;
|
final WalletInfo walletInfo;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
|
|
||||||
Future<void> init() async => await _load();
|
Future<void> init() async => await _load();
|
||||||
|
|
||||||
|
@ -33,7 +35,7 @@ abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTra
|
||||||
String path = '$dirPath/$transactionsHistoryFileNameForWallet';
|
String path = '$dirPath/$transactionsHistoryFileNameForWallet';
|
||||||
final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson()));
|
final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson()));
|
||||||
final data = json.encode({'transactions': transactionMaps});
|
final data = json.encode({'transactions': transactionMaps});
|
||||||
await writeData(path: path, password: _password, data: data);
|
await encryptionFileUtils.write(path: path, password: _password, data: data);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
log('Error while saving ${walletInfo.type.name} transaction history: ${e.toString()}');
|
log('Error while saving ${walletInfo.type.name} transaction history: ${e.toString()}');
|
||||||
log(s.toString());
|
log(s.toString());
|
||||||
|
@ -51,7 +53,7 @@ abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTra
|
||||||
String transactionsHistoryFileNameForWallet = 'tron_transactions.json';
|
String transactionsHistoryFileNameForWallet = 'tron_transactions.json';
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
String path = '$dirPath/$transactionsHistoryFileNameForWallet';
|
String path = '$dirPath/$transactionsHistoryFileNameForWallet';
|
||||||
final content = await read(path: path, password: _password);
|
final content = await encryptionFileUtils.read(path: path, password: _password);
|
||||||
if (content.isEmpty) {
|
if (content.isEmpty) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:cw_core/cake_hive.dart';
|
import 'package:cw_core/cake_hive.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/node.dart';
|
import 'package:cw_core/node.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/pending_transaction.dart';
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
|
@ -19,7 +20,6 @@ import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_keys_file.dart';
|
import 'package:cw_core/wallet_keys_file.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cw_tron/default_tron_tokens.dart';
|
import 'package:cw_tron/default_tron_tokens.dart';
|
||||||
import 'package:cw_tron/file.dart';
|
|
||||||
import 'package:cw_tron/tron_abi.dart';
|
import 'package:cw_tron/tron_abi.dart';
|
||||||
import 'package:cw_tron/tron_balance.dart';
|
import 'package:cw_tron/tron_balance.dart';
|
||||||
import 'package:cw_tron/tron_client.dart';
|
import 'package:cw_tron/tron_client.dart';
|
||||||
|
@ -46,6 +46,7 @@ abstract class TronWalletBase
|
||||||
String? privateKey,
|
String? privateKey,
|
||||||
required String password,
|
required String password,
|
||||||
TronBalance? initialBalance,
|
TronBalance? initialBalance,
|
||||||
|
required this.encryptionFileUtils,
|
||||||
}) : syncStatus = const NotConnectedSyncStatus(),
|
}) : syncStatus = const NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_mnemonic = mnemonic,
|
_mnemonic = mnemonic,
|
||||||
|
@ -57,7 +58,8 @@ abstract class TronWalletBase
|
||||||
),
|
),
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory = TronTransactionHistory(walletInfo: walletInfo, password: password);
|
transactionHistory = TronTransactionHistory(
|
||||||
|
walletInfo: walletInfo, password: password, encryptionFileUtils: encryptionFileUtils);
|
||||||
|
|
||||||
if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
|
if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
|
||||||
CakeHive.registerAdapter(TronTokenAdapter());
|
CakeHive.registerAdapter(TronTokenAdapter());
|
||||||
|
@ -67,6 +69,7 @@ abstract class TronWalletBase
|
||||||
final String? _mnemonic;
|
final String? _mnemonic;
|
||||||
final String? _hexPrivateKey;
|
final String? _hexPrivateKey;
|
||||||
final String _password;
|
final String _password;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
|
|
||||||
late final Box<TronToken> tronTokensBox;
|
late final Box<TronToken> tronTokensBox;
|
||||||
|
|
||||||
|
@ -125,13 +128,14 @@ abstract class TronWalletBase
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
}) async {
|
}) async {
|
||||||
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
|
||||||
final path = await pathForWallet(name: name, type: walletInfo.type);
|
final path = await pathForWallet(name: name, type: walletInfo.type);
|
||||||
|
|
||||||
Map<String, dynamic>? data;
|
Map<String, dynamic>? data;
|
||||||
try {
|
try {
|
||||||
final jsonSource = await read(path: path, password: password);
|
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
|
||||||
|
|
||||||
data = json.decode(jsonSource) as Map<String, dynamic>;
|
data = json.decode(jsonSource) as Map<String, dynamic>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -148,7 +152,12 @@ abstract class TronWalletBase
|
||||||
|
|
||||||
keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
|
keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
|
||||||
} else {
|
} else {
|
||||||
keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
|
keysData = await WalletKeysFile.readKeysFile(
|
||||||
|
name,
|
||||||
|
walletInfo.type,
|
||||||
|
password,
|
||||||
|
encryptionFileUtils,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TronWallet(
|
return TronWallet(
|
||||||
|
@ -157,6 +166,7 @@ abstract class TronWalletBase
|
||||||
mnemonic: keysData.mnemonic,
|
mnemonic: keysData.mnemonic,
|
||||||
privateKey: keysData.privateKey,
|
privateKey: keysData.privateKey,
|
||||||
initialBalance: balance,
|
initialBalance: balance,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,13 +440,13 @@ abstract class TronWalletBase
|
||||||
@override
|
@override
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
|
||||||
await saveKeysFile(_password);
|
await saveKeysFile(_password, encryptionFileUtils);
|
||||||
saveKeysFile(_password, true);
|
saveKeysFile(_password, encryptionFileUtils, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
await walletAddresses.updateAddressesInBox();
|
await walletAddresses.updateAddressesInBox();
|
||||||
final path = await makePath();
|
final path = await makePath();
|
||||||
await write(path: path, password: _password, data: toJSON());
|
await encryptionFileUtils.write(path: path, password: _password, data: toJSON());
|
||||||
await transactionHistory.save();
|
await transactionHistory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,4 +594,7 @@ abstract class TronWalletBase
|
||||||
_transactionsUpdateTimer?.cancel();
|
_transactionsUpdateTimer?.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get password => _password;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
class TronNewWalletCredentials extends WalletCredentials {
|
class TronNewWalletCredentials extends WalletCredentials {
|
||||||
TronNewWalletCredentials({required String name, WalletInfo? walletInfo})
|
TronNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
|
||||||
: super(name: name, walletInfo: walletInfo);
|
: super(name: name, walletInfo: walletInfo, password: password);
|
||||||
}
|
}
|
||||||
|
|
||||||
class TronRestoreWalletFromSeedCredentials extends WalletCredentials {
|
class TronRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.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/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
|
@ -21,11 +22,12 @@ class TronWalletService extends WalletService<
|
||||||
TronRestoreWalletFromSeedCredentials,
|
TronRestoreWalletFromSeedCredentials,
|
||||||
TronRestoreWalletFromPrivateKey,
|
TronRestoreWalletFromPrivateKey,
|
||||||
TronNewWalletCredentials> {
|
TronNewWalletCredentials> {
|
||||||
TronWalletService(this.walletInfoSource, {required this.client});
|
TronWalletService(this.walletInfoSource, {required this.client, required this.isDirect});
|
||||||
|
|
||||||
late TronClient client;
|
late TronClient client;
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletType getType() => WalletType.tron;
|
WalletType getType() => WalletType.tron;
|
||||||
|
@ -43,6 +45,7 @@ class TronWalletService extends WalletService<
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -62,6 +65,7 @@ class TronWalletService extends WalletService<
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -75,6 +79,7 @@ class TronWalletService extends WalletService<
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -92,6 +97,7 @@ class TronWalletService extends WalletService<
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
privateKey: credentials.privateKey,
|
privateKey: credentials.privateKey,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -114,6 +120,7 @@ class TronWalletService extends WalletService<
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -128,7 +135,11 @@ class TronWalletService extends WalletService<
|
||||||
final currentWalletInfo = walletInfoSource.values
|
final currentWalletInfo = walletInfoSource.values
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
final currentWallet = await TronWalletBase.open(
|
final currentWallet = await TronWalletBase.open(
|
||||||
password: password, name: currentName, walletInfo: currentWalletInfo);
|
password: password,
|
||||||
|
name: currentName,
|
||||||
|
walletInfo: currentWalletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
await saveBackup(newName);
|
await saveBackup(newName);
|
||||||
|
|
|
@ -50,7 +50,7 @@ abstract class WowneroWalletBase
|
||||||
extends WalletBase<WowneroBalance, WowneroTransactionHistory, WowneroTransactionInfo>
|
extends WalletBase<WowneroBalance, WowneroTransactionHistory, WowneroTransactionInfo>
|
||||||
with Store {
|
with Store {
|
||||||
WowneroWalletBase(
|
WowneroWalletBase(
|
||||||
{required WalletInfo walletInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo})
|
{required WalletInfo walletInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo, required String password})
|
||||||
: balance = ObservableMap<CryptoCurrency, WowneroBalance>.of({
|
: balance = ObservableMap<CryptoCurrency, WowneroBalance>.of({
|
||||||
CryptoCurrency.wow: WowneroBalance(
|
CryptoCurrency.wow: WowneroBalance(
|
||||||
fullBalance: wownero_wallet.getFullBalance(accountIndex: 0),
|
fullBalance: wownero_wallet.getFullBalance(accountIndex: 0),
|
||||||
|
@ -58,6 +58,7 @@ abstract class WowneroWalletBase
|
||||||
}),
|
}),
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
_hasSyncAfterStartup = false,
|
_hasSyncAfterStartup = false,
|
||||||
|
_password = password,
|
||||||
isEnabledAutoGenerateSubaddress = false,
|
isEnabledAutoGenerateSubaddress = false,
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
unspentCoins = [],
|
unspentCoins = [],
|
||||||
|
@ -109,6 +110,10 @@ abstract class WowneroWalletBase
|
||||||
|
|
||||||
String seedLegacy(String? language) => wownero_wallet.getSeedLegacy(language);
|
String seedLegacy(String? language) => wownero_wallet.getSeedLegacy(language);
|
||||||
|
|
||||||
|
String get password => _password;
|
||||||
|
|
||||||
|
String _password;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MoneroWalletKeys get keys => MoneroWalletKeys(
|
MoneroWalletKeys get keys => MoneroWalletKeys(
|
||||||
privateSpendKey: wownero_wallet.getSecretSpendKey(),
|
privateSpendKey: wownero_wallet.getSecretSpendKey(),
|
||||||
|
|
|
@ -93,7 +93,7 @@ class WowneroWalletService extends WalletService<
|
||||||
await wownero_wallet_manager.createWallet(
|
await wownero_wallet_manager.createWallet(
|
||||||
path: path, password: credentials.password!, language: credentials.language);
|
path: path, password: credentials.password!, language: credentials.language);
|
||||||
final wallet = WowneroWallet(
|
final wallet = WowneroWallet(
|
||||||
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -129,7 +129,7 @@ class WowneroWalletService extends WalletService<
|
||||||
await wownero_wallet_manager.openWalletAsync({'path': path, 'password': password});
|
await wownero_wallet_manager.openWalletAsync({'path': path, 'password': password});
|
||||||
final walletInfo = walletInfoSource.values
|
final walletInfo = walletInfoSource.values
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
||||||
wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
|
||||||
final isValid = wallet.walletAddresses.validate();
|
final isValid = wallet.walletAddresses.validate();
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
|
@ -210,7 +210,7 @@ class WowneroWalletService extends WalletService<
|
||||||
final currentWalletInfo = walletInfoSource.values
|
final currentWalletInfo = walletInfoSource.values
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
final currentWallet =
|
final currentWallet =
|
||||||
WowneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
WowneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ class WowneroWalletService extends WalletService<
|
||||||
viewKey: credentials.viewKey,
|
viewKey: credentials.viewKey,
|
||||||
spendKey: credentials.spendKey);
|
spendKey: credentials.spendKey);
|
||||||
final wallet = WowneroWallet(
|
final wallet = WowneroWallet(
|
||||||
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -268,7 +268,7 @@ class WowneroWalletService extends WalletService<
|
||||||
seed: credentials.mnemonic,
|
seed: credentials.mnemonic,
|
||||||
restoreHeight: credentials.height!);
|
restoreHeight: credentials.height!);
|
||||||
final wallet = WowneroWallet(
|
final wallet = WowneroWallet(
|
||||||
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
|
walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -315,7 +315,7 @@ class WowneroWalletService extends WalletService<
|
||||||
restoreHeight: height,
|
restoreHeight: height,
|
||||||
spendKey: spendKey);
|
spendKey: spendKey);
|
||||||
|
|
||||||
final wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
final wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
|
|
|
@ -113,6 +113,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.4.3"
|
version: "8.4.3"
|
||||||
|
cake_backup:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: main
|
||||||
|
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
||||||
|
url: "https://github.com/cake-tech/cake_backup.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.0+1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -169,6 +178,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
|
cryptography:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cryptography
|
||||||
|
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
cw_core:
|
cw_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -680,6 +705,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -29,8 +29,8 @@ class CWBitcoin extends Bitcoin {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createBitcoinNewWalletCredentials(
|
WalletCredentials createBitcoinNewWalletCredentials(
|
||||||
{required String name, WalletInfo? walletInfo}) =>
|
{required String name, WalletInfo? walletInfo, String? password}) =>
|
||||||
BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
|
BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createBitcoinHardwareWalletCredentials(
|
WalletCredentials createBitcoinHardwareWalletCredentials(
|
||||||
|
@ -203,13 +203,13 @@ class CWBitcoin extends Bitcoin {
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletService createBitcoinWalletService(
|
WalletService createBitcoinWalletService(
|
||||||
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan) {
|
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan, bool isDirect) {
|
||||||
return BitcoinWalletService(walletInfoSource, unspentCoinSource, alwaysScan);
|
return BitcoinWalletService(walletInfoSource, unspentCoinSource, alwaysScan, isDirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletService createLitecoinWalletService(
|
WalletService createLitecoinWalletService(
|
||||||
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
|
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
|
||||||
return LitecoinWalletService(walletInfoSource, unspentCoinSource);
|
return LitecoinWalletService(walletInfoSource, unspentCoinSource, isDirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -6,16 +6,17 @@ class CWBitcoinCash extends BitcoinCash {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletService createBitcoinCashWalletService(
|
WalletService createBitcoinCashWalletService(
|
||||||
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
|
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
|
||||||
return BitcoinCashWalletService(walletInfoSource, unspentCoinSource);
|
return BitcoinCashWalletService(walletInfoSource, unspentCoinSource, isDirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createBitcoinCashNewWalletCredentials({
|
WalletCredentials createBitcoinCashNewWalletCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
WalletInfo? walletInfo,
|
WalletInfo? walletInfo,
|
||||||
|
String? password,
|
||||||
}) =>
|
}) =>
|
||||||
BitcoinCashNewWalletCredentials(name: name, walletInfo: walletInfo);
|
BitcoinCashNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createBitcoinCashRestoreWalletFromSeedCredentials(
|
WalletCredentials createBitcoinCashRestoreWalletFromSeedCredentials(
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:cake_wallet/core/secure_storage.dart';
|
import 'package:cake_wallet/core/secure_storage.dart';
|
||||||
import 'package:cake_wallet/themes/theme_list.dart';
|
import 'package:cake_wallet/themes/theme_list.dart';
|
||||||
|
import 'package:cw_core/root_dir.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cw_core/root_dir.dart';
|
import 'package:cw_core/root_dir.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -20,7 +21,6 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||||
import 'package:cake_wallet/wallet_types.g.dart';
|
import 'package:cake_wallet/wallet_types.g.dart';
|
||||||
|
|
||||||
import 'package:cake_backup/backup.dart' as cake_backup;
|
import 'package:cake_backup/backup.dart' as cake_backup;
|
||||||
|
|
||||||
class BackupService {
|
class BackupService {
|
||||||
|
|
|
@ -15,7 +15,6 @@ import 'package:cw_core/wallet_type.dart';
|
||||||
class WalletCreationService {
|
class WalletCreationService {
|
||||||
WalletCreationService(
|
WalletCreationService(
|
||||||
{required WalletType initialType,
|
{required WalletType initialType,
|
||||||
required this.secureStorage,
|
|
||||||
required this.keyService,
|
required this.keyService,
|
||||||
required this.sharedPreferences,
|
required this.sharedPreferences,
|
||||||
required this.settingsStore,
|
required this.settingsStore,
|
||||||
|
@ -25,7 +24,6 @@ class WalletCreationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletType type;
|
WalletType type;
|
||||||
final SecureStorage secureStorage;
|
|
||||||
final SharedPreferences sharedPreferences;
|
final SharedPreferences sharedPreferences;
|
||||||
final SettingsStore settingsStore;
|
final SettingsStore settingsStore;
|
||||||
final KeyService keyService;
|
final KeyService keyService;
|
||||||
|
@ -56,12 +54,16 @@ class WalletCreationService {
|
||||||
|
|
||||||
Future<WalletBase> create(WalletCredentials credentials, {bool? isTestnet}) async {
|
Future<WalletBase> create(WalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
checkIfExists(credentials.name);
|
checkIfExists(credentials.name);
|
||||||
final password = generateWalletPassword();
|
|
||||||
credentials.password = password;
|
if (credentials.password == null) {
|
||||||
|
credentials.password = generateWalletPassword();
|
||||||
|
await keyService.saveWalletPassword(
|
||||||
|
password: credentials.password!, walletName: credentials.name);
|
||||||
|
}
|
||||||
|
|
||||||
if (_hasSeedPhraseLengthOption) {
|
if (_hasSeedPhraseLengthOption) {
|
||||||
credentials.seedPhraseLength = settingsStore.seedPhraseLength.value;
|
credentials.seedPhraseLength = settingsStore.seedPhraseLength.value;
|
||||||
}
|
}
|
||||||
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
|
|
||||||
final wallet = await _service!.create(credentials, isTestnet: isTestnet);
|
final wallet = await _service!.create(credentials, isTestnet: isTestnet);
|
||||||
|
|
||||||
if (wallet.type == WalletType.monero) {
|
if (wallet.type == WalletType.monero) {
|
||||||
|
@ -94,9 +96,13 @@ class WalletCreationService {
|
||||||
|
|
||||||
Future<WalletBase> restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) async {
|
Future<WalletBase> restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
checkIfExists(credentials.name);
|
checkIfExists(credentials.name);
|
||||||
final password = generateWalletPassword();
|
|
||||||
credentials.password = password;
|
if (credentials.password == null) {
|
||||||
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
|
credentials.password = generateWalletPassword();
|
||||||
|
await keyService.saveWalletPassword(
|
||||||
|
password: credentials.password!, walletName: credentials.name);
|
||||||
|
}
|
||||||
|
|
||||||
final wallet = await _service!.restoreFromKeys(credentials, isTestnet: isTestnet);
|
final wallet = await _service!.restoreFromKeys(credentials, isTestnet: isTestnet);
|
||||||
|
|
||||||
if (wallet.type == WalletType.monero) {
|
if (wallet.type == WalletType.monero) {
|
||||||
|
@ -109,9 +115,13 @@ class WalletCreationService {
|
||||||
|
|
||||||
Future<WalletBase> restoreFromSeed(WalletCredentials credentials, {bool? isTestnet}) async {
|
Future<WalletBase> restoreFromSeed(WalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
checkIfExists(credentials.name);
|
checkIfExists(credentials.name);
|
||||||
final password = generateWalletPassword();
|
|
||||||
credentials.password = password;
|
if (credentials.password == null) {
|
||||||
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
|
credentials.password = generateWalletPassword();
|
||||||
|
await keyService.saveWalletPassword(
|
||||||
|
password: credentials.password!, walletName: credentials.name);
|
||||||
|
}
|
||||||
|
|
||||||
final wallet = await _service!.restoreFromSeed(credentials, isTestnet: isTestnet);
|
final wallet = await _service!.restoreFromSeed(credentials, isTestnet: isTestnet);
|
||||||
|
|
||||||
if (wallet.type == WalletType.monero) {
|
if (wallet.type == WalletType.monero) {
|
||||||
|
|
|
@ -20,17 +20,18 @@ class WalletLoadingService {
|
||||||
final KeyService keyService;
|
final KeyService keyService;
|
||||||
final WalletService Function(WalletType type) walletServiceFactory;
|
final WalletService Function(WalletType type) walletServiceFactory;
|
||||||
|
|
||||||
Future<void> renameWallet(WalletType type, String name, String newName) async {
|
Future<void> renameWallet(WalletType type, String name, String newName,
|
||||||
|
{String? password}) async {
|
||||||
final walletService = walletServiceFactory.call(type);
|
final walletService = walletServiceFactory.call(type);
|
||||||
final password = await keyService.getWalletPassword(walletName: name);
|
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||||
|
|
||||||
// Save the current wallet's password to the new wallet name's key
|
// Save the current wallet's password to the new wallet name's key
|
||||||
await keyService.saveWalletPassword(walletName: newName, password: password);
|
await keyService.saveWalletPassword(walletName: newName, password: walletPassword);
|
||||||
// Delete previous wallet name from keyService to keep only new wallet's name
|
// Delete previous wallet name from keyService to keep only new wallet's name
|
||||||
// otherwise keeps duplicate (old and new names)
|
// otherwise keeps duplicate (old and new names)
|
||||||
await keyService.deleteWalletPassword(walletName: name);
|
await keyService.deleteWalletPassword(walletName: name);
|
||||||
|
|
||||||
await walletService.rename(name, password, newName);
|
await walletService.rename(name, walletPassword, newName);
|
||||||
|
|
||||||
// set shared preferences flag based on previous wallet name
|
// set shared preferences flag based on previous wallet name
|
||||||
if (type == WalletType.monero) {
|
if (type == WalletType.monero) {
|
||||||
|
@ -41,11 +42,11 @@ class WalletLoadingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<WalletBase> load(WalletType type, String name) async {
|
Future<WalletBase> load(WalletType type, String name, {String? password}) async {
|
||||||
try {
|
try {
|
||||||
final walletService = walletServiceFactory.call(type);
|
final walletService = walletServiceFactory.call(type);
|
||||||
final password = await keyService.getWalletPassword(walletName: name);
|
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||||
final wallet = await walletService.openWallet(name, password);
|
final wallet = await walletService.openWallet(name, walletPassword);
|
||||||
|
|
||||||
if (type == WalletType.monero) {
|
if (type == WalletType.monero) {
|
||||||
await updateMoneroWalletPassword(wallet);
|
await updateMoneroWalletPassword(wallet);
|
||||||
|
@ -67,8 +68,8 @@ class WalletLoadingService {
|
||||||
for (var walletInfo in walletInfoSource.values) {
|
for (var walletInfo in walletInfoSource.values) {
|
||||||
try {
|
try {
|
||||||
final walletService = walletServiceFactory.call(walletInfo.type);
|
final walletService = walletServiceFactory.call(walletInfo.type);
|
||||||
final password = await keyService.getWalletPassword(walletName: walletInfo.name);
|
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||||
final wallet = await walletService.openWallet(walletInfo.name, password);
|
final wallet = await walletService.openWallet(walletInfo.name, walletPassword);
|
||||||
|
|
||||||
if (walletInfo.type == WalletType.monero) {
|
if (walletInfo.type == WalletType.monero) {
|
||||||
await updateMoneroWalletPassword(wallet);
|
await updateMoneroWalletPassword(wallet);
|
||||||
|
|
86
lib/di.dart
86
lib/di.dart
|
@ -30,6 +30,7 @@ import 'package:cake_wallet/entities/contact.dart';
|
||||||
import 'package:cake_wallet/entities/contact_record.dart';
|
import 'package:cake_wallet/entities/contact_record.dart';
|
||||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||||
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||||
import 'package:cake_wallet/entities/template.dart';
|
import 'package:cake_wallet/entities/template.dart';
|
||||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||||
|
@ -113,6 +114,8 @@ import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart';
|
import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
|
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart';
|
||||||
import 'package:cake_wallet/themes/theme_list.dart';
|
import 'package:cake_wallet/themes/theme_list.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||||
|
@ -217,6 +220,8 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/wallet_unlock_loadable_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/wallet_unlock_verifiable_view_model.dart';
|
||||||
import 'package:cake_wallet/wownero/wownero.dart';
|
import 'package:cake_wallet/wownero/wownero.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/receive_page_option.dart';
|
import 'package:cw_core/receive_page_option.dart';
|
||||||
|
@ -337,7 +342,6 @@ Future<void> setup({
|
||||||
WalletCreationService(
|
WalletCreationService(
|
||||||
initialType: type,
|
initialType: type,
|
||||||
keyService: getIt.get<KeyService>(),
|
keyService: getIt.get<KeyService>(),
|
||||||
secureStorage: getIt.get<SecureStorage>(),
|
|
||||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||||
settingsStore: getIt.get<SettingsStore>(),
|
settingsStore: getIt.get<SettingsStore>(),
|
||||||
walletInfoSource: _walletInfoSource));
|
walletInfoSource: _walletInfoSource));
|
||||||
|
@ -357,6 +361,65 @@ Future<void> setup({
|
||||||
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
||||||
type: type));
|
type: type));
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<WalletUnlockPage, WalletUnlockArguments, bool>((args, closable) {
|
||||||
|
return WalletUnlockPage(
|
||||||
|
getIt.get<WalletUnlockLoadableViewModel>(param1: args),
|
||||||
|
args.callback,
|
||||||
|
args.authPasswordHandler,
|
||||||
|
closable: closable);
|
||||||
|
}, instanceName: 'wallet_unlock_loadable');
|
||||||
|
|
||||||
|
getIt.registerFactory<WalletUnlockPage>(
|
||||||
|
() => getIt.get<WalletUnlockPage>(
|
||||||
|
param1: WalletUnlockArguments(
|
||||||
|
callback: (bool successful, _) {
|
||||||
|
if (successful) {
|
||||||
|
final authStore = getIt.get<AuthenticationStore>();
|
||||||
|
authStore.allowed();
|
||||||
|
}}),
|
||||||
|
param2: false,
|
||||||
|
instanceName: 'wallet_unlock_loadable'),
|
||||||
|
instanceName: 'wallet_password_login');
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<WalletUnlockPage, WalletUnlockArguments, bool>((args, closable) {
|
||||||
|
return WalletUnlockPage(
|
||||||
|
getIt.get<WalletUnlockVerifiableViewModel>(param1: args),
|
||||||
|
args.callback,
|
||||||
|
args.authPasswordHandler,
|
||||||
|
closable: closable);
|
||||||
|
}, instanceName: 'wallet_unlock_verifiable');
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<WalletUnlockLoadableViewModel, WalletUnlockArguments, void>((args, _) {
|
||||||
|
final currentWalletName = getIt
|
||||||
|
.get<SharedPreferences>()
|
||||||
|
.getString(PreferencesKey.currentWalletName) ?? '';
|
||||||
|
final currentWalletTypeRaw =
|
||||||
|
getIt.get<SharedPreferences>()
|
||||||
|
.getInt(PreferencesKey.currentWalletType) ?? 0;
|
||||||
|
final currentWalletType = deserializeFromInt(currentWalletTypeRaw);
|
||||||
|
|
||||||
|
return WalletUnlockLoadableViewModel(
|
||||||
|
getIt.get<AppStore>(),
|
||||||
|
getIt.get<WalletLoadingService>(),
|
||||||
|
walletName: args.walletName ?? currentWalletName,
|
||||||
|
walletType: args.walletType ?? currentWalletType);
|
||||||
|
});
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<WalletUnlockVerifiableViewModel, WalletUnlockArguments, void>((args, _) {
|
||||||
|
final currentWalletName = getIt
|
||||||
|
.get<SharedPreferences>()
|
||||||
|
.getString(PreferencesKey.currentWalletName) ?? '';
|
||||||
|
final currentWalletTypeRaw =
|
||||||
|
getIt.get<SharedPreferences>()
|
||||||
|
.getInt(PreferencesKey.currentWalletType) ?? 0;
|
||||||
|
final currentWalletType = deserializeFromInt(currentWalletTypeRaw);
|
||||||
|
|
||||||
|
return WalletUnlockVerifiableViewModel(
|
||||||
|
getIt.get<AppStore>(),
|
||||||
|
walletName: args.walletName ?? currentWalletName,
|
||||||
|
walletType: args.walletType ?? currentWalletType);
|
||||||
|
});
|
||||||
|
|
||||||
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
|
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
|
||||||
return WalletRestorationFromQRVM(getIt.get<AppStore>(),
|
return WalletRestorationFromQRVM(getIt.get<AppStore>(),
|
||||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource, type);
|
getIt.get<WalletCreationService>(param1: type), _walletInfoSource, type);
|
||||||
|
@ -907,23 +970,28 @@ Future<void> setup({
|
||||||
_walletInfoSource,
|
_walletInfoSource,
|
||||||
_unspentCoinsInfoSource,
|
_unspentCoinsInfoSource,
|
||||||
getIt.get<SettingsStore>().silentPaymentsAlwaysScan,
|
getIt.get<SettingsStore>().silentPaymentsAlwaysScan,
|
||||||
|
SettingsStoreBase.walletPasswordDirectInput,
|
||||||
);
|
);
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource,
|
||||||
|
SettingsStoreBase.walletPasswordDirectInput);
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
return ethereum!.createEthereumWalletService(_walletInfoSource);
|
return ethereum!.createEthereumWalletService(
|
||||||
|
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
return bitcoinCash!
|
return bitcoinCash!.createBitcoinCashWalletService(_walletInfoSource,
|
||||||
.createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
_unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return nano!.createNanoWalletService(_walletInfoSource);
|
return nano!.createNanoWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return polygon!.createPolygonWalletService(_walletInfoSource);
|
return polygon!.createPolygonWalletService(
|
||||||
|
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
return solana!.createSolanaWalletService(_walletInfoSource);
|
return solana!.createSolanaWalletService(
|
||||||
|
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
return tron!.createTronWalletService(_walletInfoSource);
|
return tron!.createTronWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||||
case WalletType.wownero:
|
case WalletType.wownero:
|
||||||
return wownero!.createWowneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
return wownero!.createWowneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||||
|
|
||||||
Future<void> loadCurrentWallet() async {
|
Future<void> loadCurrentWallet({String? password}) async {
|
||||||
final appStore = getIt.get<AppStore>();
|
final appStore = getIt.get<AppStore>();
|
||||||
final name = getIt
|
final name = getIt
|
||||||
.get<SharedPreferences>()
|
.get<SharedPreferences>()
|
||||||
|
@ -21,7 +21,10 @@ Future<void> loadCurrentWallet() async {
|
||||||
|
|
||||||
final type = deserializeFromInt(typeRaw);
|
final type = deserializeFromInt(typeRaw);
|
||||||
final walletLoadingService = getIt.get<WalletLoadingService>();
|
final walletLoadingService = getIt.get<WalletLoadingService>();
|
||||||
final wallet = await walletLoadingService.load(type, name);
|
final wallet = await walletLoadingService.load(
|
||||||
|
type,
|
||||||
|
name,
|
||||||
|
password: password);
|
||||||
await appStore.changeCurrentWallet(wallet);
|
await appStore.changeCurrentWallet(wallet);
|
||||||
|
|
||||||
getIt.get<BackgroundTasks>().registerSyncTask();
|
getIt.get<BackgroundTasks>().registerSyncTask();
|
||||||
|
|
|
@ -4,15 +4,16 @@ class CWEthereum extends Ethereum {
|
||||||
@override
|
@override
|
||||||
List<String> getEthereumWordList(String language) => EVMChainMnemonics.englishWordlist;
|
List<String> getEthereumWordList(String language) => EVMChainMnemonics.englishWordlist;
|
||||||
|
|
||||||
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource) =>
|
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
|
||||||
EthereumWalletService(walletInfoSource, client: EthereumClient());
|
EthereumWalletService(walletInfoSource, isDirect, client: EthereumClient());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createEthereumNewWalletCredentials({
|
WalletCredentials createEthereumNewWalletCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
WalletInfo? walletInfo,
|
WalletInfo? walletInfo,
|
||||||
|
String? password,
|
||||||
}) =>
|
}) =>
|
||||||
EVMChainNewWalletCredentials(name: name, walletInfo: walletInfo);
|
EVMChainNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createEthereumRestoreWalletFromSeedCredentials({
|
WalletCredentials createEthereumRestoreWalletFromSeedCredentials({
|
||||||
|
|
|
@ -48,6 +48,7 @@ final rootKey = GlobalKey<RootState>();
|
||||||
final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
|
final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
|
|
||||||
bool isAppRunning = false;
|
bool isAppRunning = false;
|
||||||
await runZonedGuarded(() async {
|
await runZonedGuarded(() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
@ -170,7 +171,6 @@ Future<void> initializeAppConfigs() async {
|
||||||
}
|
}
|
||||||
|
|
||||||
final secureStorage = secureStorageShared;
|
final secureStorage = secureStorageShared;
|
||||||
|
|
||||||
final transactionDescriptionsBoxKey =
|
final transactionDescriptionsBoxKey =
|
||||||
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
||||||
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
|
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
|
||||||
|
@ -247,8 +247,8 @@ Future<void> initialSetup(
|
||||||
ordersSource: ordersSource,
|
ordersSource: ordersSource,
|
||||||
anonpayInvoiceInfoSource: anonpayInvoiceInfo,
|
anonpayInvoiceInfoSource: anonpayInvoiceInfo,
|
||||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||||
secureStorage: secureStorage,
|
|
||||||
navigatorKey: navigatorKey,
|
navigatorKey: navigatorKey,
|
||||||
|
secureStorage: secureStorage,
|
||||||
);
|
);
|
||||||
await bootstrap(navigatorKey);
|
await bootstrap(navigatorKey);
|
||||||
monero?.onStartup();
|
monero?.onStartup();
|
||||||
|
|
|
@ -75,8 +75,8 @@ class CWNano extends Nano {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource) {
|
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) {
|
||||||
return NanoWalletService(walletInfoSource);
|
return NanoWalletService(walletInfoSource, isDirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -4,15 +4,16 @@ class CWPolygon extends Polygon {
|
||||||
@override
|
@override
|
||||||
List<String> getPolygonWordList(String language) => EVMChainMnemonics.englishWordlist;
|
List<String> getPolygonWordList(String language) => EVMChainMnemonics.englishWordlist;
|
||||||
|
|
||||||
WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource) =>
|
WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
|
||||||
PolygonWalletService(walletInfoSource, client: PolygonClient());
|
PolygonWalletService(walletInfoSource, isDirect, client: PolygonClient());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createPolygonNewWalletCredentials({
|
WalletCredentials createPolygonNewWalletCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
WalletInfo? walletInfo,
|
WalletInfo? walletInfo,
|
||||||
|
String? password
|
||||||
}) =>
|
}) =>
|
||||||
EVMChainNewWalletCredentials(name: name, walletInfo: walletInfo);
|
EVMChainNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createPolygonRestoreWalletFromSeedCredentials({
|
WalletCredentials createPolygonRestoreWalletFromSeedCredentials({
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/entities/load_current_wallet.dart';
|
import 'package:cake_wallet/entities/load_current_wallet.dart';
|
||||||
|
@ -23,7 +24,7 @@ void startAuthenticationStateChange(
|
||||||
_onAuthenticationStateChange ??= autorun((_) async {
|
_onAuthenticationStateChange ??= autorun((_) async {
|
||||||
final state = authenticationStore.state;
|
final state = authenticationStore.state;
|
||||||
|
|
||||||
if (state == AuthenticationState.installed) {
|
if (state == AuthenticationState.installed && !SettingsStoreBase.walletPasswordDirectInput) {
|
||||||
try {
|
try {
|
||||||
await loadCurrentWallet();
|
await loadCurrentWallet();
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
|
|
|
@ -90,7 +90,11 @@ import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
|
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
|
import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/utils/payment_request.dart';
|
import 'package:cake_wallet/utils/payment_request.dart';
|
||||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
|
@ -125,6 +129,14 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
return MaterialPageRoute<void>(builder: (_) => createWelcomePage());
|
return MaterialPageRoute<void>(builder: (_) => createWelcomePage());
|
||||||
|
|
||||||
case Routes.newWalletFromWelcome:
|
case Routes.newWalletFromWelcome:
|
||||||
|
if (SettingsStoreBase.walletPasswordDirectInput) {
|
||||||
|
if (availableWalletTypes.length == 1) {
|
||||||
|
return createRoute(RouteSettings(name: Routes.newWallet, arguments: availableWalletTypes.first));
|
||||||
|
} else {
|
||||||
|
return createRoute(RouteSettings(name: Routes.newWalletType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) =>
|
builder: (_) =>
|
||||||
getIt.get<SetupPinCodePage>(param1: (PinCodeState<PinCodeWidget> context, dynamic _) {
|
getIt.get<SetupPinCodePage>(param1: (PinCodeState<PinCodeWidget> context, dynamic _) {
|
||||||
|
@ -176,6 +188,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
param2: [false, false]));
|
param2: [false, false]));
|
||||||
|
|
||||||
case Routes.restoreOptions:
|
case Routes.restoreOptions:
|
||||||
|
if (SettingsStoreBase.walletPasswordDirectInput) {
|
||||||
|
return createRoute(RouteSettings(name: Routes.restoreWalletType));
|
||||||
|
}
|
||||||
|
|
||||||
final isNewInstall = settings.arguments as bool;
|
final isNewInstall = settings.arguments as bool;
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
|
@ -328,8 +344,16 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
case Routes.auth:
|
case Routes.auth:
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (_) => getIt.get<AuthPage>(
|
builder: (_)
|
||||||
param1: settings.arguments as OnAuthenticationFinished, param2: true));
|
=> SettingsStoreBase.walletPasswordDirectInput
|
||||||
|
? getIt.get<WalletUnlockPage>(
|
||||||
|
param1: WalletUnlockArguments(
|
||||||
|
callback: settings.arguments as OnAuthenticationFinished),
|
||||||
|
instanceName: 'wallet_unlock_verifiable',
|
||||||
|
param2: true)
|
||||||
|
: getIt.get<AuthPage>(
|
||||||
|
param1: settings.arguments as OnAuthenticationFinished,
|
||||||
|
param2: true));
|
||||||
|
|
||||||
case Routes.totpAuthCodePage:
|
case Routes.totpAuthCodePage:
|
||||||
final args = settings.arguments as TotpAuthArgumentsModel;
|
final args = settings.arguments as TotpAuthArgumentsModel;
|
||||||
|
@ -340,23 +364,31 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
case Routes.login:
|
case Routes.walletUnlockLoadable:
|
||||||
return CupertinoPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
builder: (context) => WillPopScope(
|
fullscreenDialog: true,
|
||||||
child: getIt.get<AuthPage>(instanceName: 'login'),
|
builder: (_)
|
||||||
onWillPop: () async =>
|
=> getIt.get<WalletUnlockPage>(
|
||||||
// FIX-ME: Additional check does it works correctly
|
param1: settings.arguments as WalletUnlockArguments,
|
||||||
(await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ??
|
instanceName: 'wallet_unlock_loadable',
|
||||||
false),
|
param2: true));
|
||||||
),
|
|
||||||
fullscreenDialog: true);
|
|
||||||
|
|
||||||
case Routes.unlock:
|
case Routes.unlock:
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (_) => WillPopScope(
|
builder: (_)
|
||||||
|
=> SettingsStoreBase.walletPasswordDirectInput
|
||||||
|
? WillPopScope(
|
||||||
|
child: getIt.get<WalletUnlockPage>(
|
||||||
|
param1: WalletUnlockArguments(
|
||||||
|
callback: settings.arguments as OnAuthenticationFinished),
|
||||||
|
param2: false,
|
||||||
|
instanceName: 'wallet_unlock_verifiable'),
|
||||||
|
onWillPop: () async => false)
|
||||||
|
: WillPopScope(
|
||||||
child: getIt.get<AuthPage>(
|
child: getIt.get<AuthPage>(
|
||||||
param1: settings.arguments as OnAuthenticationFinished, param2: false),
|
param1: settings.arguments as OnAuthenticationFinished,
|
||||||
|
param2: false),
|
||||||
onWillPop: () async => false));
|
onWillPop: () async => false));
|
||||||
|
|
||||||
case Routes.silentPaymentsSettings:
|
case Routes.silentPaymentsSettings:
|
||||||
|
@ -397,6 +429,17 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
builder: (_) => getIt.get<NodeCreateOrEditPage>(
|
builder: (_) => getIt.get<NodeCreateOrEditPage>(
|
||||||
param1: args?['editingNode'] as Node?, param2: args?['isSelected'] as bool?));
|
param1: args?['editingNode'] as Node?, param2: args?['isSelected'] as bool?));
|
||||||
|
|
||||||
|
case Routes.login:
|
||||||
|
return CupertinoPageRoute<void>(
|
||||||
|
builder: (context) => WillPopScope(
|
||||||
|
child: SettingsStoreBase.walletPasswordDirectInput
|
||||||
|
? getIt.get<WalletUnlockPage>(instanceName: 'wallet_password_login')
|
||||||
|
: getIt.get<AuthPage>(instanceName: 'login'),
|
||||||
|
onWillPop: () async =>
|
||||||
|
// FIX-ME: Additional check does it works correctly
|
||||||
|
(await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ?? false)),
|
||||||
|
fullscreenDialog: true);
|
||||||
|
|
||||||
case Routes.newPowNode:
|
case Routes.newPowNode:
|
||||||
final args = settings.arguments as Map<String, dynamic>?;
|
final args = settings.arguments as Map<String, dynamic>?;
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
|
@ -486,7 +529,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
fullscreenDialog: true, builder: (_) => getIt.get<RestoreFromBackupPage>());
|
fullscreenDialog: true, builder: (_) => getIt.get<RestoreFromBackupPage>());
|
||||||
|
|
||||||
case Routes.support:
|
case Routes.support:
|
||||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<SupportPage>());
|
return CupertinoPageRoute<void>(
|
||||||
|
fullscreenDialog: true,
|
||||||
|
builder: (_) => getIt.get<SupportPage>());
|
||||||
|
|
||||||
case Routes.supportLiveChat:
|
case Routes.supportLiveChat:
|
||||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<SupportChatPage>());
|
return CupertinoPageRoute<void>(builder: (_) => getIt.get<SupportChatPage>());
|
||||||
|
|
|
@ -82,6 +82,8 @@ class Routes {
|
||||||
static const otherSettingsPage = '/other_settings_page';
|
static const otherSettingsPage = '/other_settings_page';
|
||||||
static const advancedPrivacySettings = '/advanced_privacy_settings';
|
static const advancedPrivacySettings = '/advanced_privacy_settings';
|
||||||
static const sweepingWalletPage = '/sweeping_wallet_page';
|
static const sweepingWalletPage = '/sweeping_wallet_page';
|
||||||
|
static const walletPasswordUnlock = '/wallet_password_unlock';
|
||||||
|
static const walletUnlockLoadable = '/wallet_unlock_loadable';
|
||||||
static const anonPayInvoicePage = '/anon_pay_invoice_page';
|
static const anonPayInvoicePage = '/anon_pay_invoice_page';
|
||||||
static const anonPayReceivePage = '/anon_pay_receive_page';
|
static const anonPayReceivePage = '/anon_pay_receive_page';
|
||||||
static const anonPayDetailsPage = '/anon_pay_details_page';
|
static const anonPayDetailsPage = '/anon_pay_details_page';
|
||||||
|
|
|
@ -4,15 +4,16 @@ class CWSolana extends Solana {
|
||||||
@override
|
@override
|
||||||
List<String> getSolanaWordList(String language) => SolanaMnemonics.englishWordlist;
|
List<String> getSolanaWordList(String language) => SolanaMnemonics.englishWordlist;
|
||||||
|
|
||||||
WalletService createSolanaWalletService(Box<WalletInfo> walletInfoSource) =>
|
WalletService createSolanaWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
|
||||||
SolanaWalletService(walletInfoSource);
|
SolanaWalletService(walletInfoSource, isDirect);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createSolanaNewWalletCredentials({
|
WalletCredentials createSolanaNewWalletCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
WalletInfo? walletInfo,
|
WalletInfo? walletInfo,
|
||||||
|
String? password,
|
||||||
}) =>
|
}) =>
|
||||||
SolanaNewWalletCredentials(name: name, walletInfo: walletInfo);
|
SolanaNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createSolanaRestoreWalletFromSeedCredentials({
|
WalletCredentials createSolanaRestoreWalletFromSeedCredentials({
|
||||||
|
|
|
@ -12,6 +12,12 @@ import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
|
||||||
typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
|
typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
|
||||||
|
|
||||||
|
abstract class AuthPageState<T extends StatefulWidget> extends State<T> {
|
||||||
|
void changeProcessText(String text);
|
||||||
|
void hideProgressText();
|
||||||
|
Future<void> close({String? route, dynamic arguments});
|
||||||
|
}
|
||||||
|
|
||||||
class AuthPage extends StatefulWidget {
|
class AuthPage extends StatefulWidget {
|
||||||
AuthPage(this.authViewModel,
|
AuthPage(this.authViewModel,
|
||||||
{required this.onAuthenticationFinished,
|
{required this.onAuthenticationFinished,
|
||||||
|
@ -22,10 +28,10 @@ class AuthPage extends StatefulWidget {
|
||||||
final bool closable;
|
final bool closable;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AuthPageState createState() => AuthPageState();
|
AuthPageState createState() => AuthPagePinCodeStateImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
class AuthPageState extends State<AuthPage> {
|
class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
|
||||||
final _key = GlobalKey<ScaffoldState>();
|
final _key = GlobalKey<ScaffoldState>();
|
||||||
final _pinCodeKey = GlobalKey<PinCodeState>();
|
final _pinCodeKey = GlobalKey<PinCodeState>();
|
||||||
final _backArrowImageDarkTheme =
|
final _backArrowImageDarkTheme =
|
||||||
|
@ -55,8 +61,6 @@ class AuthPageState extends State<AuthPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state is FailureState) {
|
if (state is FailureState) {
|
||||||
print('X');
|
|
||||||
print(state.error);
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
_pinCodeKey.currentState?.clear();
|
_pinCodeKey.currentState?.clear();
|
||||||
dismissFlushBar(_authBar);
|
dismissFlushBar(_authBar);
|
||||||
|
@ -95,17 +99,20 @@ class AuthPageState extends State<AuthPage> {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
void changeProcessText(String text) {
|
void changeProcessText(String text) {
|
||||||
dismissFlushBar(_authBar);
|
dismissFlushBar(_authBar);
|
||||||
_progressBar = createBar<void>(text, duration: null)
|
_progressBar = createBar<void>(text, duration: null)
|
||||||
..show(_key.currentContext!);
|
..show(_key.currentContext!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
void hideProgressText() {
|
void hideProgressText() {
|
||||||
dismissFlushBar(_progressBar);
|
dismissFlushBar(_progressBar);
|
||||||
_progressBar = null;
|
_progressBar = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> close({String? route, dynamic arguments}) async {
|
Future<void> close({String? route, dynamic arguments}) async {
|
||||||
if (_key.currentContext == null) {
|
if (_key.currentContext == null) {
|
||||||
throw Exception('Key context is null. Should be not happened');
|
throw Exception('Key context is null. Should be not happened');
|
||||||
|
|
|
@ -2,6 +2,9 @@ import 'package:auto_size_text/auto_size_text.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class DesktopActionButton extends StatelessWidget {
|
class DesktopActionButton extends StatelessWidget {
|
||||||
|
@ -24,7 +27,9 @@ class DesktopActionButton extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return MouseRegion(
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
|
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
|
@ -67,6 +72,7 @@ class DesktopActionButton extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,12 @@ import 'package:cake_wallet/core/auth_service.dart';
|
||||||
import 'package:cake_wallet/entities/desktop_dropdown_item.dart';
|
import 'package:cake_wallet/entities/desktop_dropdown_item.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/dropdown_item_widget.dart';
|
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/dropdown_item_widget.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/utils/show_bar.dart';
|
import 'package:cake_wallet/utils/show_bar.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||||
|
@ -176,8 +179,21 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadWallet(WalletListItem wallet) async {
|
Future<void> _loadWallet(WalletListItem wallet) async {
|
||||||
widget._authService.authenticateAction(
|
if (SettingsStoreBase.walletPasswordDirectInput) {
|
||||||
context,
|
Navigator.of(context).pushNamed(
|
||||||
|
Routes.walletUnlockLoadable,
|
||||||
|
arguments: WalletUnlockArguments(
|
||||||
|
callback: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||||
|
if (isAuthenticatedSuccessfully) {
|
||||||
|
auth.close();
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}, walletName: wallet.name,
|
||||||
|
walletType: wallet.type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
widget._authService.authenticateAction(context,
|
||||||
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||||
if (!isAuthenticatedSuccessfully) {
|
if (!isAuthenticatedSuccessfully) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -68,14 +68,19 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
_WalletNameFormState(this._walletNewVM)
|
_WalletNameFormState(this._walletNewVM)
|
||||||
: _formKey = GlobalKey<FormState>(),
|
: _formKey = GlobalKey<FormState>(),
|
||||||
_languageSelectorKey = GlobalKey<SeedLanguageSelectorState>(),
|
_languageSelectorKey = GlobalKey<SeedLanguageSelectorState>(),
|
||||||
_controller = TextEditingController();
|
_nameController = TextEditingController(),
|
||||||
|
_passwordController = _walletNewVM.hasWalletPassword ? TextEditingController() : null,
|
||||||
|
_repeatedPasswordController =
|
||||||
|
_walletNewVM.hasWalletPassword ? TextEditingController() : null;
|
||||||
|
|
||||||
static const aspectRatioImage = 1.22;
|
static const aspectRatioImage = 1.22;
|
||||||
|
|
||||||
final GlobalKey<FormState> _formKey;
|
final GlobalKey<FormState> _formKey;
|
||||||
final GlobalKey<SeedLanguageSelectorState> _languageSelectorKey;
|
final GlobalKey<SeedLanguageSelectorState> _languageSelectorKey;
|
||||||
final WalletNewVM _walletNewVM;
|
final WalletNewVM _walletNewVM;
|
||||||
final TextEditingController _controller;
|
final TextEditingController _nameController;
|
||||||
|
final TextEditingController? _passwordController;
|
||||||
|
final TextEditingController? _repeatedPasswordController;
|
||||||
ReactionDisposer? _stateReaction;
|
ReactionDisposer? _stateReaction;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -130,12 +135,11 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
padding: EdgeInsets.only(top: 24),
|
padding: EdgeInsets.only(top: 24),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Stack(
|
child: Column(
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
children: [
|
children: [
|
||||||
TextFormField(
|
TextFormField(
|
||||||
onChanged: (value) => _walletNewVM.name = value,
|
onChanged: (value) => _walletNewVM.name = value,
|
||||||
controller: _controller,
|
controller: _nameController,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
|
@ -169,10 +173,10 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_controller.text = rName;
|
_nameController.text = rName;
|
||||||
_walletNewVM.name = rName;
|
_walletNewVM.name = rName;
|
||||||
_controller.selection = TextSelection.fromPosition(
|
_nameController.selection = TextSelection.fromPosition(
|
||||||
TextPosition(offset: _controller.text.length));
|
TextPosition(offset: _nameController.text.length));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: Container(
|
icon: Container(
|
||||||
|
@ -195,6 +199,80 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
),
|
),
|
||||||
validator: WalletNameValidator(),
|
validator: WalletNameValidator(),
|
||||||
),
|
),
|
||||||
|
if (_walletNewVM.hasWalletPassword) ...[
|
||||||
|
TextFormField(
|
||||||
|
onChanged: (value) => _walletNewVM.walletPassword = value,
|
||||||
|
controller: _passwordController,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
obscureText: true,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<NewWalletTheme>()!.hintTextColor,
|
||||||
|
),
|
||||||
|
hintText: S.of(context).password,
|
||||||
|
focusedBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<NewWalletTheme>()!
|
||||||
|
.underlineColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
enabledBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<NewWalletTheme>()!
|
||||||
|
.underlineColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
onChanged: (value) => _walletNewVM.repeatedWalletPassword = value,
|
||||||
|
controller: _repeatedPasswordController,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
obscureText: true,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<NewWalletTheme>()!.hintTextColor,
|
||||||
|
),
|
||||||
|
hintText: S.of(context).repeat_wallet_password,
|
||||||
|
focusedBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<NewWalletTheme>()!
|
||||||
|
.underlineColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
enabledBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<NewWalletTheme>()!
|
||||||
|
.underlineColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -16,6 +16,9 @@ class WalletRestoreFromKeysFrom extends StatefulWidget {
|
||||||
required this.onPrivateKeyChange,
|
required this.onPrivateKeyChange,
|
||||||
required this.displayPrivateKeyField,
|
required this.displayPrivateKeyField,
|
||||||
required this.onHeightOrDateEntered,
|
required this.onHeightOrDateEntered,
|
||||||
|
required this.displayWalletPassword,
|
||||||
|
required this.onRepeatedPasswordChange,
|
||||||
|
this.onPasswordChange,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@ -23,13 +26,17 @@ class WalletRestoreFromKeysFrom extends StatefulWidget {
|
||||||
final WalletRestoreViewModel walletRestoreViewModel;
|
final WalletRestoreViewModel walletRestoreViewModel;
|
||||||
final void Function(String)? onPrivateKeyChange;
|
final void Function(String)? onPrivateKeyChange;
|
||||||
final bool displayPrivateKeyField;
|
final bool displayPrivateKeyField;
|
||||||
|
final bool displayWalletPassword;
|
||||||
|
final void Function(String)? onPasswordChange;
|
||||||
|
final void Function(String)? onRepeatedPasswordChange;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletRestoreFromKeysFromState createState() => WalletRestoreFromKeysFromState();
|
WalletRestoreFromKeysFromState createState() =>
|
||||||
|
WalletRestoreFromKeysFromState(displayWalletPassword: displayWalletPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||||
WalletRestoreFromKeysFromState()
|
WalletRestoreFromKeysFromState({required bool displayWalletPassword})
|
||||||
: formKey = GlobalKey<FormState>(),
|
: formKey = GlobalKey<FormState>(),
|
||||||
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
||||||
nameController = TextEditingController(),
|
nameController = TextEditingController(),
|
||||||
|
@ -37,7 +44,9 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||||
viewKeyController = TextEditingController(),
|
viewKeyController = TextEditingController(),
|
||||||
spendKeyController = TextEditingController(),
|
spendKeyController = TextEditingController(),
|
||||||
privateKeyController = TextEditingController(),
|
privateKeyController = TextEditingController(),
|
||||||
nameTextEditingController = TextEditingController();
|
nameTextEditingController = TextEditingController(),
|
||||||
|
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
|
||||||
|
repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null;
|
||||||
|
|
||||||
final GlobalKey<FormState> formKey;
|
final GlobalKey<FormState> formKey;
|
||||||
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
|
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
|
||||||
|
@ -47,9 +56,22 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||||
final TextEditingController spendKeyController;
|
final TextEditingController spendKeyController;
|
||||||
final TextEditingController nameTextEditingController;
|
final TextEditingController nameTextEditingController;
|
||||||
final TextEditingController privateKeyController;
|
final TextEditingController privateKeyController;
|
||||||
|
final TextEditingController? passwordTextEditingController;
|
||||||
|
final TextEditingController? repeatedPasswordTextEditingController;
|
||||||
|
void Function()? passwordListener;
|
||||||
|
void Function()? repeatedPasswordListener;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
if (passwordTextEditingController != null) {
|
||||||
|
passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text);
|
||||||
|
passwordTextEditingController?.addListener(passwordListener!);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repeatedPasswordTextEditingController != null) {
|
||||||
|
repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text);
|
||||||
|
repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!);
|
||||||
|
}
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
privateKeyController.addListener(() {
|
privateKeyController.addListener(() {
|
||||||
|
@ -67,6 +89,14 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||||
viewKeyController.dispose();
|
viewKeyController.dispose();
|
||||||
privateKeyController.dispose();
|
privateKeyController.dispose();
|
||||||
spendKeyController.dispose();
|
spendKeyController.dispose();
|
||||||
|
passwordTextEditingController?.dispose();
|
||||||
|
if (passwordListener != null) {
|
||||||
|
passwordTextEditingController?.removeListener(passwordListener!);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repeatedPasswordListener != null) {
|
||||||
|
repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!);
|
||||||
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +144,19 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
if (widget.displayWalletPassword)
|
||||||
|
...[Container(
|
||||||
|
padding: EdgeInsets.only(top: 20.0),
|
||||||
|
child: BaseTextFormField(
|
||||||
|
controller: passwordTextEditingController,
|
||||||
|
hintText: S.of(context).password,
|
||||||
|
obscureText: true)),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.only(top: 20.0),
|
||||||
|
child: BaseTextFormField(
|
||||||
|
controller: repeatedPasswordTextEditingController,
|
||||||
|
hintText: S.of(context).repeat_wallet_password,
|
||||||
|
obscureText: true))],
|
||||||
Container(height: 20),
|
Container(height: 20),
|
||||||
_restoreFromKeysFormFields(),
|
_restoreFromKeysFormFields(),
|
||||||
],
|
],
|
||||||
|
|
|
@ -22,34 +22,43 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||||
required this.displayBlockHeightSelector,
|
required this.displayBlockHeightSelector,
|
||||||
required this.displayPassphrase,
|
required this.displayPassphrase,
|
||||||
required this.type,
|
required this.type,
|
||||||
|
required this.displayWalletPassword,
|
||||||
required this.seedTypeViewModel,
|
required this.seedTypeViewModel,
|
||||||
this.blockHeightFocusNode,
|
this.blockHeightFocusNode,
|
||||||
this.onHeightOrDateEntered,
|
this.onHeightOrDateEntered,
|
||||||
this.onSeedChange,
|
this.onSeedChange,
|
||||||
this.onLanguageChange})
|
this.onLanguageChange,
|
||||||
|
this.onPasswordChange,
|
||||||
|
this.onRepeatedPasswordChange})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
final WalletType type;
|
final WalletType type;
|
||||||
final bool displayLanguageSelector;
|
final bool displayLanguageSelector;
|
||||||
final bool displayBlockHeightSelector;
|
final bool displayBlockHeightSelector;
|
||||||
|
final bool displayWalletPassword;
|
||||||
final bool displayPassphrase;
|
final bool displayPassphrase;
|
||||||
final SeedTypeViewModel seedTypeViewModel;
|
final SeedTypeViewModel seedTypeViewModel;
|
||||||
final FocusNode? blockHeightFocusNode;
|
final FocusNode? blockHeightFocusNode;
|
||||||
final Function(bool)? onHeightOrDateEntered;
|
final Function(bool)? onHeightOrDateEntered;
|
||||||
final void Function(String)? onSeedChange;
|
final void Function(String)? onSeedChange;
|
||||||
final void Function(String)? onLanguageChange;
|
final void Function(String)? onLanguageChange;
|
||||||
|
final void Function(String)? onPasswordChange;
|
||||||
|
final void Function(String)? onRepeatedPasswordChange;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletRestoreFromSeedFormState createState() => WalletRestoreFromSeedFormState('English');
|
WalletRestoreFromSeedFormState createState() =>
|
||||||
|
WalletRestoreFromSeedFormState('English', displayWalletPassword: displayWalletPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
WalletRestoreFromSeedFormState(this.language)
|
WalletRestoreFromSeedFormState(this.language, {required bool displayWalletPassword})
|
||||||
: seedWidgetStateKey = GlobalKey<SeedWidgetState>(),
|
: seedWidgetStateKey = GlobalKey<SeedWidgetState>(),
|
||||||
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
||||||
formKey = GlobalKey<FormState>(),
|
formKey = GlobalKey<FormState>(),
|
||||||
languageController = TextEditingController(),
|
languageController = TextEditingController(),
|
||||||
nameTextEditingController = TextEditingController(),
|
nameTextEditingController = TextEditingController(),
|
||||||
|
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
|
||||||
|
repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null,
|
||||||
passphraseController = TextEditingController(),
|
passphraseController = TextEditingController(),
|
||||||
seedTypeController = TextEditingController();
|
seedTypeController = TextEditingController();
|
||||||
|
|
||||||
|
@ -57,16 +66,30 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
|
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
|
||||||
final TextEditingController languageController;
|
final TextEditingController languageController;
|
||||||
final TextEditingController nameTextEditingController;
|
final TextEditingController nameTextEditingController;
|
||||||
|
final TextEditingController? passwordTextEditingController;
|
||||||
|
final TextEditingController? repeatedPasswordTextEditingController;
|
||||||
final TextEditingController seedTypeController;
|
final TextEditingController seedTypeController;
|
||||||
final TextEditingController passphraseController;
|
final TextEditingController passphraseController;
|
||||||
final GlobalKey<FormState> formKey;
|
final GlobalKey<FormState> formKey;
|
||||||
late ReactionDisposer moneroSeedTypeReaction;
|
late ReactionDisposer moneroSeedTypeReaction;
|
||||||
String language;
|
String language;
|
||||||
|
void Function()? passwordListener;
|
||||||
|
void Function()? repeatedPasswordListener;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_setSeedType(widget.seedTypeViewModel.moneroSeedType);
|
_setSeedType(widget.seedTypeViewModel.moneroSeedType);
|
||||||
_setLanguageLabel(language);
|
_setLanguageLabel(language);
|
||||||
|
|
||||||
|
if (passwordTextEditingController != null) {
|
||||||
|
passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text);
|
||||||
|
passwordTextEditingController?.addListener(passwordListener!);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repeatedPasswordTextEditingController != null) {
|
||||||
|
repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text);
|
||||||
|
repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!);
|
||||||
|
}
|
||||||
moneroSeedTypeReaction =
|
moneroSeedTypeReaction =
|
||||||
reaction((_) => widget.seedTypeViewModel.moneroSeedType, (SeedType item) {
|
reaction((_) => widget.seedTypeViewModel.moneroSeedType, (SeedType item) {
|
||||||
_setSeedType(item);
|
_setSeedType(item);
|
||||||
|
@ -78,8 +101,16 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
|
||||||
moneroSeedTypeReaction();
|
moneroSeedTypeReaction();
|
||||||
|
|
||||||
|
if (passwordListener != null) {
|
||||||
|
passwordTextEditingController?.removeListener(passwordListener!);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repeatedPasswordListener != null) {
|
||||||
|
repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!);
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSeedChange(String seed) {
|
void onSeedChange(String seed) {
|
||||||
|
@ -177,6 +208,16 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (widget.displayWalletPassword)
|
||||||
|
...[BaseTextFormField(
|
||||||
|
controller: passwordTextEditingController,
|
||||||
|
hintText: S.of(context).password,
|
||||||
|
obscureText: true),
|
||||||
|
BaseTextFormField(
|
||||||
|
controller: repeatedPasswordTextEditingController,
|
||||||
|
hintText: S.of(context).repeat_wallet_password,
|
||||||
|
obscureText: true)],
|
||||||
|
if (widget.displayLanguageSelector)
|
||||||
if (!seedTypeController.value.text.contains("14") && widget.displayLanguageSelector)
|
if (!seedTypeController.value.text.contains("14") && widget.displayLanguageSelector)
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
|
|
@ -53,7 +53,10 @@ class WalletRestorePage extends BasePage {
|
||||||
onLanguageChange: (String language) {
|
onLanguageChange: (String language) {
|
||||||
final isPolyseed = language.startsWith("POLYSEED_");
|
final isPolyseed = language.startsWith("POLYSEED_");
|
||||||
_validateOnChange(isPolyseed: isPolyseed);
|
_validateOnChange(isPolyseed: isPolyseed);
|
||||||
}));
|
},
|
||||||
|
displayWalletPassword: walletRestoreViewModel.hasWalletPassword,
|
||||||
|
onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password,
|
||||||
|
onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword));
|
||||||
break;
|
break;
|
||||||
case WalletRestoreMode.keys:
|
case WalletRestoreMode.keys:
|
||||||
_pages.add(WalletRestoreFromKeysFrom(
|
_pages.add(WalletRestoreFromKeysFrom(
|
||||||
|
@ -66,6 +69,9 @@ class WalletRestorePage extends BasePage {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
displayPrivateKeyField: walletRestoreViewModel.hasRestoreFromPrivateKey,
|
displayPrivateKeyField: walletRestoreViewModel.hasRestoreFromPrivateKey,
|
||||||
|
displayWalletPassword: walletRestoreViewModel.hasWalletPassword,
|
||||||
|
onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password,
|
||||||
|
onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword,
|
||||||
onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value));
|
onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -127,6 +133,8 @@ class WalletRestorePage extends BasePage {
|
||||||
|
|
||||||
reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode) {
|
reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode) {
|
||||||
walletRestoreViewModel.isButtonEnabled = false;
|
walletRestoreViewModel.isButtonEnabled = false;
|
||||||
|
walletRestoreViewModel.walletPassword = null;
|
||||||
|
walletRestoreViewModel.repeatedWalletPassword = null;
|
||||||
|
|
||||||
walletRestoreFromSeedFormKey
|
walletRestoreFromSeedFormKey
|
||||||
.currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
|
.currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue