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>

cyan committed Aug 13, 2024 at 00:18 UTC 1ce60d62b3121cfbd6b882c041283556c2c7bca7
178 files changed +3955 -563
.github/workflows/cache_dependencies.yml
+1 -1
@@ -25,7 +25,7 @@ jobs:
25 - uses: actions/checkout@v2
26 - uses: actions/setup-java@v1
27 with:
28 - java-version: "11.x"
28 + java-version: "17.x"
29 - name: Configure placeholder git details
30 run: |
31 git config --global user.email "CI@cakewallet.com"
.github/workflows/pr_test_build_android.yml renamed
+3 -1
@@ -53,7 +53,9 @@ jobs:
53 channel: stable
54
55 - name: Install package dependencies
56 - run: sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
56 + run: |
57 + sudo apt update
58 + sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
59
60 - name: Execute Build and Setup Commands
61 run: |
.github/workflows/pr_test_build_linux.yml new
+186
@@ -0,0 +1,186 @@
1 +name: PR Test Build linux
2 +
3 +on:
4 + pull_request:
5 + branches: [main]
6 + workflow_dispatch:
7 + inputs:
8 + branch:
9 + description: "Branch name to build"
10 + required: true
11 + default: "main"
12 +
13 +jobs:
14 + PR_test_build:
15 + runs-on: ubuntu-20.04
16 + env:
17 + STORE_PASS: test@cake_wallet
18 + KEY_PASS: test@cake_wallet
19 + PR_NUMBER: ${{ github.event.number }}
20 +
21 + steps:
22 + - name: is pr
23 + if: github.event_name == 'pull_request'
24 + run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV
25 +
26 + - name: is not pr
27 + if: github.event_name != 'pull_request'
28 + run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENVg
29 +
30 + - uses: actions/checkout@v2
31 + - uses: actions/setup-java@v1
32 + with:
33 + java-version: "17.x"
34 + - name: Configure placeholder git details
35 + run: |
36 + git config --global user.email "CI@cakewallet.com"
37 + git config --global user.name "Cake Github Actions"
38 + - name: Flutter action
39 + uses: subosito/flutter-action@v1
40 + with:
41 + flutter-version: "3.19.6"
42 + channel: stable
43 +
44 + - name: Install package dependencies
45 + run: |
46 + sudo apt update
47 + sudo apt-get install -y curl unzip automake build-essential file pkg-config git python-is-python3 libtool libtinfo5 cmake clang
48 +
49 + - name: Install desktop dependencies
50 + run: |
51 + sudo apt update
52 + sudo apt install -y ninja-build libgtk-3-dev gperf
53 + - name: Execute Build and Setup Commands
54 + run: |
55 + sudo mkdir -p /opt/android
56 + sudo chown $USER /opt/android
57 + cd /opt/android
58 + -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
59 + cargo install cargo-ndk
60 + git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }}
61 + cd scripts && ./gen_android_manifest.sh && cd ..
62 + cd cake_wallet/scripts/android/
63 + source ./app_env.sh cakewallet
64 + ./app_config.sh
65 + cd ../../..
66 + cd cake_wallet/scripts/linux/
67 + source ./app_env.sh cakewallet
68 + ./app_config.sh
69 + cd ../../..
70 +
71 + - name: Cache Externals
72 + id: cache-externals
73 + uses: actions/cache@v3
74 + with:
75 + path: |
76 + /opt/android/cake_wallet/cw_haven/android/.cxx
77 + /opt/android/cake_wallet/scripts/monero_c/release
78 + key: linux-${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh') }}
79 +
80 + - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
81 + name: Generate Externals
82 + run: |
83 + cd /opt/android/cake_wallet/scripts/linux/
84 + source ./app_env.sh cakewallet
85 + ./build_monero_all.sh
86 +
87 + - name: Install Flutter dependencies
88 + run: |
89 + cd /opt/android/cake_wallet
90 + flutter pub get
91 +
92 + - name: Generate localization
93 + run: |
94 + cd /opt/android/cake_wallet
95 + flutter packages pub run tool/generate_localization.dart
96 +
97 + - name: Build generated code
98 + run: |
99 + cd /opt/android/cake_wallet
100 + ./model_generator.sh
101 +
102 + - name: Add secrets
103 + run: |
104 + cd /opt/android/cake_wallet
105 + touch lib/.secrets.g.dart
106 + touch cw_evm/lib/.secrets.g.dart
107 + touch cw_solana/lib/.secrets.g.dart
108 + touch cw_core/lib/.secrets.g.dart
109 + touch cw_nano/lib/.secrets.g.dart
110 + touch cw_tron/lib/.secrets.g.dart
111 + echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
112 + echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
113 + echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
114 + echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart
115 + echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
116 + echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
117 + echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
118 + echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
119 + echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
120 + echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
121 + echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
122 + echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
123 + echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
124 + echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
125 + echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
126 + echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
127 + echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
128 + echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
129 + echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
130 + echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
131 + echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
132 + echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
133 + echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
134 + echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
135 + echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
136 + echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
137 + echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
138 + echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
139 + echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
140 + echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
141 + echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
142 + echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
143 + echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
144 + echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
145 + echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
146 + echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
147 + echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
148 + echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
149 + echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
150 + echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
151 + echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart
152 + echo "const quantexExchangeMarkup = '${{ secrets.QUANTEX_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
153 + echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
154 + echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
155 + echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
156 + echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
157 +
158 + - name: Rename app
159 + run: |
160 + echo -e "id=com.cakewallet.test_${{ env.PR_NUMBER }}\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
161 +
162 + - name: Build
163 + run: |
164 + cd /opt/android/cake_wallet
165 + flutter build linux --release
166 +
167 + - name: Prepare release zip file
168 + run: |
169 + cd /opt/android/cake_wallet/build/linux/x64/release
170 + zip -r ${{env.BRANCH_NAME}}.zip bundle
171 +
172 + - name: Upload Artifact
173 + uses: kittaakos/upload-artifact-as-is@v0
174 + with:
175 + path: /opt/android/cake_wallet/build/linux/x64/release/${{env.BRANCH_NAME}}.zip
176 +
177 + - name: Send Test APK
178 + continue-on-error: true
179 + uses: adrey/slack-file-upload-action@1.0.5
180 + with:
181 + token: ${{ secrets.SLACK_APP_TOKEN }}
182 + path: /opt/android/cake_wallet/build/linux/x64/release/${{env.BRANCH_NAME}}.zip
183 + channel: ${{ secrets.SLACK_APK_CHANNEL }}
184 + title: "${{ env.BRANCH_NAME }}_linux.zip"
185 + filename: ${{ env.BRANCH_NAME }}_linux.zip
186 + initial_comment: ${{ github.event.head_commit.message }}
.gitignore
+2
@@ -160,6 +160,8 @@ macos/Runner/Release.entitlements
160 macos/Runner/Runner.entitlements
161 lib/core/secure_storage.dart
162
163 +lib/core/secure_storage.dart
164 +
165 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
166 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
167 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
.metadata
+6
@@ -18,6 +18,12 @@ migration:
18 - platform: windows
19 create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
20 base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
21 + - platform: macos
22 + create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
23 + base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
24 + - platform: linux
25 + create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
26 + base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
27
28 # User provided section
29
build-guide-linux.md new
+176
@@ -0,0 +1,176 @@
1 +# Building CakeWallet for Linux
2 +
3 +## Requirements and Setup
4 +
5 +The following are the system requirements to build CakeWallet for your Linux device.
6 +
7 +```
8 +Ubuntu >= 16.04
9 +Flutter 3.10.x
10 +```
11 +
12 +## Building CakeWallet on Linux
13 +
14 +These steps will help you configure and execute a build of CakeWallet from its source code.
15 +
16 +### 1. Installing Package Dependencies
17 +
18 +CakeWallet requires some packages to be install on your build system. You may easily install them on your build system with the following command:
19 +
20 +`$ sudo apt install build-essential cmake pkg-config git curl autoconf libtool`
21 +
22 +> [!WARNING]
23 +>
24 +> ### Check gcc version
25 +>
26 +> It is needed to use gcc 10 or 9 to successfully link dependencies with flutter.\
27 +> To check what gcc version you are using:
28 +>
29 +> ```bash
30 +> $ gcc --version
31 +> $ g++ --version
32 +> ```
33 +>
34 +> If you are using gcc version newer than 10, then you need to downgrade to version 10.4.0:
35 +>
36 +> ```bash
37 +> $ sudo apt install gcc-10 g++-10
38 +> $ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
39 +> $ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
40 +> ```
41 +
42 +> [!NOTE]
43 +>
44 +> Alternatively, you can use the [nix-shell](https://nixos.org/) with the `gcc10.nix` file\
45 +> present on `scripts/linux` like so:
46 +> ```bash
47 +> $ nix-shell gcc10.nix
48 +> ```
49 +> This will get you in a nix environment with all the required dependencies that you can use to build the software from,\
50 +> and it works in any linux distro.
51 +
52 +### 2. Installing Flutter
53 +
54 +Need to install flutter. For this please check section [How to install flutter on Linux](https://docs.flutter.dev/get-started/install/linux).
55 +
56 +### 3. Verify Installations
57 +
58 +Verify that the Flutter have been correctly installed on your system with the following command:
59 +
60 +`$ flutter doctor`
61 +
62 +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.
63 +
64 +```
65 +Doctor summary (to see all details, run flutter doctor -v):
66 +[✓] Flutter (Channel stable, 3.10.x, on Linux, locale en_US.UTF-8)
67 +```
68 +
69 +### 4. Acquiring the CakeWallet Source Code
70 +
71 +Download CakeWallet source code
72 +
73 +`$ git clone https://github.com/cake-tech/cake_wallet.git --branch linux/password-direct-input`
74 +
75 +Proceed into the source code before proceeding with the next steps:
76 +
77 +`$ cd cake_wallet/scripts/linux/`
78 +
79 +To configure some project properties run:
80 +
81 +`$ ./cakewallet.sh`
82 +
83 +Build the Monero libraries and their dependencies:
84 +
85 +`$ ./build_all.sh`
86 +
87 +Now the dependencies need to be copied into the CakeWallet project with this command:
88 +
89 +`$ ./setup.sh`
90 +
91 +It is now time to change back to the base directory of the CakeWallet source code:
92 +
93 +`$ cd ../../`
94 +
95 +Install Flutter package dependencies with this command:
96 +
97 +`$ flutter pub get`
98 +
99 +> #### If you will get an error like:
100 +>
101 +> ```
102 +> 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
103 +> this command.
104 +> ```
105 +>
106 +> Then need to config Android project settings. For this open `scripts/android` (`$ cd scripts/android`) directory and run followed commands:
107 +>
108 +> ```
109 +> $ source ./app_env.sh cakewallet
110 +> $ ./app_config.sh
111 +> $ cd ../..
112 +> ```
113 +>
114 +> Then re-configure Linux project again. For this open `scripts/linux` (`$cd scripts/linux`) directory and run:
115 +> `$ ./cakewallet.sh`
116 +> and back to project root directory:
117 +> `$ cd ../..`
118 +> and fetch dependecies again
119 +> `$ flutter pub get`
120 +
121 +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:
122 +
123 +`$ flutter packages pub run tool/generate_new_secrets.dart`
124 +
125 +We will generate mobx models for the project.
126 +
127 +`$ ./model_generator.sh`
128 +
129 +Then we need to generate localization files.
130 +
131 +`$ flutter packages pub run tool/generate_localization.dart`
132 +
133 +### 5. Build!
134 +
135 +`$ flutter build linux --release`
136 +
137 +Path to executable file will be:
138 +
139 +`build/linux/x64/release/bundle/cake_wallet`
140 +
141 +> ### Troubleshooting
142 +>
143 +> 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.\
144 +> 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.
145 +
146 +# Flatpak
147 +
148 +For package the built application into flatpak you need fistly to install `flatpak` and `flatpak-builder`:
149 +
150 +`$ sudo apt install flatpak flatpak-builder`
151 +
152 +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:
153 +
154 +`$ flatpak install flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08`
155 +
156 +To build with using of `flatpak-build` directory run next:
157 +
158 +`$ flatpak-builder --force-clean flatpak-build com.cakewallet.CakeWallet.yml`
159 +
160 +And then export bundle:
161 +
162 +`$ flatpak build-export export flatpak-build`
163 +
164 +`$ flatpak build-bundle export cake_wallet.flatpak com.cakewallet.CakeWallet`
165 +
166 +Result file: `cake_wallet.flatpak` should be generated in current directory.
167 +
168 +For install generated flatpak file use:
169 +
170 +`$ flatpak --user install cake_wallet.flatpak`
171 +
172 +For run the installed application run:
173 +
174 +`$ flatpak run com.cakewallet.CakeWallet`
175 +
176 +Copyright (c) 2023 Cake Technologies LLC.
com.cakewallet.CakeWallet.yml new
+35
@@ -0,0 +1,35 @@
1 +app-id: com.cakewallet.CakeWallet
2 +runtime: org.freedesktop.Platform
3 +runtime-version: '22.08'
4 +sdk: org.freedesktop.Sdk
5 +command: cake_wallet
6 +separate-locales: false
7 +finish-args:
8 + - --share=ipc
9 + - --socket=fallback-x11
10 + - --socket=wayland
11 + - --device=dri
12 + - --socket=pulseaudio
13 + - --share=network
14 + - --filesystem=home
15 +modules:
16 + - name: cake_wallet
17 + buildsystem: simple
18 + only-arches:
19 + - x86_64
20 + build-commands:
21 + - "cp -R bundle /app/cake_wallet"
22 + - "chmod +x /app/cake_wallet/cake_wallet"
23 + - "mkdir -p /app/bin"
24 + - "ln -s /app/cake_wallet/cake_wallet /app/bin/cake_wallet"
25 + - "mkdir -p /app/share/icons/hicolor/scalable/apps"
26 + - "cp cakewallet_icon_180.png /app/share/icons/hicolor/scalable/apps/com.cakewallet.CakeWallet.png"
27 + - "mkdir -p /app/share/applications"
28 + - "cp com.cakewallet.CakeWallet.desktop /app/share/applications"
29 + sources:
30 + - type: dir
31 + path: build/linux/x64/release
32 + - type: file
33 + path: assets/images/cakewallet_icon_180.png
34 + - type: file
35 + path: linux/com.cakewallet.CakeWallet.desktop
configure_cake_wallet.sh
+10 -4
@@ -3,12 +3,13 @@
3 IOS="ios"
4 ANDROID="android"
5 MACOS="macos"
6 +LINUX="linux"
7
7 -PLATFORMS=($IOS $ANDROID $MACOS)
8 +PLATFORMS=($IOS $ANDROID $MACOS $LINUX)
9 PLATFORM=$1
10
11 if ! [[ " ${PLATFORMS[*]} " =~ " ${PLATFORM} " ]]; then
11 - echo "specify platform: ./configure_cake_wallet.sh ios|android|macos"
12 + echo "specify platform: ./configure_cake_wallet.sh ios|android|macos|linux"
13 exit 1
14 fi
15
@@ -27,9 +28,14 @@ if [ "$PLATFORM" == "$ANDROID" ]; then
28 cd scripts/android
29 fi
30
31 +if [ "$PLATFORM" == "$LINUX" ]; then
32 + echo "Configuring for linux"
33 + cd scripts/linux
34 +fi
35 +
36 source ./app_env.sh cakewallet
37 ./app_config.sh
38 cd ../.. && flutter pub get
33 -#flutter packages pub run tool/generate_localization.dart
39 +flutter packages pub run tool/generate_localization.dart
40 ./model_generator.sh
35 -#cd macos && pod install
\ No newline at end of file
41 +#cd macos && pod install
cw_bitcoin/lib/bitcoin_wallet.dart
+26 -5
@@ -5,9 +5,10 @@ import 'package:bitcoin_base/bitcoin_base.dart';
5 import 'package:blockchain_utils/blockchain_utils.dart';
6 import 'package:cw_bitcoin/bitcoin_address_record.dart';
7 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
8 +import 'package:cw_core/encryption_file_utils.dart';
9 +import 'package:cw_bitcoin/electrum_derivations.dart';
10 import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
11 import 'package:cw_bitcoin/electrum_balance.dart';
10 -import 'package:cw_bitcoin/electrum_derivations.dart';
12 import 'package:cw_bitcoin/electrum_wallet.dart';
13 import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
14 import 'package:cw_bitcoin/psbt_transaction_builder.dart';
@@ -30,6 +31,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
31 required String password,
32 required WalletInfo walletInfo,
33 required Box<UnspentCoinsInfo> unspentCoinsInfo,
34 + required EncryptionFileUtils encryptionFileUtils,
35 Uint8List? seedBytes,
36 String? mnemonic,
37 String? xpub,
@@ -58,6 +60,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
60 initialAddresses: initialAddresses,
61 initialBalance: initialBalance,
62 seedBytes: seedBytes,
63 + encryptionFileUtils: encryptionFileUtils,
64 currency:
65 networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
66 alwaysScan: alwaysScan,
@@ -90,6 +93,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
93 required String password,
94 required WalletInfo walletInfo,
95 required Box<UnspentCoinsInfo> unspentCoinsInfo,
96 + required EncryptionFileUtils encryptionFileUtils,
97 String? passphrase,
98 String? addressPageType,
99 BasedUtxoNetwork? network,
@@ -124,6 +128,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
128 initialSilentAddresses: initialSilentAddresses,
129 initialSilentAddressIndex: initialSilentAddressIndex,
130 initialBalance: initialBalance,
131 + encryptionFileUtils: encryptionFileUtils,
132 seedBytes: seedBytes,
133 initialRegularAddressIndex: initialRegularAddressIndex,
134 initialChangeAddressIndex: initialChangeAddressIndex,
@@ -137,6 +142,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
142 required WalletInfo walletInfo,
143 required Box<UnspentCoinsInfo> unspentCoinsInfo,
144 required String password,
145 + required EncryptionFileUtils encryptionFileUtils,
146 required bool alwaysScan,
147 }) async {
148 final network = walletInfo.network != null
@@ -148,7 +154,13 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
154 ElectrumWalletSnapshot? snp = null;
155
156 try {
151 - snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, network);
157 + snp = await ElectrumWalletSnapshot.load(
158 + encryptionFileUtils,
159 + name,
160 + walletInfo.type,
161 + password,
162 + network,
163 + );
164 } catch (e) {
165 if (!hasKeysFile) rethrow;
166 }
@@ -156,10 +168,18 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
168 final WalletKeysData keysData;
169 // Migrate wallet from the old scheme to then new .keys file scheme
170 if (!hasKeysFile) {
159 - keysData =
160 - WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
171 + keysData = WalletKeysData(
172 + mnemonic: snp!.mnemonic,
173 + xPub: snp.xpub,
174 + passphrase: snp.passphrase,
175 + );
176 } else {
162 - keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
177 + keysData = await WalletKeysFile.readKeysFile(
178 + name,
179 + walletInfo.type,
180 + password,
181 + encryptionFileUtils,
182 + );
183 }
184
185 walletInfo.derivationInfo ??= DerivationInfo();
@@ -198,6 +218,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
218 initialSilentAddresses: snp?.silentAddresses,
219 initialSilentAddressIndex: snp?.silentAddressIndex ?? 0,
220 initialBalance: snp?.balance,
221 + encryptionFileUtils: encryptionFileUtils,
222 seedBytes: seedBytes,
223 initialRegularAddressIndex: snp?.regularAddressIndex,
224 initialChangeAddressIndex: snp?.changeAddressIndex,
cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart
+2
@@ -6,11 +6,13 @@ class BitcoinNewWalletCredentials extends WalletCredentials {
6 BitcoinNewWalletCredentials(
7 {required String name,
8 WalletInfo? walletInfo,
9 + String? password,
10 DerivationType? derivationType,
11 String? derivationPath})
12 : super(
13 name: name,
14 walletInfo: walletInfo,
15 + password: password,
16 );
17 }
18
cw_bitcoin/lib/bitcoin_wallet_service.dart
+9 -1
@@ -3,6 +3,7 @@ import 'package:bitcoin_base/bitcoin_base.dart';
3 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
4 import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
5 import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
6 +import 'package:cw_core/encryption_file_utils.dart';
7 import 'package:cw_core/unspent_coins_info.dart';
8 import 'package:cw_core/wallet_base.dart';
9 import 'package:cw_core/wallet_service.dart';
@@ -19,11 +20,12 @@ class BitcoinWalletService extends WalletService<
20 BitcoinRestoreWalletFromSeedCredentials,
21 BitcoinRestoreWalletFromWIFCredentials,
22 BitcoinRestoreWalletFromHardware> {
22 - BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.alwaysScan);
23 + BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.alwaysScan, this.isDirect);
24
25 final Box<WalletInfo> walletInfoSource;
26 final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
27 final bool alwaysScan;
28 + final bool isDirect;
29
30 @override
31 WalletType getType() => WalletType.bitcoin;
@@ -40,6 +42,7 @@ class BitcoinWalletService extends WalletService<
42 walletInfo: credentials.walletInfo!,
43 unspentCoinsInfo: unspentCoinsInfoSource,
44 network: network,
45 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
46 );
47
48 await wallet.save();
@@ -63,6 +66,7 @@ class BitcoinWalletService extends WalletService<
66 walletInfo: walletInfo,
67 unspentCoinsInfo: unspentCoinsInfoSource,
68 alwaysScan: alwaysScan,
69 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
70 );
71 await wallet.init();
72 saveBackup(name);
@@ -75,6 +79,7 @@ class BitcoinWalletService extends WalletService<
79 walletInfo: walletInfo,
80 unspentCoinsInfo: unspentCoinsInfoSource,
81 alwaysScan: alwaysScan,
82 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
83 );
84 await wallet.init();
85 return wallet;
@@ -99,6 +104,7 @@ class BitcoinWalletService extends WalletService<
104 walletInfo: currentWalletInfo,
105 unspentCoinsInfo: unspentCoinsInfoSource,
106 alwaysScan: alwaysScan,
107 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
108 );
109
110 await currentWallet.renameWalletFiles(newName);
@@ -125,6 +131,7 @@ class BitcoinWalletService extends WalletService<
131 walletInfo: credentials.walletInfo!,
132 unspentCoinsInfo: unspentCoinsInfoSource,
133 networkParam: network,
134 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
135 );
136 await wallet.save();
137 await wallet.init();
@@ -153,6 +160,7 @@ class BitcoinWalletService extends WalletService<
160 walletInfo: credentials.walletInfo!,
161 unspentCoinsInfo: unspentCoinsInfoSource,
162 network: network,
163 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
164 );
165 await wallet.save();
166 await wallet.init();
cw_bitcoin/lib/electrum_transaction_history.dart
+8 -3
@@ -1,4 +1,5 @@
1 import 'dart:convert';
2 +import 'package:cw_core/encryption_file_utils.dart';
3
4 import 'package:cw_bitcoin/electrum_transaction_info.dart';
5 import 'package:cw_core/pathForWallet.dart';
@@ -6,6 +7,8 @@ import 'package:cw_core/transaction_history.dart';
7 import 'package:cw_core/utils/file.dart';
8 import 'package:cw_core/wallet_info.dart';
9 import 'package:mobx/mobx.dart';
10 +import 'package:cw_core/transaction_history.dart';
11 +import 'package:cw_bitcoin/electrum_transaction_info.dart';
12
13 part 'electrum_transaction_history.g.dart';
14
@@ -15,13 +18,15 @@ class ElectrumTransactionHistory = ElectrumTransactionHistoryBase with _$Electru
18
19 abstract class ElectrumTransactionHistoryBase
20 extends TransactionHistoryBase<ElectrumTransactionInfo> with Store {
18 - ElectrumTransactionHistoryBase({required this.walletInfo, required String password})
21 + ElectrumTransactionHistoryBase(
22 + {required this.walletInfo, required String password, required this.encryptionFileUtils})
23 : _password = password,
24 _height = 0 {
25 transactions = ObservableMap<String, ElectrumTransactionInfo>();
26 }
27
28 final WalletInfo walletInfo;
29 + final EncryptionFileUtils encryptionFileUtils;
30 String _password;
31 int _height;
32
@@ -44,7 +49,7 @@ abstract class ElectrumTransactionHistoryBase
49 txjson[tx.key] = tx.value.toJson();
50 }
51 final data = json.encode({'height': _height, 'transactions': txjson});
47 - await writeData(path: path, password: _password, data: data);
52 + await encryptionFileUtils.write(path: path, password: _password, data: data);
53 } catch (e) {
54 print('Error while save bitcoin transaction history: ${e.toString()}');
55 }
@@ -58,7 +63,7 @@ abstract class ElectrumTransactionHistoryBase
63 Future<Map<String, dynamic>> _read() async {
64 final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
65 final path = '$dirPath/$transactionsHistoryFileName';
61 - final content = await read(path: path, password: _password);
66 + final content = await encryptionFileUtils.read(path: path, password: _password);
67 return json.decode(content) as Map<String, dynamic>;
68 }
69
cw_bitcoin/lib/electrum_wallet.dart
+15 -7
@@ -5,6 +5,7 @@ import 'dart:isolate';
5 import 'dart:math';
6
7 import 'package:bitcoin_base/bitcoin_base.dart';
8 +import 'package:cw_core/encryption_file_utils.dart';
9 import 'package:blockchain_utils/blockchain_utils.dart';
10 import 'package:collection/collection.dart';
11 import 'package:cw_bitcoin/address_from_output.dart';
@@ -32,7 +33,6 @@ import 'package:cw_core/sync_status.dart';
33 import 'package:cw_core/transaction_direction.dart';
34 import 'package:cw_core/transaction_priority.dart';
35 import 'package:cw_core/unspent_coins_info.dart';
35 -import 'package:cw_core/utils/file.dart';
36 import 'package:cw_core/wallet_base.dart';
37 import 'package:cw_core/wallet_info.dart';
38 import 'package:cw_core/wallet_keys_file.dart';
@@ -58,6 +58,7 @@ abstract class ElectrumWalletBase
58 required WalletInfo walletInfo,
59 required Box<UnspentCoinsInfo> unspentCoinsInfo,
60 required this.network,
61 + required this.encryptionFileUtils,
62 String? xpub,
63 String? mnemonic,
64 Uint8List? seedBytes,
@@ -92,7 +93,11 @@ abstract class ElectrumWalletBase
93 super(walletInfo) {
94 this.electrumClient = electrumClient ?? ElectrumClient();
95 this.walletInfo = walletInfo;
95 - transactionHistory = ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
96 + transactionHistory = ElectrumTransactionHistory(
97 + walletInfo: walletInfo,
98 + password: password,
99 + encryptionFileUtils: encryptionFileUtils,
100 + );
101
102 reaction((_) => syncStatus, _syncStatusReaction);
103 }
@@ -127,6 +132,8 @@ abstract class ElectrumWalletBase
132 final String? _mnemonic;
133
134 Bip32Slip10Secp256k1 get hd => accountHD.childKey(Bip32KeyIndex(0));
135 +
136 + final EncryptionFileUtils encryptionFileUtils;
137 final String? passphrase;
138
139 @override
@@ -167,6 +174,9 @@ abstract class ElectrumWalletBase
174 WalletKeysData get walletKeysData =>
175 WalletKeysData(mnemonic: _mnemonic, xPub: xpub, passphrase: passphrase);
176
177 + @override
178 + String get password => _password;
179 +
180 BasedUtxoNetwork network;
181
182 @override
@@ -455,7 +465,6 @@ abstract class ElectrumWalletBase
465 }
466 }
467
458 -
468 node!.isElectrs = false;
469 node!.save();
470 return node!.isElectrs!;
@@ -1130,12 +1139,12 @@ abstract class ElectrumWalletBase
1139 @override
1140 Future<void> save() async {
1141 if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
1133 - await saveKeysFile(_password);
1134 - saveKeysFile(_password, true);
1142 + await saveKeysFile(_password, encryptionFileUtils);
1143 + saveKeysFile(_password, encryptionFileUtils, true);
1144 }
1145
1146 final path = await makePath();
1138 - await write(path: path, password: _password, data: toJSON());
1147 + await encryptionFileUtils.write(path: path, password: _password, data: toJSON());
1148 await transactionHistory.save();
1149 }
1150
@@ -2258,4 +2267,3 @@ class UtxoDetails {
2267 required this.spendsUnconfirmedTX,
2268 });
2269 }
2261 -
cw_bitcoin/lib/electrum_wallet_snapshot.dart
+3 -2
@@ -2,6 +2,7 @@ import 'dart:convert';
2 import 'package:bitcoin_base/bitcoin_base.dart';
3 import 'package:cw_bitcoin/bitcoin_address_record.dart';
4 import 'package:cw_bitcoin/electrum_balance.dart';
5 +import 'package:cw_core/encryption_file_utils.dart';
6 import 'package:cw_bitcoin/electrum_derivations.dart';
7 import 'package:cw_core/pathForWallet.dart';
8 import 'package:cw_core/wallet_info.dart';
@@ -51,9 +52,9 @@ class ElectrumWalletSnapshot {
52 String? derivationPath;
53
54 static Future<ElectrumWalletSnapshot> load(
54 - String name, WalletType type, String password, BasedUtxoNetwork network) async {
55 + EncryptionFileUtils encryptionFileUtils, String name, WalletType type, String password, BasedUtxoNetwork network) async {
56 final path = await pathForWallet(name: name, type: type);
56 - final jsonSource = await read(path: path, password: password);
57 + final jsonSource = await encryptionFileUtils.read(path: path, password: password);
58 final data = json.decode(jsonSource) as Map;
59 final addressesTmp = data['addresses'] as List? ?? <Object>[];
60 final mnemonic = data['mnemonic'] as String?;
cw_bitcoin/lib/litecoin_wallet.dart
+26 -10
@@ -4,13 +4,14 @@ import 'package:blockchain_utils/blockchain_utils.dart';
4 import 'package:cw_bitcoin/bitcoin_address_record.dart';
5 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
6 import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
7 +import 'package:cw_core/encryption_file_utils.dart';
8 +import 'package:cw_core/crypto_currency.dart';
9 +import 'package:cw_core/unspent_coins_info.dart';
10 import 'package:cw_bitcoin/electrum_balance.dart';
11 import 'package:cw_bitcoin/electrum_wallet.dart';
12 import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
13 import 'package:cw_bitcoin/litecoin_wallet_addresses.dart';
11 -import 'package:cw_core/crypto_currency.dart';
14 import 'package:cw_core/transaction_priority.dart';
13 -import 'package:cw_core/unspent_coins_info.dart';
15 import 'package:cw_core/wallet_info.dart';
16 import 'package:cw_core/wallet_keys_file.dart';
17 import 'package:flutter/foundation.dart';
@@ -28,6 +29,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
29 required WalletInfo walletInfo,
30 required Box<UnspentCoinsInfo> unspentCoinsInfo,
31 required Uint8List seedBytes,
32 + required EncryptionFileUtils encryptionFileUtils,
33 String? addressPageType,
34 List<BitcoinAddressRecord>? initialAddresses,
35 ElectrumBalance? initialBalance,
@@ -42,6 +44,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
44 initialAddresses: initialAddresses,
45 initialBalance: initialBalance,
46 seedBytes: seedBytes,
47 + encryptionFileUtils: encryptionFileUtils,
48 currency: CryptoCurrency.ltc) {
49 walletAddresses = LitecoinWalletAddresses(
50 walletInfo,
@@ -62,6 +65,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
65 required String password,
66 required WalletInfo walletInfo,
67 required Box<UnspentCoinsInfo> unspentCoinsInfo,
68 + required EncryptionFileUtils encryptionFileUtils,
69 String? passphrase,
70 String? addressPageType,
71 List<BitcoinAddressRecord>? initialAddresses,
@@ -89,6 +93,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
93 unspentCoinsInfo: unspentCoinsInfo,
94 initialAddresses: initialAddresses,
95 initialBalance: initialBalance,
96 + encryptionFileUtils: encryptionFileUtils,
97 seedBytes: seedBytes,
98 initialRegularAddressIndex: initialRegularAddressIndex,
99 initialChangeAddressIndex: initialChangeAddressIndex,
@@ -96,19 +101,24 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
101 );
102 }
103
99 - static Future<LitecoinWallet> open({
100 - required String name,
101 - required WalletInfo walletInfo,
102 - required Box<UnspentCoinsInfo> unspentCoinsInfo,
103 - required String password,
104 - }) async {
104 + static Future<LitecoinWallet> open(
105 + {required String name,
106 + required WalletInfo walletInfo,
107 + required Box<UnspentCoinsInfo> unspentCoinsInfo,
108 + required String password,
109 + required EncryptionFileUtils encryptionFileUtils}) async {
110 final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
111
112 ElectrumWalletSnapshot? snp = null;
113
114 try {
115 snp = await ElectrumWalletSnapshot.load(
111 - name, walletInfo.type, password, LitecoinNetwork.mainnet);
116 + encryptionFileUtils,
117 + name,
118 + walletInfo.type,
119 + password,
120 + LitecoinNetwork.mainnet,
121 + );
122 } catch (e) {
123 if (!hasKeysFile) rethrow;
124 }
@@ -119,7 +129,12 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
129 keysData =
130 WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
131 } else {
122 - keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
132 + keysData = await WalletKeysFile.readKeysFile(
133 + name,
134 + walletInfo.type,
135 + password,
136 + encryptionFileUtils,
137 + );
138 }
139
140 return LitecoinWallet(
@@ -130,6 +145,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
145 initialAddresses: snp?.addresses,
146 initialBalance: snp?.balance,
147 seedBytes: await mnemonicToSeedBytes(keysData.mnemonic!),
148 + encryptionFileUtils: encryptionFileUtils,
149 initialRegularAddressIndex: snp?.regularAddressIndex,
150 initialChangeAddressIndex: snp?.changeAddressIndex,
151 addressPageType: snp?.addressPageType,
cw_bitcoin/lib/litecoin_wallet_service.dart
+50 -34
@@ -1,4 +1,5 @@
1 import 'dart:io';
2 +import 'package:cw_core/encryption_file_utils.dart';
3 import 'package:cw_core/unspent_coins_info.dart';
4 import 'package:hive/hive.dart';
5 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
@@ -16,11 +17,13 @@ import 'package:bip39/bip39.dart' as bip39;
17 class LitecoinWalletService extends WalletService<
18 BitcoinNewWalletCredentials,
19 BitcoinRestoreWalletFromSeedCredentials,
19 - BitcoinRestoreWalletFromWIFCredentials,BitcoinNewWalletCredentials> {
20 - LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
20 + BitcoinRestoreWalletFromWIFCredentials,
21 + BitcoinNewWalletCredentials> {
22 + LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
23
24 final Box<WalletInfo> walletInfoSource;
25 final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
26 + final bool isDirect;
27
28 @override
29 WalletType getType() => WalletType.litecoin;
@@ -28,12 +31,13 @@ class LitecoinWalletService extends WalletService<
31 @override
32 Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
33 final wallet = await LitecoinWalletBase.create(
31 - mnemonic: await generateElectrumMnemonic(),
32 - password: credentials.password!,
33 - passphrase: credentials.passphrase,
34 - walletInfo: credentials.walletInfo!,
35 - unspentCoinsInfo: unspentCoinsInfoSource);
36 -
34 + mnemonic: await generateElectrumMnemonic(),
35 + password: credentials.password!,
36 + passphrase: credentials.passphrase,
37 + walletInfo: credentials.walletInfo!,
38 + unspentCoinsInfo: unspentCoinsInfoSource,
39 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
40 + );
41 await wallet.save();
42 await wallet.init();
43
@@ -46,21 +50,29 @@ class LitecoinWalletService extends WalletService<
50
51 @override
52 Future<LitecoinWallet> openWallet(String name, String password) async {
49 - final walletInfo = walletInfoSource.values.firstWhereOrNull(
50 - (info) => info.id == WalletBase.idFor(name, getType()))!;
53 + final walletInfo = walletInfoSource.values
54 + .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
55
56 try {
57 final wallet = await LitecoinWalletBase.open(
54 - password: password, name: name, walletInfo: walletInfo,
55 - unspentCoinsInfo: unspentCoinsInfoSource);
58 + password: password,
59 + name: name,
60 + walletInfo: walletInfo,
61 + unspentCoinsInfo: unspentCoinsInfoSource,
62 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
63 + );
64 await wallet.init();
65 saveBackup(name);
66 return wallet;
67 } catch (_) {
68 await restoreWalletFilesFromBackup(name);
69 final wallet = await LitecoinWalletBase.open(
62 - password: password, name: name, walletInfo: walletInfo,
63 - unspentCoinsInfo: unspentCoinsInfoSource);
70 + password: password,
71 + name: name,
72 + walletInfo: walletInfo,
73 + unspentCoinsInfo: unspentCoinsInfoSource,
74 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
75 + );
76 await wallet.init();
77 return wallet;
78 }
@@ -68,22 +80,23 @@ class LitecoinWalletService extends WalletService<
80
81 @override
82 Future<void> remove(String wallet) async {
71 - File(await pathForWalletDir(name: wallet, type: getType()))
72 - .delete(recursive: true);
73 - final walletInfo = walletInfoSource.values.firstWhereOrNull(
74 - (info) => info.id == WalletBase.idFor(wallet, getType()))!;
83 + File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
84 + final walletInfo = walletInfoSource.values
85 + .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
86 await walletInfoSource.delete(walletInfo.key);
87 }
88
89 @override
90 Future<void> rename(String currentName, String password, String newName) async {
80 - final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
81 - (info) => info.id == WalletBase.idFor(currentName, getType()))!;
91 + final currentWalletInfo = walletInfoSource.values
92 + .firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
93 final currentWallet = await LitecoinWalletBase.open(
83 - password: password,
84 - name: currentName,
85 - walletInfo: currentWalletInfo,
86 - unspentCoinsInfo: unspentCoinsInfoSource);
94 + password: password,
95 + name: currentName,
96 + walletInfo: currentWalletInfo,
97 + unspentCoinsInfo: unspentCoinsInfoSource,
98 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
99 + );
100
101 await currentWallet.renameWalletFiles(newName);
102 await saveBackup(newName);
@@ -97,27 +110,30 @@ class LitecoinWalletService extends WalletService<
110
111 @override
112 Future<LitecoinWallet> restoreFromHardwareWallet(BitcoinNewWalletCredentials credentials) {
100 - throw UnimplementedError("Restoring a Litecoin wallet from a hardware wallet is not yet supported!");
113 + throw UnimplementedError(
114 + "Restoring a Litecoin wallet from a hardware wallet is not yet supported!");
115 }
116
117 @override
104 - Future<LitecoinWallet> restoreFromKeys(
105 - BitcoinRestoreWalletFromWIFCredentials credentials, {bool? isTestnet}) async =>
118 + Future<LitecoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials,
119 + {bool? isTestnet}) async =>
120 throw UnimplementedError();
121
122 @override
109 - Future<LitecoinWallet> restoreFromSeed(
110 - BitcoinRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
123 + Future<LitecoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
124 + {bool? isTestnet}) async {
125 if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) {
126 throw LitecoinMnemonicIsIncorrectException();
127 }
128
129 final wallet = await LitecoinWalletBase.create(
116 - password: credentials.password!,
117 - passphrase: credentials.passphrase,
118 - mnemonic: credentials.mnemonic,
119 - walletInfo: credentials.walletInfo!,
120 - unspentCoinsInfo: unspentCoinsInfoSource);
130 + password: credentials.password!,
131 + passphrase: credentials.passphrase,
132 + mnemonic: credentials.mnemonic,
133 + walletInfo: credentials.walletInfo!,
134 + unspentCoinsInfo: unspentCoinsInfoSource,
135 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
136 + );
137 await wallet.save();
138 await wallet.init();
139 return wallet;
cw_bitcoin/pubspec.lock
+25
@@ -164,6 +164,15 @@ packages:
164 url: "https://pub.dev"
165 source: hosted
166 version: "8.9.2"
167 + cake_backup:
168 + dependency: transitive
169 + description:
170 + path: "."
171 + ref: main
172 + resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
173 + url: "https://github.com/cake-tech/cake_backup.git"
174 + source: git
175 + version: "1.0.0+1"
176 characters:
177 dependency: transitive
178 description:
@@ -236,6 +245,14 @@ packages:
245 url: "https://pub.dev"
246 source: hosted
247 version: "2.7.0"
248 + cupertino_icons:
249 + dependency: transitive
250 + description:
251 + name: cupertino_icons
252 + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
253 + url: "https://pub.dev"
254 + source: hosted
255 + version: "1.0.8"
256 cw_core:
257 dependency: "direct main"
258 description:
@@ -837,6 +854,14 @@ packages:
854 url: "https://pub.dev"
855 source: hosted
856 version: "1.0.1"
857 + tuple:
858 + dependency: transitive
859 + description:
860 + name: tuple
861 + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
862 + url: "https://pub.dev"
863 + source: hosted
864 + version: "2.0.2"
865 typed_data:
866 dependency: transitive
867 description:
cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart
+20 -3
@@ -1,6 +1,7 @@
1 import 'package:bitbox/bitbox.dart' as bitbox;
2 import 'package:bitcoin_base/bitcoin_base.dart';
3 import 'package:blockchain_utils/blockchain_utils.dart';
4 +import 'package:cw_core/encryption_file_utils.dart';
5 import 'package:cw_bitcoin/bitcoin_address_record.dart';
6 import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
7 import 'package:cw_bitcoin/electrum_balance.dart';
@@ -28,6 +29,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
29 required WalletInfo walletInfo,
30 required Box<UnspentCoinsInfo> unspentCoinsInfo,
31 required Uint8List seedBytes,
32 + required EncryptionFileUtils encryptionFileUtils,
33 BitcoinAddressType? addressPageType,
34 List<BitcoinAddressRecord>? initialAddresses,
35 ElectrumBalance? initialBalance,
@@ -42,7 +44,8 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
44 initialAddresses: initialAddresses,
45 initialBalance: initialBalance,
46 seedBytes: seedBytes,
45 - currency: CryptoCurrency.bch) {
47 + currency: CryptoCurrency.bch,
48 + encryptionFileUtils: encryptionFileUtils) {
49 walletAddresses = BitcoinCashWalletAddresses(
50 walletInfo,
51 initialAddresses: initialAddresses,
@@ -63,6 +66,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
66 required String password,
67 required WalletInfo walletInfo,
68 required Box<UnspentCoinsInfo> unspentCoinsInfo,
69 + required EncryptionFileUtils encryptionFileUtils,
70 String? addressPageType,
71 List<BitcoinAddressRecord>? initialAddresses,
72 ElectrumBalance? initialBalance,
@@ -76,6 +80,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
80 initialAddresses: initialAddresses,
81 initialBalance: initialBalance,
82 seedBytes: await MnemonicBip39.toSeed(mnemonic),
83 + encryptionFileUtils: encryptionFileUtils,
84 initialRegularAddressIndex: initialRegularAddressIndex,
85 initialChangeAddressIndex: initialChangeAddressIndex,
86 addressPageType: P2pkhAddressType.p2pkh,
@@ -87,6 +92,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
92 required WalletInfo walletInfo,
93 required Box<UnspentCoinsInfo> unspentCoinsInfo,
94 required String password,
95 + required EncryptionFileUtils encryptionFileUtils,
96 }) async {
97 final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
98
@@ -94,7 +100,12 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
100
101 try {
102 snp = await ElectrumWalletSnapshot.load(
97 - name, walletInfo.type, password, BitcoinCashNetwork.mainnet);
103 + encryptionFileUtils,
104 + name,
105 + walletInfo.type,
106 + password,
107 + BitcoinCashNetwork.mainnet,
108 + );
109 } catch (e) {
110 if (!hasKeysFile) rethrow;
111 }
@@ -105,7 +116,12 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
116 keysData =
117 WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
118 } else {
108 - keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
119 + keysData = await WalletKeysFile.readKeysFile(
120 + name,
121 + walletInfo.type,
122 + password,
123 + encryptionFileUtils,
124 + );
125 }
126
127 return BitcoinCashWallet(
@@ -135,6 +151,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
151 }).toList(),
152 initialBalance: snp?.balance,
153 seedBytes: await MnemonicBip39.toSeed(keysData.mnemonic!),
154 + encryptionFileUtils: encryptionFileUtils,
155 initialRegularAddressIndex: snp?.regularAddressIndex,
156 initialChangeAddressIndex: snp?.changeAddressIndex,
157 addressPageType: P2pkhAddressType.p2pkh,
cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_creation_credentials.dart
+2 -2
@@ -2,8 +2,8 @@ import 'package:cw_core/wallet_credentials.dart';
2 import 'package:cw_core/wallet_info.dart';
3
4 class BitcoinCashNewWalletCredentials extends WalletCredentials {
5 - BitcoinCashNewWalletCredentials({required String name, WalletInfo? walletInfo})
6 - : super(name: name, walletInfo: walletInfo);
5 + BitcoinCashNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
6 + : super(name: name, walletInfo: walletInfo, password: password);
7 }
8
9 class BitcoinCashRestoreWalletFromSeedCredentials extends WalletCredentials {
cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart
+18 -9
@@ -2,6 +2,7 @@ import 'dart:io';
2
3 import 'package:bip39/bip39.dart';
4 import 'package:cw_bitcoin_cash/cw_bitcoin_cash.dart';
5 +import 'package:cw_core/encryption_file_utils.dart';
6 import 'package:cw_core/pathForWallet.dart';
7 import 'package:cw_core/unspent_coins_info.dart';
8 import 'package:cw_core/wallet_base.dart';
@@ -16,10 +17,11 @@ class BitcoinCashWalletService extends WalletService<
17 BitcoinCashRestoreWalletFromSeedCredentials,
18 BitcoinCashRestoreWalletFromWIFCredentials,
19 BitcoinCashNewWalletCredentials> {
19 - BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
20 + BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
21
22 final Box<WalletInfo> walletInfoSource;
23 final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
24 + final bool isDirect;
25
26 @override
27 WalletType getType() => WalletType.bitcoinCash;
@@ -34,10 +36,11 @@ class BitcoinCashWalletService extends WalletService<
36
37 final wallet = await BitcoinCashWalletBase.create(
38 mnemonic: await MnemonicBip39.generate(strength: strength),
37 - password: credentials.password!,
38 - walletInfo: credentials.walletInfo!,
39 - unspentCoinsInfo: unspentCoinsInfoSource);
40 -
39 + password: credentials.password!,
40 + walletInfo: credentials.walletInfo!,
41 + unspentCoinsInfo: unspentCoinsInfoSource,
42 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
43 + );
44 await wallet.save();
45 await wallet.init();
46
@@ -54,7 +57,9 @@ class BitcoinCashWalletService extends WalletService<
57 password: password,
58 name: name,
59 walletInfo: walletInfo,
57 - unspentCoinsInfo: unspentCoinsInfoSource);
60 + unspentCoinsInfo: unspentCoinsInfoSource,
61 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
62 + );
63 await wallet.init();
64 saveBackup(name);
65 return wallet;
@@ -64,7 +69,9 @@ class BitcoinCashWalletService extends WalletService<
69 password: password,
70 name: name,
71 walletInfo: walletInfo,
67 - unspentCoinsInfo: unspentCoinsInfoSource);
72 + unspentCoinsInfo: unspentCoinsInfoSource,
73 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
74 + );
75 await wallet.init();
76 return wallet;
77 }
@@ -86,7 +93,8 @@ class BitcoinCashWalletService extends WalletService<
93 password: password,
94 name: currentName,
95 walletInfo: currentWalletInfo,
89 - unspentCoinsInfo: unspentCoinsInfoSource);
96 + unspentCoinsInfo: unspentCoinsInfoSource,
97 + encryptionFileUtils: encryptionFileUtilsFor(isDirect));
98
99 await currentWallet.renameWalletFiles(newName);
100 await saveBackup(newName);
@@ -121,7 +129,8 @@ class BitcoinCashWalletService extends WalletService<
129 password: credentials.password!,
130 mnemonic: credentials.mnemonic,
131 walletInfo: credentials.walletInfo!,
124 - unspentCoinsInfo: unspentCoinsInfoSource);
132 + unspentCoinsInfo: unspentCoinsInfoSource,
133 + encryptionFileUtils: encryptionFileUtilsFor(isDirect));
134 await wallet.save();
135 await wallet.init();
136 return wallet;
cw_core/lib/encryption_file_utils.dart new
+42
@@ -0,0 +1,42 @@
1 +import 'dart:io';
2 +import 'dart:typed_data';
3 +import 'package:cw_core/utils/file.dart' as file;
4 +import 'package:cake_backup/backup.dart' as cwb;
5 +
6 +EncryptionFileUtils encryptionFileUtilsFor(bool direct)
7 + => direct
8 + ? XChaCha20EncryptionFileUtils()
9 + : Salsa20EncryhptionFileUtils();
10 +
11 +abstract class EncryptionFileUtils {
12 + Future<void> write({required String path, required String password, required String data});
13 + Future<String> read({required String path, required String password});
14 +}
15 +
16 +class Salsa20EncryhptionFileUtils extends EncryptionFileUtils {
17 + // Requires legacy complex key + iv as password
18 + @override
19 + Future<void> write({required String path, required String password, required String data}) async
20 + => await file.write(path: path, password: password, data: data);
21 +
22 + // Requires legacy complex key + iv as password
23 + @override
24 + Future<String> read({required String path, required String password}) async
25 + => await file.read(path: path, password: password);
26 +}
27 +
28 +class XChaCha20EncryptionFileUtils extends EncryptionFileUtils {
29 + @override
30 + Future<void> write({required String path, required String password, required String data}) async {
31 + final encrypted = await cwb.encrypt(password, Uint8List.fromList(data.codeUnits));
32 + await File(path).writeAsBytes(encrypted);
33 + }
34 +
35 + @override
36 + Future<String> read({required String path, required String password}) async {
37 + final file = File(path);
38 + final encrypted = await file.readAsBytes();
39 + final bytes = await cwb.decrypt(password, encrypted);
40 + return String.fromCharCodes(bytes);
41 + }
42 +}
\ No newline at end of file
cw_core/lib/wallet_base.dart
+2
@@ -84,6 +84,8 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
84
85 Future<void> changePassword(String password);
86
87 + String get password;
88 +
89 Future<void>? updateBalance();
90
91 void setExceptionHandler(void Function(FlutterErrorDetails) onError) => null;
cw_core/lib/wallet_keys_file.dart
+20 -11
@@ -3,10 +3,10 @@ import 'dart:developer' as dev;
3 import 'dart:io';
4
5 import 'package:cw_core/balance.dart';
6 +import 'package:cw_core/encryption_file_utils.dart';
7 import 'package:cw_core/pathForWallet.dart';
8 import 'package:cw_core/transaction_history.dart';
9 import 'package:cw_core/transaction_info.dart';
9 -import 'package:cw_core/utils/file.dart';
10 import 'package:cw_core/wallet_base.dart';
11 import 'package:cw_core/wallet_type.dart';
12
@@ -20,28 +20,32 @@ mixin WalletKeysFile<BalanceType extends Balance, HistoryType extends Transactio
20
21 Future<String> makeKeysFilePath() async => "${await makePath()}.keys";
22
23 - Future<void> saveKeysFile(String password, [bool isBackup = false]) async {
23 + Future<void> saveKeysFile(String password, EncryptionFileUtils encryptionFileUtils,
24 + [bool isBackup = false]) async {
25 try {
26 final rootPath = await makeKeysFilePath();
27 final path = "$rootPath${isBackup ? ".backup" : ""}";
28 dev.log("Saving .keys file '$path'");
28 - await write(path: path, password: password, data: walletKeysData.toJSON());
29 + await encryptionFileUtils.write(
30 + path: path, password: password, data: walletKeysData.toJSON());
31 } catch (_) {}
32 }
33
32 - static Future<void> createKeysFile(
33 - String name, WalletType type, String password, WalletKeysData walletKeysData,
34 + static Future<void> createKeysFile(String name, WalletType type, String password,
35 + WalletKeysData walletKeysData, EncryptionFileUtils encryptionFileUtils,
36 [bool withBackup = true]) async {
37 try {
38 final rootPath = await pathForWallet(name: name, type: type);
39 final path = "$rootPath.keys";
40
41 dev.log("Saving .keys file '$path'");
40 - await write(path: path, password: password, data: walletKeysData.toJSON());
42 + await encryptionFileUtils.write(
43 + path: path, password: password, data: walletKeysData.toJSON());
44
45 if (withBackup) {
46 dev.log("Saving .keys.backup file '$path.backup'");
44 - await write(path: "$path.backup", password: password, data: walletKeysData.toJSON());
47 + await encryptionFileUtils.write(
48 + path: "$path.backup", password: password, data: walletKeysData.toJSON());
49 }
50 } catch (_) {}
51 }
@@ -55,14 +59,19 @@ mixin WalletKeysFile<BalanceType extends Balance, HistoryType extends Transactio
59 }
60 }
61
58 - static Future<WalletKeysData> readKeysFile(String name, WalletType type, String password) async {
62 + static Future<WalletKeysData> readKeysFile(
63 + String name,
64 + WalletType type,
65 + String password,
66 + EncryptionFileUtils encryptionFileUtils,
67 + ) async {
68 final path = await pathForWallet(name: name, type: type);
69
70 var readPath = "$path.keys";
71 try {
72 if (!File(readPath).existsSync()) throw Exception("No .keys file found for $name $type");
73
65 - final jsonSource = await read(path: readPath, password: password);
74 + final jsonSource = await encryptionFileUtils.read(path: readPath, password: password);
75 final data = json.decode(jsonSource) as Map<String, dynamic>;
76 return WalletKeysData.fromJSON(data);
77 } catch (e) {
@@ -72,12 +81,12 @@ mixin WalletKeysFile<BalanceType extends Balance, HistoryType extends Transactio
81 if (!File(readPath).existsSync())
82 throw Exception("No .keys nor a .keys.backup file found for $name $type");
83
75 - final jsonSource = await read(path: readPath, password: password);
84 + final jsonSource = await encryptionFileUtils.read(path: readPath, password: password);
85 final data = json.decode(jsonSource) as Map<String, dynamic>;
86 final keysData = WalletKeysData.fromJSON(data);
87
88 dev.log("Restoring .keys from .keys.backup");
80 - createKeysFile(name, type, password, keysData, false);
89 + createKeysFile(name, type, password, keysData, encryptionFileUtils, false);
90 return keysData;
91 }
92 }
cw_core/pubspec.lock
+33
@@ -113,6 +113,15 @@ packages:
113 url: "https://pub.dev"
114 source: hosted
115 version: "8.8.1"
116 + cake_backup:
117 + dependency: "direct main"
118 + description:
119 + path: "."
120 + ref: main
121 + resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
122 + url: "https://github.com/cake-tech/cake_backup.git"
123 + source: git
124 + version: "1.0.0+1"
125 characters:
126 dependency: transitive
127 description:
@@ -169,6 +178,22 @@ packages:
178 url: "https://pub.dev"
179 source: hosted
180 version: "3.0.3"
181 + cryptography:
182 + dependency: transitive
183 + description:
184 + name: cryptography
185 + sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
186 + url: "https://pub.dev"
187 + source: hosted
188 + version: "2.5.0"
189 + cupertino_icons:
190 + dependency: transitive
191 + description:
192 + name: cupertino_icons
193 + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
194 + url: "https://pub.dev"
195 + source: hosted
196 + version: "1.0.6"
197 dart_style:
198 dependency: transitive
199 description:
@@ -648,6 +673,14 @@ packages:
673 url: "https://pub.dev"
674 source: hosted
675 version: "1.0.1"
676 + tuple:
677 + dependency: transitive
678 + description:
679 + name: tuple
680 + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
681 + url: "https://pub.dev"
682 + source: hosted
683 + version: "2.0.2"
684 typed_data:
685 dependency: transitive
686 description:
cw_core/pubspec.yaml
+5
@@ -19,6 +19,11 @@ dependencies:
19 flutter_mobx: ^2.0.6+1
20 intl: ^0.18.0
21 encrypt: ^5.0.1
22 + cake_backup:
23 + git:
24 + url: https://github.com/cake-tech/cake_backup.git
25 + ref: main
26 + version: 1.0.0
27 socks5_proxy: ^1.0.4
28 unorm_dart: ^0.3.0
29 # tor:
cw_ethereum/lib/ethereum_transaction_history.dart
+1
@@ -7,6 +7,7 @@ class EthereumTransactionHistory extends EVMChainTransactionHistory {
7 EthereumTransactionHistory({
8 required super.walletInfo,
9 required super.password,
10 + required super.encryptionFileUtils,
11 });
12
13 @override
cw_ethereum/lib/ethereum_wallet.dart
+20 -7
@@ -2,6 +2,7 @@ import 'dart:convert';
2
3 import 'package:cw_core/cake_hive.dart';
4 import 'package:cw_core/crypto_currency.dart';
5 +import 'package:cw_core/encryption_file_utils.dart';
6 import 'package:cw_core/erc20_token.dart';
7 import 'package:cw_core/pathForWallet.dart';
8 import 'package:cw_core/transaction_direction.dart';
@@ -16,7 +17,6 @@ import 'package:cw_evm/evm_chain_transaction_info.dart';
17 import 'package:cw_evm/evm_chain_transaction_model.dart';
18 import 'package:cw_evm/evm_chain_wallet.dart';
19 import 'package:cw_evm/evm_erc20_balance.dart';
19 -import 'package:cw_evm/file.dart';
20
21 class EthereumWallet extends EVMChainWallet {
22 EthereumWallet({
@@ -26,6 +26,7 @@ class EthereumWallet extends EVMChainWallet {
26 super.mnemonic,
27 super.initialBalance,
28 super.privateKey,
29 + required super.encryptionFileUtils,
30 }) : super(nativeCurrency: CryptoCurrency.eth);
31
32 @override
@@ -117,18 +118,24 @@ class EthereumWallet extends EVMChainWallet {
118 }
119
120 @override
120 - EVMChainTransactionHistory setUpTransactionHistory(WalletInfo walletInfo, String password) {
121 - return EthereumTransactionHistory(walletInfo: walletInfo, password: password);
121 + EVMChainTransactionHistory setUpTransactionHistory(
122 + WalletInfo walletInfo, String password, EncryptionFileUtils encryptionFileUtils) {
123 + return EthereumTransactionHistory(
124 + walletInfo: walletInfo, password: password, encryptionFileUtils: encryptionFileUtils);
125 }
126
124 - static Future<EthereumWallet> open(
125 - {required String name, required String password, required WalletInfo walletInfo}) async {
127 + static Future<EthereumWallet> open({
128 + required String name,
129 + required String password,
130 + required WalletInfo walletInfo,
131 + required EncryptionFileUtils encryptionFileUtils,
132 + }) async {
133 final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
134 final path = await pathForWallet(name: name, type: walletInfo.type);
135
136 Map<String, dynamic>? data;
137 try {
131 - final jsonSource = await read(path: path, password: password);
138 + final jsonSource = await encryptionFileUtils.read(path: path, password: password);
139
140 data = json.decode(jsonSource) as Map<String, dynamic>;
141 } catch (e) {
@@ -146,7 +153,12 @@ class EthereumWallet extends EVMChainWallet {
153
154 keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
155 } else {
149 - keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
156 + keysData = await WalletKeysFile.readKeysFile(
157 + name,
158 + walletInfo.type,
159 + password,
160 + encryptionFileUtils,
161 + );
162 }
163
164 return EthereumWallet(
@@ -156,6 +168,7 @@ class EthereumWallet extends EVMChainWallet {
168 privateKey: keysData.privateKey,
169 initialBalance: balance,
170 client: EthereumClient(),
171 + encryptionFileUtils: encryptionFileUtils,
172 );
173 }
174 }
cw_ethereum/lib/ethereum_wallet_service.dart
+13 -2
@@ -1,4 +1,5 @@
1 import 'package:bip39/bip39.dart' as bip39;
2 +import 'package:cw_core/encryption_file_utils.dart';
3 import 'package:cw_core/wallet_base.dart';
4 import 'package:cw_core/wallet_info.dart';
5 import 'package:cw_core/wallet_type.dart';
@@ -9,7 +10,7 @@ import 'package:cw_evm/evm_chain_wallet_creation_credentials.dart';
10 import 'package:cw_evm/evm_chain_wallet_service.dart';
11
12 class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
12 - EthereumWalletService(super.walletInfoSource, {required this.client});
13 + EthereumWalletService(super.walletInfoSource, super.isDirect, {required this.client});
14
15 late EthereumClient client;
16
@@ -27,6 +28,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
28 mnemonic: mnemonic,
29 password: credentials.password!,
30 client: client,
31 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
32 );
33
34 await wallet.init();
@@ -46,6 +48,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
48 name: name,
49 password: password,
50 walletInfo: walletInfo,
51 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
52 );
53
54 await wallet.init();
@@ -59,6 +62,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
62 name: name,
63 password: password,
64 walletInfo: walletInfo,
65 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
66 );
67 await wallet.init();
68 await wallet.save();
@@ -71,7 +75,11 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
75 final currentWalletInfo = walletInfoSource.values
76 .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
77 final currentWallet = await EthereumWallet.open(
74 - password: password, name: currentName, walletInfo: currentWalletInfo);
78 + password: password,
79 + name: currentName,
80 + walletInfo: currentWalletInfo,
81 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
82 + );
83
84 await currentWallet.renameWalletFiles(newName);
85 await saveBackup(newName);
@@ -97,6 +105,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
105 walletInfo: credentials.walletInfo!,
106 password: credentials.password!,
107 client: client,
108 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
109 );
110
111 await wallet.init();
@@ -114,6 +123,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
123 privateKey: credentials.privateKey,
124 walletInfo: credentials.walletInfo!,
125 client: client,
126 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
127 );
128
129 await wallet.init();
@@ -135,6 +145,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
145 mnemonic: credentials.mnemonic,
146 walletInfo: credentials.walletInfo!,
147 client: client,
148 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
149 );
150
151 await wallet.init();
cw_evm/lib/evm_chain_transaction_history.dart
+6 -4
@@ -1,10 +1,10 @@
1 import 'dart:convert';
2 import 'dart:core';
3 import 'dart:developer';
4 +import 'package:cw_core/encryption_file_utils.dart';
5 import 'package:cw_core/pathForWallet.dart';
6 import 'package:cw_core/wallet_info.dart';
7 import 'package:cw_evm/evm_chain_transaction_info.dart';
7 -import 'package:cw_evm/file.dart';
8 import 'package:mobx/mobx.dart';
9 import 'package:cw_core/transaction_history.dart';
10
@@ -15,7 +15,8 @@ abstract class EVMChainTransactionHistory = EVMChainTransactionHistoryBase
15
16 abstract class EVMChainTransactionHistoryBase
17 extends TransactionHistoryBase<EVMChainTransactionInfo> with Store {
18 - EVMChainTransactionHistoryBase({required this.walletInfo, required String password})
18 + EVMChainTransactionHistoryBase(
19 + {required this.walletInfo, required String password, required this.encryptionFileUtils})
20 : _password = password {
21 transactions = ObservableMap<String, EVMChainTransactionInfo>();
22 }
@@ -23,6 +24,7 @@ abstract class EVMChainTransactionHistoryBase
24 String _password;
25
26 final WalletInfo walletInfo;
27 + final EncryptionFileUtils encryptionFileUtils;
28
29 //! Method to be overridden by all child classes
30
@@ -41,7 +43,7 @@ abstract class EVMChainTransactionHistoryBase
43 final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
44 String path = '$dirPath/$transactionsHistoryFileNameForWallet';
45 final data = json.encode({'transactions': transactions});
44 - await writeData(path: path, password: _password, data: data);
46 + await encryptionFileUtils.write(path: path, password: _password, data: data);
47 } catch (e, s) {
48 log('Error while saving ${walletInfo.type.name} transaction history: ${e.toString()}');
49 log(s.toString());
@@ -59,7 +61,7 @@ abstract class EVMChainTransactionHistoryBase
61 final transactionsHistoryFileNameForWallet = getTransactionHistoryFileName();
62 final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
63 String path = '$dirPath/$transactionsHistoryFileNameForWallet';
62 - final content = await read(path: path, password: _password);
64 + final content = await encryptionFileUtils.read(path: path, password: _password);
65 if (content.isEmpty) {
66 return {};
67 }
cw_evm/lib/evm_chain_wallet.dart
+15 -6
@@ -7,6 +7,7 @@ import 'package:bip32/bip32.dart' as bip32;
7 import 'package:bip39/bip39.dart' as bip39;
8 import 'package:cw_core/cake_hive.dart';
9 import 'package:cw_core/crypto_currency.dart';
10 +import 'package:cw_core/encryption_file_utils.dart';
11 import 'package:cw_core/erc20_token.dart';
12 import 'package:cw_core/node.dart';
13 import 'package:cw_core/pathForWallet.dart';
@@ -27,7 +28,6 @@ import 'package:cw_evm/evm_chain_transaction_model.dart';
28 import 'package:cw_evm/evm_chain_transaction_priority.dart';
29 import 'package:cw_evm/evm_chain_wallet_addresses.dart';
30 import 'package:cw_evm/evm_ledger_credentials.dart';
30 -import 'package:cw_evm/file.dart';
31 import 'package:flutter/foundation.dart';
32 import 'package:hex/hex.dart';
33 import 'package:hive/hive.dart';
@@ -68,6 +68,7 @@ abstract class EVMChainWalletBase
68 String? privateKey,
69 required String password,
70 EVMChainERC20Balance? initialBalance,
71 + required this.encryptionFileUtils,
72 }) : syncStatus = const NotConnectedSyncStatus(),
73 _password = password,
74 _mnemonic = mnemonic,
@@ -83,7 +84,7 @@ abstract class EVMChainWalletBase
84 ),
85 super(walletInfo) {
86 this.walletInfo = walletInfo;
86 - transactionHistory = setUpTransactionHistory(walletInfo, password);
87 + transactionHistory = setUpTransactionHistory(walletInfo, password, encryptionFileUtils);
88
89 if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
90 CakeHive.registerAdapter(Erc20TokenAdapter());
@@ -95,6 +96,7 @@ abstract class EVMChainWalletBase
96 final String? _mnemonic;
97 final String? _hexPrivateKey;
98 final String _password;
99 + final EncryptionFileUtils encryptionFileUtils;
100
101 late final Box<Erc20Token> erc20TokensBox;
102
@@ -149,7 +151,11 @@ abstract class EVMChainWalletBase
151
152 Erc20Token createNewErc20TokenObject(Erc20Token token, String? iconPath);
153
152 - EVMChainTransactionHistory setUpTransactionHistory(WalletInfo walletInfo, String password);
154 + EVMChainTransactionHistory setUpTransactionHistory(
155 + WalletInfo walletInfo,
156 + String password,
157 + EncryptionFileUtils encryptionFileUtils,
158 + );
159
160 //! Common Methods across child classes
161
@@ -510,13 +516,13 @@ abstract class EVMChainWalletBase
516 @override
517 Future<void> save() async {
518 if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
513 - await saveKeysFile(_password);
514 - saveKeysFile(_password, true);
519 + await saveKeysFile(_password, encryptionFileUtils);
520 + saveKeysFile(_password, encryptionFileUtils, true);
521 }
522
523 await walletAddresses.updateAddressesInBox();
524 final path = await makePath();
519 - await write(path: path, password: _password, data: toJSON());
525 + await encryptionFileUtils.write(path: path, password: _password, data: toJSON());
526 await transactionHistory.save();
527 }
528
@@ -690,4 +696,7 @@ abstract class EVMChainWalletBase
696 bytesToHex(await _evmChainPrivateKey.signPersonalMessage(ascii.encode(message)));
697
698 Web3Client? getWeb3Client() => _client.getWeb3Client();
699 +
700 + @override
701 + String get password => _password;
702 }
cw_evm/lib/evm_chain_wallet_creation_credentials.dart
+2 -2
@@ -3,8 +3,8 @@ import 'package:cw_core/wallet_credentials.dart';
3 import 'package:cw_core/wallet_info.dart';
4
5 class EVMChainNewWalletCredentials extends WalletCredentials {
6 - EVMChainNewWalletCredentials({required String name, WalletInfo? walletInfo})
7 - : super(name: name, walletInfo: walletInfo);
6 + EVMChainNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
7 + : super(name: name, walletInfo: walletInfo, password: password);
8 }
9
10 class EVMChainRestoreWalletFromSeedCredentials extends WalletCredentials {
cw_evm/lib/evm_chain_wallet_service.dart
+2 -1
@@ -15,9 +15,10 @@ abstract class EVMChainWalletService<T extends EVMChainWallet> extends WalletSer
15 EVMChainRestoreWalletFromSeedCredentials,
16 EVMChainRestoreWalletFromPrivateKey,
17 EVMChainRestoreWalletFromHardware> {
18 - EVMChainWalletService(this.walletInfoSource);
18 + EVMChainWalletService(this.walletInfoSource, this.isDirect);
19
20 final Box<WalletInfo> walletInfoSource;
21 + final bool isDirect;
22
23 @override
24 WalletType getType();
cw_evm/lib/file.dart deleted
-39
@@ -1,39 +0,0 @@
1 -import 'dart:io';
2 -import 'package:cw_core/key.dart';
3 -import 'package:encrypt/encrypt.dart' as encrypt;
4 -
5 -Future<void> write(
6 - {required String path,
7 - required String password,
8 - required String data}) async {
9 - final keys = extractKeys(password);
10 - final key = encrypt.Key.fromBase64(keys.first);
11 - final iv = encrypt.IV.fromBase64(keys.last);
12 - final encrypted = await encode(key: key, iv: iv, data: data);
13 - final f = File(path);
14 - f.writeAsStringSync(encrypted);
15 -}
16 -
17 -Future<void> writeData(
18 - {required String path,
19 - required String password,
20 - required String data}) async {
21 - final keys = extractKeys(password);
22 - final key = encrypt.Key.fromBase64(keys.first);
23 - final iv = encrypt.IV.fromBase64(keys.last);
24 - final encrypted = await encode(key: key, iv: iv, data: data);
25 - final f = File(path);
26 - f.writeAsStringSync(encrypted);
27 -}
28 -
29 -Future<String> read({required String path, required String password}) async {
30 - final file = File(path);
31 -
32 - if (!file.existsSync()) {
33 - file.createSync();
34 - }
35 -
36 - final encrypted = file.readAsStringSync();
37 -
38 - return decode(password: password, data: encrypted);
39 -}
cw_evm/pubspec.yaml
+1
@@ -20,6 +20,7 @@ dependencies:
20 hive: ^2.2.3
21 collection: ^1.17.1
22 shared_preferences: ^2.0.15
23 + mobx: ^2.0.7+4
24 cw_core:
25 path: ../cw_core
26 ledger_flutter: ^1.0.1
cw_haven/lib/haven_wallet.dart
+7 -2
@@ -38,9 +38,10 @@ class HavenWallet = HavenWalletBase with _$HavenWallet;
38
39 abstract class HavenWalletBase
40 extends WalletBase<MoneroBalance, HavenTransactionHistory, HavenTransactionInfo> with Store {
41 - HavenWalletBase({required WalletInfo walletInfo})
41 + HavenWalletBase({required WalletInfo walletInfo, String? password})
42 : balance = ObservableMap.of(getHavenBalance(accountIndex: 0)),
43 _isTransactionUpdating = false,
44 + _password = password ?? '',
45 _hasSyncAfterStartup = false,
46 walletAddresses = HavenWalletAddresses(walletInfo),
47 syncStatus = NotConnectedSyncStatus(),
@@ -56,6 +57,7 @@ abstract class HavenWalletBase
57 }
58
59 static const int _autoSaveInterval = 30;
60 + final String _password;
61
62 @override
63 HavenWalletAddresses walletAddresses;
@@ -111,7 +113,7 @@ abstract class HavenWalletBase
113 _onAccountChangeReaction?.reaction.dispose();
114 _autoSaveTimer?.cancel();
115 }
114 -
116 +
117 @override
118 Future<void> connectToNode({required Node node}) async {
119 try {
@@ -414,4 +416,7 @@ abstract class HavenWalletBase
416 print(e.toString());
417 }
418 }
419 +
420 + @override
421 + String get password => _password;
422 }
cw_haven/pubspec.lock
+33
@@ -113,6 +113,15 @@ packages:
113 url: "https://pub.dev"
114 source: hosted
115 version: "8.4.3"
116 + cake_backup:
117 + dependency: transitive
118 + description:
119 + path: "."
120 + ref: main
121 + resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
122 + url: "https://github.com/cake-tech/cake_backup.git"
123 + source: git
124 + version: "1.0.0+1"
125 characters:
126 dependency: transitive
127 description:
@@ -169,6 +178,22 @@ packages:
178 url: "https://pub.dev"
179 source: hosted
180 version: "3.0.2"
181 + cryptography:
182 + dependency: transitive
183 + description:
184 + name: cryptography
185 + sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
186 + url: "https://pub.dev"
187 + source: hosted
188 + version: "2.5.0"
189 + cupertino_icons:
190 + dependency: transitive
191 + description:
192 + name: cupertino_icons
193 + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
194 + url: "https://pub.dev"
195 + source: hosted
196 + version: "1.0.6"
197 cw_core:
198 dependency: "direct main"
199 description:
@@ -639,6 +664,14 @@ packages:
664 url: "https://pub.dev"
665 source: hosted
666 version: "1.0.1"
667 + tuple:
668 + dependency: transitive
669 + description:
670 + name: tuple
671 + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
672 + url: "https://pub.dev"
673 + source: hosted
674 + version: "2.0.2"
675 typed_data:
676 dependency: transitive
677 description:
cw_monero/.metadata
+3
@@ -18,6 +18,9 @@ migration:
18 - platform: macos
19 create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
20 base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
21 + - platform: linux
22 + create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
23 + base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
24
25 # User provided section
26
cw_monero/example/linux/.gitignore new
+1
@@ -0,0 +1 @@
1 +flutter/ephemeral
cw_monero/example/linux/CMakeLists.txt new
+138
@@ -0,0 +1,138 @@
1 +# Project-level configuration.
2 +cmake_minimum_required(VERSION 3.10)
3 +project(runner LANGUAGES CXX)
4 +
5 +# The name of the executable created for the application. Change this to change
6 +# the on-disk name of your application.
7 +set(BINARY_NAME "cw_monero_example")
8 +# The unique GTK application identifier for this application. See:
9 +# https://wiki.gnome.org/HowDoI/ChooseApplicationID
10 +set(APPLICATION_ID "com.cakewallet.cw_monero")
11 +
12 +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
13 +# versions of CMake.
14 +cmake_policy(SET CMP0063 NEW)
15 +
16 +# Load bundled libraries from the lib/ directory relative to the binary.
17 +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
18 +
19 +# Root filesystem for cross-building.
20 +if(FLUTTER_TARGET_PLATFORM_SYSROOT)
21 + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
22 + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
23 + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
24 + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
25 + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
26 + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
27 +endif()
28 +
29 +# Define build configuration options.
30 +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
31 + set(CMAKE_BUILD_TYPE "Debug" CACHE
32 + STRING "Flutter build mode" FORCE)
33 + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
34 + "Debug" "Profile" "Release")
35 +endif()
36 +
37 +# Compilation settings that should be applied to most targets.
38 +#
39 +# Be cautious about adding new options here, as plugins use this function by
40 +# default. In most cases, you should add new options to specific targets instead
41 +# of modifying this function.
42 +function(APPLY_STANDARD_SETTINGS TARGET)
43 + target_compile_features(${TARGET} PUBLIC cxx_std_14)
44 + target_compile_options(${TARGET} PRIVATE -Wall -Werror)
45 + target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
46 + target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
47 +endfunction()
48 +
49 +# Flutter library and tool build rules.
50 +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
51 +add_subdirectory(${FLUTTER_MANAGED_DIR})
52 +
53 +# System-level dependencies.
54 +find_package(PkgConfig REQUIRED)
55 +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
56 +
57 +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
58 +
59 +# Define the application target. To change its name, change BINARY_NAME above,
60 +# not the value here, or `flutter run` will no longer work.
61 +#
62 +# Any new source files that you add to the application should be added here.
63 +add_executable(${BINARY_NAME}
64 + "main.cc"
65 + "my_application.cc"
66 + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
67 +)
68 +
69 +# Apply the standard set of build settings. This can be removed for applications
70 +# that need different build settings.
71 +apply_standard_settings(${BINARY_NAME})
72 +
73 +# Add dependency libraries. Add any application-specific dependencies here.
74 +target_link_libraries(${BINARY_NAME} PRIVATE flutter)
75 +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
76 +
77 +# Run the Flutter tool portions of the build. This must not be removed.
78 +add_dependencies(${BINARY_NAME} flutter_assemble)
79 +
80 +# Only the install-generated bundle's copy of the executable will launch
81 +# correctly, since the resources must in the right relative locations. To avoid
82 +# people trying to run the unbundled copy, put it in a subdirectory instead of
83 +# the default top-level location.
84 +set_target_properties(${BINARY_NAME}
85 + PROPERTIES
86 + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
87 +)
88 +
89 +# Generated plugin build rules, which manage building the plugins and adding
90 +# them to the application.
91 +include(flutter/generated_plugins.cmake)
92 +
93 +
94 +# === Installation ===
95 +# By default, "installing" just makes a relocatable bundle in the build
96 +# directory.
97 +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
98 +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
99 + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
100 +endif()
101 +
102 +# Start with a clean build bundle directory every time.
103 +install(CODE "
104 + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
105 + " COMPONENT Runtime)
106 +
107 +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
108 +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
109 +
110 +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
111 + COMPONENT Runtime)
112 +
113 +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
114 + COMPONENT Runtime)
115 +
116 +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
117 + COMPONENT Runtime)
118 +
119 +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
120 + install(FILES "${bundled_library}"
121 + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
122 + COMPONENT Runtime)
123 +endforeach(bundled_library)
124 +
125 +# Fully re-copy the assets directory on each build to avoid having stale files
126 +# from a previous install.
127 +set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
128 +install(CODE "
129 + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
130 + " COMPONENT Runtime)
131 +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
132 + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
133 +
134 +# Install the AOT library on non-Debug builds only.
135 +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
136 + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
137 + COMPONENT Runtime)
138 +endif()
cw_monero/example/linux/flutter/CMakeLists.txt new
+88
@@ -0,0 +1,88 @@
1 +# This file controls Flutter-level build steps. It should not be edited.
2 +cmake_minimum_required(VERSION 3.10)
3 +
4 +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5 +
6 +# Configuration provided via flutter tool.
7 +include(${EPHEMERAL_DIR}/generated_config.cmake)
8 +
9 +# TODO: Move the rest of this into files in ephemeral. See
10 +# https://github.com/flutter/flutter/issues/57146.
11 +
12 +# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
13 +# which isn't available in 3.10.
14 +function(list_prepend LIST_NAME PREFIX)
15 + set(NEW_LIST "")
16 + foreach(element ${${LIST_NAME}})
17 + list(APPEND NEW_LIST "${PREFIX}${element}")
18 + endforeach(element)
19 + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
20 +endfunction()
21 +
22 +# === Flutter Library ===
23 +# System-level dependencies.
24 +find_package(PkgConfig REQUIRED)
25 +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
26 +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
27 +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
28 +
29 +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
30 +
31 +# Published to parent scope for install step.
32 +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
33 +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
34 +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
35 +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
36 +
37 +list(APPEND FLUTTER_LIBRARY_HEADERS
38 + "fl_basic_message_channel.h"
39 + "fl_binary_codec.h"
40 + "fl_binary_messenger.h"
41 + "fl_dart_project.h"
42 + "fl_engine.h"
43 + "fl_json_message_codec.h"
44 + "fl_json_method_codec.h"
45 + "fl_message_codec.h"
46 + "fl_method_call.h"
47 + "fl_method_channel.h"
48 + "fl_method_codec.h"
49 + "fl_method_response.h"
50 + "fl_plugin_registrar.h"
51 + "fl_plugin_registry.h"
52 + "fl_standard_message_codec.h"
53 + "fl_standard_method_codec.h"
54 + "fl_string_codec.h"
55 + "fl_value.h"
56 + "fl_view.h"
57 + "flutter_linux.h"
58 +)
59 +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
60 +add_library(flutter INTERFACE)
61 +target_include_directories(flutter INTERFACE
62 + "${EPHEMERAL_DIR}"
63 +)
64 +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
65 +target_link_libraries(flutter INTERFACE
66 + PkgConfig::GTK
67 + PkgConfig::GLIB
68 + PkgConfig::GIO
69 +)
70 +add_dependencies(flutter flutter_assemble)
71 +
72 +# === Flutter tool backend ===
73 +# _phony_ is a non-existent file to force this command to run every time,
74 +# since currently there's no way to get a full input/output list from the
75 +# flutter tool.
76 +add_custom_command(
77 + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
78 + ${CMAKE_CURRENT_BINARY_DIR}/_phony_
79 + COMMAND ${CMAKE_COMMAND} -E env
80 + ${FLUTTER_TOOL_ENVIRONMENT}
81 + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
82 + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
83 + VERBATIM
84 +)
85 +add_custom_target(flutter_assemble DEPENDS
86 + "${FLUTTER_LIBRARY}"
87 + ${FLUTTER_LIBRARY_HEADERS}
88 +)
cw_monero/example/linux/flutter/generated_plugin_registrant.cc new
+15
@@ -0,0 +1,15 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +// clang-format off
6 +
7 +#include "generated_plugin_registrant.h"
8 +
9 +#include <cw_monero/cw_monero_plugin.h>
10 +
11 +void fl_register_plugins(FlPluginRegistry* registry) {
12 + g_autoptr(FlPluginRegistrar) cw_monero_registrar =
13 + fl_plugin_registry_get_registrar_for_plugin(registry, "CwMoneroPlugin");
14 + cw_monero_plugin_register_with_registrar(cw_monero_registrar);
15 +}
cw_monero/example/linux/flutter/generated_plugin_registrant.h new
+15
@@ -0,0 +1,15 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +// clang-format off
6 +
7 +#ifndef GENERATED_PLUGIN_REGISTRANT_
8 +#define GENERATED_PLUGIN_REGISTRANT_
9 +
10 +#include <flutter_linux/flutter_linux.h>
11 +
12 +// Registers Flutter plugins.
13 +void fl_register_plugins(FlPluginRegistry* registry);
14 +
15 +#endif // GENERATED_PLUGIN_REGISTRANT_
cw_monero/example/linux/flutter/generated_plugins.cmake new
+24
@@ -0,0 +1,24 @@
1 +#
2 +# Generated file, do not edit.
3 +#
4 +
5 +list(APPEND FLUTTER_PLUGIN_LIST
6 + cw_monero
7 +)
8 +
9 +list(APPEND FLUTTER_FFI_PLUGIN_LIST
10 +)
11 +
12 +set(PLUGIN_BUNDLED_LIBRARIES)
13 +
14 +foreach(plugin ${FLUTTER_PLUGIN_LIST})
15 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
16 + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
17 + list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
18 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
19 +endforeach(plugin)
20 +
21 +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
22 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
23 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
24 +endforeach(ffi_plugin)
cw_monero/example/linux/main.cc new
+6
@@ -0,0 +1,6 @@
1 +#include "my_application.h"
2 +
3 +int main(int argc, char** argv) {
4 + g_autoptr(MyApplication) app = my_application_new();
5 + return g_application_run(G_APPLICATION(app), argc, argv);
6 +}
cw_monero/example/linux/my_application.cc new
+104
@@ -0,0 +1,104 @@
1 +#include "my_application.h"
2 +
3 +#include <flutter_linux/flutter_linux.h>
4 +#ifdef GDK_WINDOWING_X11
5 +#include <gdk/gdkx.h>
6 +#endif
7 +
8 +#include "flutter/generated_plugin_registrant.h"
9 +
10 +struct _MyApplication {
11 + GtkApplication parent_instance;
12 + char** dart_entrypoint_arguments;
13 +};
14 +
15 +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
16 +
17 +// Implements GApplication::activate.
18 +static void my_application_activate(GApplication* application) {
19 + MyApplication* self = MY_APPLICATION(application);
20 + GtkWindow* window =
21 + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
22 +
23 + // Use a header bar when running in GNOME as this is the common style used
24 + // by applications and is the setup most users will be using (e.g. Ubuntu
25 + // desktop).
26 + // If running on X and not using GNOME then just use a traditional title bar
27 + // in case the window manager does more exotic layout, e.g. tiling.
28 + // If running on Wayland assume the header bar will work (may need changing
29 + // if future cases occur).
30 + gboolean use_header_bar = TRUE;
31 +#ifdef GDK_WINDOWING_X11
32 + GdkScreen* screen = gtk_window_get_screen(window);
33 + if (GDK_IS_X11_SCREEN(screen)) {
34 + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
35 + if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
36 + use_header_bar = FALSE;
37 + }
38 + }
39 +#endif
40 + if (use_header_bar) {
41 + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
42 + gtk_widget_show(GTK_WIDGET(header_bar));
43 + gtk_header_bar_set_title(header_bar, "cw_monero_example");
44 + gtk_header_bar_set_show_close_button(header_bar, TRUE);
45 + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
46 + } else {
47 + gtk_window_set_title(window, "cw_monero_example");
48 + }
49 +
50 + gtk_window_set_default_size(window, 1280, 720);
51 + gtk_widget_show(GTK_WIDGET(window));
52 +
53 + g_autoptr(FlDartProject) project = fl_dart_project_new();
54 + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
55 +
56 + FlView* view = fl_view_new(project);
57 + gtk_widget_show(GTK_WIDGET(view));
58 + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
59 +
60 + fl_register_plugins(FL_PLUGIN_REGISTRY(view));
61 +
62 + gtk_widget_grab_focus(GTK_WIDGET(view));
63 +}
64 +
65 +// Implements GApplication::local_command_line.
66 +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
67 + MyApplication* self = MY_APPLICATION(application);
68 + // Strip out the first argument as it is the binary name.
69 + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
70 +
71 + g_autoptr(GError) error = nullptr;
72 + if (!g_application_register(application, nullptr, &error)) {
73 + g_warning("Failed to register: %s", error->message);
74 + *exit_status = 1;
75 + return TRUE;
76 + }
77 +
78 + g_application_activate(application);
79 + *exit_status = 0;
80 +
81 + return TRUE;
82 +}
83 +
84 +// Implements GObject::dispose.
85 +static void my_application_dispose(GObject* object) {
86 + MyApplication* self = MY_APPLICATION(object);
87 + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
88 + G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
89 +}
90 +
91 +static void my_application_class_init(MyApplicationClass* klass) {
92 + G_APPLICATION_CLASS(klass)->activate = my_application_activate;
93 + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
94 + G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
95 +}
96 +
97 +static void my_application_init(MyApplication* self) {}
98 +
99 +MyApplication* my_application_new() {
100 + return MY_APPLICATION(g_object_new(my_application_get_type(),
101 + "application-id", APPLICATION_ID,
102 + "flags", G_APPLICATION_NON_UNIQUE,
103 + nullptr));
104 +}
cw_monero/example/linux/my_application.h new
+18
@@ -0,0 +1,18 @@
1 +#ifndef FLUTTER_MY_APPLICATION_H_
2 +#define FLUTTER_MY_APPLICATION_H_
3 +
4 +#include <gtk/gtk.h>
5 +
6 +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 + GtkApplication)
8 +
9 +/**
10 + * my_application_new:
11 + *
12 + * Creates a new Flutter-based application.
13 + *
14 + * Returns: a new #MyApplication.
15 + */
16 +MyApplication* my_application_new();
17 +
18 +#endif // FLUTTER_MY_APPLICATION_H_
cw_monero/lib/api/account_list.dart
-1
@@ -34,7 +34,6 @@ List<monero.SubaddressAccountRow> getAllAccount() {
34 // final size = monero.Wallet_numSubaddressAccounts(wptr!);
35 refreshAccounts();
36 int size = monero.SubaddressAccount_getAll_size(subaddressAccount!);
37 - print("size: $size");
37 if (size == 0) {
38 monero.Wallet_addSubaddressAccount(wptr!);
39 return getAllAccount();
cw_monero/lib/api/wallet_manager.dart
+2
@@ -7,6 +7,8 @@ import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart';
7 import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
8 import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart';
9 import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart';
10 +import 'package:cw_monero/api/wallet.dart';
11 +import 'package:flutter/foundation.dart';
12 import 'package:cw_monero/api/transaction_history.dart';
13 import 'package:cw_monero/api/wallet.dart';
14 import 'package:flutter/foundation.dart';
cw_monero/lib/monero_wallet.dart
+9 -1
@@ -3,6 +3,8 @@ import 'dart:ffi';
3 import 'dart:io';
4 import 'dart:isolate';
5
6 +import 'package:cw_core/pathForWallet.dart';
7 +import 'package:cw_core/transaction_priority.dart';
8 import 'package:cw_core/account.dart';
9 import 'package:cw_core/crypto_currency.dart';
10 import 'package:cw_core/monero_amount_format.dart';
@@ -50,7 +52,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
52 MoneroTransactionHistory, MoneroTransactionInfo> with Store {
53 MoneroWalletBase(
54 {required WalletInfo walletInfo,
53 - required Box<UnspentCoinsInfo> unspentCoinsInfo})
55 + required Box<UnspentCoinsInfo> unspentCoinsInfo,
56 + required String password})
57 : balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
58 CryptoCurrency.xmr: MoneroBalance(
59 fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
@@ -59,6 +62,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
62 _isTransactionUpdating = false,
63 _hasSyncAfterStartup = false,
64 isEnabledAutoGenerateSubaddress = false,
65 + _password = password,
66 syncStatus = NotConnectedSyncStatus(),
67 unspentCoins = [],
68 this.unspentCoinsInfo = unspentCoinsInfo,
@@ -111,6 +115,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
115 String get seed => monero_wallet.getSeed();
116 String seedLegacy(String? language) => monero_wallet.getSeedLegacy(language);
117
118 + @override
119 + String get password => _password;
120 +
121 @override
122 MoneroWalletKeys get keys => MoneroWalletKeys(
123 privateSpendKey: monero_wallet.getSecretSpendKey(),
@@ -127,6 +134,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
134 bool _hasSyncAfterStartup;
135 Timer? _autoSaveTimer;
136 List<MoneroUnspent> unspentCoins;
137 + String _password;
138
139 Future<void> init() async {
140 await walletAddresses.init();
cw_monero/lib/monero_wallet_service.dart
+43 -14
@@ -93,7 +93,9 @@ class MoneroWalletService extends WalletService<
93 await monero_wallet_manager.createWallet(
94 path: path, password: credentials.password!, language: credentials.language);
95 final wallet = MoneroWallet(
96 - walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
96 + walletInfo: credentials.walletInfo!,
97 + unspentCoinsInfo: unspentCoinsInfoSource,
98 + password: credentials.password!);
99 await wallet.init();
100
101 return wallet;
@@ -126,10 +128,14 @@ class MoneroWalletService extends WalletService<
128 await repairOldAndroidWallet(name);
129 }
130
129 - await monero_wallet_manager.openWalletAsync({'path': path, 'password': password});
130 - final walletInfo = walletInfoSource.values
131 - .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
132 - wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
131 + await monero_wallet_manager
132 + .openWalletAsync({'path': path, 'password': password});
133 + final walletInfo = walletInfoSource.values.firstWhere(
134 + (info) => info.id == WalletBase.idFor(name, getType()));
135 + final wallet = MoneroWallet(
136 + walletInfo: walletInfo,
137 + unspentCoinsInfo: unspentCoinsInfoSource,
138 + password: password);
139 final isValid = wallet.walletAddresses.validate();
140
141 if (!isValid) {
@@ -162,15 +168,22 @@ class MoneroWalletService extends WalletService<
168 final bool invalidSignature = e.toString().contains('invalid signature') ||
169 (e is WalletOpeningException && e.message.contains('invalid signature'));
170
171 + final bool invalidPassword = e.toString().contains('invalid password') ||
172 + (e is WalletOpeningException && e.message.contains('invalid password'));
173 +
174 if (!isBadAlloc &&
175 !doesNotCorrespond &&
176 !isMissingCacheFilesIOS &&
177 !isMissingCacheFilesAndroid &&
178 !invalidSignature &&
179 + !invalidPassword &&
180 wallet != null &&
181 wallet.onError != null) {
182 wallet.onError!(FlutterErrorDetails(exception: e, stack: s));
183 }
184 + if (invalidPassword) {
185 + rethrow;
186 + }
187
188 await restoreOrResetWalletFiles(name);
189 return openWallet(name, password);
@@ -206,11 +219,15 @@ class MoneroWalletService extends WalletService<
219 }
220
221 @override
209 - Future<void> rename(String currentName, String password, String newName) async {
210 - final currentWalletInfo = walletInfoSource.values
211 - .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
212 - final currentWallet =
213 - MoneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
222 + Future<void> rename(
223 + String currentName, String password, String newName) async {
224 + final currentWalletInfo = walletInfoSource.values.firstWhere(
225 + (info) => info.id == WalletBase.idFor(currentName, getType()));
226 + final currentWallet = MoneroWallet(
227 + walletInfo: currentWalletInfo,
228 + unspentCoinsInfo: unspentCoinsInfoSource,
229 + password: password,
230 + );
231
232 await currentWallet.renameWalletFiles(newName);
233
@@ -235,7 +252,9 @@ class MoneroWalletService extends WalletService<
252 viewKey: credentials.viewKey,
253 spendKey: credentials.spendKey);
254 final wallet = MoneroWallet(
238 - walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
255 + walletInfo: credentials.walletInfo!,
256 + unspentCoinsInfo: unspentCoinsInfoSource,
257 + password: credentials.password!);
258 await wallet.init();
259
260 return wallet;
@@ -268,7 +287,9 @@ class MoneroWalletService extends WalletService<
287 seed: credentials.mnemonic,
288 restoreHeight: credentials.height!);
289 final wallet = MoneroWallet(
271 - walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
290 + walletInfo: credentials.walletInfo!,
291 + unspentCoinsInfo: unspentCoinsInfoSource,
292 + password: credentials.password!);
293 await wallet.init();
294
295 return wallet;
@@ -315,7 +336,11 @@ class MoneroWalletService extends WalletService<
336 restoreHeight: height,
337 spendKey: spendKey);
338
318 - final wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
339 + final wallet = MoneroWallet(
340 + walletInfo: walletInfo,
341 + unspentCoinsInfo: unspentCoinsInfoSource,
342 + password: password,
343 + );
344 await wallet.init();
345
346 return wallet;
@@ -364,7 +389,11 @@ class MoneroWalletService extends WalletService<
389 await monero_wallet_manager.openWalletAsync({'path': path, 'password': password});
390 final walletInfo = walletInfoSource.values
391 .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
367 - final wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
392 + final wallet = MoneroWallet(
393 + walletInfo: walletInfo,
394 + unspentCoinsInfo: unspentCoinsInfoSource,
395 + password: password,
396 + );
397 return wallet.seed;
398 } catch (_) {
399 // if the file couldn't be opened or read
cw_monero/linux/CMakeLists.txt new
+270
@@ -0,0 +1,270 @@
1 +# The Flutter tooling requires that developers have CMake 3.10 or later
2 +# installed. You should not increase this version, as doing so will cause
3 +# the plugin to fail to compile for some customers of the plugin.
4 +cmake_minimum_required(VERSION 3.10)
5 +
6 +# Project-level configuration.
7 +set(PROJECT_NAME "cw_monero")
8 +project(${PROJECT_NAME} LANGUAGES CXX)
9 +
10 +# This value is used when generating builds using this plugin, so it must
11 +# not be changed.
12 +set(PLUGIN_NAME "cw_monero_plugin")
13 +
14 +# Define the plugin library target. Its name must not be changed (see comment
15 +# on PLUGIN_NAME above).
16 +#
17 +# Any new source files that you add to the plugin should be added here.
18 +add_library(${PLUGIN_NAME} SHARED
19 + "cw_monero_plugin.cc"
20 + "../ios/Classes/monero_api.cpp"
21 +)
22 +
23 +# Apply a standard set of build settings that are configured in the
24 +# application-level CMakeLists.txt. This can be removed for plugins that want
25 +# full control over build settings.
26 +apply_standard_settings(${PLUGIN_NAME})
27 +
28 +# Symbols are hidden by default to reduce the chance of accidental conflicts
29 +# between plugins. This should not be removed; any symbols that should be
30 +# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro.
31 +set_target_properties(${PLUGIN_NAME} PROPERTIES
32 + CXX_VISIBILITY_PRESET hidden)
33 +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
34 +
35 +# Source include directories and library dependencies. Add any plugin-specific
36 +# dependencies here.
37 +target_include_directories(${PLUGIN_NAME} INTERFACE
38 + "${CMAKE_CURRENT_SOURCE_DIR}/include")
39 +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
40 +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK)
41 +target_link_libraries(${PLUGIN_NAME} PUBLIC cw_monero)
42 +# List of absolute paths to libraries that should be bundled with the plugin.
43 +# This list could contain prebuilt libraries, or libraries created by an
44 +# external build triggered from this build file.
45 +set(cw_monero_bundled_libraries
46 + ""
47 + PARENT_SCOPE
48 +)
49 +
50 +add_library( cw_monero
51 + STATIC
52 + ../ios/Classes/monero_api.cpp)
53 +
54 +set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../cw_shared_external/ios/External/linux)
55 +
56 +############
57 +# libsodium
58 +############
59 +
60 +add_library(sodium STATIC IMPORTED)
61 +set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
62 + ${EXTERNAL_LIBS_DIR}/lib/libsodium.a)
63 +
64 +############
65 +# OpenSSL
66 +############
67 +
68 +add_library(crypto STATIC IMPORTED)
69 +set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
70 + ${EXTERNAL_LIBS_DIR}/lib/libcrypto.a)
71 +
72 +add_library(ssl STATIC IMPORTED)
73 +set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
74 + ${EXTERNAL_LIBS_DIR}/lib/libssl.a)
75 +
76 +############
77 +# Boost
78 +############
79 +
80 +add_library(boost_chrono STATIC IMPORTED)
81 +set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
82 + ${EXTERNAL_LIBS_DIR}/lib/libboost_chrono.a)
83 +
84 +add_library(boost_date_time STATIC IMPORTED)
85 +set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
86 + ${EXTERNAL_LIBS_DIR}/lib/libboost_date_time.a)
87 +
88 +add_library(boost_filesystem STATIC IMPORTED)
89 +set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
90 + ${EXTERNAL_LIBS_DIR}/lib/libboost_filesystem.a)
91 +
92 +add_library(boost_program_options STATIC IMPORTED)
93 +set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
94 + ${EXTERNAL_LIBS_DIR}/lib/libboost_program_options.a)
95 +
96 +add_library(boost_regex STATIC IMPORTED)
97 +set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
98 + ${EXTERNAL_LIBS_DIR}/lib/libboost_regex.a)
99 +
100 +add_library(boost_serialization STATIC IMPORTED)
101 +set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
102 + ${EXTERNAL_LIBS_DIR}/lib/libboost_serialization.a)
103 +
104 +add_library(boost_system STATIC IMPORTED)
105 +set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
106 + ${EXTERNAL_LIBS_DIR}/lib/libboost_system.a)
107 +
108 +add_library(boost_thread STATIC IMPORTED)
109 +set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
110 + ${EXTERNAL_LIBS_DIR}/lib/libboost_thread.a)
111 +
112 +add_library(boost_wserialization STATIC IMPORTED)
113 +set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
114 + ${EXTERNAL_LIBS_DIR}/lib/libboost_wserialization.a)
115 +
116 +#############
117 +# Monero
118 +#############
119 +
120 +
121 +add_library(wallet STATIC IMPORTED)
122 +set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
123 + ${EXTERNAL_LIBS_DIR}/lib/monero/libwallet.a)
124 +
125 +add_library(wallet_api STATIC IMPORTED)
126 +set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
127 + ${EXTERNAL_LIBS_DIR}/lib/monero/libwallet_api.a)
128 +
129 +add_library(cryptonote_core STATIC IMPORTED)
130 +set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
131 + ${EXTERNAL_LIBS_DIR}/lib/monero/libcryptonote_core.a)
132 +
133 +add_library(cryptonote_basic STATIC IMPORTED)
134 +set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
135 + ${EXTERNAL_LIBS_DIR}/lib/monero/libcryptonote_basic.a)
136 +
137 +add_library(cryptonote_format_utils_basic STATIC IMPORTED)
138 +set_target_properties(cryptonote_format_utils_basic PROPERTIES IMPORTED_LOCATION
139 + ${EXTERNAL_LIBS_DIR}/lib/monero/libcryptonote_format_utils_basic.a)
140 +
141 +add_library(mnemonics STATIC IMPORTED)
142 +set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
143 + ${EXTERNAL_LIBS_DIR}/lib/monero/libmnemonics.a)
144 +
145 +add_library(common STATIC IMPORTED)
146 +set_target_properties(common PROPERTIES IMPORTED_LOCATION
147 + ${EXTERNAL_LIBS_DIR}/lib/monero/libcommon.a)
148 +
149 +add_library(cncrypto STATIC IMPORTED)
150 +set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
151 + ${EXTERNAL_LIBS_DIR}/lib/monero/libcncrypto.a)
152 +
153 +add_library(ringct STATIC IMPORTED)
154 +set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
155 + ${EXTERNAL_LIBS_DIR}/lib/monero/libringct.a)
156 +
157 +add_library(ringct_basic STATIC IMPORTED)
158 +set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
159 + ${EXTERNAL_LIBS_DIR}/lib/monero/libringct_basic.a)
160 +
161 +add_library(blockchain_db STATIC IMPORTED)
162 +set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
163 + ${EXTERNAL_LIBS_DIR}/lib/monero/libblockchain_db.a)
164 +
165 +add_library(lmdb STATIC IMPORTED)
166 +set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
167 + ${EXTERNAL_LIBS_DIR}/lib/monero/liblmdb.a)
168 +
169 +add_library(easylogging STATIC IMPORTED)
170 +set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
171 + ${EXTERNAL_LIBS_DIR}/lib/monero/libeasylogging.a)
172 +
173 +add_library(epee STATIC IMPORTED)
174 +set_target_properties(epee PROPERTIES IMPORTED_LOCATION
175 + ${EXTERNAL_LIBS_DIR}/lib/monero/libepee.a)
176 +
177 +add_library(blocks STATIC IMPORTED)
178 +set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
179 + ${EXTERNAL_LIBS_DIR}/lib/monero/libblocks.a)
180 +
181 +add_library(checkpoints STATIC IMPORTED)
182 +set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
183 + ${EXTERNAL_LIBS_DIR}/lib/monero/libcheckpoints.a)
184 +
185 +add_library(device STATIC IMPORTED)
186 +set_target_properties(device PROPERTIES IMPORTED_LOCATION
187 + ${EXTERNAL_LIBS_DIR}/lib/monero/libdevice.a)
188 +
189 +add_library(device_trezor STATIC IMPORTED)
190 +set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
191 + ${EXTERNAL_LIBS_DIR}/lib/monero/libdevice_trezor.a)
192 +
193 +add_library(multisig STATIC IMPORTED)
194 +set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
195 + ${EXTERNAL_LIBS_DIR}/lib/monero/libmultisig.a)
196 +
197 +add_library(version STATIC IMPORTED)
198 +set_target_properties(version PROPERTIES IMPORTED_LOCATION
199 + ${EXTERNAL_LIBS_DIR}/lib/monero/libversion.a)
200 +
201 +add_library(net STATIC IMPORTED)
202 +set_target_properties(net PROPERTIES IMPORTED_LOCATION
203 + ${EXTERNAL_LIBS_DIR}/lib/monero/libnet.a)
204 +
205 +add_library(hardforks STATIC IMPORTED)
206 +set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
207 + ${EXTERNAL_LIBS_DIR}/lib/monero/libhardforks.a)
208 +
209 +add_library(randomx STATIC IMPORTED)
210 +set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
211 + ${EXTERNAL_LIBS_DIR}/lib/monero/librandomx.a)
212 +
213 +add_library(rpc_base STATIC IMPORTED)
214 +set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
215 + ${EXTERNAL_LIBS_DIR}/lib/monero/librpc_base.a)
216 +
217 +add_library(wallet-crypto STATIC IMPORTED)
218 +set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
219 + ${EXTERNAL_LIBS_DIR}/lib/monero/libwallet-crypto.a)
220 +
221 +add_library(unbound STATIC IMPORTED)
222 +set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
223 + ${EXTERNAL_LIBS_DIR}/lib/libunbound.a)
224 +
225 +include_directories( ${EXTERNAL_LIBS_DIR}/include )
226 +
227 +target_link_libraries( cw_monero
228 +
229 + wallet_api
230 + wallet
231 + cryptonote_core
232 + cryptonote_basic
233 + cryptonote_format_utils_basic
234 + mnemonics
235 + ringct
236 + ringct_basic
237 + net
238 + common
239 + cncrypto
240 + blockchain_db
241 + lmdb
242 + easylogging
243 + unbound
244 + epee
245 + blocks
246 + checkpoints
247 + device
248 + device_trezor
249 + multisig
250 + version
251 + randomx
252 + hardforks
253 + rpc_base
254 + wallet-crypto
255 +
256 + boost_chrono
257 + boost_date_time
258 + boost_filesystem
259 + boost_program_options
260 + boost_regex
261 + boost_serialization
262 + boost_system
263 + boost_thread
264 + boost_wserialization
265 +
266 + ssl
267 + crypto
268 +
269 + sodium
270 + )
cw_monero/linux/cw_monero_plugin.cc new
+70
@@ -0,0 +1,70 @@
1 +#include "include/cw_monero/cw_monero_plugin.h"
2 +
3 +#include <flutter_linux/flutter_linux.h>
4 +#include <gtk/gtk.h>
5 +#include <sys/utsname.h>
6 +
7 +#include <cstring>
8 +
9 +#define CW_MONERO_PLUGIN(obj) \
10 + (G_TYPE_CHECK_INSTANCE_CAST((obj), cw_monero_plugin_get_type(), \
11 + CwMoneroPlugin))
12 +
13 +struct _CwMoneroPlugin {
14 + GObject parent_instance;
15 +};
16 +
17 +G_DEFINE_TYPE(CwMoneroPlugin, cw_monero_plugin, g_object_get_type())
18 +
19 +// Called when a method call is received from Flutter.
20 +static void cw_monero_plugin_handle_method_call(
21 + CwMoneroPlugin* self,
22 + FlMethodCall* method_call) {
23 + g_autoptr(FlMethodResponse) response = nullptr;
24 +
25 + const gchar* method = fl_method_call_get_name(method_call);
26 +
27 + if (strcmp(method, "getPlatformVersion") == 0) {
28 + struct utsname uname_data = {};
29 + uname(&uname_data);
30 + g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version);
31 + g_autoptr(FlValue) result = fl_value_new_string(version);
32 + response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
33 + } else {
34 + response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
35 + }
36 +
37 + fl_method_call_respond(method_call, response, nullptr);
38 +}
39 +
40 +static void cw_monero_plugin_dispose(GObject* object) {
41 + G_OBJECT_CLASS(cw_monero_plugin_parent_class)->dispose(object);
42 +}
43 +
44 +static void cw_monero_plugin_class_init(CwMoneroPluginClass* klass) {
45 + G_OBJECT_CLASS(klass)->dispose = cw_monero_plugin_dispose;
46 +}
47 +
48 +static void cw_monero_plugin_init(CwMoneroPlugin* self) {}
49 +
50 +static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call,
51 + gpointer user_data) {
52 + CwMoneroPlugin* plugin = CW_MONERO_PLUGIN(user_data);
53 + cw_monero_plugin_handle_method_call(plugin, method_call);
54 +}
55 +
56 +void cw_monero_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
57 + CwMoneroPlugin* plugin = CW_MONERO_PLUGIN(
58 + g_object_new(cw_monero_plugin_get_type(), nullptr));
59 +
60 + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
61 + g_autoptr(FlMethodChannel) channel =
62 + fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),
63 + "cw_monero",
64 + FL_METHOD_CODEC(codec));
65 + fl_method_channel_set_method_call_handler(channel, method_call_cb,
66 + g_object_ref(plugin),
67 + g_object_unref);
68 +
69 + g_object_unref(plugin);
70 +}
cw_monero/linux/flutter/generated_plugin_registrant.cc new
+11
@@ -0,0 +1,11 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +// clang-format off
6 +
7 +#include "generated_plugin_registrant.h"
8 +
9 +
10 +void fl_register_plugins(FlPluginRegistry* registry) {
11 +}
cw_monero/linux/flutter/generated_plugin_registrant.h new
+15
@@ -0,0 +1,15 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +// clang-format off
6 +
7 +#ifndef GENERATED_PLUGIN_REGISTRANT_
8 +#define GENERATED_PLUGIN_REGISTRANT_
9 +
10 +#include <flutter_linux/flutter_linux.h>
11 +
12 +// Registers Flutter plugins.
13 +void fl_register_plugins(FlPluginRegistry* registry);
14 +
15 +#endif // GENERATED_PLUGIN_REGISTRANT_
cw_monero/linux/flutter/generated_plugins.cmake new
+23
@@ -0,0 +1,23 @@
1 +#
2 +# Generated file, do not edit.
3 +#
4 +
5 +list(APPEND FLUTTER_PLUGIN_LIST
6 +)
7 +
8 +list(APPEND FLUTTER_FFI_PLUGIN_LIST
9 +)
10 +
11 +set(PLUGIN_BUNDLED_LIBRARIES)
12 +
13 +foreach(plugin ${FLUTTER_PLUGIN_LIST})
14 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
15 + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
16 + list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
17 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
18 +endforeach(plugin)
19 +
20 +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
21 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
22 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
23 +endforeach(ffi_plugin)
cw_monero/linux/include/cw_monero/cw_monero_plugin.h new
+26
@@ -0,0 +1,26 @@
1 +#ifndef FLUTTER_PLUGIN_CW_MONERO_PLUGIN_H_
2 +#define FLUTTER_PLUGIN_CW_MONERO_PLUGIN_H_
3 +
4 +#include <flutter_linux/flutter_linux.h>
5 +
6 +G_BEGIN_DECLS
7 +
8 +#ifdef FLUTTER_PLUGIN_IMPL
9 +#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default")))
10 +#else
11 +#define FLUTTER_PLUGIN_EXPORT
12 +#endif
13 +
14 +typedef struct _CwMoneroPlugin CwMoneroPlugin;
15 +typedef struct {
16 + GObjectClass parent_class;
17 +} CwMoneroPluginClass;
18 +
19 +FLUTTER_PLUGIN_EXPORT GType cw_monero_plugin_get_type();
20 +
21 +FLUTTER_PLUGIN_EXPORT void cw_monero_plugin_register_with_registrar(
22 + FlPluginRegistrar* registrar);
23 +
24 +G_END_DECLS
25 +
26 +#endif // FLUTTER_PLUGIN_CW_MONERO_PLUGIN_H_
cw_monero/pubspec.lock
+35 -2
@@ -113,6 +113,15 @@ packages:
113 url: "https://pub.dev"
114 source: hosted
115 version: "8.9.2"
116 + cake_backup:
117 + dependency: transitive
118 + description:
119 + path: "."
120 + ref: main
121 + resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
122 + url: "https://github.com/cake-tech/cake_backup.git"
123 + source: git
124 + version: "1.0.0+1"
125 characters:
126 dependency: transitive
127 description:
@@ -169,6 +178,22 @@ packages:
178 url: "https://pub.dev"
179 source: hosted
180 version: "3.0.3"
181 + cryptography:
182 + dependency: transitive
183 + description:
184 + name: cryptography
185 + sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
186 + url: "https://pub.dev"
187 + source: hosted
188 + version: "2.7.0"
189 + cupertino_icons:
190 + dependency: transitive
191 + description:
192 + name: cupertino_icons
193 + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
194 + url: "https://pub.dev"
195 + source: hosted
196 + version: "1.0.8"
197 cw_core:
198 dependency: "direct main"
199 description:
@@ -342,10 +367,10 @@ packages:
367 dependency: transitive
368 description:
369 name: js
345 - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
370 + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
371 url: "https://pub.dev"
372 source: hosted
348 - version: "0.7.1"
373 + version: "0.6.7"
374 json_annotation:
375 dependency: transitive
376 description:
@@ -696,6 +721,14 @@ packages:
721 url: "https://pub.dev"
722 source: hosted
723 version: "1.0.1"
724 + tuple:
725 + dependency: transitive
726 + description:
727 + name: tuple
728 + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
729 + url: "https://pub.dev"
730 + source: hosted
731 + version: "2.0.2"
732 typed_data:
733 dependency: transitive
734 description:
cw_nano/lib/file.dart deleted
-39
@@ -1,39 +0,0 @@
1 -import 'dart:io';
2 -import 'package:cw_core/key.dart';
3 -import 'package:encrypt/encrypt.dart' as encrypt;
4 -
5 -Future<void> write(
6 - {required String path,
7 - required String password,
8 - required String data}) async {
9 - final keys = extractKeys(password);
10 - final key = encrypt.Key.fromBase64(keys.first);
11 - final iv = encrypt.IV.fromBase64(keys.last);
12 - final encrypted = await encode(key: key, iv: iv, data: data);
13 - final f = File(path);
14 - f.writeAsStringSync(encrypted);
15 -}
16 -
17 -Future<void> writeData(
18 - {required String path,
19 - required String password,
20 - required String data}) async {
21 - final keys = extractKeys(password);
22 - final key = encrypt.Key.fromBase64(keys.first);
23 - final iv = encrypt.IV.fromBase64(keys.last);
24 - final encrypted = await encode(key: key, iv: iv, data: data);
25 - final f = File(path);
26 - f.writeAsStringSync(encrypted);
27 -}
28 -
29 -Future<String> read({required String path, required String password}) async {
30 - final file = File(path);
31 -
32 - if (!file.existsSync()) {
33 - file.createSync();
34 - }
35 -
36 - final encrypted = file.readAsStringSync();
37 -
38 - return decode(password: password, data: encrypted);
39 -}
cw_nano/lib/nano_transaction_history.dart
+15 -7
@@ -2,24 +2,29 @@ import 'dart:convert';
2 import 'dart:core';
3 import 'package:cw_core/pathForWallet.dart';
4 import 'package:cw_core/wallet_info.dart';
5 -import 'package:cw_nano/file.dart';
5 +import 'package:cw_core/encryption_file_utils.dart';
6 import 'package:mobx/mobx.dart';
7 import 'package:cw_core/transaction_history.dart';
8 import 'package:cw_nano/nano_transaction_info.dart';
9
10 part 'nano_transaction_history.g.dart';
11 +
12 const transactionsHistoryFileName = 'transactions.json';
13
14 class NanoTransactionHistory = NanoTransactionHistoryBase with _$NanoTransactionHistory;
15
15 -abstract class NanoTransactionHistoryBase
16 - extends TransactionHistoryBase<NanoTransactionInfo> with Store {
17 - NanoTransactionHistoryBase({required this.walletInfo, required String password})
18 - : _password = password {
16 +abstract class NanoTransactionHistoryBase extends TransactionHistoryBase<NanoTransactionInfo>
17 + with Store {
18 + NanoTransactionHistoryBase({
19 + required this.walletInfo,
20 + required String password,
21 + required this.encryptionFileUtils,
22 + }) : _password = password {
23 transactions = ObservableMap<String, NanoTransactionInfo>();
24 }
25
26 final WalletInfo walletInfo;
27 + final EncryptionFileUtils encryptionFileUtils;
28 String _password;
29
30 Future<void> init() async => await _load();
@@ -30,7 +35,7 @@ abstract class NanoTransactionHistoryBase
35 final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
36 final path = '$dirPath/$transactionsHistoryFileName';
37 final data = json.encode({'transactions': transactions});
33 - await writeData(path: path, password: _password, data: data);
38 + await encryptionFileUtils.write(path: path, password: _password, data: data);
39 } catch (e) {
40 print('Error while save nano transaction history: ${e.toString()}');
41 }
@@ -46,7 +51,10 @@ abstract class NanoTransactionHistoryBase
51 Future<Map<String, dynamic>> _read() async {
52 final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
53 final path = '$dirPath/$transactionsHistoryFileName';
49 - final content = await read(path: path, password: _password);
54 + final content = await encryptionFileUtils.read(path: path, password: _password);
55 + if (content.isEmpty) {
56 + return {};
57 + }
58 return json.decode(content) as Map<String, dynamic>;
59 }
60
cw_nano/lib/nano_wallet.dart
+25 -7
@@ -5,6 +5,7 @@ import 'dart:io';
5 import 'package:bip39/bip39.dart' as bip39;
6 import 'package:cw_core/cake_hive.dart';
7 import 'package:cw_core/crypto_currency.dart';
8 +import 'package:cw_core/encryption_file_utils.dart';
9 import 'package:cw_core/n2_node.dart';
10 import 'package:cw_core/nano_account.dart';
11 import 'package:cw_core/nano_account_info_response.dart';
@@ -17,7 +18,6 @@ import 'package:cw_core/transaction_priority.dart';
18 import 'package:cw_core/wallet_base.dart';
19 import 'package:cw_core/wallet_info.dart';
20 import 'package:cw_core/wallet_keys_file.dart';
20 -import 'package:cw_nano/file.dart';
21 import 'package:cw_nano/nano_balance.dart';
22 import 'package:cw_nano/nano_client.dart';
23 import 'package:cw_nano/nano_transaction_credentials.dart';
@@ -42,11 +42,13 @@ abstract class NanoWalletBase
42 required String mnemonic,
43 required String password,
44 NanoBalance? initialBalance,
45 + required EncryptionFileUtils encryptionFileUtils,
46 }) : syncStatus = NotConnectedSyncStatus(),
47 _password = password,
48 _mnemonic = mnemonic,
49 _derivationType = walletInfo.derivationInfo!.derivationType!,
50 _isTransactionUpdating = false,
51 + _encryptionFileUtils = encryptionFileUtils,
52 _client = NanoClient(),
53 walletAddresses = NanoWalletAddresses(walletInfo),
54 balance = ObservableMap<CryptoCurrency, NanoBalance>.of({
@@ -55,7 +57,11 @@ abstract class NanoWalletBase
57 }),
58 super(walletInfo) {
59 this.walletInfo = walletInfo;
58 - transactionHistory = NanoTransactionHistory(walletInfo: walletInfo, password: password);
60 + transactionHistory = NanoTransactionHistory(
61 + walletInfo: walletInfo,
62 + password: password,
63 + encryptionFileUtils: encryptionFileUtils,
64 + );
65 if (!CakeHive.isAdapterRegistered(NanoAccount.typeId)) {
66 CakeHive.registerAdapter(NanoAccountAdapter());
67 }
@@ -65,6 +71,8 @@ abstract class NanoWalletBase
71 final String _password;
72 DerivationType _derivationType;
73
74 + final EncryptionFileUtils _encryptionFileUtils;
75 +
76 String? _privateKey;
77 String? _publicAddress;
78 String? _hexSeed;
@@ -89,6 +97,9 @@ abstract class NanoWalletBase
97 @observable
98 late ObservableMap<CryptoCurrency, NanoBalance> balance;
99
100 + @override
101 + String get password => _password;
102 +
103 static const int POLL_INTERVAL_SECONDS = 10;
104
105 // initialize the different forms of private / public key we'll need:
@@ -308,13 +319,13 @@ abstract class NanoWalletBase
319 @override
320 Future<void> save() async {
321 if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
311 - await saveKeysFile(_password);
312 - saveKeysFile(_password, true);
322 + await saveKeysFile(_password, _encryptionFileUtils);
323 + saveKeysFile(_password, _encryptionFileUtils, true);
324 }
325
326 await walletAddresses.updateAddressesInBox();
327 final path = await makePath();
317 - await write(path: path, password: _password, data: toJSON());
328 + await _encryptionFileUtils.write(path: path, password: _password, data: toJSON());
329 await transactionHistory.save();
330 }
331
@@ -373,13 +384,14 @@ abstract class NanoWalletBase
384 required String name,
385 required String password,
386 required WalletInfo walletInfo,
387 + required EncryptionFileUtils encryptionFileUtils,
388 }) async {
389 final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
390 final path = await pathForWallet(name: name, type: walletInfo.type);
391
392 Map<String, dynamic>? data = null;
393 try {
382 - final jsonSource = await read(path: path, password: password);
394 + final jsonSource = await encryptionFileUtils.read(path: path, password: password);
395
396 data = json.decode(jsonSource) as Map<String, dynamic>;
397 } catch (e) {
@@ -400,7 +412,12 @@ abstract class NanoWalletBase
412 keysData = WalletKeysData(
413 mnemonic: isHexSeed ? null : mnemonic, altMnemonic: isHexSeed ? mnemonic : null);
414 } else {
403 - keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
415 + keysData = await WalletKeysFile.readKeysFile(
416 + name,
417 + walletInfo.type,
418 + password,
419 + encryptionFileUtils,
420 + );
421 }
422
423 DerivationType derivationType = DerivationType.nano;
@@ -416,6 +433,7 @@ abstract class NanoWalletBase
433 password: password,
434 mnemonic: keysData.mnemonic!,
435 initialBalance: balance,
436 + encryptionFileUtils: encryptionFileUtils,
437 );
438 // init() should always be run after this!
439 }
cw_nano/lib/nano_wallet_service.dart
+14 -3
@@ -1,6 +1,7 @@
1 import 'dart:io';
2
3 import 'package:cw_core/pathForWallet.dart';
4 +import 'package:cw_core/encryption_file_utils.dart';
5 import 'package:cw_core/wallet_base.dart';
6 import 'package:cw_core/wallet_info.dart';
7 import 'package:cw_core/wallet_service.dart';
@@ -15,9 +16,10 @@ import 'package:nanoutil/nanoutil.dart';
16
17 class NanoWalletService extends WalletService<NanoNewWalletCredentials,
18 NanoRestoreWalletFromSeedCredentials, NanoRestoreWalletFromKeysCredentials, NanoNewWalletCredentials> {
18 - NanoWalletService(this.walletInfoSource);
19 + NanoWalletService(this.walletInfoSource, this.isDirect);
20
21 final Box<WalletInfo> walletInfoSource;
22 + final bool isDirect;
23
24 static bool walletFilesExist(String path) =>
25 !File(path).existsSync() && !File('$path.keys').existsSync();
@@ -38,6 +40,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
40 walletInfo: credentials.walletInfo!,
41 mnemonic: mnemonic,
42 password: credentials.password!,
43 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
44 );
45 await wallet.init();
46 return wallet;
@@ -65,8 +68,12 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
68
69 String randomWords =
70 (List<String>.from(nm.NanoMnemomics.WORDLIST)..shuffle()).take(24).join(' ');
68 - final currentWallet =
69 - NanoWallet(walletInfo: currentWalletInfo, password: password, mnemonic: randomWords);
71 + final currentWallet = NanoWallet(
72 + walletInfo: currentWalletInfo,
73 + password: password,
74 + mnemonic: randomWords,
75 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
76 + );
77
78 await currentWallet.renameWalletFiles(newName);
79 await saveBackup(newName);
@@ -103,6 +110,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
110 password: credentials.password!,
111 mnemonic: mnemonic ?? credentials.seedKey,
112 walletInfo: credentials.walletInfo!,
113 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
114 );
115 await wallet.init();
116 await wallet.save();
@@ -139,6 +147,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
147 password: credentials.password!,
148 mnemonic: credentials.mnemonic,
149 walletInfo: credentials.walletInfo!,
150 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
151 );
152
153 await wallet.init();
@@ -160,6 +169,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
169 name: name,
170 password: password,
171 walletInfo: walletInfo,
172 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
173 );
174
175 await wallet.init();
@@ -172,6 +182,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
182 name: name,
183 password: password,
184 walletInfo: walletInfo,
185 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
186 );
187
188 await wallet.init();
cw_nano/pubspec.lock
+33
@@ -137,6 +137,15 @@ packages:
137 url: "https://pub.dev"
138 source: hosted
139 version: "8.9.2"
140 + cake_backup:
141 + dependency: transitive
142 + description:
143 + path: "."
144 + ref: main
145 + resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
146 + url: "https://github.com/cake-tech/cake_backup.git"
147 + source: git
148 + version: "1.0.0+1"
149 characters:
150 dependency: transitive
151 description:
@@ -193,6 +202,22 @@ packages:
202 url: "https://pub.dev"
203 source: hosted
204 version: "3.0.3"
205 + cryptography:
206 + dependency: transitive
207 + description:
208 + name: cryptography
209 + sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
210 + url: "https://pub.dev"
211 + source: hosted
212 + version: "2.7.0"
213 + cupertino_icons:
214 + dependency: transitive
215 + description:
216 + name: cupertino_icons
217 + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
218 + url: "https://pub.dev"
219 + source: hosted
220 + version: "1.0.8"
221 cw_core:
222 dependency: "direct main"
223 description:
@@ -797,6 +822,14 @@ packages:
822 url: "https://pub.dev"
823 source: hosted
824 version: "1.0.1"
825 + tuple:
826 + dependency: transitive
827 + description:
828 + name: tuple
829 + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
830 + url: "https://pub.dev"
831 + source: hosted
832 + version: "2.0.2"
833 typed_data:
834 dependency: transitive
835 description:
cw_polygon/lib/polygon_transaction_history.dart
+1
@@ -8,6 +8,7 @@ class PolygonTransactionHistory extends EVMChainTransactionHistory {
8 PolygonTransactionHistory({
9 required super.walletInfo,
10 required super.password,
11 + required super.encryptionFileUtils,
12 });
13
14 @override
cw_polygon/lib/polygon_wallet.dart
+23 -7
@@ -2,6 +2,7 @@ import 'dart:convert';
2
3 import 'package:cw_core/cake_hive.dart';
4 import 'package:cw_core/crypto_currency.dart';
5 +import 'package:cw_core/encryption_file_utils.dart';
6 import 'package:cw_core/erc20_token.dart';
7 import 'package:cw_core/pathForWallet.dart';
8 import 'package:cw_core/transaction_direction.dart';
@@ -12,7 +13,6 @@ import 'package:cw_evm/evm_chain_transaction_info.dart';
13 import 'package:cw_evm/evm_chain_transaction_model.dart';
14 import 'package:cw_evm/evm_chain_wallet.dart';
15 import 'package:cw_evm/evm_erc20_balance.dart';
15 -import 'package:cw_evm/file.dart';
16 import 'package:cw_polygon/default_polygon_erc20_tokens.dart';
17 import 'package:cw_polygon/polygon_client.dart';
18 import 'package:cw_polygon/polygon_transaction_history.dart';
@@ -26,6 +26,7 @@ class PolygonWallet extends EVMChainWallet {
26 super.initialBalance,
27 super.privateKey,
28 required super.client,
29 + required super.encryptionFileUtils,
30 }) : super(nativeCurrency: CryptoCurrency.maticpoly);
31
32 @override
@@ -92,18 +93,27 @@ class PolygonWallet extends EVMChainWallet {
93 }
94
95 @override
95 - EVMChainTransactionHistory setUpTransactionHistory(WalletInfo walletInfo, String password) {
96 - return PolygonTransactionHistory(walletInfo: walletInfo, password: password);
96 + EVMChainTransactionHistory setUpTransactionHistory(
97 + WalletInfo walletInfo, String password, EncryptionFileUtils encryptionFileUtils) {
98 + return PolygonTransactionHistory(
99 + walletInfo: walletInfo,
100 + password: password,
101 + encryptionFileUtils: encryptionFileUtils,
102 + );
103 }
104
99 - static Future<PolygonWallet> open(
100 - {required String name, required String password, required WalletInfo walletInfo}) async {
105 + static Future<PolygonWallet> open({
106 + required String name,
107 + required String password,
108 + required WalletInfo walletInfo,
109 + required EncryptionFileUtils encryptionFileUtils,
110 + }) async {
111 final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
112 final path = await pathForWallet(name: name, type: walletInfo.type);
113
114 Map<String, dynamic>? data;
115 try {
106 - final jsonSource = await read(path: path, password: password);
116 + final jsonSource = await encryptionFileUtils.read(path: path, password: password);
117
118 data = json.decode(jsonSource) as Map<String, dynamic>;
119 } catch (e) {
@@ -121,7 +131,12 @@ class PolygonWallet extends EVMChainWallet {
131
132 keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
133 } else {
124 - keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
134 + keysData = await WalletKeysFile.readKeysFile(
135 + name,
136 + walletInfo.type,
137 + password,
138 + encryptionFileUtils,
139 + );
140 }
141
142 return PolygonWallet(
@@ -131,6 +146,7 @@ class PolygonWallet extends EVMChainWallet {
146 privateKey: keysData.privateKey,
147 initialBalance: balance,
148 client: PolygonClient(),
149 + encryptionFileUtils: encryptionFileUtils,
150 );
151 }
152 }
cw_polygon/lib/polygon_wallet_service.dart
+13 -2
@@ -1,4 +1,5 @@
1 import 'package:bip39/bip39.dart' as bip39;
2 +import 'package:cw_core/encryption_file_utils.dart';
3 import 'package:cw_core/wallet_base.dart';
4 import 'package:cw_core/wallet_info.dart';
5 import 'package:cw_core/wallet_type.dart';
@@ -10,7 +11,7 @@ import 'package:cw_polygon/polygon_wallet.dart';
11
12 class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
13 PolygonWalletService(
13 - super.walletInfoSource, {
14 + super.walletInfoSource, super.isDirect, {
15 required this.client,
16 });
17
@@ -30,6 +31,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
31 mnemonic: mnemonic,
32 password: credentials.password!,
33 client: client,
34 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
35 );
36
37 await wallet.init();
@@ -48,6 +50,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
50 name: name,
51 password: password,
52 walletInfo: walletInfo,
53 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
54 );
55
56 await wallet.init();
@@ -61,6 +64,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
64 name: name,
65 password: password,
66 walletInfo: walletInfo,
67 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
68 );
69
70 await wallet.init();
@@ -77,6 +81,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
81 privateKey: credentials.privateKey,
82 walletInfo: credentials.walletInfo!,
83 client: client,
84 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
85 );
86
87 await wallet.init();
@@ -99,6 +104,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
104 walletInfo: credentials.walletInfo!,
105 password: credentials.password!,
106 client: client,
107 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
108 );
109
110 await wallet.init();
@@ -120,6 +126,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
126 mnemonic: credentials.mnemonic,
127 walletInfo: credentials.walletInfo!,
128 client: client,
129 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
130 );
131
132 await wallet.init();
@@ -134,7 +141,11 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
141 final currentWalletInfo = walletInfoSource.values
142 .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
143 final currentWallet = await PolygonWallet.open(
137 - password: password, name: currentName, walletInfo: currentWalletInfo);
144 + password: password,
145 + name: currentName,
146 + walletInfo: currentWalletInfo,
147 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
148 + );
149
150 await currentWallet.renameWalletFiles(newName);
151 await saveBackup(newName);
cw_solana/lib/file.dart deleted
-39
@@ -1,39 +0,0 @@
1 -import 'dart:io';
2 -import 'package:cw_core/key.dart';
3 -import 'package:encrypt/encrypt.dart' as encrypt;
4 -
5 -Future<void> write(
6 - {required String path,
7 - required String password,
8 - required String data}) async {
9 - final keys = extractKeys(password);
10 - final key = encrypt.Key.fromBase64(keys.first);
11 - final iv = encrypt.IV.fromBase64(keys.last);
12 - final encrypted = await encode(key: key, iv: iv, data: data);
13 - final f = File(path);
14 - f.writeAsStringSync(encrypted);
15 -}
16 -
17 -Future<void> writeData(
18 - {required String path,
19 - required String password,
20 - required String data}) async {
21 - final keys = extractKeys(password);
22 - final key = encrypt.Key.fromBase64(keys.first);
23 - final iv = encrypt.IV.fromBase64(keys.last);
24 - final encrypted = await encode(key: key, iv: iv, data: data);
25 - final f = File(path);
26 - f.writeAsStringSync(encrypted);
27 -}
28 -
29 -Future<String> read({required String path, required String password}) async {
30 - final file = File(path);
31 -
32 - if (!file.existsSync()) {
33 - file.createSync();
34 - }
35 -
36 - final encrypted = file.readAsStringSync();
37 -
38 - return decode(password: password, data: encrypted);
39 -}
cw_solana/lib/solana_transaction_history.dart
+6 -4
@@ -1,8 +1,8 @@
1 import 'dart:convert';
2 import 'dart:core';
3 +import 'package:cw_core/encryption_file_utils.dart';
4 import 'package:cw_core/pathForWallet.dart';
5 import 'package:cw_core/wallet_info.dart';
5 -import 'package:cw_solana/file.dart';
6 import 'package:cw_solana/solana_transaction_info.dart';
7 import 'package:mobx/mobx.dart';
8 import 'package:cw_core/transaction_history.dart';
@@ -15,12 +15,14 @@ class SolanaTransactionHistory = SolanaTransactionHistoryBase with _$SolanaTrans
15
16 abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<SolanaTransactionInfo>
17 with Store {
18 - SolanaTransactionHistoryBase({required this.walletInfo, required String password})
18 + SolanaTransactionHistoryBase(
19 + {required this.walletInfo, required String password, required this.encryptionFileUtils})
20 : _password = password {
21 transactions = ObservableMap<String, SolanaTransactionInfo>();
22 }
23
24 final WalletInfo walletInfo;
25 + final EncryptionFileUtils encryptionFileUtils;
26 String _password;
27
28 Future<void> init() async => await _load();
@@ -32,7 +34,7 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<Solan
34 final path = '$dirPath/$transactionsHistoryFileName';
35 final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson()));
36 final data = json.encode({'transactions': transactionMaps});
35 - await writeData(path: path, password: _password, data: data);
37 + await encryptionFileUtils.write(path: path, password: _password, data: data);
38 } catch (e, s) {
39 print('Error while saving solana transaction history: ${e.toString()}');
40 print(s);
@@ -49,7 +51,7 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase<Solan
51 Future<Map<String, dynamic>> _read() async {
52 final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
53 final path = '$dirPath/$transactionsHistoryFileName';
52 - final content = await read(path: path, password: _password);
54 + final content = await encryptionFileUtils.read(path: path, password: _password);
55 if (content.isEmpty) {
56 return {};
57 }
cw_solana/lib/solana_wallet.dart
+25 -9
@@ -4,6 +4,7 @@ import 'dart:io';
4
5 import 'package:cw_core/cake_hive.dart';
6 import 'package:cw_core/crypto_currency.dart';
7 +import 'package:cw_core/encryption_file_utils.dart';
8 import 'package:cw_core/node.dart';
9 import 'package:cw_core/pathForWallet.dart';
10 import 'package:cw_core/pending_transaction.dart';
@@ -15,7 +16,6 @@ import 'package:cw_core/wallet_base.dart';
16 import 'package:cw_core/wallet_info.dart';
17 import 'package:cw_core/wallet_keys_file.dart';
18 import 'package:cw_solana/default_spl_tokens.dart';
18 -import 'package:cw_solana/file.dart';
19 import 'package:cw_solana/solana_balance.dart';
20 import 'package:cw_solana/solana_client.dart';
21 import 'package:cw_solana/solana_exceptions.dart';
@@ -46,6 +46,7 @@ abstract class SolanaWalletBase
46 String? privateKey,
47 required String password,
48 SolanaBalance? initialBalance,
49 + required this.encryptionFileUtils,
50 }) : syncStatus = const NotConnectedSyncStatus(),
51 _password = password,
52 _mnemonic = mnemonic,
@@ -56,7 +57,11 @@ abstract class SolanaWalletBase
57 {CryptoCurrency.sol: initialBalance ?? SolanaBalance(BigInt.zero.toDouble())}),
58 super(walletInfo) {
59 this.walletInfo = walletInfo;
59 - transactionHistory = SolanaTransactionHistory(walletInfo: walletInfo, password: password);
60 + transactionHistory = SolanaTransactionHistory(
61 + walletInfo: walletInfo,
62 + password: password,
63 + encryptionFileUtils: encryptionFileUtils,
64 + );
65
66 if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
67 CakeHive.registerAdapter(SPLTokenAdapter());
@@ -68,6 +73,7 @@ abstract class SolanaWalletBase
73 final String _password;
74 final String? _mnemonic;
75 final String? _hexPrivateKey;
76 + final EncryptionFileUtils encryptionFileUtils;
77
78 // The Solana WalletPair
79 Ed25519HDKeyPair? _walletKeyPair;
@@ -77,7 +83,7 @@ abstract class SolanaWalletBase
83 // To access the privateKey bytes.
84 Ed25519HDKeyPairData? _keyPairData;
85
80 - late SolanaWalletClient _client;
86 + late final SolanaWalletClient _client;
87
88 @observable
89 double? estimatedFee;
@@ -97,7 +103,7 @@ abstract class SolanaWalletBase
103 @observable
104 late ObservableMap<CryptoCurrency, SolanaBalance> balance;
105
100 - Completer<SharedPreferences> _sharedPrefs = Completer();
106 + final Completer<SharedPreferences> _sharedPrefs = Completer();
107
108 @override
109 Ed25519HDKeyPairData get keys {
@@ -343,13 +349,13 @@ abstract class SolanaWalletBase
349 @override
350 Future<void> save() async {
351 if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
346 - await saveKeysFile(_password);
347 - saveKeysFile(_password, true);
352 + await saveKeysFile(_password, encryptionFileUtils);
353 + saveKeysFile(_password, encryptionFileUtils, true);
354 }
355
356 await walletAddresses.updateAddressesInBox();
357 final path = await makePath();
352 - await write(path: path, password: _password, data: toJSON());
358 + await encryptionFileUtils.write(path: path, password: _password, data: toJSON());
359 await transactionHistory.save();
360 }
361
@@ -382,13 +388,14 @@ abstract class SolanaWalletBase
388 required String name,
389 required String password,
390 required WalletInfo walletInfo,
391 + required EncryptionFileUtils encryptionFileUtils,
392 }) async {
393 final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
394 final path = await pathForWallet(name: name, type: walletInfo.type);
395
396 Map<String, dynamic>? data;
397 try {
391 - final jsonSource = await read(path: path, password: password);
398 + final jsonSource = await encryptionFileUtils.read(path: path, password: password);
399
400 data = json.decode(jsonSource) as Map<String, dynamic>;
401 } catch (e) {
@@ -405,7 +412,12 @@ abstract class SolanaWalletBase
412
413 keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
414 } else {
408 - keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
415 + keysData = await WalletKeysFile.readKeysFile(
416 + name,
417 + walletInfo.type,
418 + password,
419 + encryptionFileUtils,
420 + );
421 }
422
423 return SolanaWallet(
@@ -414,6 +426,7 @@ abstract class SolanaWalletBase
426 mnemonic: keysData.mnemonic,
427 privateKey: keysData.privateKey,
428 initialBalance: balance,
429 + encryptionFileUtils: encryptionFileUtils,
430 );
431 }
432
@@ -572,4 +585,7 @@ abstract class SolanaWalletBase
585 }
586
587 SolanaClient? get solanaClient => _client.getSolanaClient;
588 +
589 + @override
590 + String get password => _password;
591 }
cw_solana/lib/solana_wallet_creation_credentials.dart
+2 -2
@@ -2,8 +2,8 @@ import 'package:cw_core/wallet_credentials.dart';
2 import 'package:cw_core/wallet_info.dart';
3
4 class SolanaNewWalletCredentials extends WalletCredentials {
5 - SolanaNewWalletCredentials({required String name, WalletInfo? walletInfo})
6 - : super(name: name, walletInfo: walletInfo);
5 + SolanaNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
6 + : super(name: name, walletInfo: walletInfo, password: password);
7 }
8
9 class SolanaRestoreWalletFromSeedCredentials extends WalletCredentials {
cw_solana/lib/solana_wallet_service.dart
+13 -2
@@ -2,6 +2,7 @@ import 'dart:io';
2
3 import 'package:bip39/bip39.dart' as bip39;
4 import 'package:collection/collection.dart';
5 +import 'package:cw_core/encryption_file_utils.dart';
6 import 'package:cw_core/balance.dart';
7 import 'package:cw_core/pathForWallet.dart';
8 import 'package:cw_core/transaction_history.dart';
@@ -17,9 +18,10 @@ import 'package:hive/hive.dart';
18
19 class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
20 SolanaRestoreWalletFromSeedCredentials, SolanaRestoreWalletFromPrivateKey, SolanaNewWalletCredentials> {
20 - SolanaWalletService(this.walletInfoSource);
21 + SolanaWalletService(this.walletInfoSource, this.isDirect);
22
23 final Box<WalletInfo> walletInfoSource;
24 + final bool isDirect;
25
26 @override
27 Future<SolanaWallet> create(SolanaNewWalletCredentials credentials, {bool? isTestnet}) async {
@@ -31,6 +33,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
33 walletInfo: credentials.walletInfo!,
34 mnemonic: mnemonic,
35 password: credentials.password!,
36 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
37 );
38
39 await wallet.init();
@@ -56,6 +59,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
59 name: name,
60 password: password,
61 walletInfo: walletInfo,
62 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
63 );
64
65 await wallet.init();
@@ -69,6 +73,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
73 name: name,
74 password: password,
75 walletInfo: walletInfo,
76 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
77 );
78
79 await wallet.init();
@@ -92,6 +97,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
97 password: credentials.password!,
98 privateKey: credentials.privateKey,
99 walletInfo: credentials.walletInfo!,
100 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
101 );
102
103 await wallet.init();
@@ -112,6 +118,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
118 password: credentials.password!,
119 mnemonic: credentials.mnemonic,
120 walletInfo: credentials.walletInfo!,
121 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
122 );
123
124 await wallet.init();
@@ -126,7 +133,11 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
133 final currentWalletInfo = walletInfoSource.values
134 .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
135 final currentWallet = await SolanaWalletBase.open(
129 - password: password, name: currentName, walletInfo: currentWalletInfo);
136 + password: password,
137 + name: currentName,
138 + walletInfo: currentWalletInfo,
139 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
140 + );
141
142 await currentWallet.renameWalletFiles(newName);
143 await saveBackup(newName);
cw_tron/lib/file.dart deleted
-39
@@ -1,39 +0,0 @@
1 -import 'dart:io';
2 -import 'package:cw_core/key.dart';
3 -import 'package:encrypt/encrypt.dart' as encrypt;
4 -
5 -Future<void> write(
6 - {required String path,
7 - required String password,
8 - required String data}) async {
9 - final keys = extractKeys(password);
10 - final key = encrypt.Key.fromBase64(keys.first);
11 - final iv = encrypt.IV.fromBase64(keys.last);
12 - final encrypted = await encode(key: key, iv: iv, data: data);
13 - final f = File(path);
14 - f.writeAsStringSync(encrypted);
15 -}
16 -
17 -Future<void> writeData(
18 - {required String path,
19 - required String password,
20 - required String data}) async {
21 - final keys = extractKeys(password);
22 - final key = encrypt.Key.fromBase64(keys.first);
23 - final iv = encrypt.IV.fromBase64(keys.last);
24 - final encrypted = await encode(key: key, iv: iv, data: data);
25 - final f = File(path);
26 - f.writeAsStringSync(encrypted);
27 -}
28 -
29 -Future<String> read({required String path, required String password}) async {
30 - final file = File(path);
31 -
32 - if (!file.existsSync()) {
33 - file.createSync();
34 - }
35 -
36 - final encrypted = file.readAsStringSync();
37 -
38 - return decode(password: password, data: encrypted);
39 -}
cw_tron/lib/tron_transaction_history.dart
+6 -4
@@ -3,7 +3,7 @@ import 'dart:core';
3 import 'dart:developer';
4 import 'package:cw_core/pathForWallet.dart';
5 import 'package:cw_core/wallet_info.dart';
6 -import 'package:cw_evm/file.dart';
6 +import 'package:cw_core/encryption_file_utils.dart';
7 import 'package:cw_tron/tron_transaction_info.dart';
8 import 'package:mobx/mobx.dart';
9 import 'package:cw_core/transaction_history.dart';
@@ -14,7 +14,8 @@ class TronTransactionHistory = TronTransactionHistoryBase with _$TronTransaction
14
15 abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTransactionInfo>
16 with Store {
17 - TronTransactionHistoryBase({required this.walletInfo, required String password})
17 + TronTransactionHistoryBase(
18 + {required this.walletInfo, required String password, required this.encryptionFileUtils})
19 : _password = password {
20 transactions = ObservableMap<String, TronTransactionInfo>();
21 }
@@ -22,6 +23,7 @@ abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTra
23 String _password;
24
25 final WalletInfo walletInfo;
26 + final EncryptionFileUtils encryptionFileUtils;
27
28 Future<void> init() async => await _load();
29
@@ -33,7 +35,7 @@ abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTra
35 String path = '$dirPath/$transactionsHistoryFileNameForWallet';
36 final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson()));
37 final data = json.encode({'transactions': transactionMaps});
36 - await writeData(path: path, password: _password, data: data);
38 + await encryptionFileUtils.write(path: path, password: _password, data: data);
39 } catch (e, s) {
40 log('Error while saving ${walletInfo.type.name} transaction history: ${e.toString()}');
41 log(s.toString());
@@ -51,7 +53,7 @@ abstract class TronTransactionHistoryBase extends TransactionHistoryBase<TronTra
53 String transactionsHistoryFileNameForWallet = 'tron_transactions.json';
54 final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
55 String path = '$dirPath/$transactionsHistoryFileNameForWallet';
54 - final content = await read(path: path, password: _password);
56 + final content = await encryptionFileUtils.read(path: path, password: _password);
57 if (content.isEmpty) {
58 return {};
59 }
cw_tron/lib/tron_wallet.dart
+20 -7
@@ -7,6 +7,7 @@ import 'package:bip39/bip39.dart' as bip39;
7 import 'package:blockchain_utils/blockchain_utils.dart';
8 import 'package:cw_core/cake_hive.dart';
9 import 'package:cw_core/crypto_currency.dart';
10 +import 'package:cw_core/encryption_file_utils.dart';
11 import 'package:cw_core/node.dart';
12 import 'package:cw_core/pathForWallet.dart';
13 import 'package:cw_core/pending_transaction.dart';
@@ -19,7 +20,6 @@ import 'package:cw_core/wallet_info.dart';
20 import 'package:cw_core/wallet_keys_file.dart';
21 import 'package:cw_core/wallet_type.dart';
22 import 'package:cw_tron/default_tron_tokens.dart';
22 -import 'package:cw_tron/file.dart';
23 import 'package:cw_tron/tron_abi.dart';
24 import 'package:cw_tron/tron_balance.dart';
25 import 'package:cw_tron/tron_client.dart';
@@ -46,6 +46,7 @@ abstract class TronWalletBase
46 String? privateKey,
47 required String password,
48 TronBalance? initialBalance,
49 + required this.encryptionFileUtils,
50 }) : syncStatus = const NotConnectedSyncStatus(),
51 _password = password,
52 _mnemonic = mnemonic,
@@ -57,7 +58,8 @@ abstract class TronWalletBase
58 ),
59 super(walletInfo) {
60 this.walletInfo = walletInfo;
60 - transactionHistory = TronTransactionHistory(walletInfo: walletInfo, password: password);
61 + transactionHistory = TronTransactionHistory(
62 + walletInfo: walletInfo, password: password, encryptionFileUtils: encryptionFileUtils);
63
64 if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
65 CakeHive.registerAdapter(TronTokenAdapter());
@@ -67,6 +69,7 @@ abstract class TronWalletBase
69 final String? _mnemonic;
70 final String? _hexPrivateKey;
71 final String _password;
72 + final EncryptionFileUtils encryptionFileUtils;
73
74 late final Box<TronToken> tronTokensBox;
75
@@ -125,13 +128,14 @@ abstract class TronWalletBase
128 required String name,
129 required String password,
130 required WalletInfo walletInfo,
131 + required EncryptionFileUtils encryptionFileUtils,
132 }) async {
133 final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
134 final path = await pathForWallet(name: name, type: walletInfo.type);
135
136 Map<String, dynamic>? data;
137 try {
134 - final jsonSource = await read(path: path, password: password);
138 + final jsonSource = await encryptionFileUtils.read(path: path, password: password);
139
140 data = json.decode(jsonSource) as Map<String, dynamic>;
141 } catch (e) {
@@ -148,7 +152,12 @@ abstract class TronWalletBase
152
153 keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey);
154 } else {
151 - keysData = await WalletKeysFile.readKeysFile(name, walletInfo.type, password);
155 + keysData = await WalletKeysFile.readKeysFile(
156 + name,
157 + walletInfo.type,
158 + password,
159 + encryptionFileUtils,
160 + );
161 }
162
163 return TronWallet(
@@ -157,6 +166,7 @@ abstract class TronWalletBase
166 mnemonic: keysData.mnemonic,
167 privateKey: keysData.privateKey,
168 initialBalance: balance,
169 + encryptionFileUtils: encryptionFileUtils,
170 );
171 }
172
@@ -430,13 +440,13 @@ abstract class TronWalletBase
440 @override
441 Future<void> save() async {
442 if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) {
433 - await saveKeysFile(_password);
434 - saveKeysFile(_password, true);
443 + await saveKeysFile(_password, encryptionFileUtils);
444 + saveKeysFile(_password, encryptionFileUtils, true);
445 }
446
447 await walletAddresses.updateAddressesInBox();
448 final path = await makePath();
439 - await write(path: path, password: _password, data: toJSON());
449 + await encryptionFileUtils.write(path: path, password: _password, data: toJSON());
450 await transactionHistory.save();
451 }
452
@@ -584,4 +594,7 @@ abstract class TronWalletBase
594 _transactionsUpdateTimer?.cancel();
595 }
596 }
597 +
598 + @override
599 + String get password => _password;
600 }
cw_tron/lib/tron_wallet_creation_credentials.dart
+2 -2
@@ -2,8 +2,8 @@ import 'package:cw_core/wallet_credentials.dart';
2 import 'package:cw_core/wallet_info.dart';
3
4 class TronNewWalletCredentials extends WalletCredentials {
5 - TronNewWalletCredentials({required String name, WalletInfo? walletInfo})
6 - : super(name: name, walletInfo: walletInfo);
5 + TronNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
6 + : super(name: name, walletInfo: walletInfo, password: password);
7 }
8
9 class TronRestoreWalletFromSeedCredentials extends WalletCredentials {
cw_tron/lib/tron_wallet_service.dart
+13 -2
@@ -3,6 +3,7 @@ import 'dart:io';
3 import 'package:bip39/bip39.dart' as bip39;
4 import 'package:collection/collection.dart';
5 import 'package:cw_core/balance.dart';
6 +import 'package:cw_core/encryption_file_utils.dart';
7 import 'package:cw_core/pathForWallet.dart';
8 import 'package:cw_core/transaction_history.dart';
9 import 'package:cw_core/transaction_info.dart';
@@ -21,11 +22,12 @@ class TronWalletService extends WalletService<
22 TronRestoreWalletFromSeedCredentials,
23 TronRestoreWalletFromPrivateKey,
24 TronNewWalletCredentials> {
24 - TronWalletService(this.walletInfoSource, {required this.client});
25 + TronWalletService(this.walletInfoSource, {required this.client, required this.isDirect});
26
27 late TronClient client;
28
29 final Box<WalletInfo> walletInfoSource;
30 + final bool isDirect;
31
32 @override
33 WalletType getType() => WalletType.tron;
@@ -43,6 +45,7 @@ class TronWalletService extends WalletService<
45 walletInfo: credentials.walletInfo!,
46 mnemonic: mnemonic,
47 password: credentials.password!,
48 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
49 );
50
51 await wallet.init();
@@ -62,6 +65,7 @@ class TronWalletService extends WalletService<
65 name: name,
66 password: password,
67 walletInfo: walletInfo,
68 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
69 );
70
71 await wallet.init();
@@ -75,6 +79,7 @@ class TronWalletService extends WalletService<
79 name: name,
80 password: password,
81 walletInfo: walletInfo,
82 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
83 );
84
85 await wallet.init();
@@ -92,6 +97,7 @@ class TronWalletService extends WalletService<
97 password: credentials.password!,
98 privateKey: credentials.privateKey,
99 walletInfo: credentials.walletInfo!,
100 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
101 );
102
103 await wallet.init();
@@ -114,6 +120,7 @@ class TronWalletService extends WalletService<
120 password: credentials.password!,
121 mnemonic: credentials.mnemonic,
122 walletInfo: credentials.walletInfo!,
123 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
124 );
125
126 await wallet.init();
@@ -128,7 +135,11 @@ class TronWalletService extends WalletService<
135 final currentWalletInfo = walletInfoSource.values
136 .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
137 final currentWallet = await TronWalletBase.open(
131 - password: password, name: currentName, walletInfo: currentWalletInfo);
138 + password: password,
139 + name: currentName,
140 + walletInfo: currentWalletInfo,
141 + encryptionFileUtils: encryptionFileUtilsFor(isDirect),
142 + );
143
144 await currentWallet.renameWalletFiles(newName);
145 await saveBackup(newName);
cw_wownero/lib/wownero_wallet.dart
+6 -1
@@ -50,7 +50,7 @@ abstract class WowneroWalletBase
50 extends WalletBase<WowneroBalance, WowneroTransactionHistory, WowneroTransactionInfo>
51 with Store {
52 WowneroWalletBase(
53 - {required WalletInfo walletInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo})
53 + {required WalletInfo walletInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo, required String password})
54 : balance = ObservableMap<CryptoCurrency, WowneroBalance>.of({
55 CryptoCurrency.wow: WowneroBalance(
56 fullBalance: wownero_wallet.getFullBalance(accountIndex: 0),
@@ -58,6 +58,7 @@ abstract class WowneroWalletBase
58 }),
59 _isTransactionUpdating = false,
60 _hasSyncAfterStartup = false,
61 + _password = password,
62 isEnabledAutoGenerateSubaddress = false,
63 syncStatus = NotConnectedSyncStatus(),
64 unspentCoins = [],
@@ -109,6 +110,10 @@ abstract class WowneroWalletBase
110
111 String seedLegacy(String? language) => wownero_wallet.getSeedLegacy(language);
112
113 + String get password => _password;
114 +
115 + String _password;
116 +
117 @override
118 MoneroWalletKeys get keys => MoneroWalletKeys(
119 privateSpendKey: wownero_wallet.getSecretSpendKey(),
cw_wownero/lib/wownero_wallet_service.dart
+6 -6
@@ -93,7 +93,7 @@ class WowneroWalletService extends WalletService<
93 await wownero_wallet_manager.createWallet(
94 path: path, password: credentials.password!, language: credentials.language);
95 final wallet = WowneroWallet(
96 - walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
96 + walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
97 await wallet.init();
98
99 return wallet;
@@ -129,7 +129,7 @@ class WowneroWalletService extends WalletService<
129 await wownero_wallet_manager.openWalletAsync({'path': path, 'password': password});
130 final walletInfo = walletInfoSource.values
131 .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
132 - wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
132 + wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
133 final isValid = wallet.walletAddresses.validate();
134
135 if (!isValid) {
@@ -210,7 +210,7 @@ class WowneroWalletService extends WalletService<
210 final currentWalletInfo = walletInfoSource.values
211 .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
212 final currentWallet =
213 - WowneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
213 + WowneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
214
215 await currentWallet.renameWalletFiles(newName);
216
@@ -235,7 +235,7 @@ class WowneroWalletService extends WalletService<
235 viewKey: credentials.viewKey,
236 spendKey: credentials.spendKey);
237 final wallet = WowneroWallet(
238 - walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
238 + walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
239 await wallet.init();
240
241 return wallet;
@@ -268,7 +268,7 @@ class WowneroWalletService extends WalletService<
268 seed: credentials.mnemonic,
269 restoreHeight: credentials.height!);
270 final wallet = WowneroWallet(
271 - walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
271 + walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
272 await wallet.init();
273
274 return wallet;
@@ -315,7 +315,7 @@ class WowneroWalletService extends WalletService<
315 restoreHeight: height,
316 spendKey: spendKey);
317
318 - final wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
318 + final wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
319 await wallet.init();
320
321 return wallet;
cw_wownero/pubspec.lock
+33
@@ -113,6 +113,15 @@ packages:
113 url: "https://pub.dev"
114 source: hosted
115 version: "8.4.3"
116 + cake_backup:
117 + dependency: transitive
118 + description:
119 + path: "."
120 + ref: main
121 + resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
122 + url: "https://github.com/cake-tech/cake_backup.git"
123 + source: git
124 + version: "1.0.0+1"
125 characters:
126 dependency: transitive
127 description:
@@ -169,6 +178,22 @@ packages:
178 url: "https://pub.dev"
179 source: hosted
180 version: "3.0.2"
181 + cryptography:
182 + dependency: transitive
183 + description:
184 + name: cryptography
185 + sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
186 + url: "https://pub.dev"
187 + source: hosted
188 + version: "2.5.0"
189 + cupertino_icons:
190 + dependency: transitive
191 + description:
192 + name: cupertino_icons
193 + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
194 + url: "https://pub.dev"
195 + source: hosted
196 + version: "1.0.8"
197 cw_core:
198 dependency: "direct main"
199 description:
@@ -680,6 +705,14 @@ packages:
705 url: "https://pub.dev"
706 source: hosted
707 version: "1.0.1"
708 + tuple:
709 + dependency: transitive
710 + description:
711 + name: tuple
712 + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
713 + url: "https://pub.dev"
714 + source: hosted
715 + version: "2.0.2"
716 typed_data:
717 dependency: transitive
718 description:
lib/bitcoin/cw_bitcoin.dart
+6 -6
@@ -29,8 +29,8 @@ class CWBitcoin extends Bitcoin {
29
30 @override
31 WalletCredentials createBitcoinNewWalletCredentials(
32 - {required String name, WalletInfo? walletInfo}) =>
33 - BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
32 + {required String name, WalletInfo? walletInfo, String? password}) =>
33 + BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
34
35 @override
36 WalletCredentials createBitcoinHardwareWalletCredentials(
@@ -203,13 +203,13 @@ class CWBitcoin extends Bitcoin {
203 }
204
205 WalletService createBitcoinWalletService(
206 - Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan) {
207 - return BitcoinWalletService(walletInfoSource, unspentCoinSource, alwaysScan);
206 + Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan, bool isDirect) {
207 + return BitcoinWalletService(walletInfoSource, unspentCoinSource, alwaysScan, isDirect);
208 }
209
210 WalletService createLitecoinWalletService(
211 - Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
212 - return LitecoinWalletService(walletInfoSource, unspentCoinSource);
211 + Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
212 + return LitecoinWalletService(walletInfoSource, unspentCoinSource, isDirect);
213 }
214
215 @override
lib/bitcoin_cash/cw_bitcoin_cash.dart
+4 -3
@@ -6,16 +6,17 @@ class CWBitcoinCash extends BitcoinCash {
6
7 @override
8 WalletService createBitcoinCashWalletService(
9 - Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
10 - return BitcoinCashWalletService(walletInfoSource, unspentCoinSource);
9 + Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
10 + return BitcoinCashWalletService(walletInfoSource, unspentCoinSource, isDirect);
11 }
12
13 @override
14 WalletCredentials createBitcoinCashNewWalletCredentials({
15 required String name,
16 WalletInfo? walletInfo,
17 + String? password,
18 }) =>
18 - BitcoinCashNewWalletCredentials(name: name, walletInfo: walletInfo);
19 + BitcoinCashNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
20
21 @override
22 WalletCredentials createBitcoinCashRestoreWalletFromSeedCredentials(
lib/core/backup_service.dart
+1 -1
@@ -3,6 +3,7 @@ import 'dart:io';
3 import 'dart:typed_data';
4 import 'package:cake_wallet/core/secure_storage.dart';
5 import 'package:cake_wallet/themes/theme_list.dart';
6 +import 'package:cw_core/root_dir.dart';
7 import 'package:cake_wallet/utils/device_info.dart';
8 import 'package:cw_core/root_dir.dart';
9 import 'package:cw_core/wallet_type.dart';
@@ -20,7 +21,6 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
21 import 'package:cw_core/wallet_info.dart';
22 import 'package:cake_wallet/.secrets.g.dart' as secrets;
23 import 'package:cake_wallet/wallet_types.g.dart';
23 -
24 import 'package:cake_backup/backup.dart' as cake_backup;
25
26 class BackupService {
lib/core/wallet_creation_service.dart
+21 -11
@@ -15,7 +15,6 @@ import 'package:cw_core/wallet_type.dart';
15 class WalletCreationService {
16 WalletCreationService(
17 {required WalletType initialType,
18 - required this.secureStorage,
18 required this.keyService,
19 required this.sharedPreferences,
20 required this.settingsStore,
@@ -25,7 +24,6 @@ class WalletCreationService {
24 }
25
26 WalletType type;
28 - final SecureStorage secureStorage;
27 final SharedPreferences sharedPreferences;
28 final SettingsStore settingsStore;
29 final KeyService keyService;
@@ -56,12 +54,16 @@ class WalletCreationService {
54
55 Future<WalletBase> create(WalletCredentials credentials, {bool? isTestnet}) async {
56 checkIfExists(credentials.name);
59 - final password = generateWalletPassword();
60 - credentials.password = password;
57 +
58 + if (credentials.password == null) {
59 + credentials.password = generateWalletPassword();
60 + await keyService.saveWalletPassword(
61 + password: credentials.password!, walletName: credentials.name);
62 + }
63 +
64 if (_hasSeedPhraseLengthOption) {
65 credentials.seedPhraseLength = settingsStore.seedPhraseLength.value;
66 }
64 - await keyService.saveWalletPassword(password: password, walletName: credentials.name);
67 final wallet = await _service!.create(credentials, isTestnet: isTestnet);
68
69 if (wallet.type == WalletType.monero) {
@@ -94,9 +96,13 @@ class WalletCreationService {
96
97 Future<WalletBase> restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) async {
98 checkIfExists(credentials.name);
97 - final password = generateWalletPassword();
98 - credentials.password = password;
99 - await keyService.saveWalletPassword(password: password, walletName: credentials.name);
99 +
100 + if (credentials.password == null) {
101 + credentials.password = generateWalletPassword();
102 + await keyService.saveWalletPassword(
103 + password: credentials.password!, walletName: credentials.name);
104 + }
105 +
106 final wallet = await _service!.restoreFromKeys(credentials, isTestnet: isTestnet);
107
108 if (wallet.type == WalletType.monero) {
@@ -109,9 +115,13 @@ class WalletCreationService {
115
116 Future<WalletBase> restoreFromSeed(WalletCredentials credentials, {bool? isTestnet}) async {
117 checkIfExists(credentials.name);
112 - final password = generateWalletPassword();
113 - credentials.password = password;
114 - await keyService.saveWalletPassword(password: password, walletName: credentials.name);
118 +
119 + if (credentials.password == null) {
120 + credentials.password = generateWalletPassword();
121 + await keyService.saveWalletPassword(
122 + password: credentials.password!, walletName: credentials.name);
123 + }
124 +
125 final wallet = await _service!.restoreFromSeed(credentials, isTestnet: isTestnet);
126
127 if (wallet.type == WalletType.monero) {
lib/core/wallet_loading_service.dart
+10 -9
@@ -20,17 +20,18 @@ class WalletLoadingService {
20 final KeyService keyService;
21 final WalletService Function(WalletType type) walletServiceFactory;
22
23 - Future<void> renameWallet(WalletType type, String name, String newName) async {
23 + Future<void> renameWallet(WalletType type, String name, String newName,
24 + {String? password}) async {
25 final walletService = walletServiceFactory.call(type);
25 - final password = await keyService.getWalletPassword(walletName: name);
26 + final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
27
28 // Save the current wallet's password to the new wallet name's key
28 - await keyService.saveWalletPassword(walletName: newName, password: password);
29 + await keyService.saveWalletPassword(walletName: newName, password: walletPassword);
30 // Delete previous wallet name from keyService to keep only new wallet's name
31 // otherwise keeps duplicate (old and new names)
32 await keyService.deleteWalletPassword(walletName: name);
33
33 - await walletService.rename(name, password, newName);
34 + await walletService.rename(name, walletPassword, newName);
35
36 // set shared preferences flag based on previous wallet name
37 if (type == WalletType.monero) {
@@ -41,11 +42,11 @@ class WalletLoadingService {
42 }
43 }
44
44 - Future<WalletBase> load(WalletType type, String name) async {
45 + Future<WalletBase> load(WalletType type, String name, {String? password}) async {
46 try {
47 final walletService = walletServiceFactory.call(type);
47 - final password = await keyService.getWalletPassword(walletName: name);
48 - final wallet = await walletService.openWallet(name, password);
48 + final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
49 + final wallet = await walletService.openWallet(name, walletPassword);
50
51 if (type == WalletType.monero) {
52 await updateMoneroWalletPassword(wallet);
@@ -67,8 +68,8 @@ class WalletLoadingService {
68 for (var walletInfo in walletInfoSource.values) {
69 try {
70 final walletService = walletServiceFactory.call(walletInfo.type);
70 - final password = await keyService.getWalletPassword(walletName: walletInfo.name);
71 - final wallet = await walletService.openWallet(walletInfo.name, password);
71 + final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
72 + final wallet = await walletService.openWallet(walletInfo.name, walletPassword);
73
74 if (walletInfo.type == WalletType.monero) {
75 await updateMoneroWalletPassword(wallet);
lib/di.dart
+77 -9
@@ -30,6 +30,7 @@ import 'package:cake_wallet/entities/contact.dart';
30 import 'package:cake_wallet/entities/contact_record.dart';
31 import 'package:cake_wallet/entities/exchange_api_mode.dart';
32 import 'package:cake_wallet/entities/parse_address_from_domain.dart';
33 +import 'package:cake_wallet/entities/preferences_key.dart';
34 import 'package:cake_wallet/entities/qr_view_data.dart';
35 import 'package:cake_wallet/entities/template.dart';
36 import 'package:cake_wallet/entities/transaction_description.dart';
@@ -113,6 +114,8 @@ import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart';
114 import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart';
115 import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
116 import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
117 +import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
118 +import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart';
119 import 'package:cake_wallet/themes/theme_list.dart';
120 import 'package:cake_wallet/utils/device_info.dart';
121 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';
220 import 'package:cake_wallet/view_model/wallet_new_vm.dart';
221 import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
222 import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
223 +import 'package:cake_wallet/view_model/wallet_unlock_loadable_view_model.dart';
224 +import 'package:cake_wallet/view_model/wallet_unlock_verifiable_view_model.dart';
225 import 'package:cake_wallet/wownero/wownero.dart';
226 import 'package:cw_core/crypto_currency.dart';
227 import 'package:cw_core/receive_page_option.dart';
@@ -337,7 +342,6 @@ Future<void> setup({
342 WalletCreationService(
343 initialType: type,
344 keyService: getIt.get<KeyService>(),
340 - secureStorage: getIt.get<SecureStorage>(),
345 sharedPreferences: getIt.get<SharedPreferences>(),
346 settingsStore: getIt.get<SettingsStore>(),
347 walletInfoSource: _walletInfoSource));
@@ -357,6 +361,65 @@ Future<void> setup({
361 getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
362 type: type));
363
364 + getIt.registerFactoryParam<WalletUnlockPage, WalletUnlockArguments, bool>((args, closable) {
365 + return WalletUnlockPage(
366 + getIt.get<WalletUnlockLoadableViewModel>(param1: args),
367 + args.callback,
368 + args.authPasswordHandler,
369 + closable: closable);
370 + }, instanceName: 'wallet_unlock_loadable');
371 +
372 + getIt.registerFactory<WalletUnlockPage>(
373 + () => getIt.get<WalletUnlockPage>(
374 + param1: WalletUnlockArguments(
375 + callback: (bool successful, _) {
376 + if (successful) {
377 + final authStore = getIt.get<AuthenticationStore>();
378 + authStore.allowed();
379 + }}),
380 + param2: false,
381 + instanceName: 'wallet_unlock_loadable'),
382 + instanceName: 'wallet_password_login');
383 +
384 + getIt.registerFactoryParam<WalletUnlockPage, WalletUnlockArguments, bool>((args, closable) {
385 + return WalletUnlockPage(
386 + getIt.get<WalletUnlockVerifiableViewModel>(param1: args),
387 + args.callback,
388 + args.authPasswordHandler,
389 + closable: closable);
390 + }, instanceName: 'wallet_unlock_verifiable');
391 +
392 + getIt.registerFactoryParam<WalletUnlockLoadableViewModel, WalletUnlockArguments, void>((args, _) {
393 + final currentWalletName = getIt
394 + .get<SharedPreferences>()
395 + .getString(PreferencesKey.currentWalletName) ?? '';
396 + final currentWalletTypeRaw =
397 + getIt.get<SharedPreferences>()
398 + .getInt(PreferencesKey.currentWalletType) ?? 0;
399 + final currentWalletType = deserializeFromInt(currentWalletTypeRaw);
400 +
401 + return WalletUnlockLoadableViewModel(
402 + getIt.get<AppStore>(),
403 + getIt.get<WalletLoadingService>(),
404 + walletName: args.walletName ?? currentWalletName,
405 + walletType: args.walletType ?? currentWalletType);
406 + });
407 +
408 + getIt.registerFactoryParam<WalletUnlockVerifiableViewModel, WalletUnlockArguments, void>((args, _) {
409 + final currentWalletName = getIt
410 + .get<SharedPreferences>()
411 + .getString(PreferencesKey.currentWalletName) ?? '';
412 + final currentWalletTypeRaw =
413 + getIt.get<SharedPreferences>()
414 + .getInt(PreferencesKey.currentWalletType) ?? 0;
415 + final currentWalletType = deserializeFromInt(currentWalletTypeRaw);
416 +
417 + return WalletUnlockVerifiableViewModel(
418 + getIt.get<AppStore>(),
419 + walletName: args.walletName ?? currentWalletName,
420 + walletType: args.walletType ?? currentWalletType);
421 + });
422 +
423 getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
424 return WalletRestorationFromQRVM(getIt.get<AppStore>(),
425 getIt.get<WalletCreationService>(param1: type), _walletInfoSource, type);
@@ -907,23 +970,28 @@ Future<void> setup({
970 _walletInfoSource,
971 _unspentCoinsInfoSource,
972 getIt.get<SettingsStore>().silentPaymentsAlwaysScan,
973 + SettingsStoreBase.walletPasswordDirectInput,
974 );
975 case WalletType.litecoin:
912 - return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource);
976 + return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource,
977 + SettingsStoreBase.walletPasswordDirectInput);
978 case WalletType.ethereum:
914 - return ethereum!.createEthereumWalletService(_walletInfoSource);
979 + return ethereum!.createEthereumWalletService(
980 + _walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
981 case WalletType.bitcoinCash:
916 - return bitcoinCash!
917 - .createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource);
982 + return bitcoinCash!.createBitcoinCashWalletService(_walletInfoSource,
983 + _unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput);
984 case WalletType.nano:
985 case WalletType.banano:
920 - return nano!.createNanoWalletService(_walletInfoSource);
986 + return nano!.createNanoWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
987 case WalletType.polygon:
922 - return polygon!.createPolygonWalletService(_walletInfoSource);
988 + return polygon!.createPolygonWalletService(
989 + _walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
990 case WalletType.solana:
924 - return solana!.createSolanaWalletService(_walletInfoSource);
991 + return solana!.createSolanaWalletService(
992 + _walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
993 case WalletType.tron:
926 - return tron!.createTronWalletService(_walletInfoSource);
994 + return tron!.createTronWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
995 case WalletType.wownero:
996 return wownero!.createWowneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
997 case WalletType.none:
lib/entities/load_current_wallet.dart
+5 -2
@@ -6,7 +6,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
6 import 'package:cw_core/wallet_type.dart';
7 import 'package:cake_wallet/core/wallet_loading_service.dart';
8
9 -Future<void> loadCurrentWallet() async {
9 +Future<void> loadCurrentWallet({String? password}) async {
10 final appStore = getIt.get<AppStore>();
11 final name = getIt
12 .get<SharedPreferences>()
@@ -21,7 +21,10 @@ Future<void> loadCurrentWallet() async {
21
22 final type = deserializeFromInt(typeRaw);
23 final walletLoadingService = getIt.get<WalletLoadingService>();
24 - final wallet = await walletLoadingService.load(type, name);
24 + final wallet = await walletLoadingService.load(
25 + type,
26 + name,
27 + password: password);
28 await appStore.changeCurrentWallet(wallet);
29
30 getIt.get<BackgroundTasks>().registerSyncTask();
lib/ethereum/cw_ethereum.dart
+4 -3
@@ -4,15 +4,16 @@ class CWEthereum extends Ethereum {
4 @override
5 List<String> getEthereumWordList(String language) => EVMChainMnemonics.englishWordlist;
6
7 - WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource) =>
8 - EthereumWalletService(walletInfoSource, client: EthereumClient());
7 + WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
8 + EthereumWalletService(walletInfoSource, isDirect, client: EthereumClient());
9
10 @override
11 WalletCredentials createEthereumNewWalletCredentials({
12 required String name,
13 WalletInfo? walletInfo,
14 + String? password,
15 }) =>
15 - EVMChainNewWalletCredentials(name: name, walletInfo: walletInfo);
16 + EVMChainNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
17
18 @override
19 WalletCredentials createEthereumRestoreWalletFromSeedCredentials({
lib/main.dart
+2 -2
@@ -48,6 +48,7 @@ final rootKey = GlobalKey<RootState>();
48 final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
49
50 Future<void> main() async {
51 +
52 bool isAppRunning = false;
53 await runZonedGuarded(() async {
54 WidgetsFlutterBinding.ensureInitialized();
@@ -170,7 +171,6 @@ Future<void> initializeAppConfigs() async {
171 }
172
173 final secureStorage = secureStorageShared;
173 -
174 final transactionDescriptionsBoxKey =
175 await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
176 final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
@@ -247,8 +247,8 @@ Future<void> initialSetup(
247 ordersSource: ordersSource,
248 anonpayInvoiceInfoSource: anonpayInvoiceInfo,
249 unspentCoinsInfoSource: unspentCoinsInfoSource,
250 - secureStorage: secureStorage,
250 navigatorKey: navigatorKey,
251 + secureStorage: secureStorage,
252 );
253 await bootstrap(navigatorKey);
254 monero?.onStartup();
lib/nano/cw_nano.dart
+2 -2
@@ -75,8 +75,8 @@ class CWNano extends Nano {
75 }
76
77 @override
78 - WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource) {
79 - return NanoWalletService(walletInfoSource);
78 + WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) {
79 + return NanoWalletService(walletInfoSource, isDirect);
80 }
81
82 @override
lib/polygon/cw_polygon.dart
+4 -3
@@ -4,15 +4,16 @@ class CWPolygon extends Polygon {
4 @override
5 List<String> getPolygonWordList(String language) => EVMChainMnemonics.englishWordlist;
6
7 - WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource) =>
8 - PolygonWalletService(walletInfoSource, client: PolygonClient());
7 + WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
8 + PolygonWalletService(walletInfoSource, isDirect, client: PolygonClient());
9
10 @override
11 WalletCredentials createPolygonNewWalletCredentials({
12 required String name,
13 WalletInfo? walletInfo,
14 + String? password
15 }) =>
15 - EVMChainNewWalletCredentials(name: name, walletInfo: walletInfo);
16 + EVMChainNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
17
18 @override
19 WalletCredentials createPolygonRestoreWalletFromSeedCredentials({
lib/reactions/on_authentication_state_change.dart
+2 -1
@@ -2,6 +2,7 @@ import 'dart:async';
2
3 import 'package:cake_wallet/routes.dart';
4 import 'package:cake_wallet/utils/exception_handler.dart';
5 +import 'package:cake_wallet/store/settings_store.dart';
6 import 'package:flutter/widgets.dart';
7 import 'package:mobx/mobx.dart';
8 import 'package:cake_wallet/entities/load_current_wallet.dart';
@@ -23,7 +24,7 @@ void startAuthenticationStateChange(
24 _onAuthenticationStateChange ??= autorun((_) async {
25 final state = authenticationStore.state;
26
26 - if (state == AuthenticationState.installed) {
27 + if (state == AuthenticationState.installed && !SettingsStoreBase.walletPasswordDirectInput) {
28 try {
29 await loadCurrentWallet();
30 } catch (error, stack) {
lib/router.dart
+62 -17
@@ -90,7 +90,11 @@ import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
90 import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
91 import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
92 import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
93 +import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart';
94 import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
95 +import 'package:cake_wallet/store/settings_store.dart';
96 +import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
97 +import 'package:cake_wallet/store/settings_store.dart';
98 import 'package:cake_wallet/utils/payment_request.dart';
99 import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
100 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
@@ -125,6 +129,14 @@ Route<dynamic> createRoute(RouteSettings settings) {
129 return MaterialPageRoute<void>(builder: (_) => createWelcomePage());
130
131 case Routes.newWalletFromWelcome:
132 + if (SettingsStoreBase.walletPasswordDirectInput) {
133 + if (availableWalletTypes.length == 1) {
134 + return createRoute(RouteSettings(name: Routes.newWallet, arguments: availableWalletTypes.first));
135 + } else {
136 + return createRoute(RouteSettings(name: Routes.newWalletType));
137 + }
138 + }
139 +
140 return CupertinoPageRoute<void>(
141 builder: (_) =>
142 getIt.get<SetupPinCodePage>(param1: (PinCodeState<PinCodeWidget> context, dynamic _) {
@@ -176,6 +188,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
188 param2: [false, false]));
189
190 case Routes.restoreOptions:
191 + if (SettingsStoreBase.walletPasswordDirectInput) {
192 + return createRoute(RouteSettings(name: Routes.restoreWalletType));
193 + }
194 +
195 final isNewInstall = settings.arguments as bool;
196 return CupertinoPageRoute<void>(
197 fullscreenDialog: true,
@@ -328,8 +344,16 @@ Route<dynamic> createRoute(RouteSettings settings) {
344 case Routes.auth:
345 return MaterialPageRoute<void>(
346 fullscreenDialog: true,
331 - builder: (_) => getIt.get<AuthPage>(
332 - param1: settings.arguments as OnAuthenticationFinished, param2: true));
347 + builder: (_)
348 + => SettingsStoreBase.walletPasswordDirectInput
349 + ? getIt.get<WalletUnlockPage>(
350 + param1: WalletUnlockArguments(
351 + callback: settings.arguments as OnAuthenticationFinished),
352 + instanceName: 'wallet_unlock_verifiable',
353 + param2: true)
354 + : getIt.get<AuthPage>(
355 + param1: settings.arguments as OnAuthenticationFinished,
356 + param2: true));
357
358 case Routes.totpAuthCodePage:
359 final args = settings.arguments as TotpAuthArgumentsModel;
@@ -340,24 +364,32 @@ Route<dynamic> createRoute(RouteSettings settings) {
364 ),
365 );
366
343 - case Routes.login:
344 - return CupertinoPageRoute<void>(
345 - builder: (context) => WillPopScope(
346 - child: getIt.get<AuthPage>(instanceName: 'login'),
347 - onWillPop: () async =>
348 - // FIX-ME: Additional check does it works correctly
349 - (await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ??
350 - false),
351 - ),
352 - fullscreenDialog: true);
367 + case Routes.walletUnlockLoadable:
368 + return MaterialPageRoute<void>(
369 + fullscreenDialog: true,
370 + builder: (_)
371 + => getIt.get<WalletUnlockPage>(
372 + param1: settings.arguments as WalletUnlockArguments,
373 + instanceName: 'wallet_unlock_loadable',
374 + param2: true));
375
376 case Routes.unlock:
377 return MaterialPageRoute<void>(
378 fullscreenDialog: true,
357 - builder: (_) => WillPopScope(
358 - child: getIt.get<AuthPage>(
359 - param1: settings.arguments as OnAuthenticationFinished, param2: false),
360 - onWillPop: () async => false));
379 + builder: (_)
380 + => SettingsStoreBase.walletPasswordDirectInput
381 + ? WillPopScope(
382 + child: getIt.get<WalletUnlockPage>(
383 + param1: WalletUnlockArguments(
384 + callback: settings.arguments as OnAuthenticationFinished),
385 + param2: false,
386 + instanceName: 'wallet_unlock_verifiable'),
387 + onWillPop: () async => false)
388 + : WillPopScope(
389 + child: getIt.get<AuthPage>(
390 + param1: settings.arguments as OnAuthenticationFinished,
391 + param2: false),
392 + onWillPop: () async => false));
393
394 case Routes.silentPaymentsSettings:
395 return CupertinoPageRoute<void>(
@@ -397,6 +429,17 @@ Route<dynamic> createRoute(RouteSettings settings) {
429 builder: (_) => getIt.get<NodeCreateOrEditPage>(
430 param1: args?['editingNode'] as Node?, param2: args?['isSelected'] as bool?));
431
432 + case Routes.login:
433 + return CupertinoPageRoute<void>(
434 + builder: (context) => WillPopScope(
435 + child: SettingsStoreBase.walletPasswordDirectInput
436 + ? getIt.get<WalletUnlockPage>(instanceName: 'wallet_password_login')
437 + : getIt.get<AuthPage>(instanceName: 'login'),
438 + onWillPop: () async =>
439 + // FIX-ME: Additional check does it works correctly
440 + (await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ?? false)),
441 + fullscreenDialog: true);
442 +
443 case Routes.newPowNode:
444 final args = settings.arguments as Map<String, dynamic>?;
445 return CupertinoPageRoute<void>(
@@ -486,7 +529,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
529 fullscreenDialog: true, builder: (_) => getIt.get<RestoreFromBackupPage>());
530
531 case Routes.support:
489 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<SupportPage>());
532 + return CupertinoPageRoute<void>(
533 + fullscreenDialog: true,
534 + builder: (_) => getIt.get<SupportPage>());
535
536 case Routes.supportLiveChat:
537 return CupertinoPageRoute<void>(builder: (_) => getIt.get<SupportChatPage>());
lib/routes.dart
+2
@@ -82,6 +82,8 @@ class Routes {
82 static const otherSettingsPage = '/other_settings_page';
83 static const advancedPrivacySettings = '/advanced_privacy_settings';
84 static const sweepingWalletPage = '/sweeping_wallet_page';
85 + static const walletPasswordUnlock = '/wallet_password_unlock';
86 + static const walletUnlockLoadable = '/wallet_unlock_loadable';
87 static const anonPayInvoicePage = '/anon_pay_invoice_page';
88 static const anonPayReceivePage = '/anon_pay_receive_page';
89 static const anonPayDetailsPage = '/anon_pay_details_page';
lib/solana/cw_solana.dart
+4 -3
@@ -4,15 +4,16 @@ class CWSolana extends Solana {
4 @override
5 List<String> getSolanaWordList(String language) => SolanaMnemonics.englishWordlist;
6
7 - WalletService createSolanaWalletService(Box<WalletInfo> walletInfoSource) =>
8 - SolanaWalletService(walletInfoSource);
7 + WalletService createSolanaWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
8 + SolanaWalletService(walletInfoSource, isDirect);
9
10 @override
11 WalletCredentials createSolanaNewWalletCredentials({
12 required String name,
13 WalletInfo? walletInfo,
14 + String? password,
15 }) =>
15 - SolanaNewWalletCredentials(name: name, walletInfo: walletInfo);
16 + SolanaNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
17
18 @override
19 WalletCredentials createSolanaRestoreWalletFromSeedCredentials({
lib/src/screens/auth/auth_page.dart
+11 -4
@@ -12,6 +12,12 @@ import 'package:cake_wallet/core/execution_state.dart';
12
13 typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
14
15 +abstract class AuthPageState<T extends StatefulWidget> extends State<T> {
16 + void changeProcessText(String text);
17 + void hideProgressText();
18 + Future<void> close({String? route, dynamic arguments});
19 +}
20 +
21 class AuthPage extends StatefulWidget {
22 AuthPage(this.authViewModel,
23 {required this.onAuthenticationFinished,
@@ -22,10 +28,10 @@ class AuthPage extends StatefulWidget {
28 final bool closable;
29
30 @override
25 - AuthPageState createState() => AuthPageState();
31 + AuthPageState createState() => AuthPagePinCodeStateImpl();
32 }
33
28 -class AuthPageState extends State<AuthPage> {
34 +class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
35 final _key = GlobalKey<ScaffoldState>();
36 final _pinCodeKey = GlobalKey<PinCodeState>();
37 final _backArrowImageDarkTheme =
@@ -55,8 +61,6 @@ class AuthPageState extends State<AuthPage> {
61 }
62
63 if (state is FailureState) {
58 - print('X');
59 - print(state.error);
64 WidgetsBinding.instance.addPostFrameCallback((_) async {
65 _pinCodeKey.currentState?.clear();
66 dismissFlushBar(_authBar);
@@ -95,17 +99,20 @@ class AuthPageState extends State<AuthPage> {
99 super.dispose();
100 }
101
102 + @override
103 void changeProcessText(String text) {
104 dismissFlushBar(_authBar);
105 _progressBar = createBar<void>(text, duration: null)
106 ..show(_key.currentContext!);
107 }
108
109 + @override
110 void hideProgressText() {
111 dismissFlushBar(_progressBar);
112 _progressBar = null;
113 }
114
115 + @override
116 Future<void> close({String? route, dynamic arguments}) async {
117 if (_key.currentContext == null) {
118 throw Exception('Key context is null. Should be not happened');
lib/src/screens/dashboard/desktop_widgets/desktop_action_button.dart
+42 -36
@@ -2,6 +2,9 @@ import 'package:auto_size_text/auto_size_text.dart';
2 import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
3 import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
4 import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
5 +import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
6 +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
7 +import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
8 import 'package:flutter/material.dart';
9
10 class DesktopActionButton extends StatelessWidget {
@@ -24,45 +27,48 @@ class DesktopActionButton extends StatelessWidget {
27
28 @override
29 Widget build(BuildContext context) {
27 - return Padding(
28 - padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
29 - child: GestureDetector(
30 - onTap: onTap,
31 - child: Container(
32 - padding: EdgeInsets.symmetric(vertical: 25),
33 - width: double.infinity,
34 - decoration: BoxDecoration(
35 - borderRadius: BorderRadius.circular(15.0),
36 - color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
37 - ),
38 - child: Center(
39 - child: Row(
40 - mainAxisSize: MainAxisSize.min,
41 - children: [
42 - Image.asset(
43 - image,
44 - height: 30,
45 - width: 30,
46 - color: isEnabled
47 - ? Theme.of(context).extension<DashboardPageTheme>()!.textColor
48 - : Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
49 - ),
50 - const SizedBox(width: 10),
51 - AutoSizeText(
52 - title,
53 - style: TextStyle(
54 - fontSize: 24,
55 - fontFamily: 'Lato',
56 - fontWeight: FontWeight.bold,
30 + return MouseRegion(
31 + cursor: SystemMouseCursors.click,
32 + child: Padding(
33 + padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
34 + child: GestureDetector(
35 + onTap: onTap,
36 + child: Container(
37 + padding: EdgeInsets.symmetric(vertical: 25),
38 + width: double.infinity,
39 + decoration: BoxDecoration(
40 + borderRadius: BorderRadius.circular(15.0),
41 + color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
42 + ),
43 + child: Center(
44 + child: Row(
45 + mainAxisSize: MainAxisSize.min,
46 + children: [
47 + Image.asset(
48 + image,
49 + height: 30,
50 + width: 30,
51 color: isEnabled
52 ? Theme.of(context).extension<DashboardPageTheme>()!.textColor
59 - : null,
60 - height: 1,
53 + : Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
54 ),
62 - maxLines: 1,
63 - textAlign: TextAlign.center,
64 - )
65 - ],
55 + const SizedBox(width: 10),
56 + AutoSizeText(
57 + title,
58 + style: TextStyle(
59 + fontSize: 24,
60 + fontFamily: 'Lato',
61 + fontWeight: FontWeight.bold,
62 + color: isEnabled
63 + ? Theme.of(context).extension<DashboardPageTheme>()!.textColor
64 + : null,
65 + height: 1,
66 + ),
67 + maxLines: 1,
68 + textAlign: TextAlign.center,
69 + )
70 + ],
71 + ),
72 ),
73 ),
74 ),
lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart
+22 -6
@@ -4,9 +4,12 @@ import 'package:cake_wallet/core/auth_service.dart';
4 import 'package:cake_wallet/entities/desktop_dropdown_item.dart';
5 import 'package:cake_wallet/generated/i18n.dart';
6 import 'package:cake_wallet/routes.dart';
7 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
8 import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/dropdown_item_widget.dart';
9 +import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
10 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
11 import 'package:cake_wallet/themes/extensions/menu_theme.dart';
12 +import 'package:cake_wallet/store/settings_store.dart';
13 import 'package:cake_wallet/utils/show_bar.dart';
14 import 'package:cake_wallet/utils/show_pop_up.dart';
15 import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
@@ -176,12 +179,25 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
179 }
180
181 Future<void> _loadWallet(WalletListItem wallet) async {
179 - widget._authService.authenticateAction(
180 - context,
181 - onAuthSuccess: (isAuthenticatedSuccessfully) async {
182 - if (!isAuthenticatedSuccessfully) {
183 - return;
184 - }
182 + if (SettingsStoreBase.walletPasswordDirectInput) {
183 + Navigator.of(context).pushNamed(
184 + Routes.walletUnlockLoadable,
185 + arguments: WalletUnlockArguments(
186 + callback: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
187 + if (isAuthenticatedSuccessfully) {
188 + auth.close();
189 + setState(() {});
190 + }
191 + }, walletName: wallet.name,
192 + walletType: wallet.type));
193 + return;
194 + }
195 +
196 + widget._authService.authenticateAction(context,
197 + onAuthSuccess: (isAuthenticatedSuccessfully) async {
198 + if (!isAuthenticatedSuccessfully) {
199 + return;
200 + }
201
202 try {
203 if (context.mounted) {
lib/src/screens/new_wallet/new_wallet_page.dart
+86 -8
@@ -68,14 +68,19 @@ class _WalletNameFormState extends State<WalletNameForm> {
68 _WalletNameFormState(this._walletNewVM)
69 : _formKey = GlobalKey<FormState>(),
70 _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>(),
71 - _controller = TextEditingController();
71 + _nameController = TextEditingController(),
72 + _passwordController = _walletNewVM.hasWalletPassword ? TextEditingController() : null,
73 + _repeatedPasswordController =
74 + _walletNewVM.hasWalletPassword ? TextEditingController() : null;
75
76 static const aspectRatioImage = 1.22;
77
78 final GlobalKey<FormState> _formKey;
79 final GlobalKey<SeedLanguageSelectorState> _languageSelectorKey;
80 final WalletNewVM _walletNewVM;
78 - final TextEditingController _controller;
81 + final TextEditingController _nameController;
82 + final TextEditingController? _passwordController;
83 + final TextEditingController? _repeatedPasswordController;
84 ReactionDisposer? _stateReaction;
85
86 @override
@@ -130,12 +135,11 @@ class _WalletNameFormState extends State<WalletNameForm> {
135 padding: EdgeInsets.only(top: 24),
136 child: Form(
137 key: _formKey,
133 - child: Stack(
134 - alignment: Alignment.centerRight,
138 + child: Column(
139 children: [
140 TextFormField(
141 onChanged: (value) => _walletNewVM.name = value,
138 - controller: _controller,
142 + controller: _nameController,
143 textAlign: TextAlign.center,
144 style: TextStyle(
145 fontSize: 20.0,
@@ -169,10 +173,10 @@ class _WalletNameFormState extends State<WalletNameForm> {
173 FocusManager.instance.primaryFocus?.unfocus();
174
175 setState(() {
172 - _controller.text = rName;
176 + _nameController.text = rName;
177 _walletNewVM.name = rName;
174 - _controller.selection = TextSelection.fromPosition(
175 - TextPosition(offset: _controller.text.length));
178 + _nameController.selection = TextSelection.fromPosition(
179 + TextPosition(offset: _nameController.text.length));
180 });
181 },
182 icon: Container(
@@ -195,6 +199,80 @@ class _WalletNameFormState extends State<WalletNameForm> {
199 ),
200 validator: WalletNameValidator(),
201 ),
202 + if (_walletNewVM.hasWalletPassword) ...[
203 + TextFormField(
204 + onChanged: (value) => _walletNewVM.walletPassword = value,
205 + controller: _passwordController,
206 + textAlign: TextAlign.center,
207 + obscureText: true,
208 + style: TextStyle(
209 + fontSize: 20.0,
210 + fontWeight: FontWeight.w600,
211 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
212 + ),
213 + decoration: InputDecoration(
214 + hintStyle: TextStyle(
215 + fontSize: 18.0,
216 + fontWeight: FontWeight.w500,
217 + color:
218 + Theme.of(context).extension<NewWalletTheme>()!.hintTextColor,
219 + ),
220 + hintText: S.of(context).password,
221 + focusedBorder: UnderlineInputBorder(
222 + borderSide: BorderSide(
223 + color: Theme.of(context)
224 + .extension<NewWalletTheme>()!
225 + .underlineColor,
226 + width: 1.0,
227 + ),
228 + ),
229 + enabledBorder: UnderlineInputBorder(
230 + borderSide: BorderSide(
231 + color: Theme.of(context)
232 + .extension<NewWalletTheme>()!
233 + .underlineColor,
234 + width: 1.0,
235 + ),
236 + ),
237 + ),
238 + ),
239 + TextFormField(
240 + onChanged: (value) => _walletNewVM.repeatedWalletPassword = value,
241 + controller: _repeatedPasswordController,
242 + textAlign: TextAlign.center,
243 + obscureText: true,
244 + style: TextStyle(
245 + fontSize: 20.0,
246 + fontWeight: FontWeight.w600,
247 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
248 + ),
249 + decoration: InputDecoration(
250 + hintStyle: TextStyle(
251 + fontSize: 18.0,
252 + fontWeight: FontWeight.w500,
253 + color:
254 + Theme.of(context).extension<NewWalletTheme>()!.hintTextColor,
255 + ),
256 + hintText: S.of(context).repeat_wallet_password,
257 + focusedBorder: UnderlineInputBorder(
258 + borderSide: BorderSide(
259 + color: Theme.of(context)
260 + .extension<NewWalletTheme>()!
261 + .underlineColor,
262 + width: 1.0,
263 + ),
264 + ),
265 + enabledBorder: UnderlineInputBorder(
266 + borderSide: BorderSide(
267 + color: Theme.of(context)
268 + .extension<NewWalletTheme>()!
269 + .underlineColor,
270 + width: 1.0,
271 + ),
272 + ),
273 + ),
274 + ),
275 + ],
276 ],
277 ),
278 ),
lib/src/screens/restore/wallet_restore_from_keys_form.dart
+46 -3
@@ -16,6 +16,9 @@ class WalletRestoreFromKeysFrom extends StatefulWidget {
16 required this.onPrivateKeyChange,
17 required this.displayPrivateKeyField,
18 required this.onHeightOrDateEntered,
19 + required this.displayWalletPassword,
20 + required this.onRepeatedPasswordChange,
21 + this.onPasswordChange,
22 Key? key,
23 }) : super(key: key);
24
@@ -23,13 +26,17 @@ class WalletRestoreFromKeysFrom extends StatefulWidget {
26 final WalletRestoreViewModel walletRestoreViewModel;
27 final void Function(String)? onPrivateKeyChange;
28 final bool displayPrivateKeyField;
29 + final bool displayWalletPassword;
30 + final void Function(String)? onPasswordChange;
31 + final void Function(String)? onRepeatedPasswordChange;
32
33 @override
28 - WalletRestoreFromKeysFromState createState() => WalletRestoreFromKeysFromState();
34 + WalletRestoreFromKeysFromState createState() =>
35 + WalletRestoreFromKeysFromState(displayWalletPassword: displayWalletPassword);
36 }
37
38 class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
32 - WalletRestoreFromKeysFromState()
39 + WalletRestoreFromKeysFromState({required bool displayWalletPassword})
40 : formKey = GlobalKey<FormState>(),
41 blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
42 nameController = TextEditingController(),
@@ -37,7 +44,9 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
44 viewKeyController = TextEditingController(),
45 spendKeyController = TextEditingController(),
46 privateKeyController = TextEditingController(),
40 - nameTextEditingController = TextEditingController();
47 + nameTextEditingController = TextEditingController(),
48 + passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
49 + repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null;
50
51 final GlobalKey<FormState> formKey;
52 final GlobalKey<BlockchainHeightState> blockchainHeightKey;
@@ -47,9 +56,22 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
56 final TextEditingController spendKeyController;
57 final TextEditingController nameTextEditingController;
58 final TextEditingController privateKeyController;
59 + final TextEditingController? passwordTextEditingController;
60 + final TextEditingController? repeatedPasswordTextEditingController;
61 + void Function()? passwordListener;
62 + void Function()? repeatedPasswordListener;
63
64 @override
65 void initState() {
66 + if (passwordTextEditingController != null) {
67 + passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text);
68 + passwordTextEditingController?.addListener(passwordListener!);
69 + }
70 +
71 + if (repeatedPasswordTextEditingController != null) {
72 + repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text);
73 + repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!);
74 + }
75 super.initState();
76
77 privateKeyController.addListener(() {
@@ -67,6 +89,14 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
89 viewKeyController.dispose();
90 privateKeyController.dispose();
91 spendKeyController.dispose();
92 + passwordTextEditingController?.dispose();
93 + if (passwordListener != null) {
94 + passwordTextEditingController?.removeListener(passwordListener!);
95 + }
96 +
97 + if (repeatedPasswordListener != null) {
98 + repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!);
99 + }
100 super.dispose();
101 }
102
@@ -114,6 +144,19 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
144 ),
145 ],
146 ),
147 + if (widget.displayWalletPassword)
148 + ...[Container(
149 + padding: EdgeInsets.only(top: 20.0),
150 + child: BaseTextFormField(
151 + controller: passwordTextEditingController,
152 + hintText: S.of(context).password,
153 + obscureText: true)),
154 + Container(
155 + padding: EdgeInsets.only(top: 20.0),
156 + child: BaseTextFormField(
157 + controller: repeatedPasswordTextEditingController,
158 + hintText: S.of(context).repeat_wallet_password,
159 + obscureText: true))],
160 Container(height: 20),
161 _restoreFromKeysFormFields(),
162 ],
lib/src/screens/restore/wallet_restore_from_seed_form.dart
+45 -4
@@ -22,34 +22,43 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
22 required this.displayBlockHeightSelector,
23 required this.displayPassphrase,
24 required this.type,
25 + required this.displayWalletPassword,
26 required this.seedTypeViewModel,
27 this.blockHeightFocusNode,
28 this.onHeightOrDateEntered,
29 this.onSeedChange,
29 - this.onLanguageChange})
30 + this.onLanguageChange,
31 + this.onPasswordChange,
32 + this.onRepeatedPasswordChange})
33 : super(key: key);
34
35 final WalletType type;
36 final bool displayLanguageSelector;
37 final bool displayBlockHeightSelector;
38 + final bool displayWalletPassword;
39 final bool displayPassphrase;
40 final SeedTypeViewModel seedTypeViewModel;
41 final FocusNode? blockHeightFocusNode;
42 final Function(bool)? onHeightOrDateEntered;
43 final void Function(String)? onSeedChange;
44 final void Function(String)? onLanguageChange;
45 + final void Function(String)? onPasswordChange;
46 + final void Function(String)? onRepeatedPasswordChange;
47
48 @override
43 - WalletRestoreFromSeedFormState createState() => WalletRestoreFromSeedFormState('English');
49 + WalletRestoreFromSeedFormState createState() =>
50 + WalletRestoreFromSeedFormState('English', displayWalletPassword: displayWalletPassword);
51 }
52
53 class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
47 - WalletRestoreFromSeedFormState(this.language)
54 + WalletRestoreFromSeedFormState(this.language, {required bool displayWalletPassword})
55 : seedWidgetStateKey = GlobalKey<SeedWidgetState>(),
56 blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
57 formKey = GlobalKey<FormState>(),
58 languageController = TextEditingController(),
59 nameTextEditingController = TextEditingController(),
60 + passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
61 + repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null,
62 passphraseController = TextEditingController(),
63 seedTypeController = TextEditingController();
64
@@ -57,16 +66,30 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
66 final GlobalKey<BlockchainHeightState> blockchainHeightKey;
67 final TextEditingController languageController;
68 final TextEditingController nameTextEditingController;
69 + final TextEditingController? passwordTextEditingController;
70 + final TextEditingController? repeatedPasswordTextEditingController;
71 final TextEditingController seedTypeController;
72 final TextEditingController passphraseController;
73 final GlobalKey<FormState> formKey;
74 late ReactionDisposer moneroSeedTypeReaction;
75 String language;
76 + void Function()? passwordListener;
77 + void Function()? repeatedPasswordListener;
78
79 @override
80 void initState() {
81 _setSeedType(widget.seedTypeViewModel.moneroSeedType);
82 _setLanguageLabel(language);
83 +
84 + if (passwordTextEditingController != null) {
85 + passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text);
86 + passwordTextEditingController?.addListener(passwordListener!);
87 + }
88 +
89 + if (repeatedPasswordTextEditingController != null) {
90 + repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text);
91 + repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!);
92 + }
93 moneroSeedTypeReaction =
94 reaction((_) => widget.seedTypeViewModel.moneroSeedType, (SeedType item) {
95 _setSeedType(item);
@@ -78,8 +101,16 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
101
102 @override
103 void dispose() {
81 - super.dispose();
104 moneroSeedTypeReaction();
105 +
106 + if (passwordListener != null) {
107 + passwordTextEditingController?.removeListener(passwordListener!);
108 + }
109 +
110 + if (repeatedPasswordListener != null) {
111 + repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!);
112 + }
113 + super.dispose();
114 }
115
116 void onSeedChange(String seed) {
@@ -177,6 +208,16 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
208 ),
209 ),
210 ),
211 + if (widget.displayWalletPassword)
212 + ...[BaseTextFormField(
213 + controller: passwordTextEditingController,
214 + hintText: S.of(context).password,
215 + obscureText: true),
216 + BaseTextFormField(
217 + controller: repeatedPasswordTextEditingController,
218 + hintText: S.of(context).repeat_wallet_password,
219 + obscureText: true)],
220 + if (widget.displayLanguageSelector)
221 if (!seedTypeController.value.text.contains("14") && widget.displayLanguageSelector)
222 GestureDetector(
223 onTap: () async {
lib/src/screens/restore/wallet_restore_page.dart
+9 -1
@@ -53,7 +53,10 @@ class WalletRestorePage extends BasePage {
53 onLanguageChange: (String language) {
54 final isPolyseed = language.startsWith("POLYSEED_");
55 _validateOnChange(isPolyseed: isPolyseed);
56 - }));
56 + },
57 + displayWalletPassword: walletRestoreViewModel.hasWalletPassword,
58 + onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password,
59 + onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword));
60 break;
61 case WalletRestoreMode.keys:
62 _pages.add(WalletRestoreFromKeysFrom(
@@ -66,6 +69,9 @@ class WalletRestorePage extends BasePage {
69 }
70 },
71 displayPrivateKeyField: walletRestoreViewModel.hasRestoreFromPrivateKey,
72 + displayWalletPassword: walletRestoreViewModel.hasWalletPassword,
73 + onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password,
74 + onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword,
75 onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value));
76 break;
77 default:
@@ -127,6 +133,8 @@ class WalletRestorePage extends BasePage {
133
134 reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode) {
135 walletRestoreViewModel.isButtonEnabled = false;
136 + walletRestoreViewModel.walletPassword = null;
137 + walletRestoreViewModel.repeatedWalletPassword = null;
138
139 walletRestoreFromSeedFormKey
140 .currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
lib/src/screens/root/root.dart
+1
@@ -1,4 +1,5 @@
1 import 'dart:async';
2 +import 'dart:io';
3 import 'package:cake_wallet/core/auth_service.dart';
4 import 'package:cake_wallet/core/totp_request_details.dart';
5 import 'package:cake_wallet/utils/device_info.dart';
lib/src/screens/settings/security_backup_page.dart
+10 -9
@@ -10,6 +10,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arro
10 import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
11 import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
12 import 'package:cake_wallet/utils/device_info.dart';
13 +import 'package:cake_wallet/store/settings_store.dart';
14 import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
15 import 'package:flutter/material.dart';
16 import 'package:flutter_mobx/flutter_mobx.dart';
@@ -41,15 +42,16 @@ class SecurityBackupPage extends BasePage {
42 _securitySettingsViewModel.shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
43 ),
44 ),
44 - SettingsCellWithArrow(
45 - title: S.current.create_backup,
46 - handler: (_) => _authService.authenticateAction(
47 - context,
48 - route: Routes.backup,
49 - conditionToDetermineIfToUse2FA: _securitySettingsViewModel
50 - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
45 + if (!SettingsStoreBase.walletPasswordDirectInput)
46 + SettingsCellWithArrow(
47 + title: S.current.create_backup,
48 + handler: (_) => _authService.authenticateAction(
49 + context,
50 + route: Routes.backup,
51 + conditionToDetermineIfToUse2FA: _securitySettingsViewModel
52 + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
53 + ),
54 ),
52 - ),
55 SettingsCellWithArrow(
56 title: S.current.settings_change_pin,
57 handler: (_) => _authService.authenticateAction(
@@ -119,6 +121,5 @@ class SecurityBackupPage extends BasePage {
121 ],
122 ),
123 );
122 -
124 }
125 }
lib/src/screens/wallet/wallet_edit_page.dart
+42 -7
@@ -4,6 +4,12 @@ import 'package:cake_wallet/core/wallet_name_validator.dart';
4 import 'package:cake_wallet/palette.dart';
5 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
6 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
7 +import 'package:cake_wallet/routes.dart';
8 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
9 +import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
10 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
11 +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
12 +import 'package:cake_wallet/store/settings_store.dart';
13 import 'package:cake_wallet/utils/show_bar.dart';
14 import 'package:cake_wallet/utils/show_pop_up.dart';
15 import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
@@ -94,9 +100,38 @@ class WalletEditPage extends BasePage {
100 );
101 } else {
102 try {
97 - await walletEditViewModel.changeName(editingWallet);
98 - Navigator.of(context).pop();
99 - walletEditViewModel.resetState();
103 + bool confirmed = false;
104 +
105 + if (SettingsStoreBase
106 + .walletPasswordDirectInput) {
107 + await Navigator.of(context).pushNamed(
108 + Routes.walletUnlockLoadable,
109 + arguments: WalletUnlockArguments(
110 + authPasswordHandler:
111 + (String password) async {
112 + await walletEditViewModel
113 + .changeName(editingWallet,
114 + password: password);
115 + },
116 + callback: (bool
117 + isAuthenticatedSuccessfully,
118 + AuthPageState auth) async {
119 + if (isAuthenticatedSuccessfully) {
120 + auth.close();
121 + confirmed = true;
122 + }
123 + },
124 + walletName: editingWallet.name,
125 + walletType: editingWallet.type));
126 + } else {
127 + await walletEditViewModel.changeName(editingWallet);
128 + confirmed = true;
129 + }
130 +
131 + if (confirmed) {
132 + Navigator.of(context).pop();
133 + walletEditViewModel.resetState();
134 + }
135 } catch (e) {}
136 }
137 }
@@ -120,11 +155,11 @@ class WalletEditPage extends BasePage {
155
156 Future<void> _removeWallet(BuildContext context) async {
157 authService.authenticateAction(context, onAuthSuccess: (isAuthenticatedSuccessfully) async {
123 - if (!isAuthenticatedSuccessfully) {
124 - return;
125 - }
158 + if (!isAuthenticatedSuccessfully) {
159 + return;
160 + }
161
127 - _onSuccessfulAuth(context);
162 + _onSuccessfulAuth(context);
163 },
164 conditionToDetermineIfToUse2FA: false,
165 );
lib/src/screens/wallet_list/wallet_list_page.dart
+17
@@ -1,7 +1,10 @@
1 import 'package:cake_wallet/entities/wallet_list_order_types.dart';
2 import 'package:cake_wallet/src/screens/dashboard/widgets/filter_list_widget.dart';
3 import 'package:cake_wallet/src/screens/wallet_list/filtered_list.dart';
4 +import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
5 +import 'package:cake_wallet/store/settings_store.dart';
6 import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
7 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
8 import 'package:cake_wallet/core/auth_service.dart';
9 import 'package:cake_wallet/themes/extensions/filter_theme.dart';
10 import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
@@ -336,6 +339,20 @@ class WalletListBodyState extends State<WalletListBody> {
339 }
340
341 Future<void> _loadWallet(WalletListItem wallet) async {
342 + if (SettingsStoreBase.walletPasswordDirectInput) {
343 + Navigator.of(context).pushNamed(
344 + Routes.walletUnlockLoadable,
345 + arguments: WalletUnlockArguments(
346 + callback: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
347 + if (isAuthenticatedSuccessfully) {
348 + auth.close();
349 + setState(() {});
350 + }
351 + }, walletName: wallet.name,
352 + walletType: wallet.type));
353 + return;
354 + }
355 +
356 await widget.authService.authenticateAction(
357 context,
358 onAuthSuccess: (isAuthenticatedSuccessfully) async {
lib/src/screens/wallet_unlock/wallet_unlock_arguments.dart new
+17
@@ -0,0 +1,17 @@
1 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
2 +import 'package:cw_core/wallet_type.dart';
3 +
4 +typedef AuthPasswordHandler = Future<void> Function(String);
5 +
6 +class WalletUnlockArguments {
7 + WalletUnlockArguments(
8 + {required this.callback,
9 + this.walletName,
10 + this.walletType,
11 + this.authPasswordHandler});
12 +
13 + final OnAuthenticationFinished callback;
14 + final AuthPasswordHandler? authPasswordHandler;
15 + final String? walletName;
16 + final WalletType? walletType;
17 +}
lib/src/screens/wallet_unlock/wallet_unlock_page.dart new
+238
@@ -0,0 +1,238 @@
1 +import 'package:another_flushbar/flushbar.dart';
2 +import 'package:cake_wallet/core/execution_state.dart';
3 +import 'package:cake_wallet/generated/i18n.dart';
4 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
5 +import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
6 +import 'package:cake_wallet/src/widgets/primary_button.dart';
7 +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
8 +import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
9 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
10 +import 'package:cake_wallet/utils/show_bar.dart';
11 +import 'package:flutter/cupertino.dart';
12 +import 'package:flutter/material.dart';
13 +import 'package:cake_wallet/view_model/wallet_unlock_view_model.dart';
14 +import 'package:flutter_mobx/flutter_mobx.dart';
15 +import 'package:mobx/mobx.dart';
16 +
17 +class WalletUnlockPage extends StatefulWidget {
18 + WalletUnlockPage(
19 + this.walletUnlockViewModel, this.onAuthenticationFinished, this.authPasswordHandler,
20 + {required this.closable});
21 +
22 + final WalletUnlockViewModel walletUnlockViewModel;
23 + final OnAuthenticationFinished onAuthenticationFinished;
24 + final AuthPasswordHandler? authPasswordHandler;
25 + final bool closable;
26 +
27 + @override
28 + State<StatefulWidget> createState() => WalletUnlockPageState();
29 +}
30 +
31 +class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> {
32 + WalletUnlockPageState() : _passwordController = TextEditingController();
33 +
34 + final TextEditingController _passwordController;
35 + final _key = GlobalKey<ScaffoldState>();
36 + final _backArrowImageDarkTheme = Image.asset('assets/images/close_button.png');
37 + ReactionDisposer? _reaction;
38 + Flushbar<void>? _authBar;
39 + Flushbar<void>? _progressBar;
40 + void Function()? _passwordControllerListener;
41 +
42 + @override
43 + void initState() {
44 + _reaction ??= reaction((_) => widget.walletUnlockViewModel.state, (ExecutionState state) {
45 + if (state is ExecutedSuccessfullyState) {
46 + WidgetsBinding.instance.addPostFrameCallback((_) {
47 + widget.onAuthenticationFinished(true, this);
48 + });
49 + setState(() {});
50 + }
51 +
52 + if (state is IsExecutingState) {
53 + WidgetsBinding.instance.addPostFrameCallback((_) {
54 + // null duration to make it indefinite until its disposed
55 + _authBar = createBar<void>(S.of(context).authentication, duration: null)..show(context);
56 + });
57 + }
58 +
59 + if (state is FailureState) {
60 + WidgetsBinding.instance.addPostFrameCallback((_) async {
61 + dismissFlushBar(_authBar);
62 + showBar<void>(context, S.of(context).failed_authentication(state.error));
63 +
64 + widget.onAuthenticationFinished(false, this);
65 + });
66 + }
67 + });
68 +
69 + _passwordControllerListener =
70 + () => widget.walletUnlockViewModel.setPassword(_passwordController.text);
71 +
72 + if (_passwordControllerListener != null) {
73 + _passwordController.addListener(_passwordControllerListener!);
74 + }
75 +
76 + super.initState();
77 + }
78 +
79 + @override
80 + void dispose() {
81 + _reaction?.reaction.dispose();
82 +
83 + if (_passwordControllerListener != null) {
84 + _passwordController.removeListener(_passwordControllerListener!);
85 + }
86 +
87 + super.dispose();
88 + }
89 +
90 + @override
91 + void changeProcessText(String text) {
92 + dismissFlushBar(_authBar);
93 + _progressBar = createBar<void>(text, duration: null)..show(_key.currentContext!);
94 + }
95 +
96 + @override
97 + void hideProgressText() {
98 + dismissFlushBar(_progressBar);
99 + _progressBar = null;
100 + }
101 +
102 + void dismissFlushBar(Flushbar<dynamic>? bar) {
103 + WidgetsBinding.instance.addPostFrameCallback((_) async {
104 + await bar?.dismiss();
105 + });
106 + }
107 +
108 + @override
109 + Future<void> close({String? route, arguments}) async {
110 + if (_key.currentContext == null) {
111 + throw Exception('Key context is null. Should be not happened');
112 + }
113 +
114 + /// not the best scenario, but WidgetsBinding is not behaving correctly on Android
115 + await Future<void>.delayed(Duration(milliseconds: 50));
116 + await _authBar?.dismiss();
117 + await Future<void>.delayed(Duration(milliseconds: 50));
118 + await _progressBar?.dismiss();
119 + await Future<void>.delayed(Duration(milliseconds: 50));
120 + if (route != null) {
121 + Navigator.of(_key.currentContext!).pushReplacementNamed(route, arguments: arguments);
122 + } else {
123 + Navigator.of(_key.currentContext!).pop();
124 + }
125 + }
126 +
127 + @override
128 + Widget build(BuildContext context) {
129 + return Scaffold(
130 + key: _key,
131 + appBar: CupertinoNavigationBar(
132 + leading: widget.closable
133 + ? Container(
134 + padding: EdgeInsets.only(top: 10),
135 + child: SizedBox(
136 + height: 37,
137 + width: 37,
138 + child: InkWell(
139 + onTap: () => Navigator.of(context).pop(),
140 + child: _backArrowImageDarkTheme,
141 + ),
142 + ))
143 + : Container(),
144 + backgroundColor: Theme.of(context).colorScheme.background,
145 + border: null),
146 + resizeToAvoidBottomInset: false,
147 + body: Center(
148 + child: ConstrainedBox(
149 + constraints: BoxConstraints(
150 + maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint,
151 + ),
152 + child: Column(
153 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
154 + crossAxisAlignment: CrossAxisAlignment.center,
155 + children: [
156 + Expanded(
157 + child: Column(
158 + mainAxisAlignment: MainAxisAlignment.center,
159 + crossAxisAlignment: CrossAxisAlignment.center,
160 + children: [
161 + Text(
162 + widget.walletUnlockViewModel.walletName,
163 + textAlign: TextAlign.center,
164 + style: TextStyle(
165 + fontSize: 24,
166 + fontWeight: FontWeight.w500,
167 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
168 + ),
169 + ),
170 + SizedBox(height: 24),
171 + Form(
172 + child: TextFormField(
173 + onChanged: (value) => null,
174 + controller: _passwordController,
175 + textAlign: TextAlign.center,
176 + obscureText: true,
177 + style: TextStyle(
178 + fontSize: 20.0,
179 + fontWeight: FontWeight.w600,
180 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
181 + ),
182 + decoration: InputDecoration(
183 + hintStyle: TextStyle(
184 + fontSize: 18.0,
185 + fontWeight: FontWeight.w500,
186 + color: Theme.of(context).extension<NewWalletTheme>()!.hintTextColor,
187 + ),
188 + hintText: S.of(context).enter_wallet_password,
189 + focusedBorder: UnderlineInputBorder(
190 + borderSide: BorderSide(
191 + color: Theme.of(context).extension<NewWalletTheme>()!.underlineColor,
192 + width: 1.0,
193 + ),
194 + ),
195 + enabledBorder: UnderlineInputBorder(
196 + borderSide: BorderSide(
197 + color: Theme.of(context).extension<NewWalletTheme>()!.underlineColor,
198 + width: 1.0,
199 + ),
200 + ),
201 + ),
202 + ),
203 + ),
204 + ],
205 + ),
206 + ),
207 + Padding(
208 + padding: EdgeInsets.only(bottom: 24),
209 + child: Observer(
210 + builder: (_) => LoadingPrimaryButton(
211 + onPressed: () async {
212 + if (widget.authPasswordHandler != null) {
213 + try {
214 + await widget
215 + .authPasswordHandler!(widget.walletUnlockViewModel.password);
216 + widget.walletUnlockViewModel.success();
217 + } catch (e) {
218 + widget.walletUnlockViewModel.failure(e);
219 + }
220 + return;
221 + }
222 +
223 + widget.walletUnlockViewModel.unlock();
224 + },
225 + text: S.of(context).unlock,
226 + color: Colors.green,
227 + textColor: Colors.white,
228 + isLoading: widget.walletUnlockViewModel.state is IsExecutingState,
229 + isDisabled: widget.walletUnlockViewModel.state is IsExecutingState),
230 + ),
231 + ),
232 + ],
233 + ),
234 + ),
235 + ),
236 + );
237 + }
238 +}
lib/src/widgets/address_text_field.dart
+5 -2
@@ -1,5 +1,5 @@
1 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
1 import 'package:cake_wallet/utils/device_info.dart';
2 +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 import 'package:cake_wallet/utils/responsive_layout_util.dart';
4 import 'package:flutter/services.dart';
5 import 'package:flutter/material.dart';
@@ -19,7 +19,10 @@ class AddressTextField extends StatelessWidget {
19 {required this.controller,
20 this.isActive = true,
21 this.placeholder,
22 - this.options = const [AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook],
22 + this.options = const [
23 + AddressTextFieldOption.qrCode,
24 + AddressTextFieldOption.addressBook
25 + ],
26 this.onURIScanned,
27 this.focusNode,
28 this.isBorderExist = true,
lib/store/settings_store.dart
+1
@@ -553,6 +553,7 @@ abstract class SettingsStoreBase with Store {
553 static const defaultActionsMode = 11;
554 static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes;
555 static const defaultAutoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.initialized;
556 + static final walletPasswordDirectInput = Platform.isLinux;
557 static const defaultSeedPhraseLength = SeedPhraseLength.twelveWords;
558 static const defaultMoneroSeedType = SeedType.defaultSeedType;
559
lib/tron/cw_tron.dart
+5 -3
@@ -4,15 +4,17 @@ class CWTron extends Tron {
4 @override
5 List<String> getTronWordList(String language) => EVMChainMnemonics.englishWordlist;
6
7 - WalletService createTronWalletService(Box<WalletInfo> walletInfoSource) =>
8 - TronWalletService(walletInfoSource, client: TronClient());
7 + @override
8 + WalletService createTronWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
9 + TronWalletService(walletInfoSource, client: TronClient(), isDirect: isDirect);
10
11 @override
12 WalletCredentials createTronNewWalletCredentials({
13 required String name,
14 WalletInfo? walletInfo,
15 + String? password,
16 }) =>
15 - TronNewWalletCredentials(name: name, walletInfo: walletInfo);
17 + TronNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
18
19 @override
20 WalletCredentials createTronRestoreWalletFromSeedCredentials({
lib/utils/package_info.dart
+1 -1
@@ -1,5 +1,5 @@
1 import 'dart:io';
2 -import 'package:package_info/package_info.dart' as __package_info__;
2 +import 'package:package_info_plus/package_info_plus.dart' as __package_info__;
3
4 abstract class _EnvKeys {
5 static const kWinAppName = 'CW_WIN_APP_NAME';
lib/view_model/wallet_creation_vm.dart
+18
@@ -1,5 +1,7 @@
1 import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/core/wallet_creation_service.dart';
3 +import 'package:cake_wallet/generated/i18n.dart';
4 +import 'package:cake_wallet/store/settings_store.dart';
5 import 'package:cake_wallet/di.dart';
6 import 'package:cake_wallet/entities/background_tasks.dart';
7 import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
@@ -37,6 +39,14 @@ abstract class WalletCreationVMBase with Store {
39 @observable
40 ExecutionState state;
41
42 + @observable
43 + String? walletPassword;
44 +
45 + @observable
46 + String? repeatedWalletPassword;
47 +
48 + bool get hasWalletPassword => SettingsStoreBase.walletPasswordDirectInput;
49 +
50 WalletType type;
51 final bool isRecovery;
52 final WalletCreationService walletCreationService;
@@ -59,6 +69,14 @@ abstract class WalletCreationVMBase with Store {
69 name = await generateName();
70 }
71
72 + if (hasWalletPassword && (walletPassword?.isEmpty ?? true)) {
73 + throw Exception(S.current.wallet_password_is_empty);
74 + }
75 +
76 + if (hasWalletPassword && walletPassword != repeatedWalletPassword) {
77 + throw Exception(S.current.repeated_password_is_incorrect);
78 + }
79 +
80 walletCreationService.checkIfExists(name);
81 final dirPath = await pathForWalletDir(name: name, type: type);
82 final path = await pathForWallet(name: name, type: type);
lib/view_model/wallet_list/wallet_edit_view_model.dart
+3 -2
@@ -32,10 +32,11 @@ abstract class WalletEditViewModelBase with Store {
32 final WalletLoadingService _walletLoadingService;
33
34 @action
35 - Future<void> changeName(WalletListItem walletItem) async {
35 + Future<void> changeName(WalletListItem walletItem, {String? password}) async {
36 state = WalletEditRenamePending();
37 await _walletLoadingService.renameWallet(
38 - walletItem.type, walletItem.name, newName);
38 + walletItem.type, walletItem.name, newName,
39 + password: password);
40 _walletListViewModel.updateList();
41 }
42
lib/view_model/wallet_new_vm.dart
+9 -9
@@ -66,25 +66,25 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
66 switch (type) {
67 case WalletType.monero:
68 return monero!.createMoneroNewWalletCredentials(
69 - name: name, language: options!.first as String, isPolyseed: options.last as bool);
69 + name: name, language: options!.first as String, password: walletPassword, isPolyseed: options.last as bool);
70 case WalletType.bitcoin:
71 - return bitcoin!.createBitcoinNewWalletCredentials(name: name);
71 + return bitcoin!.createBitcoinNewWalletCredentials(name: name, password: walletPassword);
72 case WalletType.litecoin:
73 - return bitcoin!.createBitcoinNewWalletCredentials(name: name);
73 + return bitcoin!.createBitcoinNewWalletCredentials(name: name, password: walletPassword);
74 case WalletType.haven:
75 - return haven!
76 - .createHavenNewWalletCredentials(name: name, language: options!.first as String);
75 + return haven!.createHavenNewWalletCredentials(
76 + name: name, language: options!.first as String, password: walletPassword);
77 case WalletType.ethereum:
78 - return ethereum!.createEthereumNewWalletCredentials(name: name);
78 + return ethereum!.createEthereumNewWalletCredentials(name: name, password: walletPassword);
79 case WalletType.bitcoinCash:
80 - return bitcoinCash!.createBitcoinCashNewWalletCredentials(name: name);
80 + return bitcoinCash!.createBitcoinCashNewWalletCredentials(name: name, password: walletPassword);
81 case WalletType.nano:
82 case WalletType.banano:
83 return nano!.createNanoNewWalletCredentials(name: name);
84 case WalletType.polygon:
85 - return polygon!.createPolygonNewWalletCredentials(name: name);
85 + return polygon!.createPolygonNewWalletCredentials(name: name, password: walletPassword);
86 case WalletType.solana:
87 - return solana!.createSolanaNewWalletCredentials(name: name);
87 + return solana!.createSolanaNewWalletCredentials(name: name, password: walletPassword);
88 case WalletType.tron:
89 return tron!.createTronNewWalletCredentials(name: name);
90 case WalletType.wownero:
lib/view_model/wallet_restore_view_model.dart
+1 -1
@@ -86,7 +86,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
86
87 @override
88 WalletCredentials getCredentials(dynamic options) {
89 - final password = generateWalletPassword();
89 + final password = walletPassword ?? generateWalletPassword();
90 String? passphrase = options['passphrase'] as String?;
91 final height = options['height'] as int? ?? 0;
92 name = options['name'] as String;
lib/view_model/wallet_unlock_loadable_view_model.dart new
+63
@@ -0,0 +1,63 @@
1 +import 'package:mobx/mobx.dart';
2 +import 'package:cake_wallet/core/execution_state.dart';
3 +import 'package:cake_wallet/core/wallet_loading_service.dart';
4 +import 'package:cake_wallet/store/app_store.dart';
5 +import 'package:cw_core/wallet_type.dart';
6 +import 'package:cake_wallet/view_model/wallet_unlock_view_model.dart';
7 +
8 +part 'wallet_unlock_loadable_view_model.g.dart';
9 +
10 +class WalletUnlockLoadableViewModel = WalletUnlockLoadableViewModelBase
11 + with _$WalletUnlockLoadableViewModel;
12 +
13 +abstract class WalletUnlockLoadableViewModelBase extends WalletUnlockViewModel with Store {
14 + WalletUnlockLoadableViewModelBase(this._appStore, this._walletLoadingService,
15 + {required this.walletName, required this.walletType})
16 + : password = '',
17 + state = InitialExecutionState();
18 +
19 + final String walletName;
20 +
21 + final WalletType walletType;
22 +
23 + @override
24 + @observable
25 + String password;
26 +
27 + @override
28 + @observable
29 + ExecutionState state;
30 +
31 + final WalletLoadingService _walletLoadingService;
32 +
33 + final AppStore _appStore;
34 +
35 + @override
36 + @action
37 + void setPassword(String password) => this.password = password;
38 +
39 + @override
40 + @action
41 + Future<void> unlock() async {
42 + try {
43 + state = InitialExecutionState();
44 + final wallet = await _walletLoadingService.load(walletType, walletName, password: password);
45 + _appStore.changeCurrentWallet(wallet);
46 + success();
47 + } catch (e) {
48 + failure(e.toString());
49 + }
50 + }
51 +
52 + @override
53 + @action
54 + void success() {
55 + state = ExecutedSuccessfullyState();
56 + }
57 +
58 + @override
59 + @action
60 + void failure(e) {
61 + state = FailureState(e.toString());
62 + }
63 +}
lib/view_model/wallet_unlock_verifiable_view_model.dart new
+60
@@ -0,0 +1,60 @@
1 +import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cake_wallet/store/app_store.dart';
3 +import 'package:mobx/mobx.dart';
4 +import 'package:cw_core/wallet_type.dart';
5 +import 'package:cake_wallet/core/execution_state.dart';
6 +import 'package:cake_wallet/view_model/wallet_unlock_view_model.dart';
7 +
8 +part 'wallet_unlock_verifiable_view_model.g.dart';
9 +
10 +class WalletUnlockVerifiableViewModel = WalletUnlockVerifiableViewModelBase
11 + with _$WalletUnlockVerifiableViewModel;
12 +
13 +abstract class WalletUnlockVerifiableViewModelBase extends WalletUnlockViewModel with Store {
14 + WalletUnlockVerifiableViewModelBase(this.appStore,
15 + {required this.walletName, required this.walletType})
16 + : password = '',
17 + state = InitialExecutionState();
18 +
19 + final String walletName;
20 +
21 + final WalletType walletType;
22 +
23 + final AppStore appStore;
24 +
25 + @override
26 + @observable
27 + String password;
28 +
29 + @override
30 + @observable
31 + ExecutionState state;
32 +
33 + @override
34 + @action
35 + void setPassword(String password) => this.password = password;
36 +
37 + @override
38 + @action
39 + Future<void> unlock() async {
40 + try {
41 + state = appStore.wallet!.password == password
42 + ? ExecutedSuccessfullyState()
43 + : FailureState(S.current.invalid_password);
44 + } catch (e) {
45 + failure('${S.current.invalid_password}\n${e.toString()}');
46 + }
47 + }
48 +
49 + @override
50 + @action
51 + void success() {
52 + state = ExecutedSuccessfullyState();
53 + }
54 +
55 + @override
56 + @action
57 + void failure(e) {
58 + state = FailureState(e.toString());
59 + }
60 +}
lib/view_model/wallet_unlock_view_model.dart new
+11
@@ -0,0 +1,11 @@
1 +import 'package:cake_wallet/core/execution_state.dart';
2 +
3 +abstract class WalletUnlockViewModel {
4 + String get walletName;
5 + String get password;
6 + void setPassword(String password);
7 + ExecutionState get state;
8 + Future<void> unlock();
9 + void success();
10 + void failure(dynamic e);
11 +}
linux/.gitignore new
+1
@@ -0,0 +1 @@
1 +flutter/ephemeral
linux/CMakeLists.txt new
+144
@@ -0,0 +1,144 @@
1 +# Project-level configuration.
2 +cmake_minimum_required(VERSION 3.10)
3 +project(runner LANGUAGES CXX)
4 +
5 +# The name of the executable created for the application. Change this to change
6 +# the on-disk name of your application.
7 +set(BINARY_NAME "cake_wallet")
8 +# The unique GTK application identifier for this application. See:
9 +# https://wiki.gnome.org/HowDoI/ChooseApplicationID
10 +set(APPLICATION_ID "com.example.cake_wallet")
11 +
12 +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
13 +# versions of CMake.
14 +cmake_policy(SET CMP0063 NEW)
15 +
16 +# Load bundled libraries from the lib/ directory relative to the binary.
17 +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
18 +
19 +# Root filesystem for cross-building.
20 +if(FLUTTER_TARGET_PLATFORM_SYSROOT)
21 + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
22 + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
23 + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
24 + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
25 + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
26 + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
27 +endif()
28 +
29 +# Define build configuration options.
30 +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
31 + set(CMAKE_BUILD_TYPE "Debug" CACHE
32 + STRING "Flutter build mode" FORCE)
33 + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
34 + "Debug" "Profile" "Release")
35 +endif()
36 +
37 +# Compilation settings that should be applied to most targets.
38 +#
39 +# Be cautious about adding new options here, as plugins use this function by
40 +# default. In most cases, you should add new options to specific targets instead
41 +# of modifying this function.
42 +function(APPLY_STANDARD_SETTINGS TARGET)
43 + target_compile_features(${TARGET} PUBLIC cxx_std_14)
44 + target_compile_options(${TARGET} PRIVATE -Wall -Werror)
45 + target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
46 + target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
47 +endfunction()
48 +
49 +# Flutter library and tool build rules.
50 +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
51 +add_subdirectory(${FLUTTER_MANAGED_DIR})
52 +
53 +# System-level dependencies.
54 +find_package(PkgConfig REQUIRED)
55 +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
56 +
57 +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
58 +
59 +# Define the application target. To change its name, change BINARY_NAME above,
60 +# not the value here, or `flutter run` will no longer work.
61 +#
62 +# Any new source files that you add to the application should be added here.
63 +add_executable(${BINARY_NAME}
64 + "main.cc"
65 + "my_application.cc"
66 + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
67 +)
68 +
69 +# Apply the standard set of build settings. This can be removed for applications
70 +# that need different build settings.
71 +apply_standard_settings(${BINARY_NAME})
72 +
73 +# Add dependency libraries. Add any application-specific dependencies here.
74 +target_link_libraries(${BINARY_NAME} PRIVATE flutter)
75 +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
76 +
77 +# Run the Flutter tool portions of the build. This must not be removed.
78 +add_dependencies(${BINARY_NAME} flutter_assemble)
79 +
80 +# Only the install-generated bundle's copy of the executable will launch
81 +# correctly, since the resources must in the right relative locations. To avoid
82 +# people trying to run the unbundled copy, put it in a subdirectory instead of
83 +# the default top-level location.
84 +set_target_properties(${BINARY_NAME}
85 + PROPERTIES
86 + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
87 +)
88 +
89 +# Generated plugin build rules, which manage building the plugins and adding
90 +# them to the application.
91 +include(flutter/generated_plugins.cmake)
92 +
93 +
94 +# === Installation ===
95 +# By default, "installing" just makes a relocatable bundle in the build
96 +# directory.
97 +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
98 +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
99 + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
100 +endif()
101 +
102 +# Start with a clean build bundle directory every time.
103 +install(CODE "
104 + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
105 + " COMPONENT Runtime)
106 +
107 +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
108 +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
109 +
110 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/monero/x86_64-linux-gnu_libwallet2_api_c.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "monero_libwallet2_api_c.so"
111 + COMPONENT Runtime)
112 +
113 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/wownero/x86_64-linux-gnu_libwallet2_api_c.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "wownero_libwallet2_api_c.so"
114 + COMPONENT Runtime)
115 +
116 +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
117 + COMPONENT Runtime)
118 +
119 +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
120 + COMPONENT Runtime)
121 +
122 +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
123 + COMPONENT Runtime)
124 +
125 +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
126 + install(FILES "${bundled_library}"
127 + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
128 + COMPONENT Runtime)
129 +endforeach(bundled_library)
130 +
131 +# Fully re-copy the assets directory on each build to avoid having stale files
132 +# from a previous install.
133 +set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
134 +install(CODE "
135 + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
136 + " COMPONENT Runtime)
137 +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
138 + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
139 +
140 +# Install the AOT library on non-Debug builds only.
141 +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
142 + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
143 + COMPONENT Runtime)
144 +endif()
linux/com.cakewallet.CakeWallet.desktop new
+9
@@ -0,0 +1,9 @@
1 +[Desktop Entry]
2 +Version=1.0
3 +Type=Application
4 +Name=Cake Wallet
5 +Comment=A noncustodial multi-currency wallet
6 +Categories=Office;Finance;
7 +Terminal=false
8 +Icon=com.cakewallet.CakeWallet
9 +Exec=cake_wallet
linux/flutter/CMakeLists.txt new
+88
@@ -0,0 +1,88 @@
1 +# This file controls Flutter-level build steps. It should not be edited.
2 +cmake_minimum_required(VERSION 3.10)
3 +
4 +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5 +
6 +# Configuration provided via flutter tool.
7 +include(${EPHEMERAL_DIR}/generated_config.cmake)
8 +
9 +# TODO: Move the rest of this into files in ephemeral. See
10 +# https://github.com/flutter/flutter/issues/57146.
11 +
12 +# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
13 +# which isn't available in 3.10.
14 +function(list_prepend LIST_NAME PREFIX)
15 + set(NEW_LIST "")
16 + foreach(element ${${LIST_NAME}})
17 + list(APPEND NEW_LIST "${PREFIX}${element}")
18 + endforeach(element)
19 + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
20 +endfunction()
21 +
22 +# === Flutter Library ===
23 +# System-level dependencies.
24 +find_package(PkgConfig REQUIRED)
25 +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
26 +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
27 +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
28 +
29 +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
30 +
31 +# Published to parent scope for install step.
32 +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
33 +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
34 +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
35 +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
36 +
37 +list(APPEND FLUTTER_LIBRARY_HEADERS
38 + "fl_basic_message_channel.h"
39 + "fl_binary_codec.h"
40 + "fl_binary_messenger.h"
41 + "fl_dart_project.h"
42 + "fl_engine.h"
43 + "fl_json_message_codec.h"
44 + "fl_json_method_codec.h"
45 + "fl_message_codec.h"
46 + "fl_method_call.h"
47 + "fl_method_channel.h"
48 + "fl_method_codec.h"
49 + "fl_method_response.h"
50 + "fl_plugin_registrar.h"
51 + "fl_plugin_registry.h"
52 + "fl_standard_message_codec.h"
53 + "fl_standard_method_codec.h"
54 + "fl_string_codec.h"
55 + "fl_value.h"
56 + "fl_view.h"
57 + "flutter_linux.h"
58 +)
59 +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
60 +add_library(flutter INTERFACE)
61 +target_include_directories(flutter INTERFACE
62 + "${EPHEMERAL_DIR}"
63 +)
64 +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
65 +target_link_libraries(flutter INTERFACE
66 + PkgConfig::GTK
67 + PkgConfig::GLIB
68 + PkgConfig::GIO
69 +)
70 +add_dependencies(flutter flutter_assemble)
71 +
72 +# === Flutter tool backend ===
73 +# _phony_ is a non-existent file to force this command to run every time,
74 +# since currently there's no way to get a full input/output list from the
75 +# flutter tool.
76 +add_custom_command(
77 + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
78 + ${CMAKE_CURRENT_BINARY_DIR}/_phony_
79 + COMMAND ${CMAKE_COMMAND} -E env
80 + ${FLUTTER_TOOL_ENVIRONMENT}
81 + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
82 + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
83 + VERBATIM
84 +)
85 +add_custom_target(flutter_assemble DEPENDS
86 + "${FLUTTER_LIBRARY}"
87 + ${FLUTTER_LIBRARY_HEADERS}
88 +)
linux/flutter/generated_plugin_registrant.cc new
+27
@@ -0,0 +1,27 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +// clang-format off
6 +
7 +#include "generated_plugin_registrant.h"
8 +
9 +#include <devicelocale/devicelocale_plugin.h>
10 +#include <flutter_local_authentication/flutter_local_authentication_plugin.h>
11 +#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
12 +#include <url_launcher_linux/url_launcher_plugin.h>
13 +
14 +void fl_register_plugins(FlPluginRegistry* registry) {
15 + g_autoptr(FlPluginRegistrar) devicelocale_registrar =
16 + fl_plugin_registry_get_registrar_for_plugin(registry, "DevicelocalePlugin");
17 + devicelocale_plugin_register_with_registrar(devicelocale_registrar);
18 + g_autoptr(FlPluginRegistrar) flutter_local_authentication_registrar =
19 + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterLocalAuthenticationPlugin");
20 + flutter_local_authentication_plugin_register_with_registrar(flutter_local_authentication_registrar);
21 + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
22 + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
23 + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
24 + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
25 + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
26 + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
27 +}
linux/flutter/generated_plugin_registrant.h new
+15
@@ -0,0 +1,15 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +// clang-format off
6 +
7 +#ifndef GENERATED_PLUGIN_REGISTRANT_
8 +#define GENERATED_PLUGIN_REGISTRANT_
9 +
10 +#include <flutter_linux/flutter_linux.h>
11 +
12 +// Registers Flutter plugins.
13 +void fl_register_plugins(FlPluginRegistry* registry);
14 +
15 +#endif // GENERATED_PLUGIN_REGISTRANT_
linux/flutter/generated_plugins.cmake new
+28
@@ -0,0 +1,28 @@
1 +#
2 +# Generated file, do not edit.
3 +#
4 +
5 +list(APPEND FLUTTER_PLUGIN_LIST
6 + devicelocale
7 + flutter_local_authentication
8 + flutter_secure_storage_linux
9 + url_launcher_linux
10 +)
11 +
12 +list(APPEND FLUTTER_FFI_PLUGIN_LIST
13 + sp_scanner
14 +)
15 +
16 +set(PLUGIN_BUNDLED_LIBRARIES)
17 +
18 +foreach(plugin ${FLUTTER_PLUGIN_LIST})
19 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
20 + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
21 + list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
22 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
23 +endforeach(plugin)
24 +
25 +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
26 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
27 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
28 +endforeach(ffi_plugin)
linux/main.cc new
+6
@@ -0,0 +1,6 @@
1 +#include "my_application.h"
2 +
3 +int main(int argc, char** argv) {
4 + g_autoptr(MyApplication) app = my_application_new();
5 + return g_application_run(G_APPLICATION(app), argc, argv);
6 +}
linux/my_application.cc new
+104
@@ -0,0 +1,104 @@
1 +#include "my_application.h"
2 +
3 +#include <flutter_linux/flutter_linux.h>
4 +#ifdef GDK_WINDOWING_X11
5 +#include <gdk/gdkx.h>
6 +#endif
7 +
8 +#include "flutter/generated_plugin_registrant.h"
9 +
10 +struct _MyApplication {
11 + GtkApplication parent_instance;
12 + char** dart_entrypoint_arguments;
13 +};
14 +
15 +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
16 +
17 +// Implements GApplication::activate.
18 +static void my_application_activate(GApplication* application) {
19 + MyApplication* self = MY_APPLICATION(application);
20 + GtkWindow* window =
21 + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
22 +
23 + // Use a header bar when running in GNOME as this is the common style used
24 + // by applications and is the setup most users will be using (e.g. Ubuntu
25 + // desktop).
26 + // If running on X and not using GNOME then just use a traditional title bar
27 + // in case the window manager does more exotic layout, e.g. tiling.
28 + // If running on Wayland assume the header bar will work (may need changing
29 + // if future cases occur).
30 + gboolean use_header_bar = TRUE;
31 +#ifdef GDK_WINDOWING_X11
32 + GdkScreen* screen = gtk_window_get_screen(window);
33 + if (GDK_IS_X11_SCREEN(screen)) {
34 + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
35 + if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
36 + use_header_bar = FALSE;
37 + }
38 + }
39 +#endif
40 + if (use_header_bar) {
41 + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
42 + gtk_widget_show(GTK_WIDGET(header_bar));
43 + gtk_header_bar_set_title(header_bar, "cake_wallet");
44 + gtk_header_bar_set_show_close_button(header_bar, TRUE);
45 + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
46 + } else {
47 + gtk_window_set_title(window, "cake_wallet");
48 + }
49 +
50 + gtk_window_set_default_size(window, 1280, 720);
51 + gtk_widget_show(GTK_WIDGET(window));
52 +
53 + g_autoptr(FlDartProject) project = fl_dart_project_new();
54 + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
55 +
56 + FlView* view = fl_view_new(project);
57 + gtk_widget_show(GTK_WIDGET(view));
58 + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
59 +
60 + fl_register_plugins(FL_PLUGIN_REGISTRY(view));
61 +
62 + gtk_widget_grab_focus(GTK_WIDGET(view));
63 +}
64 +
65 +// Implements GApplication::local_command_line.
66 +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
67 + MyApplication* self = MY_APPLICATION(application);
68 + // Strip out the first argument as it is the binary name.
69 + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
70 +
71 + g_autoptr(GError) error = nullptr;
72 + if (!g_application_register(application, nullptr, &error)) {
73 + g_warning("Failed to register: %s", error->message);
74 + *exit_status = 1;
75 + return TRUE;
76 + }
77 +
78 + g_application_activate(application);
79 + *exit_status = 0;
80 +
81 + return TRUE;
82 +}
83 +
84 +// Implements GObject::dispose.
85 +static void my_application_dispose(GObject* object) {
86 + MyApplication* self = MY_APPLICATION(object);
87 + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
88 + G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
89 +}
90 +
91 +static void my_application_class_init(MyApplicationClass* klass) {
92 + G_APPLICATION_CLASS(klass)->activate = my_application_activate;
93 + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
94 + G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
95 +}
96 +
97 +static void my_application_init(MyApplication* self) {}
98 +
99 +MyApplication* my_application_new() {
100 + return MY_APPLICATION(g_object_new(my_application_get_type(),
101 + "application-id", APPLICATION_ID,
102 + "flags", G_APPLICATION_NON_UNIQUE,
103 + nullptr));
104 +}
linux/my_application.h new
+18
@@ -0,0 +1,18 @@
1 +#ifndef FLUTTER_MY_APPLICATION_H_
2 +#define FLUTTER_MY_APPLICATION_H_
3 +
4 +#include <gtk/gtk.h>
5 +
6 +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 + GtkApplication)
8 +
9 +/**
10 + * my_application_new:
11 + *
12 + * Creates a new Flutter-based application.
13 + *
14 + * Returns: a new #MyApplication.
15 + */
16 +MyApplication* my_application_new();
17 +
18 +#endif // FLUTTER_MY_APPLICATION_H_
macos/CakeWallet/decrypt.swift new
+16
@@ -0,0 +1,16 @@
1 +import Foundation
2 +import CryptoSwift
3 +
4 +func decrypt(data: Data, key: String, salt: String) -> String? {
5 + let keyBytes = key.data(using: .utf8)?.bytes ?? []
6 + let saltBytes = salt.data(using: .utf8)?.bytes ?? []
7 +
8 + guard let PBKDF2key = try? PKCS5.PBKDF2(password: keyBytes, salt: saltBytes, iterations: 4096, variant: .sha256).calculate(),
9 + let cipher = try? Blowfish(key: PBKDF2key, padding: .pkcs7),
10 + let decryptedBytes = try? cipher.decrypt(data.bytes) else {
11 + return nil
12 + }
13 +
14 + let decryptedData = Data(decryptedBytes)
15 + return String(data: decryptedData, encoding: .utf8)
16 +}
macos/Flutter/GeneratedPluginRegistrant.swift
-2
@@ -12,7 +12,6 @@ import flutter_inappwebview_macos
12 import flutter_local_authentication
13 import flutter_secure_storage_macos
14 import in_app_review
15 -import package_info
15 import package_info_plus
16 import path_provider_foundation
17 import share_plus
@@ -28,7 +27,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
27 FlutterLocalAuthenticationPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalAuthenticationPlugin"))
28 FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
29 InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
31 - FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
30 FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
31 PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
32 SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
macos/Runner/RunnerBase.entitlements
+1 -1
@@ -11,4 +11,4 @@
11 <string>$(AppIdentifierPrefix)${BUNDLE_ID}</string>
12 </array>
13 </dict>
14 -</plist>
14 +</plist>
\ No newline at end of file
model_generator.sh
+1
@@ -1,3 +1,4 @@
1 +#!/bin/bash
2 cd cw_core; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
3 cd cw_evm; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
4 cd cw_monero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
pubspec_base.yaml
+2 -2
@@ -31,8 +31,7 @@ dependencies:
31 flutter_local_authentication:
32 git:
33 url: https://github.com/cake-tech/flutter_local_authentication
34 - package_info: ^2.0.0
35 - #package_info_plus: ^1.4.2
34 + package_info_plus: ^8.0.1
35 devicelocale:
36 git:
37 url: https://github.com/cake-tech/flutter-devicelocale
@@ -80,6 +79,7 @@ dependencies:
79 path_provider_android: ^2.2.1
80 shared_preferences_android: 2.0.17
81 url_launcher_android: 6.0.24
82 + url_launcher_linux: 3.1.1 # https://github.com/flutter/flutter/issues/153083
83 sensitive_clipboard: ^1.0.0
84 walletconnect_flutter_v2: ^2.1.4
85 eth_sig_util: ^0.0.9
res/values/strings_ar.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "ادخل الرمز",
237 "enter_seed_phrase": "أدخل عبارة البذور الخاصة بك",
238 "enter_totp_code": "الرجاء إدخال رمز TOTP.",
239 + "enter_wallet_password": "أدخل كلمة مرور المحفظة",
240 "enter_your_note": "أدخل ملاحظتك ...",
241 "enter_your_pin": "أدخل كود الرقم السري",
242 "enter_your_pin_again": "أدخل PIN الخاص بك مرة أخرى",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "ليس لديك ما يكفي من SOL لتغطية رسوم المعاملة والإيجار للحساب. يرجى إضافة المزيد من sol إلى محفظتك أو تقليل مبلغ sol الذي ترسله",
342 "introducing_cake_pay": "نقدم لكم Cake Pay!",
343 "invalid_input": "مدخل غير صالح",
344 + "invalid_password": "رمز مرور خاطئ",
345 "invoice_details": "تفاصيل الفاتورة",
346 "is_percentage": "يكون",
347 "last_30_days": "آخر 30 يومًا",
@@ -499,6 +501,8 @@
501 "rename": "إعادة تسمية",
502 "rep_warning": "تحذير تمثيلي",
503 "rep_warning_sub": "لا يبدو أن ممثلك في وضع جيد. اضغط هنا لاختيار واحدة جديدة",
504 + "repeat_wallet_password": "كرر كلمة مرور المحفظة",
505 + "repeated_password_is_incorrect": "كلمة المرور المتكررة غير صحيحة. يرجى تكرار كلمة مرور المحفظة مرة أخرى.",
506 "require_for_adding_contacts": "تتطلب إضافة جهات اتصال",
507 "require_for_all_security_and_backup_settings": "مطلوب لجميع إعدادات الأمان والنسخ الاحتياطي",
508 "require_for_assessing_wallet": "تتطلب الوصول إلى المحفظة",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": ".ﺎﻫﺪﻴﻤﺠﺗ ءﺎﻐﻟﺇ ﺭﺮﻘﺗ ﻰﺘﺣ ﺕﻼﻣﺎﻌﻤﻠﻟ ﻝﻮﺻﻮﻠﻟ ﺔﻠﺑﺎﻗ ﺮﻴﻏ ﺓﺪﻤﺠﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﻞﻈﺗ ﺎﻤﻨﻴﺑ ،ﺎﻬﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻣﺎﻌﻤﻟﺍ ﻝﺎﻤﺘﻛﺍ ﺩﺮﺠﻤﺑ ﺔﺣﺎﺘﻣ ﺔﻠﻔﻘﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﺢﺒﺼﺘﺳ .ﻚﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻤﻌﻟﺍ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺕﺍﺩﺍﺪﻋﺇ ﻲﻓ ﻂﺸﻧ ﻞﻜﺸﺑ ﺎﻫﺪﻴﻤﺠﺘﺑ ﺖﻤﻗ",
802 "unconfirmed": "رصيد غير مؤكد",
803 "understand": "لقد فهمت",
804 + "unlock": "الغاء القفل",
805 "unmatched_currencies": "عملة محفظتك الحالية لا تتطابق مع عملة QR الممسوحة ضوئيًا",
806 "unspent_change": "يتغير",
807 "unspent_coins_details_title": "تفاصيل العملات الغير المنفقة",
@@ -838,6 +843,7 @@
843 "wallet_menu": "قائمة",
844 "wallet_name": "اسم المحفظة",
845 "wallet_name_exists": "توجد بالفعل محفظة بهذا الاسم. الرجاء اختيار اسم مختلف أو إعادة تسمية المحفظة الأخرى أولاً.",
846 + "wallet_password_is_empty": "كلمة مرور المحفظة فارغة. يجب ألا تكون كلمة مرور المحفظة فارغة",
847 "wallet_recovery_height": "ارتفاع الاسترداد",
848 "wallet_restoration_store_incorrect_seed_length": "طول السييد غير صحيح",
849 "wallet_seed": "سييد المحفظة",
res/values/strings_bg.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Въведете код",
237 "enter_seed_phrase": "Въведете вашата фраза за семена",
238 "enter_totp_code": "Моля, въведете TOTP кода.",
239 + "enter_wallet_password": "Въведете паролата за портфейла",
240 "enter_your_note": "Въвеждане на бележка…",
241 "enter_your_pin": "Въведете PIN",
242 "enter_your_pin_again": "Въведете своя PIN отново",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Нямате достатъчно SOL, за да покриете таксата за транзакцията и наемането на сметката. Моля, добавете повече SOL към портфейла си или намалете сумата на SOL, която изпращате",
342 "introducing_cake_pay": "Запознайте се с Cake Pay!",
343 "invalid_input": "Невалиден вход",
344 + "invalid_password": "Невалидна парола",
345 "invoice_details": "IДанни за фактура",
346 "is_percentage": "е",
347 "last_30_days": "Последните 30 дни",
@@ -499,6 +501,8 @@
501 "rename": "Промяна на името",
502 "rep_warning": "Представително предупреждение",
503 "rep_warning_sub": "Вашият представител изглежда не е в добро състояние. Докоснете тук, за да изберете нов",
504 + "repeat_wallet_password": "Повторете паролата на портфейла",
505 + "repeated_password_is_incorrect": "Многократната парола е неправилна. Моля, повторете отново паролата за портфейла.",
506 "require_for_adding_contacts": "Изисква се за добавяне на контакти",
507 "require_for_all_security_and_backup_settings": "Изисква се за всички настройки за сигурност и архивиране",
508 "require_for_assessing_wallet": "Изискване за достъп до портфейла",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "Неналично салдо: Тази обща сума включва средства, които са заключени в чакащи транзакции и тези, които сте замразили активно в настройките за контрол на монетите. Заключените баланси ще станат достъпни, след като съответните им транзакции бъдат завършени, докато замразените баланси остават недостъпни за транзакции, докато не решите да ги размразите.",
802 "unconfirmed": "Непотвърден баланс",
803 "understand": "Разбирам",
804 + "unlock": "Отключване",
805 "unmatched_currencies": "Валутата на този портфейл не съвпада с тази от сканирания QR код",
806 "unspent_change": "Промяна",
807 "unspent_coins_details_title": "Подробности за неизползваните монети",
@@ -838,6 +843,7 @@
843 "wallet_menu": "Меню",
844 "wallet_name": "Име на портфейл",
845 "wallet_name_exists": "Вече има портфейл с това име. Моля, изберете друго име или преименувайте другия портфейл.",
846 + "wallet_password_is_empty": "Паролата за портфейл е празна. Паролата за портфейл не трябва да е празна",
847 "wallet_recovery_height": "Височина на възстановяване",
848 "wallet_restoration_store_incorrect_seed_length": "Грешна дължина на seed-а",
849 "wallet_seed": "Seed на портфейла",
res/values/strings_cs.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Zadejte kód",
237 "enter_seed_phrase": "Zadejte svou frázi semen",
238 "enter_totp_code": "Zadejte kód TOTP.",
239 + "enter_wallet_password": "Zadejte heslo peněženky",
240 "enter_your_note": "Zadejte poznámku…",
241 "enter_your_pin": "Zadejte svůj PIN",
242 "enter_your_pin_again": "Zadejte znovu svůj PIN",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Nemáte dostatek SOL na pokrytí transakčního poplatku a nájemného za účet. Laskavě přidejte do své peněženky více SOL nebo snižte množství Sol, kterou odesíláte",
342 "introducing_cake_pay": "Představujeme Cake Pay!",
343 "invalid_input": "Neplatný vstup",
344 + "invalid_password": "Neplatné heslo",
345 "invoice_details": "detaily faktury",
346 "is_percentage": "je",
347 "last_30_days": "Posledních 30 dnů",
@@ -499,6 +501,8 @@
501 "rename": "Přejmenovat",
502 "rep_warning": "Reprezentativní varování",
503 "rep_warning_sub": "Zdá se, že váš zástupce není v dobrém stavu. Klepnutím zde vyberte nový",
504 + "repeat_wallet_password": "Opakujte heslo peněženky",
505 + "repeated_password_is_incorrect": "Opakované heslo je nesprávné. Znovu opakujte heslo peněženky.",
506 "require_for_adding_contacts": "Vyžadovat pro přidání kontaktů",
507 "require_for_all_security_and_backup_settings": "Vyžadovat všechna nastavení zabezpečení a zálohování",
508 "require_for_assessing_wallet": "Vyžadovat pro přístup k peněžence",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "Nedostupný zůstatek: Tento součet zahrnuje prostředky, které jsou uzamčeny v nevyřízených transakcích a ty, které jste aktivně zmrazili v nastavení kontroly mincí. Uzamčené zůstatky budou k dispozici po dokončení příslušných transakcí, zatímco zmrazené zůstatky zůstanou pro transakce nepřístupné, dokud se nerozhodnete je uvolnit.",
802 "unconfirmed": "Nepotvrzený zůstatek",
803 "understand": "Rozumím",
804 + "unlock": "Odemknout",
805 "unmatched_currencies": "Měna vaší současné peněženky neodpovídá té v naskenovaném QR kódu",
806 "unspent_change": "Změna",
807 "unspent_coins_details_title": "Podrobnosti o neutracených mincích",
@@ -838,6 +843,7 @@
843 "wallet_menu": "Menu",
844 "wallet_name": "Název peněženky",
845 "wallet_name_exists": "Peněženka s tímto názvem už existuje. Prosím zvolte si jiný název, nebo nejprve přejmenujte nejprve druhou peněženku.",
846 + "wallet_password_is_empty": "Heslo peněženky je prázdné. Heslo peněženky by nemělo být prázdné",
847 "wallet_recovery_height": "Výška zotavení",
848 "wallet_restoration_store_incorrect_seed_length": "Nesprávná délka seedu",
849 "wallet_seed": "Seed peněženky",
res/values/strings_de.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Code eingeben",
237 "enter_seed_phrase": "Geben Sie Ihre Seed-Phrase ein",
238 "enter_totp_code": "Bitte geben Sie den TOTP-Code ein.",
239 + "enter_wallet_password": "Geben Sie das Brieftaschenkennwort ein",
240 "enter_your_note": "Geben Sie Ihre Bemerkung ein…",
241 "enter_your_pin": "PIN eingeben",
242 "enter_your_pin_again": "Geben Sie Ihre PIN erneut ein",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Sie haben nicht genug SOL, um die Transaktionsgebühr und die Miete für das Konto zu decken. Bitte fügen Sie mehr Sol zu Ihrer Brieftasche hinzu oder reduzieren Sie den von Ihnen gesendeten Sol -Betrag",
342 "introducing_cake_pay": "Einführung von Cake Pay!",
343 "invalid_input": "Ungültige Eingabe",
344 + "invalid_password": "Ungültiges Passwort",
345 "invoice_details": "Rechnungs-Details",
346 "is_percentage": "ist",
347 "last_30_days": "Letzte 30 Tage",
@@ -500,6 +502,8 @@
502 "rename": "Umbenennen",
503 "rep_warning": "Repräsentative Warnung",
504 "rep_warning_sub": "Ihr Vertreter scheint nicht gut zu sein. Tippen Sie hier, um eine neue auszuwählen",
505 + "repeat_wallet_password": "Wiederholen Sie das Brieftaschenkennwort",
506 + "repeated_password_is_incorrect": "Wiederholtes Passwort ist falsch. Bitte wiederholen Sie das Brieftaschenkennwort erneut.",
507 "require_for_adding_contacts": "Erforderlich zum Hinzufügen von Kontakten",
508 "require_for_all_security_and_backup_settings": "Für alle Sicherheits- und Sicherungseinstellungen erforderlich",
509 "require_for_assessing_wallet": "Für den Zugriff auf die Wallet erforderlich",
@@ -799,6 +803,7 @@
803 "unconfirmed": "Unbestätigter Saldo",
804 "und": "und",
805 "understand": "Ich verstehe",
806 + "unlock": "Freischalten",
807 "unmatched_currencies": "Die Währung Ihres aktuellen Wallets stimmt nicht mit der des gescannten QR überein",
808 "unspent_change": "Wechselgeld",
809 "unspent_coins_details_title": "Details zu nicht ausgegebenen Coins",
@@ -841,6 +846,7 @@
846 "wallet_menu": "Wallet-Menü",
847 "wallet_name": "Walletname",
848 "wallet_name_exists": "Wallet mit diesem Namen existiert bereits",
849 + "wallet_password_is_empty": "Brieftaschenkennwort ist leer. Brieftaschenkennwort sollte nicht leer sein",
850 "wallet_recovery_height": "Erstellungshöhe",
851 "wallet_restoration_store_incorrect_seed_length": "Falsche Seed-Länge",
852 "wallet_seed": "Wallet-Seed",
res/values/strings_en.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Enter code",
237 "enter_seed_phrase": "Enter your seed phrase",
238 "enter_totp_code": "Please enter the TOTP Code.",
239 + "enter_wallet_password": "Enter the wallet password",
240 "enter_your_note": "Enter your note…",
241 "enter_your_pin": "Enter your PIN",
242 "enter_your_pin_again": "Enter your pin again",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "You do not have enough SOL to cover the transaction fee and rent for the account. Kindly add more SOL to your wallet or reduce the SOL amount you\\'re sending",
342 "introducing_cake_pay": "Introducing Cake Pay!",
343 "invalid_input": "Invalid input",
344 + "invalid_password": "Invalid password",
345 "invoice_details": "Invoice details",
346 "is_percentage": "is",
347 "last_30_days": "Last 30 days",
@@ -499,6 +501,8 @@
501 "rename": "Rename",
502 "rep_warning": "Representative Warning",
503 "rep_warning_sub": "Your representative does not appear to be in good standing. Tap here to select a new one",
504 + "repeat_wallet_password": "Repeat the wallet password",
505 + "repeated_password_is_incorrect": "Repeated password is incorrect. Please repeat the wallet password again.",
506 "require_for_adding_contacts": "Require for adding contacts",
507 "require_for_all_security_and_backup_settings": "Require for all security and backup settings",
508 "require_for_assessing_wallet": "Require for accessing wallet",
@@ -798,6 +802,7 @@
802 "unavailable_balance_description": "Unavailable Balance: This total includes funds that are locked in pending transactions and those you have actively frozen in your coin control settings. Locked balances will become available once their respective transactions are completed, while frozen balances remain inaccessible for transactions until you decide to unfreeze them.",
803 "unconfirmed": "Unconfirmed Balance",
804 "understand": "I understand",
805 + "unlock": "Unlock",
806 "unmatched_currencies": "Your current wallet's currency does not match that of the scanned QR",
807 "unspent_change": "Change",
808 "unspent_coins_details_title": "Unspent coins details",
@@ -839,6 +844,7 @@
844 "wallet_menu": "Menu",
845 "wallet_name": "Wallet name",
846 "wallet_name_exists": "A wallet with that name already exists. Please choose a different name or rename the other wallet first.",
847 + "wallet_password_is_empty": "Wallet password is empty. Wallet password should not be empty",
848 "wallet_recovery_height": "Recovery Height",
849 "wallet_restoration_store_incorrect_seed_length": "Incorrect seed length",
850 "wallet_seed": "Wallet seed",
res/values/strings_es.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Ingresar código",
237 "enter_seed_phrase": "Ingrese su frase de semillas",
238 "enter_totp_code": "Ingrese el código TOTP.",
239 + "enter_wallet_password": "Ingrese la contraseña de la billetera",
240 "enter_your_note": "Ingresa tu nota…",
241 "enter_your_pin": "Introduce tu PIN",
242 "enter_your_pin_again": "Ingrese su PIN nuevamente",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "No tiene suficiente SOL para cubrir la tarifa de transacción y alquilar para la cuenta. Por favor, agregue más sol a su billetera o reduzca la cantidad de sol que está enviando",
342 "introducing_cake_pay": "¡Presentamos Cake Pay!",
343 "invalid_input": "Entrada inválida",
344 + "invalid_password": "Contraseña invalida",
345 "invoice_details": "Detalles de la factura",
346 "is_percentage": "es",
347 "last_30_days": "Últimos 30 días",
@@ -500,6 +502,8 @@
502 "rename": "Rebautizar",
503 "rep_warning": "Advertencia representativa",
504 "rep_warning_sub": "Su representante no parece estar en buena posición. Toque aquí para seleccionar uno nuevo",
505 + "repeat_wallet_password": "Repita la contraseña de billetera",
506 + "repeated_password_is_incorrect": "La contraseña repetida es incorrecta. Repita la contraseña de la billetera nuevamente.",
507 "require_for_adding_contacts": "Requerido para agregar contactos",
508 "require_for_all_security_and_backup_settings": "Requerido para todas las configuraciones de seguridad y copia de seguridad",
509 "require_for_assessing_wallet": "Requerido para acceder a la billetera",
@@ -798,6 +802,7 @@
802 "unavailable_balance_description": "Saldo no disponible: este total incluye fondos que están bloqueados en transacciones pendientes y aquellos que usted ha congelado activamente en su configuración de control de monedas. Los saldos bloqueados estarán disponibles una vez que se completen sus respectivas transacciones, mientras que los saldos congelados permanecerán inaccesibles para las transacciones hasta que usted decida descongelarlos.",
803 "unconfirmed": "Saldo no confirmado",
804 "understand": "Entiendo",
805 + "unlock": "desbloquear",
806 "unmatched_currencies": "La moneda de su billetera actual no coincide con la del QR escaneado",
807 "unspent_change": "Cambiar",
808 "unspent_coins_details_title": "Detalles de monedas no gastadas",
@@ -839,6 +844,7 @@
844 "wallet_menu": "Menú de billetera",
845 "wallet_name": "Nombre de la billetera",
846 "wallet_name_exists": "Wallet con ese nombre ya ha existido",
847 + "wallet_password_is_empty": "La contraseña de billetera está vacía. La contraseña de la billetera no debe estar vacía",
848 "wallet_recovery_height": "Altura de recuperación",
849 "wallet_restoration_store_incorrect_seed_length": "Longitud de semilla incorrecta",
850 "wallet_seed": "Semilla de billetera",
res/values/strings_fr.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Entrez le code",
237 "enter_seed_phrase": "Entrez votre phrase secrète (seed)",
238 "enter_totp_code": "Veuillez entrer le code TOTP.",
239 + "enter_wallet_password": "Entrez le mot de passe du portefeuille",
240 "enter_your_note": "Entrez votre note…",
241 "enter_your_pin": "Entrez votre code PIN",
242 "enter_your_pin_again": "Entrez à nouveau votre code PIN",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Vous n'avez pas assez de SOL pour couvrir les frais de transaction et le loyer pour le compte. Veuillez ajouter plus de Sol à votre portefeuille ou réduire la quantité de sol que vous envoyez",
342 "introducing_cake_pay": "Présentation de Cake Pay !",
343 "invalid_input": "Entrée invalide",
344 + "invalid_password": "Mot de passe incorrect",
345 "invoice_details": "Détails de la facture",
346 "is_percentage": "est",
347 "last_30_days": "30 derniers jours",
@@ -499,6 +501,8 @@
501 "rename": "Renommer",
502 "rep_warning": "Avertissement représentatif",
503 "rep_warning_sub": "Votre représentant ne semble pas être en règle. Appuyez ici pour en sélectionner un nouveau",
504 + "repeat_wallet_password": "Répétez le mot de passe du portefeuille",
505 + "repeated_password_is_incorrect": "Le mot de passe répété est incorrect. Veuillez répéter le mot de passe du portefeuille.",
506 "require_for_adding_contacts": "Requis pour ajouter des contacts",
507 "require_for_all_security_and_backup_settings": "Exiger pour tous les paramètres de sécurité et de sauvegarde",
508 "require_for_assessing_wallet": "Nécessaire pour accéder au portefeuille",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "Solde indisponible : ce total comprend les fonds bloqués dans les transactions en attente et ceux que vous avez activement gelés dans vos paramètres de contrôle des pièces. Les soldes bloqués deviendront disponibles une fois leurs transactions respectives terminées, tandis que les soldes gelés resteront inaccessibles aux transactions jusqu'à ce que vous décidiez de les débloquer.",
802 "unconfirmed": "Solde non confirmé",
803 "understand": "J'ai compris",
804 + "unlock": "Ouvrir",
805 "unmatched_currencies": "La devise de votre portefeuille (wallet) actuel ne correspond pas à celle du QR code scanné",
806 "unspent_change": "Monnaie",
807 "unspent_coins_details_title": "Détails des pièces (coins) non dépensées",
@@ -838,6 +843,7 @@
843 "wallet_menu": "Menu",
844 "wallet_name": "Nom du Portefeuille (Wallet)",
845 "wallet_name_exists": "Un portefeuille (wallet) portant ce nom existe déjà",
846 + "wallet_password_is_empty": "Le mot de passe du portefeuille est vide. Le mot de passe du portefeuille ne doit pas être vide",
847 "wallet_recovery_height": "Hauteur de récupération",
848 "wallet_restoration_store_incorrect_seed_length": "Longueur de phrase secrète (seed) incorrecte",
849 "wallet_seed": "Phrase secrète (seed) du portefeuille (wallet)",
res/values/strings_ha.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Shigar da lamba",
237 "enter_seed_phrase": "Shigar da Sert Sentarku",
238 "enter_totp_code": "Da fatan za a shigar da lambar tnp.",
239 + "enter_wallet_password": "Shigar da kalmar sirri ta walat",
240 "enter_your_note": "Shigar da bayanin kula…",
241 "enter_your_pin": "Shigar da PIN",
242 "enter_your_pin_again": "Shigar da PIN ɗinku na sake",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Ba ku da isasshen Sol don rufe kuɗin ma'amala da haya don asusun. Da kyau ƙara ƙarin sool zuwa walat ɗinku ko rage adadin Sol ɗin da kuke aikawa",
342 "introducing_cake_pay": "Gabatar da Cake Pay!",
343 "invalid_input": "Shigar da ba daidai ba",
344 + "invalid_password": "Kalmar sirri mara inganci",
345 "invoice_details": "Bayanin wadannan",
346 "is_percentage": "shine",
347 "last_30_days": "Kwanaki 30 na ƙarshe",
@@ -501,6 +503,8 @@
503 "rename": "Sake suna",
504 "rep_warning": "Gargadi Wakilin",
505 "rep_warning_sub": "Wakilinku bai bayyana ya kasance cikin kyakkyawan yanayi ba. Matsa nan don zaɓar sabon",
506 + "repeat_wallet_password": "Maimaita kalmar sirri",
507 + "repeated_password_is_incorrect": "Maimaita kalmar sirri ba daidai ba ce. Da fatan za a sake maimaita kalmar sirri.",
508 "require_for_adding_contacts": "Bukatar ƙara lambobin sadarwa",
509 "require_for_all_security_and_backup_settings": "Bukatar duk tsaro da saitunan wariyar ajiya",
510 "require_for_assessing_wallet": "Bukatar samun damar walat",
@@ -799,6 +803,7 @@
803 "unavailable_balance_description": "Ma'auni Babu: Wannan jimlar ya haɗa da kuɗi waɗanda ke kulle a cikin ma'amaloli da ke jiran aiki da waɗanda kuka daskare sosai a cikin saitunan sarrafa kuɗin ku. Ma'auni da aka kulle za su kasance da zarar an kammala ma'amalolinsu, yayin da daskararrun ma'auni ba za su iya samun damar yin ciniki ba har sai kun yanke shawarar cire su.",
804 "unconfirmed": "Ba a tabbatar ba",
805 "understand": "na gane",
806 + "unlock": "Buɗe",
807 "unmatched_currencies": "Nau'in walat ɗin ku na yanzu bai dace da na lambar QR da aka bincika ba",
808 "unspent_change": "Canza",
809 "unspent_coins_details_title": "Bayanan tsabar kudi da ba a kashe ba",
@@ -840,6 +845,7 @@
845 "wallet_menu": "Menu",
846 "wallet_name": "Sunan walat",
847 "wallet_name_exists": "Wallet mai wannan sunan ya riga ya wanzu. Da fatan za a zaɓi wani suna daban ko sake suna ɗayan walat tukuna.",
848 + "wallet_password_is_empty": "Alamar Wallet babu komai. Al'adun Wallet bai zama komai ba",
849 "wallet_recovery_height": "Mai Tsaro",
850 "wallet_restoration_store_incorrect_seed_length": "kalmar sirrin iri ba daidai ba",
851 "wallet_seed": "kalmar sirri na walat",
res/values/strings_hi.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "कोड दर्ज करें",
237 "enter_seed_phrase": "अपना बीज वाक्यांश दर्ज करें",
238 "enter_totp_code": "कृपया TOTP कोड दर्ज करें।",
239 + "enter_wallet_password": "वॉलेट पासवर्ड दर्ज करें",
240 "enter_your_note": "अपना नोट दर्ज करें ...",
241 "enter_your_pin": "अपना पिन दर्ज करो",
242 "enter_your_pin_again": "फिर से अपना पिन डालें",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "आपके पास लेन -देन शुल्क और खाते के लिए किराए को कवर करने के लिए पर्याप्त सोल नहीं है। कृपया अपने बटुए में अधिक सोल जोड़ें या सोल राशि को कम करें जिसे आप भेज रहे हैं",
342 "introducing_cake_pay": "परिचय Cake Pay!",
343 "invalid_input": "अमान्य निवेश",
344 + "invalid_password": "अवैध पासवर्ड",
345 "invoice_details": "चालान विवरण",
346 "is_percentage": "है",
347 "last_30_days": "पिछले 30 दिन",
@@ -501,6 +503,8 @@
503 "rename": "नाम बदलें",
504 "rep_warning": "प्रतिनिधि चेतावनी",
505 "rep_warning_sub": "आपका प्रतिनिधि अच्छी स्थिति में नहीं दिखाई देता है। एक नया चयन करने के लिए यहां टैप करें",
506 + "repeat_wallet_password": "वॉलेट पासवर्ड दोहराएं",
507 + "repeated_password_is_incorrect": "बार -बार पासवर्ड गलत है। कृपया फिर से वॉलेट पासवर्ड दोहराएं।",
508 "require_for_adding_contacts": "संपर्क जोड़ने के लिए आवश्यकता है",
509 "require_for_all_security_and_backup_settings": "सभी सुरक्षा और बैकअप सेटिंग्स की आवश्यकता है",
510 "require_for_assessing_wallet": "वॉलेट तक पहुँचने के लिए आवश्यकता है",
@@ -799,6 +803,7 @@
803 "unavailable_balance_description": "अनुपलब्ध शेष राशि: इस कुल में वे धनराशि शामिल हैं जो लंबित लेनदेन में बंद हैं और जिन्हें आपने अपनी सिक्का नियंत्रण सेटिंग्स में सक्रिय रूप से जमा कर रखा है। लॉक किए गए शेष उनके संबंधित लेन-देन पूरे होने के बाद उपलब्ध हो जाएंगे, जबकि जमे हुए शेष लेन-देन के लिए अप्राप्य रहेंगे जब तक कि आप उन्हें अनफ्रीज करने का निर्णय नहीं लेते।",
804 "unconfirmed": "अपुष्ट शेष राशि",
805 "understand": "मुझे समझ",
806 + "unlock": "अनलॉक",
807 "unmatched_currencies": "आपके वर्तमान वॉलेट की मुद्रा स्कैन किए गए क्यूआर से मेल नहीं खाती",
808 "unspent_change": "परिवर्तन",
809 "unspent_coins_details_title": "अव्ययित सिक्कों का विवरण",
@@ -840,6 +845,7 @@
845 "wallet_menu": "बटुआ मेनू",
846 "wallet_name": "बटुए का नाम",
847 "wallet_name_exists": "उस नाम वाला वॉलेट पहले से मौजूद है",
848 + "wallet_password_is_empty": "वॉलेट पासवर्ड खाली है। वॉलेट पासवर्ड खाली नहीं होना चाहिए",
849 "wallet_recovery_height": "वसूली ऊंचाई",
850 "wallet_restoration_store_incorrect_seed_length": "गलत बीज की लंबाई",
851 "wallet_seed": "बटुआ का बीज",
res/values/strings_hr.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Unesite kod",
237 "enter_seed_phrase": "Unesite svoju sjemensku frazu",
238 "enter_totp_code": "Unesite TOTP kod.",
239 + "enter_wallet_password": "Unesite lozinku za novčanik",
240 "enter_your_note": "Unesite svoju poruku…",
241 "enter_your_pin": "Upišite PIN",
242 "enter_your_pin_again": "Ponovno upišite pin",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Nemate dovoljno SOL -a za pokrivanje naknade za transakciju i najamninu za račun. Ljubazno dodajte više sol u svoj novčanik ili smanjite količinu SOL -a koju šaljete",
342 "introducing_cake_pay": "Predstavljamo Cake Pay!",
343 "invalid_input": "Pogrešan unos",
344 + "invalid_password": "Netočna zaporka",
345 "invoice_details": "Podaci o fakturi",
346 "is_percentage": "je",
347 "last_30_days": "Zadnjih 30 dana",
@@ -499,6 +501,8 @@
501 "rename": "Preimenuj",
502 "rep_warning": "Reprezentativno upozorenje",
503 "rep_warning_sub": "Čini se da vaš predstavnik nije u dobrom stanju. Dodirnite ovdje za odabir novog",
504 + "repeat_wallet_password": "Ponovite lozinku za novčanik",
505 + "repeated_password_is_incorrect": "Ponovljena lozinka je netočna. Molimo ponovite lozinku za novčanik.",
506 "require_for_adding_contacts": "Zahtijeva za dodavanje kontakata",
507 "require_for_all_security_and_backup_settings": "Zahtijeva za sve postavke sigurnosti i sigurnosne kopije",
508 "require_for_assessing_wallet": "Potreban za pristup novčaniku",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "Nedostupno stanje: Ovaj ukupni iznos uključuje sredstva koja su zaključana u transakcijama na čekanju i ona koja ste aktivno zamrznuli u postavkama kontrole novčića. Zaključani saldi postat će dostupni kada se dovrše njihove transakcije, dok zamrznuti saldi ostaju nedostupni za transakcije sve dok ih ne odlučite odmrznuti.",
802 "unconfirmed": "Nepotvrđeno stanje",
803 "understand": "Razumijem",
804 + "unlock": "Otključati",
805 "unmatched_currencies": "Valuta vašeg trenutnog novčanika ne odgovara onoj na skeniranom QR-u",
806 "unspent_change": "Promijeniti",
807 "unspent_coins_details_title": "Nepotrošeni detalji o novčićima",
@@ -838,6 +843,7 @@
843 "wallet_menu": "Izbornik",
844 "wallet_name": "Ime novčanika",
845 "wallet_name_exists": "Novčanik s tim nazivom već postoji",
846 + "wallet_password_is_empty": "Lozinka za novčanik je prazna. Lozinka za novčanik ne bi trebala biti prazna",
847 "wallet_recovery_height": "Visina oporavka",
848 "wallet_restoration_store_incorrect_seed_length": "Netočna dužina pristupnog izraza",
849 "wallet_seed": "Pristupni izraz novčanika",
res/values/strings_id.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Masukkan kode",
237 "enter_seed_phrase": "Masukkan frasa benih Anda",
238 "enter_totp_code": "Masukkan Kode TOTP.",
239 + "enter_wallet_password": "Masukkan Kata Sandi Dompet",
240 "enter_your_note": "Masukkan catatan Anda...",
241 "enter_your_pin": "Masukkan PIN Anda",
242 "enter_your_pin_again": "Masukkan PIN Anda lagi",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Anda tidak memiliki cukup SOL untuk menutupi biaya transaksi dan menyewa untuk akun tersebut. Mohon tambahkan lebih banyak sol ke dompet Anda atau kurangi jumlah sol yang Anda kirim",
342 "introducing_cake_pay": "Perkenalkan Cake Pay!",
343 "invalid_input": "Masukan tidak valid",
344 + "invalid_password": "Kata sandi salah",
345 "invoice_details": "Detail faktur",
346 "is_percentage": "adalah",
347 "last_30_days": "30 hari terakhir",
@@ -501,6 +503,8 @@
503 "rename": "Ganti nama",
504 "rep_warning": "Peringatan Perwakilan",
505 "rep_warning_sub": "Perwakilan Anda tampaknya tidak bereputasi baik. Ketuk di sini untuk memilih yang baru",
506 + "repeat_wallet_password": "Ulangi Kata Sandi Dompet",
507 + "repeated_password_is_incorrect": "Kata sandi yang diulang tidak benar. Harap ulangi kata sandi dompet lagi.",
508 "require_for_adding_contacts": "Membutuhkan untuk menambahkan kontak",
509 "require_for_all_security_and_backup_settings": "Memerlukan untuk semua pengaturan keamanan dan pencadangan",
510 "require_for_assessing_wallet": "Diperlukan untuk mengakses dompet",
@@ -800,6 +804,7 @@
804 "unavailable_balance_description": "Saldo Tidak Tersedia: Total ini termasuk dana yang terkunci dalam transaksi yang tertunda dan dana yang telah Anda bekukan secara aktif di pengaturan kontrol koin Anda. Saldo yang terkunci akan tersedia setelah transaksi masing-masing selesai, sedangkan saldo yang dibekukan tetap tidak dapat diakses untuk transaksi sampai Anda memutuskan untuk mencairkannya.",
805 "unconfirmed": "Saldo Belum Dikonfirmasi",
806 "understand": "Saya mengerti",
807 + "unlock": "Membuka kunci",
808 "unmatched_currencies": "Mata uang dompet Anda saat ini tidak cocok dengan yang ditandai QR",
809 "unspent_change": "Mengubah",
810 "unspent_coins_details_title": "Rincian koin yang tidak terpakai",
@@ -841,6 +846,7 @@
846 "wallet_menu": "Menu",
847 "wallet_name": "Nama Dompet",
848 "wallet_name_exists": "Nama dompet sudah ada. Silakan pilih nama yang berbeda atau ganti nama dompet yang lain terlebih dahulu.",
849 + "wallet_password_is_empty": "Kata sandi dompet kosong. Kata sandi dompet tidak boleh kosong",
850 "wallet_recovery_height": "Tinggi pemulihan",
851 "wallet_restoration_store_incorrect_seed_length": "Panjang seed yang salah",
852 "wallet_seed": "Seed dompet",
res/values/strings_it.arb
+6
@@ -237,6 +237,7 @@
237 "enter_code": "Inserisci codice",
238 "enter_seed_phrase": "Inserisci la tua frase di semi",
239 "enter_totp_code": "Inserisci il codice TOTP.",
240 + "enter_wallet_password": "Immettere la password del portafoglio",
241 "enter_your_note": "Inserisci la tua nota…",
242 "enter_your_pin": "Inserisci il tuo PIN",
243 "enter_your_pin_again": "Inserisci il tuo pin di nuovo",
@@ -341,6 +342,7 @@
342 "insufficientFundsForRentError": "Non hai abbastanza SOL per coprire la tassa di transazione e l'affitto per il conto. Si prega di aggiungere più SOL al tuo portafoglio o ridurre l'importo SOL che stai inviando",
343 "introducing_cake_pay": "Presentazione di Cake Pay!",
344 "invalid_input": "Inserimento non valido",
345 + "invalid_password": "Password non valida",
346 "invoice_details": "Dettagli della fattura",
347 "is_percentage": "è",
348 "last_30_days": "Ultimi 30 giorni",
@@ -501,6 +503,8 @@
503 "rename": "Rinomina",
504 "rep_warning": "Avvertenza rappresentativa",
505 "rep_warning_sub": "Il tuo rappresentante non sembra essere in regola. Tocca qui per selezionarne uno nuovo",
506 + "repeat_wallet_password": "Ripeti la password del portafoglio",
507 + "repeated_password_is_incorrect": "La password ripetuta non è corretta. Si prega di ripetere di nuovo la password del portafoglio.",
508 "require_for_adding_contacts": "Richiesto per l'aggiunta di contatti",
509 "require_for_all_security_and_backup_settings": "Richiedi per tutte le impostazioni di sicurezza e backup",
510 "require_for_assessing_wallet": "Richiesto per l'accesso al portafoglio",
@@ -799,6 +803,7 @@
803 "unavailable_balance_description": "Saldo non disponibile: questo totale include i fondi bloccati nelle transazioni in sospeso e quelli che hai congelato attivamente nelle impostazioni di controllo delle monete. I saldi bloccati diventeranno disponibili una volta completate le rispettive transazioni, mentre i saldi congelati rimarranno inaccessibili per le transazioni finché non deciderai di sbloccarli.",
804 "unconfirmed": "Saldo non confermato",
805 "understand": "Capisco",
806 + "unlock": "Sbloccare",
807 "unmatched_currencies": "La valuta del tuo portafoglio attuale non corrisponde a quella del QR scansionato",
808 "unspent_change": "Modifica",
809 "unspent_coins_details_title": "Dettagli sulle monete non spese",
@@ -841,6 +846,7 @@
846 "wallet_menu": "Menù",
847 "wallet_name": "Nome del Portafoglio",
848 "wallet_name_exists": "Il portafoglio con quel nome è già esistito",
849 + "wallet_password_is_empty": "La password del portafoglio è vuota. La password del portafoglio non dovrebbe essere vuota",
850 "wallet_recovery_height": "Altezza di recupero",
851 "wallet_restoration_store_incorrect_seed_length": "Lunghezza seme non corretta",
852 "wallet_seed": "Seme Portafoglio",
res/values/strings_ja.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "コードを入力",
237 "enter_seed_phrase": "シードフレーズを入力してください",
238 "enter_totp_code": "TOTPコードを入力してください。",
239 + "enter_wallet_password": "ウォレットパスワードを入力します",
240 "enter_your_note": "メモを入力してください…",
241 "enter_your_pin": "PINを入力してください",
242 "enter_your_pin_again": "ピンをもう一度入力してください",
@@ -341,6 +342,7 @@
342 "insufficientFundsForRentError": "アカウントの取引料金とレンタルをカバーするのに十分なソルがありません。財布にソルを追加するか、送信するソル量を減らしてください",
343 "introducing_cake_pay": "序章Cake Pay!",
344 "invalid_input": "無効入力",
345 + "invalid_password": "無効なパスワード",
346 "invoice_details": "請求の詳細",
347 "is_percentage": "is",
348 "last_30_days": "過去30日",
@@ -500,6 +502,8 @@
502 "rename": "リネーム",
503 "rep_warning": "代表的な警告",
504 "rep_warning_sub": "あなたの代表者は良好な状態ではないようです。ここをタップして、新しいものを選択します",
505 + "repeat_wallet_password": "ウォレットパスワードを繰り返します",
506 + "repeated_password_is_incorrect": "繰り返しパスワードが正しくありません。ウォレットのパスワードをもう一度繰り返してください。",
507 "require_for_adding_contacts": "連絡先の追加に必要",
508 "require_for_all_security_and_backup_settings": "すべてのセキュリティおよびバックアップ設定に必須",
509 "require_for_assessing_wallet": "ウォレットにアクセスするために必要です",
@@ -798,6 +802,7 @@
802 "unavailable_balance_description": "利用不可能な残高: この合計には、保留中のトランザクションにロックされている資金と、コイン管理設定でアクティブに凍結した資金が含まれます。ロックされた残高は、それぞれの取引が完了すると利用可能になりますが、凍結された残高は、凍結を解除するまで取引にアクセスできません。",
803 "unconfirmed": "残高未確認",
804 "understand": "わかります",
805 + "unlock": "ロックを解除します",
806 "unmatched_currencies": "現在のウォレットの通貨がスキャンされたQRの通貨と一致しません",
807 "unspent_change": "変化",
808 "unspent_coins_details_title": "未使用のコインの詳細",
@@ -839,6 +844,7 @@
844 "wallet_menu": "ウォレットメニュー",
845 "wallet_name": "ウォレット名",
846 "wallet_name_exists": "その名前のウォレットはすでに存在しています",
847 + "wallet_password_is_empty": "ウォレットパスワードは空です。ウォレットのパスワードは空にしてはいけません",
848 "wallet_recovery_height": "回復の高さ",
849 "wallet_restoration_store_incorrect_seed_length": "誤ったシード長s",
850 "wallet_seed": "ウォレットシード",
res/values/strings_ko.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "코드 입력",
237 "enter_seed_phrase": "시드 문구를 입력하십시오",
238 "enter_totp_code": "TOTP 코드를 입력하세요.",
239 + "enter_wallet_password": "지갑 암호를 입력하십시오",
240 "enter_your_note": "메모를 입력하세요…",
241 "enter_your_pin": "PIN을 입력하십시오",
242 "enter_your_pin_again": "다시 핀을 입력",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "거래 수수료와 계좌 임대료를 충당하기에 충분한 SOL이 없습니다. 지갑에 더 많은 솔을 추가하거나 보내는 솔을 줄이십시오.",
342 "introducing_cake_pay": "소개 Cake Pay!",
343 "invalid_input": "잘못된 입력",
344 + "invalid_password": "유효하지 않은 비밀번호",
345 "invoice_details": "인보이스 세부정보",
346 "is_percentage": "이다",
347 "last_30_days": "지난 30일",
@@ -500,6 +502,8 @@
502 "rename": "이름 바꾸기",
503 "rep_warning": "대표 경고",
504 "rep_warning_sub": "귀하의 대표는 양호한 상태가 아닌 것 같습니다. 새 것을 선택하려면 여기를 탭하십시오",
505 + "repeat_wallet_password": "지갑 암호를 반복하십시오",
506 + "repeated_password_is_incorrect": "반복 된 비밀번호가 올바르지 않습니다. 지갑 암호를 다시 반복하십시오.",
507 "require_for_adding_contacts": "연락처 추가에 필요",
508 "require_for_all_security_and_backup_settings": "모든 보안 및 백업 설정에 필요",
509 "require_for_assessing_wallet": "지갑 접근을 위해 필요",
@@ -798,6 +802,7 @@
802 "unavailable_balance_description": "사용할 수 없는 잔액: 이 총계에는 보류 중인 거래에 잠겨 있는 자금과 코인 관리 설정에서 적극적으로 동결된 자금이 포함됩니다. 잠긴 잔액은 해당 거래가 완료되면 사용할 수 있게 되며, 동결된 잔액은 동결을 해제하기 전까지 거래에 액세스할 수 없습니다.",
803 "unconfirmed": "확인되지 않은 잔액",
804 "understand": "이해 했어요",
805 + "unlock": "터놓다",
806 "unmatched_currencies": "현재 지갑의 통화가 스캔한 QR의 통화와 일치하지 않습니다.",
807 "unspent_change": "변화",
808 "unspent_coins_details_title": "사용하지 않은 동전 세부 정보",
@@ -839,6 +844,7 @@
844 "wallet_menu": "월렛 메뉴",
845 "wallet_name": "지갑 이름",
846 "wallet_name_exists": "해당 이름의 지갑이 이미 존재합니다.",
847 + "wallet_password_is_empty": "지갑 암호는 비어 있습니다. 지갑 암호는 비어 있지 않아야합니다",
848 "wallet_recovery_height": "복구 높이",
849 "wallet_restoration_store_incorrect_seed_length": "시드 길이가 잘못되었습니다",
850 "wallet_seed": "지갑 시드",
res/values/strings_my.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "ကုဒ်ထည့်ပါ။",
237 "enter_seed_phrase": "သင့်ရဲ့မျိုးစေ့စကားစုကိုရိုက်ထည့်ပါ",
238 "enter_totp_code": "ကျေးဇူးပြု၍ TOTP ကုဒ်ကို ထည့်ပါ။",
239 + "enter_wallet_password": "ပိုက်ဆံအိတ်စကားဝှက်ကိုရိုက်ထည့်ပါ",
240 "enter_your_note": "သင့်မှတ်စုကို ထည့်ပါ...",
241 "enter_your_pin": "သင်၏ PIN ကိုထည့်ပါ။",
242 "enter_your_pin_again": "သင့်ပင်နံပါတ်ကို ထပ်မံထည့်သွင်းပါ။",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "သင်ငွေပေးချေမှုအခကြေးငွေကိုဖုံးအုပ်ရန်နှင့်အကောင့်ငှားရန်လုံလောက်သော sol ရှိသည်မဟုတ်ကြဘူး။ ကြင်နာစွာသင်၏ပိုက်ဆံအိတ်သို့ပိုမို sol ကိုပိုမိုထည့်ပါသို့မဟုတ်သင်ပို့ခြင်း sol ပမာဏကိုလျှော့ချပါ",
342 "introducing_cake_pay": "Cake Pay ကို မိတ်ဆက်ခြင်း။",
343 "invalid_input": "ထည့်သွင်းမှု မမှန်ကန်ပါ။",
344 + "invalid_password": "မမှန်ကန်သောစကားဝှက်",
345 "invoice_details": "ပြေစာအသေးစိတ်",
346 "is_percentage": "သည်",
347 "last_30_days": "လွန်ခဲ့သော ရက် 30",
@@ -499,6 +501,8 @@
501 "rename": "အမည်ပြောင်းပါ။",
502 "rep_warning": "ကိုယ်စားလှယ်သတိပေးချက်",
503 "rep_warning_sub": "သင်၏ကိုယ်စားလှယ်သည်ကောင်းမွန်သောရပ်တည်မှုတွင်မဖြစ်သင့်ပါ။ အသစ်တစ်ခုကိုရွေးချယ်ရန်ဤနေရာတွင်အသာပုတ်ပါ",
504 + "repeat_wallet_password": "ပိုက်ဆံအိတ်စကားဝှက်ကိုပြန်လုပ်ပါ",
505 + "repeated_password_is_incorrect": "ထပ်ခါတလဲလဲစကားဝှက်မမှန်ကန်ပါ ကျေးဇူးပြုပြီးပိုက်ဆံအိတ်စကားဝှက်ကိုပြန်လုပ်ပါ။",
506 "require_for_adding_contacts": "အဆက်အသွယ်များထည့်ရန် လိုအပ်သည်။",
507 "require_for_all_security_and_backup_settings": "လုံခြုံရေးနှင့် အရန်ဆက်တင်များအားလုံးအတွက် လိုအပ်ပါသည်။",
508 "require_for_assessing_wallet": "ပိုက်ဆံအိတ်ကို ဝင်သုံးရန် လိုအပ်သည်။",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "မရရှိနိုင်သော လက်ကျန်ငွေ- ဤစုစုပေါင်းတွင် ဆိုင်းငံ့ထားသော ငွေပေးငွေယူများတွင် သော့ခတ်ထားသော ငွေကြေးများနှင့် သင်၏ coin ထိန်းချုပ်မှုဆက်တင်များတွင် သင် တက်ကြွစွာ အေးခဲထားသော ငွေများ ပါဝင်သည်။ သော့ခတ်ထားသော လက်ကျန်ငွေများကို ၎င်းတို့၏ သက်ဆိုင်ရာ ငွေပေးငွေယူများ ပြီးမြောက်သည်နှင့် တပြိုင်နက် ရရှိနိုင်မည်ဖြစ်ပြီး၊ အေးခဲထားသော လက်ကျန်များကို ၎င်းတို့အား ပြန်ဖြုတ်ရန် သင်ဆုံးဖြတ်သည်အထိ ငွေပေးငွေယူများအတွက် ဆက်လက်၍မရနိုင်ပါ။",
802 "unconfirmed": "အတည်မပြုနိုင်သော လက်ကျန်ငွေ",
803 "understand": "ကျွန်တော်နားလည်ပါတယ်",
804 + "unlock": "သော့ဖွင့်",
805 "unmatched_currencies": "သင့်လက်ရှိပိုက်ဆံအိတ်၏ငွေကြေးသည် စကင်ဖတ်ထားသော QR နှင့် မကိုက်ညီပါ။",
806 "unspent_change": "ပေြာင်းလဲခြင်း",
807 "unspent_coins_details_title": "အသုံးမဝင်သော အကြွေစေ့အသေးစိတ်များ",
@@ -838,6 +843,7 @@
843 "wallet_menu": "မီနူး",
844 "wallet_name": "ပိုက်ဆံအိတ်နာမည",
845 "wallet_name_exists": "ထိုအမည်ဖြင့် ပိုက်ဆံအိတ်တစ်ခု ရှိနှင့်ပြီးဖြစ်သည်။ အခြားအမည်တစ်ခုကို ရွေးပါ သို့မဟုတ် အခြားပိုက်ဆံအိတ်ကို ဦးစွာ အမည်ပြောင်းပါ။",
846 + "wallet_password_is_empty": "ပိုက်ဆံအိတ်စကားဝှက်သည်ဗလာဖြစ်သည်။ ပိုက်ဆံအိတ်စကားဝှက်သည်အချည်းနှီးဖြစ်သင့်သည်",
847 "wallet_recovery_height": "ပြန်လည်ထူထောင်ရေးအမြင့်",
848 "wallet_restoration_store_incorrect_seed_length": "မျိုးစေ့အရှည် မမှန်ပါ။",
849 "wallet_seed": "ပိုက်ဆံအိတ်စေ့",
res/values/strings_nl.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Voer code in",
237 "enter_seed_phrase": "Voer uw zaadzin in",
238 "enter_totp_code": "Voer de TOTP-code in.",
239 + "enter_wallet_password": "Voer het Wallet -wachtwoord in",
240 "enter_your_note": "Voer uw notitie in ...",
241 "enter_your_pin": "Voer uw pincode in",
242 "enter_your_pin_again": "Voer uw PIN opnieuw in",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "U hebt niet genoeg SOL om de transactiekosten en huur voor de rekening te dekken. Voeg vriendelijk meer SOL toe aan uw portemonnee of verminder de SOL -hoeveelheid die u verzendt",
342 "introducing_cake_pay": "Introductie van Cake Pay!",
343 "invalid_input": "Ongeldige invoer",
344 + "invalid_password": "Ongeldig wachtwoord",
345 "invoice_details": "Factuurgegevens",
346 "is_percentage": "is",
347 "last_30_days": "Laatste 30 dagen",
@@ -499,6 +501,8 @@
501 "rename": "Hernoemen",
502 "rep_warning": "Representatieve waarschuwing",
503 "rep_warning_sub": "Uw vertegenwoordiger lijkt niet goed te staan. Tik hier om een ​​nieuwe te selecteren",
504 + "repeat_wallet_password": "Herhaal het Wallet -wachtwoord",
505 + "repeated_password_is_incorrect": "Herhaald wachtwoord is onjuist. Herhaal het Wallet -wachtwoord opnieuw.",
506 "require_for_adding_contacts": "Vereist voor het toevoegen van contacten",
507 "require_for_all_security_and_backup_settings": "Vereist voor alle beveiligings- en back-upinstellingen",
508 "require_for_assessing_wallet": "Vereist voor toegang tot portemonnee",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "Niet-beschikbaar saldo: Dit totaal omvat het geld dat is vergrendeld in lopende transacties en het geld dat u actief hebt bevroren in uw muntcontrole-instellingen. Vergrendelde saldi komen beschikbaar zodra de betreffende transacties zijn voltooid, terwijl bevroren saldi ontoegankelijk blijven voor transacties totdat u besluit ze weer vrij te geven.",
802 "unconfirmed": "Onbevestigd saldo",
803 "understand": "Ik begrijp het",
804 + "unlock": "Ontgrendelen",
805 "unmatched_currencies": "De valuta van uw huidige portemonnee komt niet overeen met die van de gescande QR",
806 "unspent_change": "Wijziging",
807 "unspent_coins_details_title": "Details van niet-uitgegeven munten",
@@ -839,6 +844,7 @@
844 "wallet_menu": "Portemonnee-menu",
845 "wallet_name": "Portemonnee naam",
846 "wallet_name_exists": "Portemonnee met die naam bestaat al",
847 + "wallet_password_is_empty": "Wallet -wachtwoord is leeg. Wallet -wachtwoord mag niet leeg zijn",
848 "wallet_recovery_height": "Herstelhoogte",
849 "wallet_restoration_store_incorrect_seed_length": "Onjuiste zaadlengte",
850 "wallet_seed": "Portemonnee zaad",
res/values/strings_pl.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Wprowadź kod",
237 "enter_seed_phrase": "Wprowadź swoją frazę nasienną",
238 "enter_totp_code": "Wprowadź kod TOTP.",
239 + "enter_wallet_password": "Wprowadź hasło portfela",
240 "enter_your_note": "Wpisz notatkę…",
241 "enter_your_pin": "Wpisz kod PIN",
242 "enter_your_pin_again": "Wprowadź ponownie swój kod PIN",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Nie masz wystarczającej ilości SOL, aby pokryć opłatę za transakcję i czynsz za konto. Uprzejmie dodaj więcej sol do portfela lub zmniejsz solę, którą wysyłasz",
342 "introducing_cake_pay": "Przedstawiamy Cake Pay!",
343 "invalid_input": "Nieprawidłowe dane wejściowe",
344 + "invalid_password": "Nieprawidłowe hasło",
345 "invoice_details": "Dane do faktury",
346 "is_percentage": "jest",
347 "last_30_days": "Ostatnie 30 dni",
@@ -499,6 +501,8 @@
501 "rename": "Zmień nazwę",
502 "rep_warning": "Przedstawicielskie ostrzeżenie",
503 "rep_warning_sub": "Twój przedstawiciel nie wydaje się mieć dobrej opinii. Stuknij tutaj, aby wybrać nowy",
504 + "repeat_wallet_password": "Powtórz hasło portfela",
505 + "repeated_password_is_incorrect": "Powtarzane hasło jest nieprawidłowe. Powtórz ponownie hasło portfela.",
506 "require_for_adding_contacts": "Wymagane do dodania kontaktów",
507 "require_for_all_security_and_backup_settings": "Wymagaj dla wszystkich ustawień zabezpieczeń i kopii zapasowych",
508 "require_for_assessing_wallet": "Wymagaj dostępu do portfela",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "Niedostępne saldo: Suma ta obejmuje środki zablokowane w transakcjach oczekujących oraz te, które aktywnie zamroziłeś w ustawieniach kontroli monet. Zablokowane salda staną się dostępne po zakończeniu odpowiednich transakcji, natomiast zamrożone salda pozostaną niedostępne dla transakcji, dopóki nie zdecydujesz się ich odblokować.",
802 "unconfirmed": "Niepotwierdzone saldo",
803 "understand": "Rozumiem",
804 + "unlock": "Odblokować",
805 "unmatched_currencies": "Waluta Twojego obecnego portfela nie zgadza się z waluctą zeskanowanego kodu QR",
806 "unspent_change": "Zmiana",
807 "unspent_coins_details_title": "Szczegóły niewydanych monet",
@@ -838,6 +843,7 @@
843 "wallet_menu": "Menu portfela",
844 "wallet_name": "Nazwa portfela",
845 "wallet_name_exists": "Portfel o tej nazwie już istnieje",
846 + "wallet_password_is_empty": "Hasło portfela jest puste. Hasło portfela nie powinno być puste",
847 "wallet_recovery_height": "Wysokość odzysku",
848 "wallet_restoration_store_incorrect_seed_length": "Nieprawidłowa długość frazy seed",
849 "wallet_seed": "Seed portfela",
res/values/strings_pt.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Digite o código",
237 "enter_seed_phrase": "Digite sua frase de semente",
238 "enter_totp_code": "Digite o código TOTP.",
239 + "enter_wallet_password": "Digite a senha da carteira",
240 "enter_your_note": "Insira sua nota ...",
241 "enter_your_pin": "Insira seu PIN",
242 "enter_your_pin_again": "Insira seu PIN novamente",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Você não tem Sol suficiente para cobrir a taxa de transação e o aluguel da conta. Por favor, adicione mais sol à sua carteira ou reduza a quantidade de sol que você envia",
342 "introducing_cake_pay": "Apresentando o Cake Pay!",
343 "invalid_input": "Entrada inválida",
344 + "invalid_password": "Senha inválida",
345 "invoice_details": "Detalhes da fatura",
346 "is_percentage": "é",
347 "last_30_days": "Últimos 30 dias",
@@ -501,6 +503,8 @@
503 "rename": "Renomear",
504 "rep_warning": "Aviso representativo",
505 "rep_warning_sub": "Seu representante não parece estar em boa posição. Toque aqui para selecionar um novo",
506 + "repeat_wallet_password": "Repita a senha da carteira",
507 + "repeated_password_is_incorrect": "A senha repetida está incorreta. Repita a senha da carteira novamente.",
508 "require_for_adding_contacts": "Requer para adicionar contatos",
509 "require_for_all_security_and_backup_settings": "Exigir todas as configurações de segurança e backup",
510 "require_for_assessing_wallet": "Requer para acessar a carteira",
@@ -799,6 +803,7 @@
803 "unavailable_balance_description": "Saldo Indisponível: Este total inclui fundos bloqueados em transações pendentes e aqueles que você congelou ativamente nas configurações de controle de moedas. Os saldos bloqueados ficarão disponíveis assim que suas respectivas transações forem concluídas, enquanto os saldos congelados permanecerão inacessíveis para transações até que você decida descongelá-los.",
804 "unconfirmed": "Saldo não confirmado",
805 "understand": "Entendo",
806 + "unlock": "Desbloquear",
807 "unmatched_currencies": "A moeda da sua carteira atual não corresponde à do QR digitalizado",
808 "unspent_change": "Troco",
809 "unspent_coins_details_title": "Detalhes de moedas não gastas",
@@ -841,6 +846,7 @@
846 "wallet_menu": "Menu",
847 "wallet_name": "Nome da carteira",
848 "wallet_name_exists": "A carteira com esse nome já existe",
849 + "wallet_password_is_empty": "A senha da carteira está vazia. A senha da carteira não deve estar vazia",
850 "wallet_recovery_height": "Altura de recuperação",
851 "wallet_restoration_store_incorrect_seed_length": "Comprimento de semente incorreto",
852 "wallet_seed": "Semente de carteira",
res/values/strings_ru.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Введите код",
237 "enter_seed_phrase": "Введите свою семенную фразу",
238 "enter_totp_code": "Пожалуйста, введите TOTP-код.",
239 + "enter_wallet_password": "Введите пароль кошелька",
240 "enter_your_note": "Введите примечание…",
241 "enter_your_pin": "Введите ваш PIN",
242 "enter_your_pin_again": "Введите PIN еще раз",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "У вас недостаточно Sol, чтобы покрыть плату за транзакцию и аренду для счета. Пожалуйста, добавьте больше Sol в свой кошелек или уменьшите сумму Sol, которую вы отправляете",
342 "introducing_cake_pay": "Представляем Cake Pay!",
343 "invalid_input": "Неверный Ввод",
344 + "invalid_password": "Неверный пароль",
345 "invoice_details": "Детали счета",
346 "is_percentage": "есть",
347 "last_30_days": "Последние 30 дней",
@@ -500,6 +502,8 @@
502 "rename": "Переименовать",
503 "rep_warning": "Представительное предупреждение",
504 "rep_warning_sub": "Ваш представитель, похоже, не в хорошей репутации. Нажмите здесь, чтобы выбрать новый",
505 + "repeat_wallet_password": "Повторите пароль кошелька",
506 + "repeated_password_is_incorrect": "Повторный пароль неверен. Пожалуйста, повторите пароль кошелька снова.",
507 "require_for_adding_contacts": "Требовать добавления контактов",
508 "require_for_all_security_and_backup_settings": "Требовать все настройки безопасности и резервного копирования",
509 "require_for_assessing_wallet": "Требовать для доступа к кошельку",
@@ -798,6 +802,7 @@
802 "unavailable_balance_description": "Недоступный баланс: в эту сумму входят средства, заблокированные в ожидающих транзакциях, и средства, которые вы активно заморозили в настройках управления монетами. Заблокированные балансы станут доступны после завершения соответствующих транзакций, а замороженные балансы останутся недоступными для транзакций, пока вы не решите их разморозить.",
803 "unconfirmed": "Неподтвержденный баланс",
804 "understand": "Понятно",
805 + "unlock": "Разблокировать",
806 "unmatched_currencies": "Валюта вашего текущего кошелька не соответствует валюте отсканированного QR-кода.",
807 "unspent_change": "Изменять",
808 "unspent_coins_details_title": "Сведения о неизрасходованных монетах",
@@ -839,6 +844,7 @@
844 "wallet_menu": "Меню кошелька",
845 "wallet_name": "Имя кошелька",
846 "wallet_name_exists": "Кошелек с таким именем уже существует",
847 + "wallet_password_is_empty": "Пароль кошелька пуст. Пароль кошелька не должен быть пустым",
848 "wallet_recovery_height": "Высота восстановления",
849 "wallet_restoration_store_incorrect_seed_length": "Неверная длина мнемонической фразы",
850 "wallet_seed": "Мнемоническая фраза кошелька",
res/values/strings_th.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "กรอกรหัส",
237 "enter_seed_phrase": "ป้อนวลีเมล็ดพันธุ์ของคุณ",
238 "enter_totp_code": "กรุณาใส่รหัสทีโอที",
239 + "enter_wallet_password": "ป้อนรหัสผ่านกระเป๋าเงิน",
240 "enter_your_note": "ใส่บันทึกของคุณ...",
241 "enter_your_pin": "ใส่ PIN ของคุณ",
242 "enter_your_pin_again": "ใส่ PIN ของคุณอีกครั้ง",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "คุณไม่มีโซลเพียงพอที่จะครอบคลุมค่าธรรมเนียมการทำธุรกรรมและค่าเช่าสำหรับบัญชี กรุณาเพิ่มโซลให้มากขึ้นลงในกระเป๋าเงินของคุณหรือลดจำนวนโซลที่คุณส่งมา",
342 "introducing_cake_pay": "ยินดีต้อนรับสู่ Cake Pay!",
343 "invalid_input": "อินพุตไม่ถูกต้อง",
344 + "invalid_password": "รหัสผ่านไม่ถูกต้อง",
345 "invoice_details": "รายละเอียดใบแจ้งหนี้",
346 "is_percentage": "เป็น",
347 "last_30_days": "30 วันล่าสุด",
@@ -499,6 +501,8 @@
501 "rename": "เปลี่ยนชื่อ",
502 "rep_warning": "คำเตือนตัวแทน",
503 "rep_warning_sub": "ตัวแทนของคุณดูเหมือนจะไม่อยู่ในสถานะที่ดี แตะที่นี่เพื่อเลือกอันใหม่",
504 + "repeat_wallet_password": "ทำซ้ำรหัสผ่านกระเป๋าเงิน",
505 + "repeated_password_is_incorrect": "รหัสผ่านซ้ำไม่ถูกต้อง โปรดทำซ้ำรหัสผ่านกระเป๋าเงินอีกครั้ง",
506 "require_for_adding_contacts": "ต้องการสำหรับการเพิ่มผู้ติดต่อ",
507 "require_for_all_security_and_backup_settings": "จำเป็นสำหรับการตั้งค่าความปลอดภัยและการสำรองข้อมูลทั้งหมด",
508 "require_for_assessing_wallet": "จำเป็นสำหรับการเข้าถึงกระเป๋าเงิน",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "ยอดคงเหลือที่ไม่พร้อมใช้งาน: ยอดรวมนี้รวมถึงเงินทุนที่ถูกล็อคในการทำธุรกรรมที่รอดำเนินการและที่คุณได้แช่แข็งไว้ในการตั้งค่าการควบคุมเหรียญของคุณ ยอดคงเหลือที่ถูกล็อคจะพร้อมใช้งานเมื่อธุรกรรมที่เกี่ยวข้องเสร็จสมบูรณ์ ในขณะที่ยอดคงเหลือที่แช่แข็งจะไม่สามารถเข้าถึงได้สำหรับธุรกรรมจนกว่าคุณจะตัดสินใจยกเลิกการแช่แข็ง",
802 "unconfirmed": "ยอดคงเหลือที่ไม่ได้รับการยืนยัน",
803 "understand": "ฉันเข้าใจ",
804 + "unlock": "ปลดล็อค",
805 "unmatched_currencies": "สกุลเงินของกระเป๋าปัจจุบันของคุณไม่ตรงกับของ QR ที่สแกน",
806 "unspent_change": "เปลี่ยน",
807 "unspent_coins_details_title": "รายละเอียดเหรียญที่ไม่ได้ใช้",
@@ -838,6 +843,7 @@
843 "wallet_menu": "เมนู",
844 "wallet_name": "ชื่อกระเป๋า",
845 "wallet_name_exists": "กระเป๋าที่มีชื่อนี้มีอยู่แล้ว โปรดเลือกชื่ออื่นหรือเปลี่ยนชื่อกระเป๋าอื่นก่อน",
846 + "wallet_password_is_empty": "รหัสผ่านกระเป๋าเงินว่างเปล่า รหัสผ่านกระเป๋าเงินไม่ควรว่างเปล่า",
847 "wallet_recovery_height": "ความสูงของการกู้คืน",
848 "wallet_restoration_store_incorrect_seed_length": "ความยาวของซีดไม่ถูกต้อง",
849 "wallet_seed": "ซีดของกระเป๋า",
res/values/strings_tl.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Ipasok ang code",
237 "enter_seed_phrase": "Ipasok ang iyong pariralang binhi",
238 "enter_totp_code": "Mangyaring ipasok ang TOTP code.",
239 + "enter_wallet_password": "Ipasok ang password ng pitaka",
240 "enter_your_note": "Ipasok ang iyong tala ...",
241 "enter_your_pin": "Ipasok ang iyong pin",
242 "enter_your_pin_again": "Ipasok muli ang iyong pin",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "Wala kang sapat na sol upang masakop ang bayad sa transaksyon at upa para sa account. Mabait na magdagdag ng higit pa sa iyong pitaka o bawasan ang halaga ng sol na iyong ipinapadala",
342 "introducing_cake_pay": "Ipinakikilala ang cake pay!",
343 "invalid_input": "Di -wastong input",
344 + "invalid_password": "Di wastong password",
345 "invoice_details": "Mga detalye ng invoice",
346 "is_percentage": "ay",
347 "last_30_days": "Huling 30 araw",
@@ -499,6 +501,8 @@
501 "rename": "Palitan ang pangalan",
502 "rep_warning": "Babala ng kinatawan",
503 "rep_warning_sub": "Ang iyong kinatawan ay hindi lilitaw na nasa mabuting kalagayan. Tapikin dito upang pumili ng bago",
504 + "repeat_wallet_password": "Ulitin ang password ng pitaka",
505 + "repeated_password_is_incorrect": "Ang paulit -ulit na password ay hindi tama. Mangyaring ulitin muli ang password ng pitaka.",
506 "require_for_adding_contacts": "Nangangailangan para sa pagdaragdag ng mga contact",
507 "require_for_all_security_and_backup_settings": "Nangangailangan para sa lahat ng mga setting ng seguridad at backup",
508 "require_for_assessing_wallet": "Nangangailangan para sa pag -access ng pitaka",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "Hindi Available na Balanse: Kasama sa kabuuang ito ang mga pondong naka-lock sa mga nakabinbing transaksyon at ang mga aktibong na-freeze mo sa iyong mga setting ng kontrol ng coin. Magiging available ang mga naka-lock na balanse kapag nakumpleto na ang kani-kanilang mga transaksyon, habang ang mga nakapirming balanse ay nananatiling hindi naa-access para sa mga transaksyon hanggang sa magpasya kang i-unfreeze ang mga ito.",
802 "unconfirmed": "Hindi nakumpirma na balanse",
803 "understand": "naiintindihan ko",
804 + "unlock": "I -unlock",
805 "unmatched_currencies": "Ang pera ng iyong kasalukuyang pitaka ay hindi tumutugma sa na -scan na QR",
806 "unspent_change": "Baguhin",
807 "unspent_coins_details_title": "Mga Detalye ng Unspent Coins",
@@ -838,6 +843,7 @@
843 "wallet_menu": "Menu",
844 "wallet_name": "Pangalan ng Wallet",
845 "wallet_name_exists": "Ang isang pitaka na may pangalang iyon ay mayroon na. Mangyaring pumili ng ibang pangalan o palitan muna ang iba pang pitaka.",
846 + "wallet_password_is_empty": "Walang laman ang password ng wallet. Ang password ng wallet ay hindi dapat walang laman",
847 "wallet_recovery_height": "Taas ng pagbawi",
848 "wallet_restoration_store_incorrect_seed_length": "Maling haba ng binhi",
849 "wallet_seed": "SEED ng Wallet",
res/values/strings_tr.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Kodu girin",
237 "enter_seed_phrase": "Tohum ifadenizi girin",
238 "enter_totp_code": "Lütfen TOTP Kodunu giriniz.",
239 + "enter_wallet_password": "Cüzdan şifresini girin",
240 "enter_your_note": "Notunu gir…",
241 "enter_your_pin": "PIN'ini gir",
242 "enter_your_pin_again": "PIN kodunu tekrar girin",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "İşlem ücretini karşılamak ve hesap için kiralamak için yeterli SOL'nuz yok. Lütfen cüzdanınıza daha fazla sol ekleyin veya gönderdiğiniz sol miktarını azaltın",
342 "introducing_cake_pay": "Cake Pay ile tanışın!",
343 "invalid_input": "Geçersiz Giriş",
344 + "invalid_password": "Geçersiz şifre",
345 "invoice_details": "fatura detayları",
346 "is_percentage": "is",
347 "last_30_days": "Son 30 gün",
@@ -499,6 +501,8 @@
501 "rename": "Yeniden adlandır",
502 "rep_warning": "Temsilci uyarı",
503 "rep_warning_sub": "Temsilciniz iyi durumda görünmüyor. Yeni bir tane seçmek için buraya dokunun",
504 + "repeat_wallet_password": "Cüzdan şifresini tekrarlayın",
505 + "repeated_password_is_incorrect": "Tekrarlanan şifre yanlış. Lütfen cüzdan şifresini tekrarlayın.",
506 "require_for_adding_contacts": "Kişi eklemek için gerekli",
507 "require_for_all_security_and_backup_settings": "Tüm güvenlik ve yedekleme ayarları için iste",
508 "require_for_assessing_wallet": "Cüzdana erişmek için gerekli",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "Kullanılamayan Bakiye: Bu toplam, bekleyen işlemlerde kilitlenen fonları ve jeton kontrol ayarlarınızda aktif olarak dondurduğunuz fonları içerir. Kilitli bakiyeler, ilgili işlemleri tamamlandıktan sonra kullanılabilir hale gelir; dondurulmuş bakiyeler ise siz onları dondurmaya karar verene kadar işlemler için erişilemez durumda kalır.",
802 "unconfirmed": "Onaylanmamış Bakiye",
803 "understand": "Anladım",
804 + "unlock": "Kilidini aç",
805 "unmatched_currencies": "Mevcut cüzdanınızın para birimi taranan QR ile eşleşmiyor",
806 "unspent_change": "Değiştirmek",
807 "unspent_coins_details_title": "Harcanmamış koin detayları",
@@ -838,6 +843,7 @@
843 "wallet_menu": "Menü",
844 "wallet_name": "Cüzdan ismi",
845 "wallet_name_exists": "Bu isimde bir cüzdan zaten mevcut. Lütfen farklı bir isim seç veya önce diğer cüzdanı yeniden adlandır.",
846 + "wallet_password_is_empty": "Cüzdan şifresi boş. Cüzdan şifresi boş olmamalı",
847 "wallet_recovery_height": "Kurtarma Yüksekliği",
848 "wallet_restoration_store_incorrect_seed_length": "Yanlış tohum uzunluğu",
849 "wallet_seed": "Cüzdan tohumu",
res/values/strings_uk.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "Введіть код",
237 "enter_seed_phrase": "Введіть свою насіннєву фразу",
238 "enter_totp_code": "Будь ласка, введіть код TOTP.",
239 + "enter_wallet_password": "Введіть пароль гаманця",
240 "enter_your_note": "Введіть примітку…",
241 "enter_your_pin": "Введіть ваш PIN",
242 "enter_your_pin_again": "Введіть PIN ще раз",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "У вас недостатньо SOL, щоб покрити плату за транзакцію та оренду на рахунок. Будь ласка, додайте до свого гаманця більше SOL або зменшіть суму, яку ви надсилаєте",
342 "introducing_cake_pay": "Представляємо Cake Pay!",
343 "invalid_input": "Неправильні дані",
344 + "invalid_password": "Недійсний пароль",
345 "invoice_details": "Реквізити рахунку-фактури",
346 "is_percentage": "є",
347 "last_30_days": "Останні 30 днів",
@@ -500,6 +502,8 @@
502 "rename": "Перейменувати",
503 "rep_warning": "Представницьке попередження",
504 "rep_warning_sub": "Ваш представник, схоже, не має доброго становища. Торкніться тут, щоб вибрати новий",
505 + "repeat_wallet_password": "Повторіть пароль гаманця",
506 + "repeated_password_is_incorrect": "Повторний пароль невірний. Будь ласка, повторіть пароль гаманця ще раз.",
507 "require_for_adding_contacts": "Потрібен для додавання контактів",
508 "require_for_all_security_and_backup_settings": "Вимагати всіх налаштувань безпеки та резервного копіювання",
509 "require_for_assessing_wallet": "Потрібен доступ до гаманця",
@@ -798,6 +802,7 @@
802 "unavailable_balance_description": "Недоступний баланс: ця сума включає кошти, заблоковані в незавершених транзакціях, і ті, які ви активно заморозили в налаштуваннях контролю монет. Заблоковані баланси стануть доступними після завершення відповідних транзакцій, тоді як заморожені баланси залишаються недоступними для транзакцій, доки ви не вирішите їх розморозити.",
803 "unconfirmed": "Непідтверджений баланс",
804 "understand": "Зрозуміло",
805 + "unlock": "Розблокувати",
806 "unmatched_currencies": "Валюта вашого гаманця не збігається з валютою сканованого QR-коду",
807 "unspent_change": "Зміна",
808 "unspent_coins_details_title": "Відомості про невитрачені монети",
@@ -839,6 +844,7 @@
844 "wallet_menu": "Меню гаманця",
845 "wallet_name": "Ім'я гаманця",
846 "wallet_name_exists": "Гаманець з такою назвою вже існує",
847 + "wallet_password_is_empty": "Пароль гаманця порожній. Пароль гаманця не повинен бути порожнім",
848 "wallet_recovery_height": "Висота відновлення",
849 "wallet_restoration_store_incorrect_seed_length": "Невірна довжина мнемонічної фрази",
850 "wallet_seed": "Мнемонічна фраза гаманця",
res/values/strings_ur.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "کوڈ درج کریں",
237 "enter_seed_phrase": "اپنے بیج کا جملہ درج کریں",
238 "enter_totp_code": "براہ کرم TOTP کوڈ درج کریں۔",
239 + "enter_wallet_password": "پرس کا پاس ورڈ درج کریں",
240 "enter_your_note": "اپنا نوٹ درج کریں…",
241 "enter_your_pin": "اپنا PIN درج کریں۔",
242 "enter_your_pin_again": "اپنا پن دوبارہ درج کریں۔",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "آپ کے پاس ٹرانزیکشن فیس اور اکاؤنٹ کے لئے کرایہ لینے کے ل enough اتنا SOL نہیں ہے۔ برائے مہربانی اپنے بٹوے میں مزید سول شامل کریں یا آپ کو بھیجنے والی سول رقم کو کم کریں",
342 "introducing_cake_pay": "Cake پے کا تعارف!",
343 "invalid_input": "غلط ان پٹ",
344 + "invalid_password": "غلط پاسورڈ",
345 "invoice_details": "رسید کی تفصیلات",
346 "is_percentage": "ہے",
347 "last_30_days": "آخری 30 دن",
@@ -501,6 +503,8 @@
503 "rename": "نام تبدیل کریں۔",
504 "rep_warning": "نمائندہ انتباہ",
505 "rep_warning_sub": "آپ کا نمائندہ اچھ standing ے مقام پر نہیں دکھائی دیتا ہے۔ نیا منتخب کرنے کے لئے یہاں ٹیپ کریں",
506 + "repeat_wallet_password": "بٹوے کا پاس ورڈ دہرائیں",
507 + "repeated_password_is_incorrect": "بار بار پاس ورڈ غلط ہے۔ براہ کرم دوبارہ پرس کا پاس ورڈ دہرائیں۔",
508 "require_for_adding_contacts": "رابطوں کو شامل کرنے کی ضرورت ہے۔",
509 "require_for_all_security_and_backup_settings": "تمام سیکورٹی اور بیک اپ کی ترتیبات کے لیے درکار ہے۔",
510 "require_for_assessing_wallet": "بٹوے تک رسائی کے لیے درکار ہے۔",
@@ -799,6 +803,7 @@
803 "unavailable_balance_description": "۔ﮯﺗﺮﮐ ﮟﯿﮩﻧ ﮧﻠﺼﯿﻓ ﺎﮐ ﮯﻧﺮﮐ ﺪﻤﺠﻨﻣ ﻥﺍ ﮟﯿﮩﻧﺍ ﭖﺁ ﮧﮐ ﮏﺗ ﺐﺟ ﮟﯿﮨ ﮯﺘﮨﺭ ﯽﺋﺎﺳﺭ ﻞﺑﺎﻗﺎﻧ ﮏﺗ ﺖﻗﻭ ﺱﺍ ﮯﯿﻟ ﮯﮐ ﻦﯾﺩ ﻦﯿﻟ ﺲﻨﻠﯿﺑ ﺪﻤﺠﻨﻣ ﮧﮐ ﺐﺟ ،ﮯﮔ ﮟﯿﺋﺎﺟ ﻮﮨ ﺏﺎﯿﺘﺳﺩ ﺲﻨﻠﯿﺑ ﻞﻔﻘﻣ ﺪﻌﺑ ﮯﮐ ﮯﻧﻮﮨ ﻞﻤﮑﻣ ﻦﯾﺩ ﻦﯿﻟ ﮧﻘﻠﻌﺘﻣ ﮯﮐ ﻥﺍ ۔ﮯﮨ ﺎﮭﮐﺭ ﺮ",
804 "unconfirmed": "غیر تصدیق شدہ بیلنس",
805 "understand": "میں سمجھتا ہوں۔",
806 + "unlock": "غیر مقفل",
807 "unmatched_currencies": "آپ کے پرس کی موجودہ کرنسی اسکین شدہ QR سے مماثل نہیں ہے۔",
808 "unspent_change": "تبدیل کریں",
809 "unspent_coins_details_title": "غیر خرچ شدہ سککوں کی تفصیلات",
@@ -840,6 +845,7 @@
845 "wallet_menu": "مینو",
846 "wallet_name": "بٹوے کا نام",
847 "wallet_name_exists": "اس نام کا پرس پہلے سے موجود ہے۔ براہ کرم ایک مختلف نام منتخب کریں یا پہلے دوسرے بٹوے کا نام تبدیل کریں۔",
848 + "wallet_password_is_empty": "پرس کا پاس ورڈ خالی ہے۔ پرس کا پاس ورڈ خالی نہیں ہونا چاہئے",
849 "wallet_recovery_height": "بحالی کی اونچائی",
850 "wallet_restoration_store_incorrect_seed_length": "غلط بیج کی لمبائی",
851 "wallet_seed": "بٹوے کا بیج",
res/values/strings_yo.arb
+6
@@ -237,6 +237,7 @@
237 "enter_code": "Tẹ̀ ọ̀rọ̀",
238 "enter_seed_phrase": "Tẹ ọrọ-iru irugbin rẹ",
239 "enter_totp_code": "Jọwọ pọ koodu TOTP.",
240 + "enter_wallet_password": "Tẹ ọrọ igbaniwọle apamọwọ",
241 "enter_your_note": "Tẹ̀ àkọsílẹ̀ yín",
242 "enter_your_pin": "Tẹ̀ òǹkà ìdánimọ̀ àdáni yín",
243 "enter_your_pin_again": "Tún òǹkà ìdánimọ̀ àdáni yín tẹ̀",
@@ -341,6 +342,7 @@
342 "insufficientFundsForRentError": "O ko ni Sol kan lati bo owo isanwo naa ki o yalo fun iroyin naa. Fi agbara kun Sol diẹ sii si apamọwọ rẹ tabi dinku soso naa ti o \\ 'tun n firanṣẹ",
343 "introducing_cake_pay": "Ẹ bá Cake Pay!",
344 "invalid_input": "Iṣawọle ti ko tọ",
345 + "invalid_password": "Ọrọ igbaniwọle ti ko wulo",
346 "invoice_details": "Iru awọn ẹya ọrọ",
347 "is_percentage": "jẹ́",
348 "last_30_days": "Ọ̀jọ̀ mọ́gbọ̀n tó kọjà",
@@ -500,6 +502,8 @@
502 "rename": "Pààrọ̀ orúkọ",
503 "rep_warning": "Ikilọ aṣoju",
504 "rep_warning_sub": "Aṣoju rẹ ko han lati wa ni iduro to dara. Fọwọ ba ibi lati yan ọkan titun kan",
505 + "repeat_wallet_password": "Tun ọrọ igbaniwọle apamọwọ naa",
506 + "repeated_password_is_incorrect": "Ọrọ igbaniwọle tun jẹ aṣiṣe. Jọwọ tun ọrọigbaniwọle apamọwọ lẹẹkansi.",
507 "require_for_adding_contacts": "Beere fun fifi awọn olubasọrọ kun",
508 "require_for_all_security_and_backup_settings": "Beere fun gbogbo aabo ati awọn eto afẹyinti",
509 "require_for_assessing_wallet": "Beere fun wiwọle si apamọwọ",
@@ -798,6 +802,7 @@
802 "unavailable_balance_description": "Iwontunws.funfun ti ko si: Lapapọ yii pẹlu awọn owo ti o wa ni titiipa ni awọn iṣowo isunmọ ati awọn ti o ti didi ni itara ninu awọn eto iṣakoso owo rẹ. Awọn iwọntunwọnsi titiipa yoo wa ni kete ti awọn iṣowo oniwun wọn ba ti pari, lakoko ti awọn iwọntunwọnsi tio tutunini ko ni iraye si fun awọn iṣowo titi iwọ o fi pinnu lati mu wọn kuro.",
803 "unconfirmed": "A kò tí ì jẹ́rìí ẹ̀",
804 "understand": "Ó ye mi",
805 + "unlock": "Sisalẹ",
806 "unmatched_currencies": "Irú owó ti àpamọ́wọ́ yín kì í ṣe irú ti yíya àmì ìlujá",
807 "unspent_change": "Yipada",
808 "unspent_coins_details_title": "Àwọn owó ẹyọ t'á kò tí ì san",
@@ -839,6 +844,7 @@
844 "wallet_menu": "Mẹ́nù",
845 "wallet_name": "Orúkọ àpamọ́wọ́",
846 "wallet_name_exists": "Ẹ ti ní àpamọ́wọ́ pẹ̀lú orúkọ̀ yẹn. Ẹ jọ̀wọ́ yàn orúkọ̀ tó yàtọ̀ tàbí pààrọ̀ orúkọ ti àpamọ́wọ́ tẹ́lẹ̀.",
847 + "wallet_password_is_empty": "Ọrọ igbaniwọle apamọwọ ti ṣofo. Ọrọ igbaniwọle apamọwọ ko yẹ ki o ṣofo",
848 "wallet_recovery_height": "Iga Imularada",
849 "wallet_restoration_store_incorrect_seed_length": "Gígùn hóró tí a máa ń lò kọ́ ni èyí",
850 "wallet_seed": "Hóró àpamọ́wọ́",
res/values/strings_zh.arb
+6
@@ -236,6 +236,7 @@
236 "enter_code": "输入代码",
237 "enter_seed_phrase": "输入您的种子短语",
238 "enter_totp_code": "请输入 TOTP 代码。",
239 + "enter_wallet_password": "输入钱包密码",
240 "enter_your_note": "输入您的笔记...",
241 "enter_your_pin": "输入密码",
242 "enter_your_pin_again": "再次输入您的PIN码",
@@ -340,6 +341,7 @@
341 "insufficientFundsForRentError": "您没有足够的溶胶来支付该帐户的交易费和租金。请在钱包中添加更多溶胶或减少您发送的溶胶量",
342 "introducing_cake_pay": "介绍 Cake Pay!",
343 "invalid_input": "输入无效",
344 + "invalid_password": "无效的密码",
345 "invoice_details": "发票明细",
346 "is_percentage": "是",
347 "last_30_days": "过去 30 天",
@@ -499,6 +501,8 @@
501 "rename": "重命名",
502 "rep_warning": "代表性警告",
503 "rep_warning_sub": "您的代表似乎并不信誉良好。点击这里选择一个新的",
504 + "repeat_wallet_password": "重复钱包密码",
505 + "repeated_password_is_incorrect": "重复密码不正确。请再次重复钱包密码。",
506 "require_for_adding_contacts": "需要添加联系人",
507 "require_for_all_security_and_backup_settings": "需要所有安全和备份设置",
508 "require_for_assessing_wallet": "需要访问钱包",
@@ -797,6 +801,7 @@
801 "unavailable_balance_description": "不可用余额:此总额包括锁定在待处理交易中的资金以及您在硬币控制设置中主动冻结的资金。一旦各自的交易完成,锁定的余额将变得可用,而冻结的余额在您决定解冻之前仍然无法进行交易。",
802 "unconfirmed": "未确认余额",
803 "understand": "我已知晓",
804 + "unlock": "开锁",
805 "unmatched_currencies": "您当前钱包的货币与扫描的 QR 的货币不匹配",
806 "unspent_change": "改变",
807 "unspent_coins_details_title": "未使用代幣詳情",
@@ -838,6 +843,7 @@
843 "wallet_menu": "钱包菜单",
844 "wallet_name": "钱包名称",
845 "wallet_name_exists": "同名的钱包已经存在",
846 + "wallet_password_is_empty": "钱包密码为空。钱包密码不应为空",
847 "wallet_recovery_height": "恢复高度",
848 "wallet_restoration_store_incorrect_seed_length": "种子长度错误",
849 "wallet_seed": "钱包种子",
scripts/android/shell.nix deleted
-16
@@ -1,16 +0,0 @@
1 -{ pkgs ? import <nixpkgs> {} }:
2 -
3 -pkgs.mkShell {
4 - buildInputs = [
5 - pkgs.curl
6 - pkgs.unzip
7 - pkgs.automake
8 - pkgs.file
9 - pkgs.pkg-config
10 - pkgs.git
11 - pkgs.libtool
12 - pkgs.ncurses5
13 - pkgs.openjdk8
14 - pkgs.clang
15 - ];
16 -}
scripts/ios/gen_framework.sh
+1 -1
@@ -28,4 +28,4 @@ fi
28 cd $FRWK_DIR # go to iOS framework dir
29 lipo -create $DYLIB_LINK_PATH -output WowneroWallet
30
31 -echo "Generated ${FRWK_DIR}"
\ No newline at end of file
31 +echo "Generated ${FRWK_DIR}"
scripts/linux/app_config.sh new
+25
@@ -0,0 +1,25 @@
1 +#!/bin/bash
2 +
3 +CAKEWALLET="cakewallet"
4 +DIR=`pwd`
5 +
6 +if [ -z "$APP_LINUX_TYPE" ]; then
7 + echo "Please set APP_LINUX_TYPE"
8 + exit 1
9 +fi
10 +
11 +cd ../.. # go to root
12 +CONFIG_ARGS=""
13 +
14 +case $APP_LINUX_TYPE in
15 + $CAKEWALLET)
16 + CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero --excludeFlutterSecureStorage";;
17 +esac
18 +
19 +cp -rf pubspec_description.yaml pubspec.yaml
20 +flutter pub get
21 +flutter pub run tool/generate_pubspec.dart
22 +flutter pub get
23 +flutter packages pub run tool/configure.dart $CONFIG_ARGS
24 +sed -i '0,/version: 0.0.0/s//version: '"${APP_LINUX_VERSION}"'+'"${APP_LINUX_BUILD_NUMBER}"'/' pubspec.yaml
25 +cd $DIR
scripts/linux/app_env.fish new
+35
@@ -0,0 +1,35 @@
1 +#!/usr/bin/env fish
2 +
3 +set -g APP_LINUX_NAME ""
4 +set -g APP_LINUX_VERSION ""
5 +set -g APP_LINUX_BUILD_NUMBER ""
6 +
7 +set -g CAKEWALLET "cakewallet"
8 +
9 +set -g TYPES $CAKEWALLET
10 +set -g APP_LINUX_TYPE $CAKEWALLET
11 +
12 +if test -n "$argv[1]"
13 + set -g APP_LINUX_TYPE $argv[1]
14 +end
15 +
16 +set -g CAKEWALLET_NAME "Cake Wallet"
17 +set -g CAKEWALLET_VERSION "1.9.0"
18 +set -g CAKEWALLET_BUILD_NUMBER 29
19 +
20 +if not contains -- $APP_LINUX_TYPE $TYPES
21 + echo "Wrong app type."
22 + exit 1
23 +end
24 +
25 +switch $APP_LINUX_TYPE
26 + case $CAKEWALLET
27 + set -g APP_LINUX_NAME $CAKEWALLET_NAME
28 + set -g APP_LINUX_VERSION $CAKEWALLET_VERSION
29 + set -g APP_LINUX_BUILD_NUMBER $CAKEWALLET_BUILD_NUMBER
30 +end
31 +
32 +export APP_LINUX_TYPE
33 +export APP_LINUX_NAME
34 +export APP_LINUX_VERSION
35 +export APP_LINUX_BUILD_NUMBER
scripts/linux/app_env.sh new
+35
@@ -0,0 +1,35 @@
1 +#!/bin/sh
2 +
3 +APP_LINUX_NAME=""
4 +APP_LINUX_VERSION=""
5 +APP_LINUX_BUILD_VERSION=""
6 +
7 +CAKEWALLET="cakewallet"
8 +
9 +TYPES=($CAKEWALLET)
10 +APP_LINUX_TYPE=$CAKEWALLET
11 +
12 +if [ -n "$1" ]; then
13 + APP_LINUX_TYPE=$1
14 +fi
15 +
16 +CAKEWALLET_NAME="Cake Wallet"
17 +CAKEWALLET_VERSION="1.9.2"
18 +CAKEWALLET_BUILD_NUMBER=30
19 +
20 +if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then
21 + echo "Wrong app type."
22 + exit 1
23 +fi
24 +
25 +case $APP_LINUX_TYPE in
26 + $CAKEWALLET)
27 + APP_LINUX_NAME=$CAKEWALLET_NAME
28 + APP_LINUX_VERSION=$CAKEWALLET_VERSION
29 + APP_LINUX_BUILD_NUMBER=$CAKEWALLET_BUILD_NUMBER;;
30 +esac
31 +
32 +export APP_LINUX_TYPE
33 +export APP_LINUX_NAME
34 +export APP_LINUX_VERSION
35 +export APP_LINUX_BUILD_NUMBER
scripts/linux/build_all.sh new
+3
@@ -0,0 +1,3 @@
1 +#!/bin/sh
2 +
3 +./build_monero_all.sh
scripts/linux/build_boost.sh new
+36
@@ -0,0 +1,36 @@
1 +#!/bin/sh
2 +
3 +set -e
4 +
5 +. ./config.sh
6 +
7 +BOOST_SRC_DIR=${EXTERNAL_LINUX_SOURCE_DIR}/boost_1_82_0
8 +BOOST_FILENAME=boost_1_82_0.tar.bz2
9 +BOOST_VERSION=1.82.0
10 +BOOST_FILE_PATH=${EXTERNAL_LINUX_SOURCE_DIR}/$BOOST_FILENAME
11 +BOOST_SHA256="a6e1ab9b0860e6a2881dd7b21fe9f737a095e5f33a3a874afc6a345228597ee6"
12 +
13 +if [ ! -e "$BOOST_FILE_PATH" ]; then
14 + curl -L http://downloads.sourceforge.net/project/boost/boost/${BOOST_VERSION}/${BOOST_FILENAME} > $BOOST_FILE_PATH
15 +fi
16 +
17 +echo $BOOST_SHA256 $BOOST_FILE_PATH | sha256sum -c - || exit 1
18 +
19 +cd $EXTERNAL_LINUX_SOURCE_DIR
20 +rm -rf $BOOST_SRC_DIR
21 +tar -xvf $BOOST_FILE_PATH -C $EXTERNAL_LINUX_SOURCE_DIR
22 +cd $BOOST_SRC_DIR
23 +./bootstrap.sh --prefix=${EXTERNAL_LINUX_DIR}
24 +./b2 cxxflags=-fPIC cflags=-fPIC \
25 + --with-chrono \
26 + --with-date_time \
27 + --with-filesystem \
28 + --with-program_options \
29 + --with-regex \
30 + --with-serialization \
31 + --with-system \
32 + --with-thread \
33 + --with-locale \
34 + link=static \
35 + install
36 +
scripts/linux/build_expat.sh new
+20
@@ -0,0 +1,20 @@
1 +#!/bin/sh
2 +
3 +set -e
4 +
5 +. ./config.sh
6 +
7 +
8 +EXPAT_VERSION=R_2_4_8
9 +EXPAT_HASH="3bab6c09bbe8bf42d84b81563ddbcf4cca4be838"
10 +EXPAT_SRC_DIR=${EXTERNAL_LINUX_SOURCE_DIR}/libexpat
11 +
12 +git clone https://github.com/libexpat/libexpat.git -b ${EXPAT_VERSION} ${EXPAT_SRC_DIR}
13 +cd $EXPAT_SRC_DIR
14 +test `git rev-parse HEAD` = ${EXPAT_HASH} || exit 1
15 +cd $EXPAT_SRC_DIR/expat
16 +
17 +./buildconf.sh
18 +./configure --enable-static --disable-shared --prefix=${EXTERNAL_LINUX_DIR}
19 +make
20 +make install
scripts/linux/build_iconv.sh new
+22
@@ -0,0 +1,22 @@
1 +#!/bin/sh
2 +
3 +set -e
4 +
5 +. ./config.sh
6 +
7 +export ICONV_FILENAME=libiconv-1.16.tar.gz
8 +export ICONV_FILE_PATH=${EXTERNAL_LINUX_SOURCE_DIR}/${ICONV_FILENAME}
9 +export ICONV_SRC_DIR=${EXTERNAL_LINUX_SOURCE_DIR}/libiconv-1.16
10 +ICONV_SHA256="e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04"
11 +
12 +curl http://ftp.gnu.org/pub/gnu/libiconv/${ICONV_FILENAME} -o $ICONV_FILE_PATH
13 +echo $ICONV_SHA256 $ICONV_FILE_PATH | sha256sum -c - || exit 1
14 +
15 +cd $EXTERNAL_LINUX_SOURCE_DIR
16 +rm -rf $ICONV_SRC_DIR
17 +tar -xzf $ICONV_FILE_PATH -C $EXTERNAL_LINUX_SOURCE_DIR
18 +cd $ICONV_SRC_DIR
19 +
20 +./configure --prefix=${EXTERNAL_LINUX_DIR}
21 +make
22 +make install
scripts/linux/build_monero.sh new
+40
@@ -0,0 +1,40 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +MONERO_URL="https://github.com/cake-tech/monero.git"
6 +MONERO_DIR_PATH="${EXTERNAL_LINUX_SOURCE_DIR}/monero"
7 +MONERO_VERSION=release-v0.18.3.2
8 +PREFIX=${EXTERNAL_LINUX_DIR}
9 +DEST_LIB_DIR=${EXTERNAL_LINUX_LIB_DIR}/monero
10 +DEST_INCLUDE_DIR=${EXTERNAL_LINUX_INCLUDE_DIR}/monero
11 +
12 +echo "Cloning monero from - $MONERO_URL to - $MONERO_DIR_PATH"
13 +git clone $MONERO_URL $MONERO_DIR_PATH
14 +cd $MONERO_DIR_PATH
15 +git checkout $MONERO_VERSION
16 +git submodule update --init --force
17 +rm -rf ./build/release
18 +mkdir -p ./build/release
19 +cd ./build/release
20 +
21 +mkdir -p $DEST_LIB_DIR
22 +mkdir -p $DEST_INCLUDE_DIR
23 +
24 +echo "Building LINUX"
25 +export CMAKE_INCLUDE_PATH="${PREFIX}/include"
26 +export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
27 +
28 +cmake -DSTATIC=ON \
29 + -DBUILD_GUI_DEPS=ON \
30 + -DUNBOUND_INCLUDE_DIR=${EXTERNAL_LINUX_INCLUDE_DIR} \
31 + -DCMAKE_INSTALL_PREFIX=${PREFIX} \
32 + -DUSE_DEVICE_TREZOR=OFF \
33 + -DMANUAL_SUBMODULES=1 \
34 + ../..
35 +
36 +make wallet_api -j$(($(nproc) / 2))
37 +
38 +find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
39 +cp -r ./lib/* $DEST_LIB_DIR
40 +cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
scripts/linux/build_monero_all.sh new
+21
@@ -0,0 +1,21 @@
1 +#!/bin/bash
2 +
3 +
4 +. ./config.sh
5 +
6 +
7 +set -x -e
8 +
9 +cd "$(dirname "$0")"
10 +
11 +NPROC="-j$(nproc)"
12 +
13 +../prepare_moneroc.sh
14 +
15 +for COIN in monero wownero;
16 +do
17 + pushd ../monero_c
18 + ./build_single.sh ${COIN} $(gcc -dumpmachine) $NPROC
19 + popd
20 + unxz -f ../monero_c/release/${COIN}/$(gcc -dumpmachine)_libwallet2_api_c.so.xz
21 +done
scripts/linux/build_openssl.sh new
+19
@@ -0,0 +1,19 @@
1 +#!/bin/sh
2 +
3 +set -e
4 +
5 +. ./config.sh
6 +
7 +OPENSSL_FILENAME=openssl-1.1.1q.tar.gz
8 +OPENSSL_FILE_PATH=${EXTERNAL_LINUX_SOURCE_DIR}/${OPENSSL_FILENAME}
9 +OPENSSL_SRC_DIR=${EXTERNAL_LINUX_SOURCE_DIR}/openssl-1.1.1q
10 +OPENSSL_SHA256="d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca"
11 +
12 +curl https://www.openssl.org/source/${OPENSSL_FILENAME} -o ${OPENSSL_FILE_PATH}
13 +
14 +rm -rf $OPENSSL_SRC_DIR
15 +tar -xzf $OPENSSL_FILE_PATH -C $EXTERNAL_LINUX_SOURCE_DIR
16 +cd $OPENSSL_SRC_DIR
17 +export CFLAGS=-fPIC
18 +./config -fPIC shared --prefix=${EXTERNAL_LINUX_DIR}
19 +make install
scripts/linux/build_sodium.sh new
+19
@@ -0,0 +1,19 @@
1 +#!/bin/sh
2 +
3 +set -e
4 +
5 +. ./config.sh
6 +
7 +SODIUM_PATH="${EXTERNAL_LINUX_SOURCE_DIR}/libsodium"
8 +SODIUM_URL="https://github.com/jedisct1/libsodium.git"
9 +
10 +echo "============================ SODIUM ============================"
11 +
12 +echo "Cloning SODIUM from - $SODIUM_URL"
13 +git clone $SODIUM_URL $SODIUM_PATH --branch stable
14 +cd $SODIUM_PATH
15 +
16 +
17 +./configure --prefix=${EXTERNAL_LINUX_DIR}
18 +make
19 +make install
scripts/linux/build_unbound.sh new
+25
@@ -0,0 +1,25 @@
1 +#!/bin/sh
2 +
3 +set -e
4 +
5 +. ./config.sh
6 +
7 +UNBOUND_VERSION=release-1.16.2
8 +UNBOUND_HASH="cbed768b8ff9bfcf11089a5f1699b7e5707f1ea5"
9 +UNBOUND_DIR_PATH="${EXTERNAL_LINUX_SOURCE_DIR}/unbound-1.16.2"
10 +
11 +echo "============================ Unbound ============================"
12 +rm -rf ${UNBOUND_DIR_PATH}
13 +git clone https://github.com/NLnetLabs/unbound.git -b ${UNBOUND_VERSION} ${UNBOUND_DIR_PATH}
14 +cd $UNBOUND_DIR_PATH
15 +test `git rev-parse HEAD` = ${UNBOUND_HASH} || exit 1
16 +
17 +export CFLAGS=-fPIC
18 +./configure cxxflags=-fPIC cflags=-fPIC \
19 + --prefix="${EXTERNAL_LINUX_DIR}" \
20 + --with-ssl="${EXTERNAL_LINUX_DIR}" \
21 + --with-libexpat="${EXTERNAL_LINUX_DIR}" \
22 + --enable-static \
23 + --disable-flto
24 +make
25 +make install
scripts/linux/build_zmq.sh new
+17
@@ -0,0 +1,17 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +ZMQ_PATH="${EXTERNAL_LINUX_SOURCE_DIR}/libzmq"
6 +ZMQ_URL="https://github.com/zeromq/libzmq.git"
7 +
8 +echo "============================ ZMQ ============================"
9 +
10 +echo "Cloning ZMQ from - $ZMQ_URL"
11 +git clone $ZMQ_URL $ZMQ_PATH
12 +cd $ZMQ_PATH
13 +mkdir cmake-build
14 +cd cmake-build
15 +cmake .. -DCMAKE_INSTALL_PREFIX="${EXTERNAL_LINUX_DIR}"
16 +make
17 +make install
scripts/linux/cakewallet.sh new
+4
@@ -0,0 +1,4 @@
1 +#!/bin/bash
2 +
3 +. ./app_env.sh "cakewallet"
4 +. ./app_config.sh
scripts/linux/config.sh new
+13
@@ -0,0 +1,13 @@
1 +#!/bin/sh
2 +
3 +export LINUX_SCRIPTS_DIR=`pwd`
4 +export CW_ROOT=${LINUX_SCRIPTS_DIR}/../..
5 +export EXTERNAL_DIR=${CW_ROOT}/cw_shared_external/ios/External
6 +export EXTERNAL_LINUX_DIR=${EXTERNAL_DIR}/linux
7 +export EXTERNAL_LINUX_SOURCE_DIR=${EXTERNAL_LINUX_DIR}/sources
8 +export EXTERNAL_LINUX_LIB_DIR=${EXTERNAL_LINUX_DIR}/lib
9 +export EXTERNAL_LINUX_INCLUDE_DIR=${EXTERNAL_LINUX_DIR}/include
10 +
11 +mkdir -p $EXTERNAL_LINUX_LIB_DIR
12 +mkdir -p $EXTERNAL_LINUX_INCLUDE_DIR
13 +mkdir -p $EXTERNAL_LINUX_SOURCE_DIR
scripts/linux/gcc10.nix new
+12
@@ -0,0 +1,12 @@
1 +with import <nixpkgs> {};
2 +gcc10Stdenv.mkDerivation {
3 + name="gcc10-stdenv";
4 + buildInputs = [
5 + pkgs.cmake
6 + pkgs.pkg-config
7 + pkgs.autoconf
8 + pkgs.libtool
9 + pkgs.expat
10 + ];
11 +}
12 +
scripts/linux/setup.sh new
+9
@@ -0,0 +1,9 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +CW_EXTERNAL_DIR=${CW_ROOT}/cw_monero/ios/External/linux
6 +CW_EXTERNAL_DIR_INCLUDE=${CW_EXTERNAL_DIR}/include
7 +
8 +mkdir -p $CW_EXTERNAL_DIR_INCLUDE
9 +cp $EXTERNAL_LINUX_INCLUDE_DIR/monero/wallet2_api.h $CW_EXTERNAL_DIR_INCLUDE
tool/configure.dart
+17 -17
@@ -150,7 +150,7 @@ abstract class Bitcoin {
150 String? passphrase,
151 });
152 WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo});
153 - WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo});
153 + WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password});
154 WalletCredentials createBitcoinHardwareWalletCredentials({required String name, required HardwareAccountData accountData, WalletInfo? walletInfo});
155 List<String> getWordList();
156 Map<String, String> getWalletKeys(Object wallet);
@@ -179,8 +179,8 @@ abstract class Bitcoin {
179 List<Unspent> getUnspents(Object wallet);
180 Future<void> updateUnspents(Object wallet);
181 WalletService createBitcoinWalletService(
182 - Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan);
183 - WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
182 + Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan, bool isDirect);
183 + WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect);
184 TransactionPriority getBitcoinTransactionPriorityMedium();
185 TransactionPriority getBitcoinTransactionPriorityCustom();
186 TransactionPriority getLitecoinTransactionPriorityMedium();
@@ -369,7 +369,7 @@ abstract class Monero {
369 required String language,
370 required int height});
371 WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
372 - WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String password});
372 + WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String? password});
373 Map<String, String> getKeys(Object wallet);
374 int? getRestoreHeight(Object wallet);
375 Object createMoneroTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority});
@@ -734,7 +734,7 @@ abstract class Haven {
734 required String language,
735 required int height});
736 WalletCredentials createHavenRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
737 - WalletCredentials createHavenNewWalletCredentials({required String name, required String language, String password});
737 + WalletCredentials createHavenNewWalletCredentials({required String name, required String language, String? password});
738 Map<String, String> getKeys(Object wallet);
739 Object createHavenTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority, required String assetType});
740 String formatterMoneroAmountToString({required int amount});
@@ -828,8 +828,8 @@ import 'package:eth_sig_util/util/utils.dart';
828 const ethereumContent = """
829 abstract class Ethereum {
830 List<String> getEthereumWordList(String language);
831 - WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource);
832 - WalletCredentials createEthereumNewWalletCredentials({required String name, WalletInfo? walletInfo});
831 + WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
832 + WalletCredentials createEthereumNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password});
833 WalletCredentials createEthereumRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
834 WalletCredentials createEthereumRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password});
835 WalletCredentials createEthereumHardwareWalletCredentials({required String name, required HardwareAccountData hwAccountData, WalletInfo? walletInfo});
@@ -932,8 +932,8 @@ import 'package:eth_sig_util/util/utils.dart';
932 const polygonContent = """
933 abstract class Polygon {
934 List<String> getPolygonWordList(String language);
935 - WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource);
936 - WalletCredentials createPolygonNewWalletCredentials({required String name, WalletInfo? walletInfo});
935 + WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
936 + WalletCredentials createPolygonNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password});
937 WalletCredentials createPolygonRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
938 WalletCredentials createPolygonRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password});
939 WalletCredentials createPolygonHardwareWalletCredentials({required String name, required HardwareAccountData hwAccountData, WalletInfo? walletInfo});
@@ -1017,10 +1017,10 @@ abstract class BitcoinCash {
1017 String getCashAddrFormat(String address);
1018
1019 WalletService createBitcoinCashWalletService(
1020 - Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
1020 + Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect);
1021
1022 WalletCredentials createBitcoinCashNewWalletCredentials(
1023 - {required String name, WalletInfo? walletInfo});
1023 + {required String name, WalletInfo? walletInfo, String? password});
1024
1025 WalletCredentials createBitcoinCashRestoreWalletFromSeedCredentials(
1026 {required String name, required String mnemonic, required String password});
@@ -1097,11 +1097,11 @@ abstract class Nano {
1097
1098 void setCurrentAccount(Object wallet, int id, String label, String? balance);
1099
1100 - WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource);
1100 + WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
1101
1102 WalletCredentials createNanoNewWalletCredentials({
1103 required String name,
1104 - String password,
1104 + String? password,
1105 });
1106
1107 WalletCredentials createNanoRestoreWalletFromSeedCredentials({
@@ -1215,9 +1215,9 @@ import 'package:cw_solana/solana_wallet_creation_credentials.dart';
1215 const solanaContent = """
1216 abstract class Solana {
1217 List<String> getSolanaWordList(String language);
1218 - WalletService createSolanaWalletService(Box<WalletInfo> walletInfoSource);
1218 + WalletService createSolanaWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
1219 WalletCredentials createSolanaNewWalletCredentials(
1220 - {required String name, WalletInfo? walletInfo});
1220 + {required String name, WalletInfo? walletInfo, String? password});
1221 WalletCredentials createSolanaRestoreWalletFromSeedCredentials(
1222 {required String name, required String mnemonic, required String password});
1223 WalletCredentials createSolanaRestoreWalletFromPrivateKey(
@@ -1302,8 +1302,8 @@ import 'package:cw_tron/tron_wallet_service.dart';
1302 const tronContent = """
1303 abstract class Tron {
1304 List<String> getTronWordList(String language);
1305 - WalletService createTronWalletService(Box<WalletInfo> walletInfoSource);
1306 - WalletCredentials createTronNewWalletCredentials({required String name, WalletInfo? walletInfo});
1305 + WalletService createTronWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
1306 + WalletCredentials createTronNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password});
1307 WalletCredentials createTronRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
1308 WalletCredentials createTronRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password});
1309 String getAddress(WalletBase wallet);