Wownero (#1485)

* fix: scanning issues * fix: sync, storing silent unspents * chore: deps * fix: label issues, clear spent utxo * chore: deps * fix: build * fix: missing types * feat: new electrs API & changes, fixes for last block scanning * 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 * 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 * fix: send all with multiple outs * add missing monero_c command * add android build script * 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 * Add tron to windows application configuration. * Add macOS option for description message in configure_cake_wallet.sh * Include missed monero dll for windows. * 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. * 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++ * 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 * 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 * 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 * Update macOS build guide. Change brew dependencies for build unbound locally. * fix conflicts and update macos build guide * remove build cache when on gh actions * update secure storage * free up even more storage * free up more storage * Add initial wownero * fix conflicts * fix workflow issue * build wownero * ios and windows changes * macos * complete wownero flow (app side) * add keychain group entitlement and update script for RunnerBase on macos * update secure_storage version to 8.1.0 in configure.dart * add wownero framework * update ios builds * proper path for wownero and monero * finalizing wownero * finalizing wownero * free up even more storage * revert commenting of build gradle configs * revert commenting of secrets [skip ci] * free more storage * minor fixes * link android wownero libraries * bump monero_c commit * wownero fixes * rename target * build_single.sh using clean env * bump monero_c commit * minor fix * Add wownero polyseed * fix conflicts with main * fix: wallet seed display fix: wownero not refreshing * fix: wallet seed display fix: wownero not refreshing * bump monero_c commit * minor fixes * fix: incorrectly displaying XMR instead of WOW * fix: incorrect restore height in wownero * bump monero_c commit * Add Inno Setup Script for windows exe installer * drop libc++_shared.so * fixes from comments * Fix CMake for windows * Merge latest monero dart changes [skip ci] * bump monero_c commit * add wownero to build scripts for macos [skip ci] * add 14 word seed support to wownero * UI fixes for wownero seed restore * minor fixes * reformat code to pass lints * wownero: fixes haven: removal popup * minor iOS fix [skip ci] * fix: wownero confirmation count (it is spendable after 3 confirms) fix: transaction history not displaying in WOW and XMR when tx has 0 confirms, This is more of a workaround, because I have no idea why would the cpp code not return pending transaction. * Update preferences_key.dart [skip ci] * minor fixes --------- Co-authored-by: Rafael Saes <git@rafael.saes.dev> Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net> Co-authored-by: M <m@cakewallet.com> Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com> Co-authored-by: Matthew Fosse <matt@fosse.co>

Omar Hatem committed Jul 4, 2024 at 22:43 UTC 36eacd869808d86a3a504186c9dbb1034882c7f9
309 files changed +26272 -6362
.github/workflows/cache_dependencies.yml
+1
@@ -46,6 +46,7 @@ jobs:
46 /opt/android/cake_wallet/cw_monero/android/.cxx
47 /opt/android/cake_wallet/cw_monero/ios/External
48 /opt/android/cake_wallet/cw_shared_external/ios/External
49 + /opt/android/cake_wallet/scripts/monero_c/release
50 key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
51
52 - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
.github/workflows/pr_test_build.yml
+16 -8
@@ -27,18 +27,25 @@ jobs:
27 if: github.event_name != 'pull_request'
28 run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENV
29
30 - - name: Free Up GitHub Actions Ubuntu Runner Disk Space
31 - run: |
32 - sudo rm -rf /usr/share/dotnet
33 - sudo rm -rf /opt/ghc
34 - sudo rm -rf "/usr/local/share/boost"
35 - sudo rm -rf "$AGENT_TOOLSDIRECTORY"
30 + - name: Free Disk Space (Ubuntu)
31 + uses: insightsengineering/disk-space-reclaimer@v1
32 + with:
33 + tools-cache: true
34 + android: false
35 + dotnet: true
36 + haskell: true
37 + large-packages: true
38 + swap-storage: true
39 + docker-images: true
40
41 - uses: actions/checkout@v2
42 - uses: actions/setup-java@v1
43 with:
44 java-version: "11.x"
41 -
45 + - name: Configure placeholder git details
46 + run: |
47 + git config --global user.email "CI@cakewallet.com"
48 + git config --global user.name "Cake Github Actions"
49 - name: Flutter action
50 uses: subosito/flutter-action@v1
51 with:
@@ -72,7 +79,8 @@ jobs:
79 /opt/android/cake_wallet/cw_monero/android/.cxx
80 /opt/android/cake_wallet/cw_monero/ios/External
81 /opt/android/cake_wallet/cw_shared_external/ios/External
75 - key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
82 + /opt/android/cake_wallet/scripts/monero_c/release
83 + key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
84
85 - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
86 name: Generate Externals
.gitignore
+8
@@ -136,6 +136,7 @@ lib/nano/nano.dart
136 lib/polygon/polygon.dart
137 lib/solana/solana.dart
138 lib/tron/tron.dart
139 +lib/wownero/wownero.dart
140
141 ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
142 ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png
@@ -156,6 +157,7 @@ assets/images/app_logo.png
157 macos/Runner/Info.plist
158 macos/Runner/DebugProfile.entitlements
159 macos/Runner/Release.entitlements
160 +macos/Runner/Runner.entitlements
161 lib/core/secure_storage.dart
162
163 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
@@ -166,3 +168,9 @@ macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
168 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
169 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
170 macos/Runner/Configs/AppInfo.xcconfig
171 +
172 +# Monero.dart (Monero_C)
173 +scripts/monero_c
174 +# iOS generated framework bin
175 +ios/MoneroWallet.framework/MoneroWallet
176 +ios/WowneroWallet.framework/WowneroWallet
.metadata
+8 -8
@@ -1,11 +1,11 @@
1 # This file tracks properties of this Flutter project.
2 # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 #
4 -# This file should be version controlled.
4 +# This file should be version controlled and should not be manually edited.
5
6 version:
7 - revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
8 - channel: stable
7 + revision: "367f9ea16bfae1ca451b9cc27c1366870b187ae2"
8 + channel: "stable"
9
10 project_type: app
11
@@ -13,11 +13,11 @@ project_type: app
13 migration:
14 platforms:
15 - platform: root
16 - create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
17 - base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
18 - - platform: macos
19 - create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
20 - base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
16 + create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
17 + base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
18 + - platform: windows
19 + create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
20 + base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
21
22 # User provided section
23
android/app/src/main/AndroidManifestBase.xml
+5 -1
@@ -38,7 +38,8 @@
38 android:fullBackupContent="false"
39 android:versionCode="__versionCode__"
40 android:versionName="__versionName__"
41 - android:requestLegacyExternalStorage="true">
41 + android:requestLegacyExternalStorage="true"
42 + android:extractNativeLibs="true">
43 <activity
44 android:name=".MainActivity"
45 android:launchMode="singleInstance"
@@ -90,6 +91,9 @@
91 <data android:scheme="tron" />
92 <data android:scheme="tron-wallet" />
93 <data android:scheme="tron_wallet" />
94 + <data android:scheme="wownero" />
95 + <data android:scheme="wownero-wallet" />
96 + <data android:scheme="wownero_wallet" />
97 </intent-filter>
98 <!-- nano-gpt link scheme -->
99 <intent-filter android:autoVerify="true">
android/app/src/main/jniLibs/arm64-v8a/.gitkeep renamed
android/app/src/main/jniLibs/arm64-v8a/libmonero_libwallet2_api_c.so new
+1
@@ -0,0 +1 @@
1 +../../../../../../scripts/monero_c/release/monero/aarch64-linux-android_libwallet2_api_c.so
\ No newline at end of file
android/app/src/main/jniLibs/arm64-v8a/libwownero_libwallet2_api_c.so new
+1
@@ -0,0 +1 @@
1 +../../../../../../scripts/monero_c/release/wownero/aarch64-linux-android_libwallet2_api_c.so
\ No newline at end of file
android/app/src/main/jniLibs/armeabi-v7a/.gitkeep
android/app/src/main/jniLibs/armeabi-v7a/libmonero_libwallet2_api_c.so new
+1
@@ -0,0 +1 @@
1 +../../../../../../scripts/monero_c/release/monero/armv7a-linux-androideabi_libwallet2_api_c.so
\ No newline at end of file
android/app/src/main/jniLibs/armeabi-v7a/libwownero_libwallet2_api_c.so new
+1
@@ -0,0 +1 @@
1 +../../../../../../scripts/monero_c/release/wownero/armv7a-linux-androideabi_libwallet2_api_c.so
\ No newline at end of file
android/app/src/main/jniLibs/x86/.gitkeep
android/app/src/main/jniLibs/x86_64/.gitkeep
android/app/src/main/jniLibs/x86_64/libmonero_libwallet2_api_c.so new
+1
@@ -0,0 +1 @@
1 +../../../../../../scripts/monero_c/release/monero/x86_64-linux-android_libwallet2_api_c.so
\ No newline at end of file
android/app/src/main/jniLibs/x86_64/libwownero_libwallet2_api_c.so new
+1
@@ -0,0 +1 @@
1 +../../../../../../scripts/monero_c/release/wownero/x86_64-linux-android_libwallet2_api_c.so
\ No newline at end of file
assets/bitcoin_electrum_server_list.yml
+7 -1
@@ -1,2 +1,8 @@
1 -
2 - uri: electrum.cakewallet.com:50002
\ No newline at end of file
2 + uri: electrum.cakewallet.com:50002
3 + useSSL: true
4 +-
5 + uri: btc-electrum.cakewallet.com:50002
6 + isDefault: true
7 +-
8 + uri: electrs.cakewallet.com:50001
assets/images/wownero_icon.png
Binary files /dev/null and b/assets/images/wownero_icon.png differ
assets/images/wownero_menu.png
Binary files /dev/null and b/assets/images/wownero_menu.png differ
assets/text/Monerocom_Release_Notes.txt
+2 -2
@@ -1,2 +1,2 @@
1 -In-app Cake Pay is Back
2 -Bug fixes and generic enhancements
\ No newline at end of file
1 +Monero enhancements
2 +Bug fixes
\ No newline at end of file
assets/text/Release_Notes.txt
+2 -3
@@ -1,3 +1,2 @@
1 -In-app Cake Pay is Back
2 -Bitcoin nodes stability enhancements
3 -Bug fixes and generic enhancements
\ No newline at end of file
1 +Monero enhancements
2 +Bug fixes
\ No newline at end of file
assets/wownero_node_list.yml new
+12
@@ -0,0 +1,12 @@
1 +-
2 + uri: node3.monerodevs.org:34568
3 + is_default: true
4 + useSSL: false
5 +-
6 + uri: node2.monerodevs.org:34568
7 + is_default: false
8 + useSSL: false
9 +-
10 + uri: node.monerodevs.org:34568
11 + is_default: false
12 + useSSL: false
build-guide-win.md new
+38
@@ -0,0 +1,38 @@
1 +# Building CakeWallet for Windows
2 +
3 +## Requirements and Setup
4 +
5 +The following are the system requirements to build CakeWallet for your Windows PC.
6 +
7 +```
8 +Windows 10 or later (64-bit), x86-64 based
9 +Flutter 3 or above
10 +```
11 +
12 +## Building CakeWallet on Windows
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 +For build CakeWallet windows application from sources you will be needed to have:
19 +> [Install Flutter]Follow installation guide (https://docs.flutter.dev/get-started/install/windows) and install do not miss to dev tools (install https://docs.flutter.dev/get-started/install/windows/desktop#development-tools) which are required for windows desktop development (need to install Git for Windows and Visual Studio 2022). Then install `Desktop development with C++` packages via GUI Visual Studio 2022, or Visual Studio Build Tools 2022 including: `C++ Build Tools core features`, `C++ 2022 Redistributable Update`, `C++ core desktop features`, `MVC v143 - VS 2022 C++ x64/x86 build tools`, `C++ CMake tools for Windwos`, `Testing tools core features - Build Tools`, `C++ AddressSanitizer`.
20 +> [Install WSL] for building monero dependencies need to install Windows WSL (https://learn.microsoft.com/en-us/windows/wsl/install) and required packages for WSL (Ubuntu):
21 +`$ sudo apt update `
22 +`$ sudo apt build-essential cmake gcc-mingw-w64 g++-mingw-w64 autoconf libtool pkg-config`
23 +
24 +### 2. Pull CakeWallet source code
25 +
26 +You can downlaod CakeWallet source code from our [GitHub repository](github.com/cake-tech/cake_wallet) via git by following next command:
27 +`$ git clone https://github.com/cake-tech/cake_wallet.git --branch MrCyjaneK-cyjan-monerodart`
28 +OR you can download it as [Zip archive](https://github.com/cake-tech/cake_wallet/archive/refs/heads/MrCyjaneK-cyjan-monerodart.zip)
29 +
30 +### 3. Build Monero, Monero_c and their dependencies
31 +
32 +For use monero in the application need to build Monero wrapper - Monero_C which will be used by monero.dart package. For that need to run shell (bash - typically same named utility should be available after WSL is enabled in your system) with previously installed WSL, then change current directory to the application project directory with your used shell and then change current directory to `scripts/windows`: `$ cd scripts/windows`. Run build script: `$ ./build_all.sh`.
33 +
34 +### 4. Configure and build CakeWallet application
35 +
36 +To configure the application open directory where you have downloaded or unarchived CakeWallet sources and run `cakewallet.bat`.
37 +Or if you used WSL and have active shell session you can run `$ ./cakewallet.sh` script in `scripts/windows` which will run `cakewallet.bat` in WSL.
38 +After execution of `cakewallet.bat` you should to get `Cake Wallet.zip` in project root directory which will contains `CakeWallet.exe` file and another needed files for run the application. Now you can extract files from `Cake Wallet.zip` archive and run the application.
cakewallet.bat new
+51
@@ -0,0 +1,51 @@
1 +@echo off
2 +set cw_win_app_config=--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron
3 +set cw_root=%cd%
4 +set cw_archive_name=Cake Wallet.zip
5 +set cw_archive_path=%cw_root%\%cw_archive_name%
6 +set secrets_file_path=lib\.secrets.g.dart
7 +set release_dir=build\windows\x64\runner\Release
8 +@REM Path could be different
9 +if [%~1]==[] (set tools_root=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Redist\MSVC\14.38.33135\x64\Microsoft.VC143.CRT) else (set tools_root=%1)
10 +@REM Generate android manifest file
11 +cd scripts
12 +bash.exe gen_android_manifest.sh
13 +cd /d %cw_root%
14 +echo === Generating pubspec.yaml ===
15 +copy /Y pubspec_description.yaml pubspec.yaml > nul
16 +call flutter pub get > nul
17 +call dart run tool\generate_pubspec.dart
18 +call flutter pub get > nul
19 +call dart run tool\configure.dart %cw_win_app_config%
20 +
21 +IF NOT EXIST "%secrets_file_path%" (
22 + echo === Generating new secrets file ===
23 + call dart run tool\generate_new_secrets.dart
24 +) ELSE (echo === Using previously/already generated secrets file: %secrets_file_path% ===)
25 +
26 +echo === Generating mobx models ===
27 +for /d %%i in (cw_core cw_monero cw_bitcoin cw_ethereum cw_evm cw_polygon cw_nano cw_bitcoin_cash cw_solana cw_tron .) do (
28 + cd %%i
29 + call flutter pub get > nul
30 + call dart run build_runner build --delete-conflicting-outputs > nul
31 + cd /d %cw_root%
32 +)
33 +
34 +echo === Generating localization files ===
35 +call dart run tool\generate_localization.dart
36 +
37 +echo === Building the application executable file ===
38 +call flutter build windows --dart-define-from-file=env.json --release
39 +
40 +echo === Prepare distribution actions. Copy needed files to the application bundle ===
41 +copy /Y "%tools_root%\msvcp140.dll" "%release_dir%\" > nul
42 +copy /Y "%tools_root%\vcruntime140.dll" "%release_dir%\" > nul
43 +copy /Y "%tools_root%\vcruntime140_1.dll" "%release_dir%\" > nul
44 +
45 +echo === Generate the application archive ===
46 +xcopy /s /e /v /Y "%release_dir%\*.*" "build\Cake Wallet\" > nul
47 +tar acf "%cw_archive_name%" -C build\ "Cake Wallet"
48 +
49 +echo === Open Explorer with the application archive ===
50 +echo Cake Wallet created archive at: %cw_archive_path%
51 +%SystemRoot%\explorer.exe /select, %cw_archive_path%
configure_cake_wallet.sh
+12 -3
@@ -1,11 +1,14 @@
1 +#!/bin/bash
2 +
3 IOS="ios"
4 ANDROID="android"
5 +MACOS="macos"
6
4 -PLATFORMS=($IOS $ANDROID)
7 +PLATFORMS=($IOS $ANDROID $MACOS)
8 PLATFORM=$1
9
10 if ! [[ " ${PLATFORMS[*]} " =~ " ${PLATFORM} " ]]; then
8 - echo "specify platform: ./configure_cake_wallet.sh ios|android"
11 + echo "specify platform: ./configure_cake_wallet.sh ios|android|macos"
12 exit 1
13 fi
14
@@ -14,6 +17,11 @@ if [ "$PLATFORM" == "$IOS" ]; then
17 cd scripts/ios
18 fi
19
20 +if [ "$PLATFORM" == "$MACOS" ]; then
21 + echo "Configuring for macOS"
22 + cd scripts/macos
23 +fi
24 +
25 if [ "$PLATFORM" == "$ANDROID" ]; then
26 echo "Configuring for Android"
27 cd scripts/android
@@ -22,5 +30,6 @@ fi
30 source ./app_env.sh cakewallet
31 ./app_config.sh
32 cd ../.. && flutter pub get
25 -flutter packages pub run tool/generate_localization.dart
33 +#flutter packages pub run tool/generate_localization.dart
34 ./model_generator.sh
35 +#cd macos && pod install
\ No newline at end of file
cw_core/lib/amount_converter.dart
+13 -90
@@ -4,10 +4,8 @@ import 'package:cw_core/crypto_currency.dart';
4 class AmountConverter {
5 static const _moneroAmountLength = 12;
6 static const _moneroAmountDivider = 1000000000000;
7 - static const _litecoinAmountDivider = 100000000;
8 - static const _ethereumAmountDivider = 1000000000000000000;
9 - static const _dashAmountDivider = 100000000;
10 - static const _bitcoinCashAmountDivider = 100000000;
7 + static const _wowneroAmountLength = 11;
8 + static const _wowneroAmountDivider = 100000000000;
9 static const _bitcoinAmountDivider = 100000000;
10 static const _bitcoinAmountLength = 8;
11 static final _bitcoinAmountFormat = NumberFormat()
@@ -16,69 +14,16 @@ class AmountConverter {
14 static final _moneroAmountFormat = NumberFormat()
15 ..maximumFractionDigits = _moneroAmountLength
16 ..minimumFractionDigits = 1;
19 -
20 - static double amountIntToDouble(CryptoCurrency cryptoCurrency, int amount) {
21 - switch (cryptoCurrency) {
22 - case CryptoCurrency.xmr:
23 - return _moneroAmountToDouble(amount);
24 - case CryptoCurrency.btc:
25 - return _bitcoinAmountToDouble(amount);
26 - case CryptoCurrency.bch:
27 - return _bitcoinCashAmountToDouble(amount);
28 - case CryptoCurrency.dash:
29 - return _dashAmountToDouble(amount);
30 - case CryptoCurrency.eth:
31 - return _ethereumAmountToDouble(amount);
32 - case CryptoCurrency.ltc:
33 - return _litecoinAmountToDouble(amount);
34 - case CryptoCurrency.xhv:
35 - case CryptoCurrency.xag:
36 - case CryptoCurrency.xau:
37 - case CryptoCurrency.xaud:
38 - case CryptoCurrency.xbtc:
39 - case CryptoCurrency.xcad:
40 - case CryptoCurrency.xchf:
41 - case CryptoCurrency.xcny:
42 - case CryptoCurrency.xeur:
43 - case CryptoCurrency.xgbp:
44 - case CryptoCurrency.xjpy:
45 - case CryptoCurrency.xnok:
46 - case CryptoCurrency.xnzd:
47 - case CryptoCurrency.xusd:
48 - return _moneroAmountToDouble(amount);
49 - default:
50 - return 0.0;
51 - }
52 - }
53 -
54 - static int amountStringToInt(CryptoCurrency cryptoCurrency, String amount) {
55 - switch (cryptoCurrency) {
56 - case CryptoCurrency.xmr:
57 - return _moneroParseAmount(amount);
58 - case CryptoCurrency.xhv:
59 - case CryptoCurrency.xag:
60 - case CryptoCurrency.xau:
61 - case CryptoCurrency.xaud:
62 - case CryptoCurrency.xbtc:
63 - case CryptoCurrency.xcad:
64 - case CryptoCurrency.xchf:
65 - case CryptoCurrency.xcny:
66 - case CryptoCurrency.xeur:
67 - case CryptoCurrency.xgbp:
68 - case CryptoCurrency.xjpy:
69 - case CryptoCurrency.xnok:
70 - case CryptoCurrency.xnzd:
71 - case CryptoCurrency.xusd:
72 - return _moneroParseAmount(amount);
73 - default:
74 - return 0;
75 - }
76 - }
17 + static final _wowneroAmountFormat = NumberFormat()
18 + ..maximumFractionDigits = _wowneroAmountLength
19 + ..minimumFractionDigits = 1;
20
21 static String amountIntToString(CryptoCurrency cryptoCurrency, int amount) {
22 switch (cryptoCurrency) {
23 case CryptoCurrency.xmr:
24 return _moneroAmountToString(amount);
25 + case CryptoCurrency.wow:
26 + return _wowneroAmountToString(amount);
27 case CryptoCurrency.btc:
28 case CryptoCurrency.bch:
29 case CryptoCurrency.ltc:
@@ -106,34 +51,12 @@ class AmountConverter {
51 static double cryptoAmountToDouble({required num amount, required num divider}) =>
52 amount / divider;
53
109 - static String _moneroAmountToString(int amount) => _moneroAmountFormat.format(
110 - cryptoAmountToDouble(amount: amount, divider: _moneroAmountDivider));
111 -
112 - static double _moneroAmountToDouble(int amount) =>
113 - cryptoAmountToDouble(amount: amount, divider: _moneroAmountDivider);
114 -
115 - static int _moneroParseAmount(String amount) =>
116 - _moneroAmountFormat.parse(amount).toInt();
117 -
118 - static String _bitcoinAmountToString(int amount) =>
119 - _bitcoinAmountFormat.format(
120 - cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));
121 -
122 - static double _bitcoinAmountToDouble(int amount) =>
123 - cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider);
124 -
125 - static int _doubleToBitcoinAmount(double amount) =>
126 - (amount * _bitcoinAmountDivider).toInt();
127 -
128 - static double _bitcoinCashAmountToDouble(int amount) =>
129 - cryptoAmountToDouble(amount: amount, divider: _bitcoinCashAmountDivider);
130 -
131 - static double _dashAmountToDouble(int amount) =>
132 - cryptoAmountToDouble(amount: amount, divider: _dashAmountDivider);
54 + static String _moneroAmountToString(int amount) => _moneroAmountFormat
55 + .format(cryptoAmountToDouble(amount: amount, divider: _moneroAmountDivider));
56
134 - static double _ethereumAmountToDouble(num amount) =>
135 - cryptoAmountToDouble(amount: amount, divider: _ethereumAmountDivider);
57 + static String _bitcoinAmountToString(int amount) => _bitcoinAmountFormat
58 + .format(cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));
59
137 - static double _litecoinAmountToDouble(int amount) =>
138 - cryptoAmountToDouble(amount: amount, divider: _litecoinAmountDivider);
60 + static String _wowneroAmountToString(int amount) => _wowneroAmountFormat
61 + .format(cryptoAmountToDouble(amount: amount, divider: _wowneroAmountDivider));
62 }
cw_core/lib/crypto_currency.dart
+2
@@ -105,6 +105,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
105 CryptoCurrency.usdtSol,
106 CryptoCurrency.usdcTrc20,
107 CryptoCurrency.tbtc,
108 + CryptoCurrency.wow,
109 ];
110
111 static const havenCurrencies = [
@@ -221,6 +222,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
222 static const usdtSol = CryptoCurrency(title: 'USDT', tag: 'SOL', fullName: 'USDT Tether', raw: 91, name: 'usdtsol', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
223 static const usdcTrc20 = CryptoCurrency(title: 'USDC', tag: 'TRX', fullName: 'USDC Coin', raw: 92, name: 'usdctrc20', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
224 static const tbtc = CryptoCurrency(title: 'tBTC', fullName: 'Testnet Bitcoin', raw: 93, name: 'tbtc', iconPath: 'assets/images/tbtc.png', decimals: 8);
225 + static const wow = CryptoCurrency(title: 'WOW', fullName: 'Wownero', raw: 94, name: 'wow', iconPath: 'assets/images/wownero_icon.png', decimals: 11);
226
227
228 static final Map<int, CryptoCurrency> _rawCurrencyMap =
cw_core/lib/currency_for_wallet_type.dart
+3 -1
@@ -28,7 +28,9 @@ CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
28 return CryptoCurrency.sol;
29 case WalletType.tron:
30 return CryptoCurrency.trx;
31 - default:
31 + case WalletType.wownero:
32 + return CryptoCurrency.wow;
33 + case WalletType.none:
34 throw Exception(
35 'Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
36 }
cw_core/lib/get_height_by_date.dart
+78
@@ -297,3 +297,81 @@ DateTime getDateByBitcoinHeight(int height) {
297
298 return estimatedDate;
299 }
300 +
301 +// TODO: enhance all of this global const lists
302 +const wowDates = {
303 + "2023-12": 583048,
304 + "2023-11": 575048,
305 + "2023-10": 566048,
306 + "2023-09": 558048,
307 + "2023-08": 549048,
308 + "2023-07": 540048,
309 + "2023-06": 532048,
310 + "2023-05": 523048,
311 + "2023-04": 514048,
312 + "2023-03": 505048,
313 + "2023-02": 497048,
314 + "2023-01": 488048,
315 + "2022-12": 479048,
316 + "2022-11": 471048,
317 + "2022-10": 462048,
318 + "2022-09": 453048,
319 + "2022-08": 444048,
320 + "2022-07": 435048,
321 + "2022-06": 427048,
322 + "2022-05": 418048,
323 + "2022-04": 410048,
324 + "2022-03": 401048,
325 + "2022-02": 393048,
326 + "2022-01": 384048,
327 + "2021-12": 375048,
328 + "2021-11": 367048,
329 + "2021-10": 358048,
330 + "2021-09": 349048,
331 + "2021-08": 340048,
332 + "2021-07": 331048,
333 + "2021-06": 322048,
334 + "2021-05": 313048,
335 + "2021-04": 305048,
336 + "2021-03": 295048,
337 + "2021-02": 287048,
338 + "2021-01": 279148,
339 + "2020-10": 252000,
340 + "2020-09": 243000,
341 + "2020-08": 234000,
342 + "2020-07": 225000,
343 + "2020-06": 217500,
344 + "2020-05": 208500,
345 + "2020-04": 199500,
346 + "2020-03": 190500,
347 + "2020-02": 183000,
348 + "2020-01": 174000,
349 + "2019-12": 165000,
350 + "2019-11": 156000,
351 + "2019-10": 147000,
352 + "2019-09": 138000,
353 + "2019-08": 129000,
354 + "2019-07": 120000,
355 + "2019-06": 112500,
356 + "2019-05": 103500,
357 + "2019-04": 94500,
358 + "2019-03": 85500,
359 + "2019-02": 79500,
360 + "2019-01": 73500,
361 + "2018-12": 67500,
362 + "2018-11": 61500,
363 + "2018-10": 52500,
364 + "2018-09": 45000,
365 + "2018-08": 36000,
366 + "2018-07": 27000,
367 + "2018-06": 18000,
368 + "2018-05": 9000,
369 + "2018-04": 1
370 +};
371 +
372 +int getWowneroHeightByDate({required DateTime date}) {
373 + String closestKey =
374 + wowDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
375 +
376 + return wowDates[closestKey] ?? 0;
377 +}
\ No newline at end of file
cw_core/lib/node.dart
+4 -2
@@ -79,6 +79,7 @@ class Node extends HiveObject with Keyable {
79 switch (type) {
80 case WalletType.monero:
81 case WalletType.haven:
82 + case WalletType.wownero:
83 return Uri.http(uriRaw, '');
84 case WalletType.bitcoin:
85 case WalletType.litecoin:
@@ -96,7 +97,7 @@ class Node extends HiveObject with Keyable {
97 case WalletType.solana:
98 case WalletType.tron:
99 return Uri.https(uriRaw, path ?? '');
99 - default:
100 + case WalletType.none:
101 throw Exception('Unexpected type ${type.toString()} for Node uri');
102 }
103 }
@@ -143,6 +144,7 @@ class Node extends HiveObject with Keyable {
144 switch (type) {
145 case WalletType.monero:
146 case WalletType.haven:
147 + case WalletType.wownero:
148 return requestMoneroNode();
149 case WalletType.nano:
150 case WalletType.banano:
@@ -155,7 +157,7 @@ class Node extends HiveObject with Keyable {
157 case WalletType.solana:
158 case WalletType.tron:
159 return requestElectrumServer();
158 - default:
160 + case WalletType.none:
161 return false;
162 }
163 } catch (_) {
cw_core/lib/pathForWallet.dart
+4 -3
@@ -1,9 +1,10 @@
1 import 'dart:io';
2 +import 'package:cw_core/root_dir.dart';
3 import 'package:cw_core/wallet_type.dart';
4 import 'package:path_provider/path_provider.dart';
5
6 Future<String> pathForWalletDir({required String name, required WalletType type}) async {
6 - final root = await getApplicationDocumentsDirectory();
7 + final root = await getAppDir();
8 final prefix = walletTypeToString(type).toLowerCase();
9 final walletsDir = Directory('${root.path}/wallets');
10 final walletDire = Directory('${walletsDir.path}/$prefix/$name');
@@ -20,8 +21,8 @@ Future<String> pathForWallet({required String name, required WalletType type}) a
21 .then((path) => path + '/$name');
22
23 Future<String> outdatedAndroidPathForWalletDir({required String name}) async {
23 - final directory = await getApplicationDocumentsDirectory();
24 + final directory = await getAppDir();
25 final pathDir = directory.path + '/$name';
26
27 return pathDir;
27 -}
\ No newline at end of file
28 +}
cw_core/lib/root_dir.dart new
+35
@@ -0,0 +1,35 @@
1 +import 'dart:io';
2 +import 'package:path_provider/path_provider.dart';
3 +
4 +String? _rootDirPath;
5 +
6 +void setRootDirFromEnv() => _rootDirPath = Platform.environment['CAKE_WALLET_DIR'];
7 +
8 +Future<Directory> getAppDir({String appName = 'cake_wallet'}) async {
9 + Directory dir;
10 +
11 + if (_rootDirPath != null && _rootDirPath!.isNotEmpty) {
12 + dir = Directory.fromUri(Uri.file(_rootDirPath!));
13 + dir.create(recursive: true);
14 + } else {
15 + if (Platform.isWindows) {
16 + dir = await getApplicationSupportDirectory();
17 + } else if (Platform.isLinux) {
18 + String appDirPath;
19 +
20 + try {
21 + dir = await getApplicationDocumentsDirectory();
22 + appDirPath = '${dir.path}/$appName';
23 + } catch (e) {
24 + appDirPath = '/home/${Platform.environment['USER']}/.$appName';
25 + }
26 +
27 + dir = Directory.fromUri(Uri.file(appDirPath));
28 + await dir.create(recursive: true);
29 + } else {
30 + dir = await getApplicationDocumentsDirectory();
31 + }
32 + }
33 +
34 + return dir;
35 +}
cw_core/lib/sec_random_native.dart
+8
@@ -1,3 +1,5 @@
1 +import 'dart:io';
2 +import 'dart:math';
3 import 'dart:typed_data';
4
5 import 'package:flutter/services.dart';
@@ -6,6 +8,12 @@ const utils = const MethodChannel('com.cake_wallet/native_utils');
8
9 Future<Uint8List> secRandom(int count) async {
10 try {
11 + if (Platform.isWindows || Platform.isLinux) {
12 + // Used method to get securely generated random bytes from cake backups
13 + const byteSize = 256;
14 + final rng = Random.secure();
15 + return Uint8List.fromList(List<int>.generate(count, (_) => rng.nextInt(byteSize)));
16 + }
17 return await utils.invokeMethod<Uint8List>('sec_random', {'count': count}) ?? Uint8List.fromList([]);
18 } on PlatformException catch (_) {
19 return Uint8List.fromList([]);
cw_core/lib/wallet_type.dart
+18 -5
@@ -54,7 +54,10 @@ enum WalletType {
54 solana,
55
56 @HiveField(11)
57 - tron
57 + tron,
58 +
59 + @HiveField(12)
60 + wownero,
61 }
62
63 int serializeToInt(WalletType type) {
@@ -81,7 +84,9 @@ int serializeToInt(WalletType type) {
84 return 9;
85 case WalletType.tron:
86 return 10;
84 - default:
87 + case WalletType.wownero:
88 + return 11;
89 + case WalletType.none:
90 return -1;
91 }
92 }
@@ -110,6 +115,8 @@ WalletType deserializeFromInt(int raw) {
115 return WalletType.solana;
116 case 10:
117 return WalletType.tron;
118 + case 11:
119 + return WalletType.wownero;
120 default:
121 throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
122 }
@@ -139,7 +146,9 @@ String walletTypeToString(WalletType type) {
146 return 'Solana';
147 case WalletType.tron:
148 return 'Tron';
142 - default:
149 + case WalletType.wownero:
150 + return 'Wownero';
151 + case WalletType.none:
152 return '';
153 }
154 }
@@ -168,7 +177,9 @@ String walletTypeToDisplayName(WalletType type) {
177 return 'Solana (SOL)';
178 case WalletType.tron:
179 return 'Tron (TRX)';
171 - default:
180 + case WalletType.wownero:
181 + return 'Wownero (WOW)';
182 + case WalletType.none:
183 return '';
184 }
185 }
@@ -200,7 +211,9 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
211 return CryptoCurrency.sol;
212 case WalletType.tron:
213 return CryptoCurrency.trx;
203 - default:
214 + case WalletType.wownero:
215 + return CryptoCurrency.wow;
216 + case WalletType.none:
217 throw Exception(
218 'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
219 }
cw_core/lib/wownero_amount_format.dart new
+18
@@ -0,0 +1,18 @@
1 +import 'package:intl/intl.dart';
2 +import 'package:cw_core/crypto_amount_format.dart';
3 +
4 +const wowneroAmountLength = 11;
5 +const wowneroAmountDivider = 100000000000;
6 +final wowneroAmountFormat = NumberFormat()
7 + ..maximumFractionDigits = wowneroAmountLength
8 + ..minimumFractionDigits = 1;
9 +
10 +String wowneroAmountToString({required int amount}) => wowneroAmountFormat
11 + .format(cryptoAmountToDouble(amount: amount, divider: wowneroAmountDivider))
12 + .replaceAll(',', '');
13 +
14 +double wowneroAmountToDouble({required int amount}) =>
15 + cryptoAmountToDouble(amount: amount, divider: wowneroAmountDivider);
16 +
17 +int wowneroParseAmount({required String amount}) =>
18 + (double.parse(amount) * wowneroAmountDivider).round();
\ No newline at end of file
cw_core/lib/wownero_balance.dart new
+38
@@ -0,0 +1,38 @@
1 +import 'package:cw_core/balance.dart';
2 +import 'package:cw_core/wownero_amount_format.dart';
3 +
4 +class WowneroBalance extends Balance {
5 + WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
6 + : formattedFullBalance = wowneroAmountToString(amount: fullBalance),
7 + formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
8 + formattedLockedBalance =
9 + wowneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
10 + super(unlockedBalance, fullBalance);
11 +
12 + WowneroBalance.fromString(
13 + {required this.formattedFullBalance,
14 + required this.formattedUnlockedBalance,
15 + this.formattedLockedBalance = '0.0'})
16 + : fullBalance = wowneroParseAmount(amount: formattedFullBalance),
17 + unlockedBalance = wowneroParseAmount(amount: formattedUnlockedBalance),
18 + frozenBalance = wowneroParseAmount(amount: formattedLockedBalance),
19 + super(wowneroParseAmount(amount: formattedUnlockedBalance),
20 + wowneroParseAmount(amount: formattedFullBalance));
21 +
22 + final int fullBalance;
23 + final int unlockedBalance;
24 + final int frozenBalance;
25 + final String formattedFullBalance;
26 + final String formattedUnlockedBalance;
27 + final String formattedLockedBalance;
28 +
29 + @override
30 + String get formattedUnAvailableBalance =>
31 + formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
32 +
33 + @override
34 + String get formattedAvailableBalance => formattedUnlockedBalance;
35 +
36 + @override
37 + String get formattedAdditionalBalance => formattedFullBalance;
38 +}
\ No newline at end of file
cw_core/pubspec.lock
+2 -2
@@ -660,10 +660,10 @@ packages:
660 dependency: "direct main"
661 description:
662 name: unorm_dart
663 - sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b"
663 + sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
664 url: "https://pub.dev"
665 source: hosted
666 - version: "0.2.0"
666 + version: "0.3.0"
667 vector_math:
668 dependency: transitive
669 description:
cw_haven/lib/api/account_list.dart
+2 -4
@@ -4,7 +4,6 @@ import 'package:cw_haven/api/signatures.dart';
4 import 'package:cw_haven/api/types.dart';
5 import 'package:cw_haven/api/haven_api.dart';
6 import 'package:cw_haven/api/structs/account_row.dart';
7 -import 'package:flutter/foundation.dart';
7 import 'package:cw_haven/api/wallet.dart';
8
9 final accountSizeNative = havenApi
@@ -72,12 +71,11 @@ void _setLabelForAccount(Map<String, dynamic> args) {
71 }
72
73 Future<void> addAccount({required String label}) async {
75 - await compute(_addAccount, label);
74 + _addAccount(label);
75 await store();
76 }
77
78 Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
80 - await compute(
81 - _setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
79 + _setLabelForAccount({'accountIndex': accountIndex, 'label': label});
80 await store();
81 }
\ No newline at end of file
cw_monero/android/.classpath deleted
-6
@@ -1,6 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<classpath>
3 - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
4 - <classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
5 - <classpathentry kind="output" path="bin/default"/>
6 -</classpath>
cw_monero/android/.gitignore deleted
-8
@@ -1,8 +0,0 @@
1 -*.iml
2 -.gradle
3 -/local.properties
4 -/.idea/workspace.xml
5 -/.idea/libraries
6 -.DS_Store
7 -/build
8 -/captures
cw_monero/android/.project deleted
-23
@@ -1,23 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<projectDescription>
3 - <name>cw_monero</name>
4 - <comment>Project android created by Buildship.</comment>
5 - <projects>
6 - </projects>
7 - <buildSpec>
8 - <buildCommand>
9 - <name>org.eclipse.jdt.core.javabuilder</name>
10 - <arguments>
11 - </arguments>
12 - </buildCommand>
13 - <buildCommand>
14 - <name>org.eclipse.buildship.core.gradleprojectbuilder</name>
15 - <arguments>
16 - </arguments>
17 - </buildCommand>
18 - </buildSpec>
19 - <natures>
20 - <nature>org.eclipse.jdt.core.javanature</nature>
21 - <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
22 - </natures>
23 -</projectDescription>
cw_monero/android/.settings/org.eclipse.buildship.core.prefs deleted
-13
@@ -1,13 +0,0 @@
1 -arguments=
2 -auto.sync=false
3 -build.scans.enabled=false
4 -connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.0-20191016123526+0000))
5 -connection.project.dir=../../android
6 -eclipse.preferences.version=1
7 -gradle.user.home=
8 -java.home=
9 -jvm.arguments=
10 -offline.mode=false
11 -override.workspace.settings=true
12 -show.console.view=true
13 -show.executions.view=true
cw_monero/android/CMakeLists.txt deleted
-232
@@ -1,232 +0,0 @@
1 -cmake_minimum_required(VERSION 3.4.1)
2 -
3 -add_library( cw_monero
4 - SHARED
5 - ./jni/monero_jni.cpp
6 - ../ios/Classes/monero_api.cpp)
7 -
8 - find_library( log-lib log )
9 -
10 -set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../../cw_shared_external/ios/External/android)
11 -
12 -############
13 -# libsodium
14 -############
15 -
16 -add_library(sodium STATIC IMPORTED)
17 -set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
18 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libsodium.a)
19 -
20 -############
21 -# OpenSSL
22 -############
23 -
24 -add_library(crypto STATIC IMPORTED)
25 -set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
26 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libcrypto.a)
27 -
28 -add_library(ssl STATIC IMPORTED)
29 -set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
30 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libssl.a)
31 -
32 -############
33 -# Boost
34 -############
35 -
36 -add_library(boost_chrono STATIC IMPORTED)
37 -set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
38 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_chrono.a)
39 -
40 -add_library(boost_date_time STATIC IMPORTED)
41 -set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
42 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_date_time.a)
43 -
44 -add_library(boost_filesystem STATIC IMPORTED)
45 -set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
46 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_filesystem.a)
47 -
48 -add_library(boost_program_options STATIC IMPORTED)
49 -set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
50 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_program_options.a)
51 -
52 -add_library(boost_regex STATIC IMPORTED)
53 -set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
54 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_regex.a)
55 -
56 -add_library(boost_serialization STATIC IMPORTED)
57 -set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
58 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_serialization.a)
59 -
60 -add_library(boost_system STATIC IMPORTED)
61 -set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
62 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_system.a)
63 -
64 -add_library(boost_thread STATIC IMPORTED)
65 -set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
66 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_thread.a)
67 -
68 -add_library(boost_wserialization STATIC IMPORTED)
69 -set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
70 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_wserialization.a)
71 -
72 -#############
73 -# Monero
74 -#############
75 -
76 -add_library(wallet_api STATIC IMPORTED)
77 -set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
78 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libwallet_api.a)
79 -
80 -add_library(wallet STATIC IMPORTED)
81 -set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
82 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libwallet.a)
83 -
84 -add_library(cryptonote_core STATIC IMPORTED)
85 -set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
86 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcryptonote_core.a)
87 -
88 -add_library(cryptonote_basic STATIC IMPORTED)
89 -set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
90 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcryptonote_basic.a)
91 -
92 -add_library(cryptonote_format_utils_basic STATIC IMPORTED)
93 -set_target_properties(cryptonote_format_utils_basic PROPERTIES IMPORTED_LOCATION
94 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcryptonote_format_utils_basic.a)
95 -
96 -add_library(mnemonics STATIC IMPORTED)
97 -set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
98 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libmnemonics.a)
99 -
100 -add_library(common STATIC IMPORTED)
101 -set_target_properties(common PROPERTIES IMPORTED_LOCATION
102 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcommon.a)
103 -
104 -add_library(cncrypto STATIC IMPORTED)
105 -set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
106 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcncrypto.a)
107 -
108 -add_library(ringct STATIC IMPORTED)
109 -set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
110 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libringct.a)
111 -
112 -add_library(ringct_basic STATIC IMPORTED)
113 -set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
114 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libringct_basic.a)
115 -
116 -add_library(blockchain_db STATIC IMPORTED)
117 -set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
118 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libblockchain_db.a)
119 -
120 -add_library(lmdb STATIC IMPORTED)
121 -set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
122 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/liblmdb.a)
123 -
124 -add_library(easylogging STATIC IMPORTED)
125 -set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
126 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libeasylogging.a)
127 -
128 -add_library(unbound STATIC IMPORTED)
129 -set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
130 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libunbound.a)
131 -
132 -add_library(epee STATIC IMPORTED)
133 -set_target_properties(epee PROPERTIES IMPORTED_LOCATION
134 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libepee.a)
135 -
136 -add_library(blocks STATIC IMPORTED)
137 -set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
138 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libblocks.a)
139 -
140 -add_library(checkpoints STATIC IMPORTED)
141 -set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
142 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcheckpoints.a)
143 -
144 -add_library(device STATIC IMPORTED)
145 -set_target_properties(device PROPERTIES IMPORTED_LOCATION
146 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libdevice.a)
147 -
148 -add_library(device_trezor STATIC IMPORTED)
149 -set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
150 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libdevice_trezor.a)
151 -
152 -add_library(multisig STATIC IMPORTED)
153 -set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
154 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libmultisig.a)
155 -
156 -add_library(version STATIC IMPORTED)
157 -set_target_properties(version PROPERTIES IMPORTED_LOCATION
158 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libversion.a)
159 -
160 -add_library(net STATIC IMPORTED)
161 -set_target_properties(net PROPERTIES IMPORTED_LOCATION
162 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libnet.a)
163 -
164 -add_library(hardforks STATIC IMPORTED)
165 -set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
166 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libhardforks.a)
167 -
168 -add_library(randomx STATIC IMPORTED)
169 -set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
170 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/librandomx.a)
171 -
172 -add_library(rpc_base STATIC IMPORTED)
173 -set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
174 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/librpc_base.a)
175 -
176 -add_library(wallet-crypto STATIC IMPORTED)
177 -set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
178 - ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libwallet-crypto.a)
179 -
180 -set(WALLET_CRYPTO "")
181 -
182 -if(${ANDROID_ABI} STREQUAL "x86_64")
183 - set(WALLET_CRYPTO "wallet-crypto")
184 -endif()
185 -
186 -include_directories( ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/include )
187 -
188 -target_link_libraries( cw_monero
189 -
190 - wallet_api
191 - wallet
192 - cryptonote_core
193 - cryptonote_basic
194 - cryptonote_format_utils_basic
195 - mnemonics
196 - ringct
197 - ringct_basic
198 - net
199 - common
200 - cncrypto
201 - blockchain_db
202 - lmdb
203 - easylogging
204 - unbound
205 - epee
206 - blocks
207 - checkpoints
208 - device
209 - device_trezor
210 - multisig
211 - version
212 - randomx
213 - hardforks
214 - rpc_base
215 - ${WALLET_CRYPTO}
216 -
217 - boost_chrono
218 - boost_date_time
219 - boost_filesystem
220 - boost_program_options
221 - boost_regex
222 - boost_serialization
223 - boost_system
224 - boost_thread
225 - boost_wserialization
226 -
227 - ssl
228 - crypto
229 -
230 - sodium
231 -
232 - ${log-lib} )
\ No newline at end of file
cw_monero/android/build.gradle deleted
-49
@@ -1,49 +0,0 @@
1 -group 'com.cakewallet.monero'
2 -version '1.0-SNAPSHOT'
3 -
4 -buildscript {
5 - ext.kotlin_version = '1.7.10'
6 - repositories {
7 - google()
8 - jcenter()
9 - }
10 -
11 - dependencies {
12 - classpath 'com.android.tools.build:gradle:7.3.0'
13 - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 - }
15 -}
16 -
17 -rootProject.allprojects {
18 - repositories {
19 - google()
20 - jcenter()
21 - }
22 -}
23 -
24 -apply plugin: 'com.android.library'
25 -apply plugin: 'kotlin-android'
26 -
27 -android {
28 - compileSdkVersion 28
29 -
30 - sourceSets {
31 - main.java.srcDirs += 'src/main/kotlin'
32 - }
33 - defaultConfig {
34 - minSdkVersion 21
35 - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
36 - }
37 - lintOptions {
38 - disable 'InvalidPackage'
39 - }
40 - externalNativeBuild {
41 - cmake {
42 - path "CMakeLists.txt"
43 - }
44 - }
45 -}
46 -
47 -dependencies {
48 - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
49 -}
cw_monero/android/gradle.properties deleted
-4
@@ -1,4 +0,0 @@
1 -org.gradle.jvmargs=-Xmx1536M
2 -android.enableR8=true
3 -android.useAndroidX=true
4 -android.enableJetifier=true
cw_monero/android/gradle/wrapper/gradle-wrapper.properties deleted
-5
@@ -1,5 +0,0 @@
1 -distributionBase=GRADLE_USER_HOME
2 -distributionPath=wrapper/dists
3 -zipStoreBase=GRADLE_USER_HOME
4 -zipStorePath=wrapper/dists
5 -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
cw_monero/android/jni/monero_jni.cpp deleted
-74
@@ -1,74 +0,0 @@
1 -#include <string.h>
2 -#include <jni.h>
3 -#include "../../ios/Classes/monero_api.h"
4 -#include <stdbool.h>
5 -
6 -#ifdef __cplusplus
7 -extern "C" {
8 -#endif
9 -
10 -JNIEXPORT void JNICALL
11 -Java_com_cakewallet_monero_MoneroApi_setNodeAddressJNI(
12 - JNIEnv *env,
13 - jobject inst,
14 - jstring uri,
15 - jstring login,
16 - jstring password,
17 - jboolean use_ssl,
18 - jboolean is_light_wallet) {
19 - const char *_uri = env->GetStringUTFChars(uri, 0);
20 - const char *_login = "";
21 - const char *_password = "";
22 - char *error;
23 -
24 - if (login != NULL) {
25 - _login = env->GetStringUTFChars(login, 0);
26 - }
27 -
28 - if (password != NULL) {
29 - _password = env->GetStringUTFChars(password, 0);
30 - }
31 - char *__uri = (char*) _uri;
32 - char *__login = (char*) _login;
33 - char *__password = (char*) _password;
34 - bool inited = setup_node(__uri, __login, __password, false, false, error);
35 -
36 - if (!inited) {
37 - env->ThrowNew(env->FindClass("java/lang/Exception"), error);
38 - }
39 -}
40 -
41 -JNIEXPORT void JNICALL
42 -Java_com_cakewallet_monero_MoneroApi_connectToNodeJNI(
43 - JNIEnv *env,
44 - jobject inst) {
45 - char *error;
46 - bool is_connected = connect_to_node(error);
47 -
48 - if (!is_connected) {
49 - env->ThrowNew(env->FindClass("java/lang/Exception"), error);
50 - }
51 -}
52 -
53 -JNIEXPORT void JNICALL
54 -Java_com_cakewallet_monero_MoneroApi_startSyncJNI(
55 - JNIEnv *env,
56 - jobject inst) {
57 - start_refresh();
58 -}
59 -
60 -JNIEXPORT void JNICALL
61 -Java_com_cakewallet_monero_MoneroApi_loadWalletJNI(
62 - JNIEnv *env,
63 - jobject inst,
64 - jstring path,
65 - jstring password) {
66 - char *_path = (char *) env->GetStringUTFChars(path, 0);
67 - char *_password = (char *) env->GetStringUTFChars(password, 0);
68 -
69 - load_wallet(_path, _password, 0);
70 -}
71 -
72 -#ifdef __cplusplus
73 -}
74 -#endif
\ No newline at end of file
cw_monero/android/settings.gradle deleted
-1
@@ -1 +0,0 @@
1 -rootProject.name = 'cw_monero'
cw_monero/android/src/main/AndroidManifest.xml deleted
-4
@@ -1,4 +0,0 @@
1 -<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 - package="com.cakewallet.monero">
3 - <uses-permission android:name="android.permission.INTERNET"/>
4 -</manifest>
cw_monero/android/src/main/kotlin/com/cakewallet/monero/CwMoneroPlugin.kt deleted
-74
@@ -1,74 +0,0 @@
1 -package com.cakewallet.monero
2 -
3 -import android.app.Activity
4 -import android.os.AsyncTask
5 -import android.os.Looper
6 -import android.os.Handler
7 -import android.os.Process
8 -
9 -import io.flutter.plugin.common.MethodCall
10 -import io.flutter.plugin.common.MethodChannel
11 -import io.flutter.plugin.common.MethodChannel.MethodCallHandler
12 -import io.flutter.plugin.common.MethodChannel.Result
13 -import io.flutter.plugin.common.PluginRegistry.Registrar
14 -
15 -class doAsync(val handler: () -> Unit) : AsyncTask<Void, Void, Void>() {
16 - override fun doInBackground(vararg params: Void?): Void? {
17 - Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
18 - handler()
19 - return null
20 - }
21 -}
22 -
23 -class CwMoneroPlugin: MethodCallHandler {
24 - companion object {
25 -// val moneroApi = MoneroApi()
26 - val main = Handler(Looper.getMainLooper());
27 -
28 - init {
29 - System.loadLibrary("cw_monero")
30 - }
31 -
32 - @JvmStatic
33 - fun registerWith(registrar: Registrar) {
34 - val channel = MethodChannel(registrar.messenger(), "cw_monero")
35 - channel.setMethodCallHandler(CwMoneroPlugin())
36 - }
37 - }
38 -
39 - override fun onMethodCall(call: MethodCall, result: Result) {
40 - if (call.method == "setupNode") {
41 - val uri = call.argument("address") ?: ""
42 - val login = call.argument("login") ?: ""
43 - val password = call.argument("password") ?: ""
44 - val useSSL = false
45 - val isLightWallet = false
46 -// doAsync {
47 -// try {
48 -// moneroApi.setNodeAddressJNI(uri, login, password, useSSL, isLightWallet)
49 -// main.post({
50 -// result.success(true)
51 -// });
52 -// } catch(e: Throwable) {
53 -// main.post({
54 -// result.error("CONNECTION_ERROR", e.message, null)
55 -// });
56 -// }
57 -// }.execute()
58 - }
59 - if (call.method == "startSync") {
60 -// doAsync {
61 -// moneroApi.startSyncJNI()
62 -// main.post({
63 -// result.success(true)
64 -// });
65 -// }.execute()
66 - }
67 - if (call.method == "loadWallet") {
68 - val path = call.argument("path") ?: ""
69 - val password = call.argument("password") ?: ""
70 -// moneroApi.loadWalletJNI(path, password)
71 - result.success(true)
72 - }
73 - }
74 -}
cw_monero/example/.gitignore deleted
-44
@@ -1,44 +0,0 @@
1 -# Miscellaneous
2 -*.class
3 -*.log
4 -*.pyc
5 -*.swp
6 -.DS_Store
7 -.atom/
8 -.buildlog/
9 -.history
10 -.svn/
11 -migrate_working_dir/
12 -
13 -# IntelliJ related
14 -*.iml
15 -*.ipr
16 -*.iws
17 -.idea/
18 -
19 -# The .vscode folder contains launch configuration and tasks you configure in
20 -# VS Code which you may wish to be included in version control, so this line
21 -# is commented out by default.
22 -#.vscode/
23 -
24 -# Flutter/Dart/Pub related
25 -**/doc/api/
26 -**/ios/Flutter/.last_build_id
27 -.dart_tool/
28 -.flutter-plugins
29 -.flutter-plugins-dependencies
30 -.packages
31 -.pub-cache/
32 -.pub/
33 -/build/
34 -
35 -# Symbolication related
36 -app.*.symbols
37 -
38 -# Obfuscation related
39 -app.*.map.json
40 -
41 -# Android Studio will place build artifacts here
42 -/android/app/debug
43 -/android/app/profile
44 -/android/app/release
cw_monero/example/README.md deleted
-16
@@ -1,16 +0,0 @@
1 -# cw_monero_example
2 -
3 -Demonstrates how to use the cw_monero plugin.
4 -
5 -## Getting Started
6 -
7 -This project is a starting point for a Flutter application.
8 -
9 -A few resources to get you started if this is your first Flutter project:
10 -
11 -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
12 -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
13 -
14 -For help getting started with Flutter development, view the
15 -[online documentation](https://docs.flutter.dev/), which offers tutorials,
16 -samples, guidance on mobile development, and a full API reference.
cw_monero/example/analysis_options.yaml deleted
-29
@@ -1,29 +0,0 @@
1 -# This file configures the analyzer, which statically analyzes Dart code to
2 -# check for errors, warnings, and lints.
3 -#
4 -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 -# invoked from the command line by running `flutter analyze`.
7 -
8 -# The following line activates a set of recommended lints for Flutter apps,
9 -# packages, and plugins designed to encourage good coding practices.
10 -include: package:flutter_lints/flutter.yaml
11 -
12 -linter:
13 - # The lint rules applied to this project can be customized in the
14 - # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 - # included above or to enable additional rules. A list of all available lints
16 - # and their documentation is published at
17 - # https://dart-lang.github.io/linter/lints/index.html.
18 - #
19 - # Instead of disabling a lint rule for the entire project in the
20 - # section below, it can also be suppressed for a single line of code
21 - # or a specific dart file by using the `// ignore: name_of_lint` and
22 - # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 - # producing the lint.
24 - rules:
25 - # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 -
28 -# Additional information about this file can be found at
29 -# https://dart.dev/guides/language/analysis-options
cw_monero/example/lib/main.dart deleted
-63
@@ -1,63 +0,0 @@
1 -import 'package:flutter/material.dart';
2 -import 'dart:async';
3 -
4 -import 'package:flutter/services.dart';
5 -import 'package:cw_monero/cw_monero.dart';
6 -
7 -void main() {
8 - runApp(const MyApp());
9 -}
10 -
11 -class MyApp extends StatefulWidget {
12 - const MyApp({super.key});
13 -
14 - @override
15 - State<MyApp> createState() => _MyAppState();
16 -}
17 -
18 -class _MyAppState extends State<MyApp> {
19 - String _platformVersion = 'Unknown';
20 - final _cwMoneroPlugin = CwMonero();
21 -
22 - @override
23 - void initState() {
24 - super.initState();
25 - initPlatformState();
26 - }
27 -
28 - // Platform messages are asynchronous, so we initialize in an async method.
29 - Future<void> initPlatformState() async {
30 - String platformVersion;
31 - // Platform messages may fail, so we use a try/catch PlatformException.
32 - // We also handle the message potentially returning null.
33 - try {
34 - platformVersion =
35 - await _cwMoneroPlugin.getPlatformVersion() ?? 'Unknown platform version';
36 - } on PlatformException {
37 - platformVersion = 'Failed to get platform version.';
38 - }
39 -
40 - // If the widget was removed from the tree while the asynchronous platform
41 - // message was in flight, we want to discard the reply rather than calling
42 - // setState to update our non-existent appearance.
43 - if (!mounted) return;
44 -
45 - setState(() {
46 - _platformVersion = platformVersion;
47 - });
48 - }
49 -
50 - @override
51 - Widget build(BuildContext context) {
52 - return MaterialApp(
53 - home: Scaffold(
54 - appBar: AppBar(
55 - title: const Text('Plugin example app'),
56 - ),
57 - body: Center(
58 - child: Text('Running on: $_platformVersion\n'),
59 - ),
60 - ),
61 - );
62 - }
63 -}
cw_monero/example/macos/.gitignore deleted
-7
@@ -1,7 +0,0 @@
1 -# Flutter-related
2 -**/Flutter/ephemeral/
3 -**/Pods/
4 -
5 -# Xcode-related
6 -**/dgph
7 -**/xcuserdata/
cw_monero/example/macos/Flutter/Flutter-Debug.xcconfig deleted
-2
@@ -1,2 +0,0 @@
1 -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 -#include "ephemeral/Flutter-Generated.xcconfig"
cw_monero/example/macos/Flutter/Flutter-Release.xcconfig deleted
-2
@@ -1,2 +0,0 @@
1 -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 -#include "ephemeral/Flutter-Generated.xcconfig"
cw_monero/example/macos/Flutter/GeneratedPluginRegistrant.swift deleted
-14
@@ -1,14 +0,0 @@
1 -//
2 -// Generated file. Do not edit.
3 -//
4 -
5 -import FlutterMacOS
6 -import Foundation
7 -
8 -import cw_monero
9 -import path_provider_foundation
10 -
11 -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
12 - CwMoneroPlugin.register(with: registry.registrar(forPlugin: "CwMoneroPlugin"))
13 - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
14 -}
cw_monero/example/macos/Podfile deleted
-40
@@ -1,40 +0,0 @@
1 -platform :osx, '10.11'
2 -
3 -# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 -ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 -
6 -project 'Runner', {
7 - 'Debug' => :debug,
8 - 'Profile' => :release,
9 - 'Release' => :release,
10 -}
11 -
12 -def flutter_root
13 - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 - unless File.exist?(generated_xcode_build_settings_path)
15 - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 - end
17 -
18 - File.foreach(generated_xcode_build_settings_path) do |line|
19 - matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 - return matches[1].strip if matches
21 - end
22 - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 -end
24 -
25 -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 -
27 -flutter_macos_podfile_setup
28 -
29 -target 'Runner' do
30 - use_frameworks!
31 - use_modular_headers!
32 -
33 - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 -end
35 -
36 -post_install do |installer|
37 - installer.pods_project.targets.each do |target|
38 - flutter_additional_macos_build_settings(target)
39 - end
40 -end
cw_monero/example/macos/Podfile.lock deleted
-22
@@ -1,22 +0,0 @@
1 -PODS:
2 - - FlutterMacOS (1.0.0)
3 - - path_provider_macos (0.0.1):
4 - - FlutterMacOS
5 -
6 -DEPENDENCIES:
7 - - FlutterMacOS (from `Flutter/ephemeral`)
8 - - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
9 -
10 -EXTERNAL SOURCES:
11 - FlutterMacOS:
12 - :path: Flutter/ephemeral
13 - path_provider_macos:
14 - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
15 -
16 -SPEC CHECKSUMS:
17 - FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
18 - path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
19 -
20 -PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
21 -
22 -COCOAPODS: 1.11.2
cw_monero/example/macos/Runner.xcodeproj/project.pbxproj deleted
-632
@@ -1,632 +0,0 @@
1 -// !$*UTF8*$!
2 -{
3 - archiveVersion = 1;
4 - classes = {
5 - };
6 - objectVersion = 51;
7 - objects = {
8 -
9 -/* Begin PBXAggregateTarget section */
10 - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
11 - isa = PBXAggregateTarget;
12 - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
13 - buildPhases = (
14 - 33CC111E2044C6BF0003C045 /* ShellScript */,
15 - );
16 - dependencies = (
17 - );
18 - name = "Flutter Assemble";
19 - productName = FLX;
20 - };
21 -/* End PBXAggregateTarget section */
22 -
23 -/* Begin PBXBuildFile section */
24 - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
25 - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
26 - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
27 - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
28 - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
29 - 428E7496E2068D0AB138F295 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C29B2253BA962B7A415DBA77 /* Pods_Runner.framework */; };
30 -/* End PBXBuildFile section */
31 -
32 -/* Begin PBXContainerItemProxy section */
33 - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
34 - isa = PBXContainerItemProxy;
35 - containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
36 - proxyType = 1;
37 - remoteGlobalIDString = 33CC111A2044C6BA0003C045;
38 - remoteInfo = FLX;
39 - };
40 -/* End PBXContainerItemProxy section */
41 -
42 -/* Begin PBXCopyFilesBuildPhase section */
43 - 33CC110E2044A8840003C045 /* Bundle Framework */ = {
44 - isa = PBXCopyFilesBuildPhase;
45 - buildActionMask = 2147483647;
46 - dstPath = "";
47 - dstSubfolderSpec = 10;
48 - files = (
49 - );
50 - name = "Bundle Framework";
51 - runOnlyForDeploymentPostprocessing = 0;
52 - };
53 -/* End PBXCopyFilesBuildPhase section */
54 -
55 -/* Begin PBXFileReference section */
56 - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
57 - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
58 - 33CC10ED2044A3C60003C045 /* cw_monero_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = cw_monero_example.app; sourceTree = BUILT_PRODUCTS_DIR; };
59 - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
60 - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
61 - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
62 - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
63 - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
64 - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
65 - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
66 - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
67 - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
68 - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
69 - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
70 - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
71 - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
72 - A9CDA1605413332AB9056C23 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
73 - C29B2253BA962B7A415DBA77 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74 - E434913D71DC2682EF8E9059 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
75 - EEF09839C86335F78056F812 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
76 -/* End PBXFileReference section */
77 -
78 -/* Begin PBXFrameworksBuildPhase section */
79 - 33CC10EA2044A3C60003C045 /* Frameworks */ = {
80 - isa = PBXFrameworksBuildPhase;
81 - buildActionMask = 2147483647;
82 - files = (
83 - 428E7496E2068D0AB138F295 /* Pods_Runner.framework in Frameworks */,
84 - );
85 - runOnlyForDeploymentPostprocessing = 0;
86 - };
87 -/* End PBXFrameworksBuildPhase section */
88 -
89 -/* Begin PBXGroup section */
90 - 33BA886A226E78AF003329D5 /* Configs */ = {
91 - isa = PBXGroup;
92 - children = (
93 - 33E5194F232828860026EE4D /* AppInfo.xcconfig */,
94 - 9740EEB21CF90195004384FC /* Debug.xcconfig */,
95 - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
96 - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
97 - );
98 - path = Configs;
99 - sourceTree = "<group>";
100 - };
101 - 33CC10E42044A3C60003C045 = {
102 - isa = PBXGroup;
103 - children = (
104 - 33FAB671232836740065AC1E /* Runner */,
105 - 33CEB47122A05771004F2AC0 /* Flutter */,
106 - 33CC10EE2044A3C60003C045 /* Products */,
107 - D73912EC22F37F3D000D13A0 /* Frameworks */,
108 - 77870A4C94A9AB6EEC2EE261 /* Pods */,
109 - );
110 - sourceTree = "<group>";
111 - };
112 - 33CC10EE2044A3C60003C045 /* Products */ = {
113 - isa = PBXGroup;
114 - children = (
115 - 33CC10ED2044A3C60003C045 /* cw_monero_example.app */,
116 - );
117 - name = Products;
118 - sourceTree = "<group>";
119 - };
120 - 33CC11242044D66E0003C045 /* Resources */ = {
121 - isa = PBXGroup;
122 - children = (
123 - 33CC10F22044A3C60003C045 /* Assets.xcassets */,
124 - 33CC10F42044A3C60003C045 /* MainMenu.xib */,
125 - 33CC10F72044A3C60003C045 /* Info.plist */,
126 - );
127 - name = Resources;
128 - path = ..;
129 - sourceTree = "<group>";
130 - };
131 - 33CEB47122A05771004F2AC0 /* Flutter */ = {
132 - isa = PBXGroup;
133 - children = (
134 - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
135 - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
136 - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
137 - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
138 - );
139 - path = Flutter;
140 - sourceTree = "<group>";
141 - };
142 - 33FAB671232836740065AC1E /* Runner */ = {
143 - isa = PBXGroup;
144 - children = (
145 - 33CC10F02044A3C60003C045 /* AppDelegate.swift */,
146 - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
147 - 33E51913231747F40026EE4D /* DebugProfile.entitlements */,
148 - 33E51914231749380026EE4D /* Release.entitlements */,
149 - 33CC11242044D66E0003C045 /* Resources */,
150 - 33BA886A226E78AF003329D5 /* Configs */,
151 - );
152 - path = Runner;
153 - sourceTree = "<group>";
154 - };
155 - 77870A4C94A9AB6EEC2EE261 /* Pods */ = {
156 - isa = PBXGroup;
157 - children = (
158 - EEF09839C86335F78056F812 /* Pods-Runner.debug.xcconfig */,
159 - A9CDA1605413332AB9056C23 /* Pods-Runner.release.xcconfig */,
160 - E434913D71DC2682EF8E9059 /* Pods-Runner.profile.xcconfig */,
161 - );
162 - name = Pods;
163 - path = Pods;
164 - sourceTree = "<group>";
165 - };
166 - D73912EC22F37F3D000D13A0 /* Frameworks */ = {
167 - isa = PBXGroup;
168 - children = (
169 - C29B2253BA962B7A415DBA77 /* Pods_Runner.framework */,
170 - );
171 - name = Frameworks;
172 - sourceTree = "<group>";
173 - };
174 -/* End PBXGroup section */
175 -
176 -/* Begin PBXNativeTarget section */
177 - 33CC10EC2044A3C60003C045 /* Runner */ = {
178 - isa = PBXNativeTarget;
179 - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
180 - buildPhases = (
181 - 0A239C1738C005E3F6E4DFC6 /* [CP] Check Pods Manifest.lock */,
182 - 33CC10E92044A3C60003C045 /* Sources */,
183 - 33CC10EA2044A3C60003C045 /* Frameworks */,
184 - 33CC10EB2044A3C60003C045 /* Resources */,
185 - 33CC110E2044A8840003C045 /* Bundle Framework */,
186 - 3399D490228B24CF009A79C7 /* ShellScript */,
187 - 0CEAA82AE8A029C31B39F234 /* [CP] Embed Pods Frameworks */,
188 - );
189 - buildRules = (
190 - );
191 - dependencies = (
192 - 33CC11202044C79F0003C045 /* PBXTargetDependency */,
193 - );
194 - name = Runner;
195 - productName = Runner;
196 - productReference = 33CC10ED2044A3C60003C045 /* cw_monero_example.app */;
197 - productType = "com.apple.product-type.application";
198 - };
199 -/* End PBXNativeTarget section */
200 -
201 -/* Begin PBXProject section */
202 - 33CC10E52044A3C60003C045 /* Project object */ = {
203 - isa = PBXProject;
204 - attributes = {
205 - LastSwiftUpdateCheck = 0920;
206 - LastUpgradeCheck = 1300;
207 - ORGANIZATIONNAME = "";
208 - TargetAttributes = {
209 - 33CC10EC2044A3C60003C045 = {
210 - CreatedOnToolsVersion = 9.2;
211 - LastSwiftMigration = 1100;
212 - ProvisioningStyle = Automatic;
213 - SystemCapabilities = {
214 - com.apple.Sandbox = {
215 - enabled = 1;
216 - };
217 - };
218 - };
219 - 33CC111A2044C6BA0003C045 = {
220 - CreatedOnToolsVersion = 9.2;
221 - ProvisioningStyle = Manual;
222 - };
223 - };
224 - };
225 - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
226 - compatibilityVersion = "Xcode 9.3";
227 - developmentRegion = en;
228 - hasScannedForEncodings = 0;
229 - knownRegions = (
230 - en,
231 - Base,
232 - );
233 - mainGroup = 33CC10E42044A3C60003C045;
234 - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
235 - projectDirPath = "";
236 - projectRoot = "";
237 - targets = (
238 - 33CC10EC2044A3C60003C045 /* Runner */,
239 - 33CC111A2044C6BA0003C045 /* Flutter Assemble */,
240 - );
241 - };
242 -/* End PBXProject section */
243 -
244 -/* Begin PBXResourcesBuildPhase section */
245 - 33CC10EB2044A3C60003C045 /* Resources */ = {
246 - isa = PBXResourcesBuildPhase;
247 - buildActionMask = 2147483647;
248 - files = (
249 - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
250 - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
251 - );
252 - runOnlyForDeploymentPostprocessing = 0;
253 - };
254 -/* End PBXResourcesBuildPhase section */
255 -
256 -/* Begin PBXShellScriptBuildPhase section */
257 - 0A239C1738C005E3F6E4DFC6 /* [CP] Check Pods Manifest.lock */ = {
258 - isa = PBXShellScriptBuildPhase;
259 - buildActionMask = 2147483647;
260 - files = (
261 - );
262 - inputFileListPaths = (
263 - );
264 - inputPaths = (
265 - "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
266 - "${PODS_ROOT}/Manifest.lock",
267 - );
268 - name = "[CP] Check Pods Manifest.lock";
269 - outputFileListPaths = (
270 - );
271 - outputPaths = (
272 - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
273 - );
274 - runOnlyForDeploymentPostprocessing = 0;
275 - shellPath = /bin/sh;
276 - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
277 - showEnvVarsInLog = 0;
278 - };
279 - 0CEAA82AE8A029C31B39F234 /* [CP] Embed Pods Frameworks */ = {
280 - isa = PBXShellScriptBuildPhase;
281 - buildActionMask = 2147483647;
282 - files = (
283 - );
284 - inputFileListPaths = (
285 - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
286 - );
287 - name = "[CP] Embed Pods Frameworks";
288 - outputFileListPaths = (
289 - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
290 - );
291 - runOnlyForDeploymentPostprocessing = 0;
292 - shellPath = /bin/sh;
293 - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
294 - showEnvVarsInLog = 0;
295 - };
296 - 3399D490228B24CF009A79C7 /* ShellScript */ = {
297 - isa = PBXShellScriptBuildPhase;
298 - buildActionMask = 2147483647;
299 - files = (
300 - );
301 - inputFileListPaths = (
302 - );
303 - inputPaths = (
304 - );
305 - outputFileListPaths = (
306 - );
307 - outputPaths = (
308 - );
309 - runOnlyForDeploymentPostprocessing = 0;
310 - shellPath = /bin/sh;
311 - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
312 - };
313 - 33CC111E2044C6BF0003C045 /* ShellScript */ = {
314 - isa = PBXShellScriptBuildPhase;
315 - buildActionMask = 2147483647;
316 - files = (
317 - );
318 - inputFileListPaths = (
319 - Flutter/ephemeral/FlutterInputs.xcfilelist,
320 - );
321 - inputPaths = (
322 - Flutter/ephemeral/tripwire,
323 - );
324 - outputFileListPaths = (
325 - Flutter/ephemeral/FlutterOutputs.xcfilelist,
326 - );
327 - outputPaths = (
328 - );
329 - runOnlyForDeploymentPostprocessing = 0;
330 - shellPath = /bin/sh;
331 - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
332 - };
333 -/* End PBXShellScriptBuildPhase section */
334 -
335 -/* Begin PBXSourcesBuildPhase section */
336 - 33CC10E92044A3C60003C045 /* Sources */ = {
337 - isa = PBXSourcesBuildPhase;
338 - buildActionMask = 2147483647;
339 - files = (
340 - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
341 - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
342 - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
343 - );
344 - runOnlyForDeploymentPostprocessing = 0;
345 - };
346 -/* End PBXSourcesBuildPhase section */
347 -
348 -/* Begin PBXTargetDependency section */
349 - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
350 - isa = PBXTargetDependency;
351 - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
352 - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
353 - };
354 -/* End PBXTargetDependency section */
355 -
356 -/* Begin PBXVariantGroup section */
357 - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
358 - isa = PBXVariantGroup;
359 - children = (
360 - 33CC10F52044A3C60003C045 /* Base */,
361 - );
362 - name = MainMenu.xib;
363 - path = Runner;
364 - sourceTree = "<group>";
365 - };
366 -/* End PBXVariantGroup section */
367 -
368 -/* Begin XCBuildConfiguration section */
369 - 338D0CE9231458BD00FA5F75 /* Profile */ = {
370 - isa = XCBuildConfiguration;
371 - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
372 - buildSettings = {
373 - ALWAYS_SEARCH_USER_PATHS = NO;
374 - CLANG_ANALYZER_NONNULL = YES;
375 - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
376 - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
377 - CLANG_CXX_LIBRARY = "libc++";
378 - CLANG_ENABLE_MODULES = YES;
379 - CLANG_ENABLE_OBJC_ARC = YES;
380 - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
381 - CLANG_WARN_BOOL_CONVERSION = YES;
382 - CLANG_WARN_CONSTANT_CONVERSION = YES;
383 - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
384 - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
385 - CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
386 - CLANG_WARN_EMPTY_BODY = YES;
387 - CLANG_WARN_ENUM_CONVERSION = YES;
388 - CLANG_WARN_INFINITE_RECURSION = YES;
389 - CLANG_WARN_INT_CONVERSION = YES;
390 - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
391 - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
392 - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
393 - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
394 - CLANG_WARN_SUSPICIOUS_MOVE = YES;
395 - CODE_SIGN_IDENTITY = "-";
396 - COPY_PHASE_STRIP = NO;
397 - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
398 - ENABLE_NS_ASSERTIONS = NO;
399 - ENABLE_STRICT_OBJC_MSGSEND = YES;
400 - GCC_C_LANGUAGE_STANDARD = gnu11;
401 - GCC_NO_COMMON_BLOCKS = YES;
402 - GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
403 - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
404 - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
405 - GCC_WARN_UNUSED_FUNCTION = YES;
406 - GCC_WARN_UNUSED_VARIABLE = YES;
407 - MACOSX_DEPLOYMENT_TARGET = 10.11;
408 - MTL_ENABLE_DEBUG_INFO = NO;
409 - SDKROOT = macosx;
410 - SWIFT_COMPILATION_MODE = wholemodule;
411 - SWIFT_OPTIMIZATION_LEVEL = "-O";
412 - };
413 - name = Profile;
414 - };
415 - 338D0CEA231458BD00FA5F75 /* Profile */ = {
416 - isa = XCBuildConfiguration;
417 - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
418 - buildSettings = {
419 - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
420 - CLANG_ENABLE_MODULES = YES;
421 - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
422 - CODE_SIGN_STYLE = Automatic;
423 - COMBINE_HIDPI_IMAGES = YES;
424 - INFOPLIST_FILE = Runner/Info.plist;
425 - LD_RUNPATH_SEARCH_PATHS = (
426 - "$(inherited)",
427 - "@executable_path/../Frameworks",
428 - );
429 - PROVISIONING_PROFILE_SPECIFIER = "";
430 - SWIFT_VERSION = 5.0;
431 - };
432 - name = Profile;
433 - };
434 - 338D0CEB231458BD00FA5F75 /* Profile */ = {
435 - isa = XCBuildConfiguration;
436 - buildSettings = {
437 - CODE_SIGN_STYLE = Manual;
438 - PRODUCT_NAME = "$(TARGET_NAME)";
439 - };
440 - name = Profile;
441 - };
442 - 33CC10F92044A3C60003C045 /* Debug */ = {
443 - isa = XCBuildConfiguration;
444 - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
445 - buildSettings = {
446 - ALWAYS_SEARCH_USER_PATHS = NO;
447 - CLANG_ANALYZER_NONNULL = YES;
448 - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
449 - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
450 - CLANG_CXX_LIBRARY = "libc++";
451 - CLANG_ENABLE_MODULES = YES;
452 - CLANG_ENABLE_OBJC_ARC = YES;
453 - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
454 - CLANG_WARN_BOOL_CONVERSION = YES;
455 - CLANG_WARN_CONSTANT_CONVERSION = YES;
456 - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
457 - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
458 - CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
459 - CLANG_WARN_EMPTY_BODY = YES;
460 - CLANG_WARN_ENUM_CONVERSION = YES;
461 - CLANG_WARN_INFINITE_RECURSION = YES;
462 - CLANG_WARN_INT_CONVERSION = YES;
463 - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
464 - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
465 - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
466 - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
467 - CLANG_WARN_SUSPICIOUS_MOVE = YES;
468 - CODE_SIGN_IDENTITY = "-";
469 - COPY_PHASE_STRIP = NO;
470 - DEBUG_INFORMATION_FORMAT = dwarf;
471 - ENABLE_STRICT_OBJC_MSGSEND = YES;
472 - ENABLE_TESTABILITY = YES;
473 - GCC_C_LANGUAGE_STANDARD = gnu11;
474 - GCC_DYNAMIC_NO_PIC = NO;
475 - GCC_NO_COMMON_BLOCKS = YES;
476 - GCC_OPTIMIZATION_LEVEL = 0;
477 - GCC_PREPROCESSOR_DEFINITIONS = (
478 - "DEBUG=1",
479 - "$(inherited)",
480 - );
481 - GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
482 - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
483 - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
484 - GCC_WARN_UNUSED_FUNCTION = YES;
485 - GCC_WARN_UNUSED_VARIABLE = YES;
486 - MACOSX_DEPLOYMENT_TARGET = 10.11;
487 - MTL_ENABLE_DEBUG_INFO = YES;
488 - ONLY_ACTIVE_ARCH = YES;
489 - SDKROOT = macosx;
490 - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
491 - SWIFT_OPTIMIZATION_LEVEL = "-Onone";
492 - };
493 - name = Debug;
494 - };
495 - 33CC10FA2044A3C60003C045 /* Release */ = {
496 - isa = XCBuildConfiguration;
497 - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
498 - buildSettings = {
499 - ALWAYS_SEARCH_USER_PATHS = NO;
500 - CLANG_ANALYZER_NONNULL = YES;
501 - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
502 - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
503 - CLANG_CXX_LIBRARY = "libc++";
504 - CLANG_ENABLE_MODULES = YES;
505 - CLANG_ENABLE_OBJC_ARC = YES;
506 - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
507 - CLANG_WARN_BOOL_CONVERSION = YES;
508 - CLANG_WARN_CONSTANT_CONVERSION = YES;
509 - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
510 - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
511 - CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
512 - CLANG_WARN_EMPTY_BODY = YES;
513 - CLANG_WARN_ENUM_CONVERSION = YES;
514 - CLANG_WARN_INFINITE_RECURSION = YES;
515 - CLANG_WARN_INT_CONVERSION = YES;
516 - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
517 - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
518 - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
519 - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
520 - CLANG_WARN_SUSPICIOUS_MOVE = YES;
521 - CODE_SIGN_IDENTITY = "-";
522 - COPY_PHASE_STRIP = NO;
523 - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
524 - ENABLE_NS_ASSERTIONS = NO;
525 - ENABLE_STRICT_OBJC_MSGSEND = YES;
526 - GCC_C_LANGUAGE_STANDARD = gnu11;
527 - GCC_NO_COMMON_BLOCKS = YES;
528 - GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
529 - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
530 - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
531 - GCC_WARN_UNUSED_FUNCTION = YES;
532 - GCC_WARN_UNUSED_VARIABLE = YES;
533 - MACOSX_DEPLOYMENT_TARGET = 10.11;
534 - MTL_ENABLE_DEBUG_INFO = NO;
535 - SDKROOT = macosx;
536 - SWIFT_COMPILATION_MODE = wholemodule;
537 - SWIFT_OPTIMIZATION_LEVEL = "-O";
538 - };
539 - name = Release;
540 - };
541 - 33CC10FC2044A3C60003C045 /* Debug */ = {
542 - isa = XCBuildConfiguration;
543 - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
544 - buildSettings = {
545 - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
546 - CLANG_ENABLE_MODULES = YES;
547 - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
548 - CODE_SIGN_STYLE = Automatic;
549 - COMBINE_HIDPI_IMAGES = YES;
550 - INFOPLIST_FILE = Runner/Info.plist;
551 - LD_RUNPATH_SEARCH_PATHS = (
552 - "$(inherited)",
553 - "@executable_path/../Frameworks",
554 - );
555 - PROVISIONING_PROFILE_SPECIFIER = "";
556 - SWIFT_OPTIMIZATION_LEVEL = "-Onone";
557 - SWIFT_VERSION = 5.0;
558 - };
559 - name = Debug;
560 - };
561 - 33CC10FD2044A3C60003C045 /* Release */ = {
562 - isa = XCBuildConfiguration;
563 - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
564 - buildSettings = {
565 - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
566 - CLANG_ENABLE_MODULES = YES;
567 - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
568 - CODE_SIGN_STYLE = Automatic;
569 - COMBINE_HIDPI_IMAGES = YES;
570 - INFOPLIST_FILE = Runner/Info.plist;
571 - LD_RUNPATH_SEARCH_PATHS = (
572 - "$(inherited)",
573 - "@executable_path/../Frameworks",
574 - );
575 - PROVISIONING_PROFILE_SPECIFIER = "";
576 - SWIFT_VERSION = 5.0;
577 - };
578 - name = Release;
579 - };
580 - 33CC111C2044C6BA0003C045 /* Debug */ = {
581 - isa = XCBuildConfiguration;
582 - buildSettings = {
583 - CODE_SIGN_STYLE = Manual;
584 - PRODUCT_NAME = "$(TARGET_NAME)";
585 - };
586 - name = Debug;
587 - };
588 - 33CC111D2044C6BA0003C045 /* Release */ = {
589 - isa = XCBuildConfiguration;
590 - buildSettings = {
591 - CODE_SIGN_STYLE = Automatic;
592 - PRODUCT_NAME = "$(TARGET_NAME)";
593 - };
594 - name = Release;
595 - };
596 -/* End XCBuildConfiguration section */
597 -
598 -/* Begin XCConfigurationList section */
599 - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
600 - isa = XCConfigurationList;
601 - buildConfigurations = (
602 - 33CC10F92044A3C60003C045 /* Debug */,
603 - 33CC10FA2044A3C60003C045 /* Release */,
604 - 338D0CE9231458BD00FA5F75 /* Profile */,
605 - );
606 - defaultConfigurationIsVisible = 0;
607 - defaultConfigurationName = Release;
608 - };
609 - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
610 - isa = XCConfigurationList;
611 - buildConfigurations = (
612 - 33CC10FC2044A3C60003C045 /* Debug */,
613 - 33CC10FD2044A3C60003C045 /* Release */,
614 - 338D0CEA231458BD00FA5F75 /* Profile */,
615 - );
616 - defaultConfigurationIsVisible = 0;
617 - defaultConfigurationName = Release;
618 - };
619 - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
620 - isa = XCConfigurationList;
621 - buildConfigurations = (
622 - 33CC111C2044C6BA0003C045 /* Debug */,
623 - 33CC111D2044C6BA0003C045 /* Release */,
624 - 338D0CEB231458BD00FA5F75 /* Profile */,
625 - );
626 - defaultConfigurationIsVisible = 0;
627 - defaultConfigurationName = Release;
628 - };
629 -/* End XCConfigurationList section */
630 - };
631 - rootObject = 33CC10E52044A3C60003C045 /* Project object */;
632 -}
cw_monero/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted
-8
@@ -1,8 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 -<plist version="1.0">
4 -<dict>
5 - <key>IDEDidComputeMac32BitWarning</key>
6 - <true/>
7 -</dict>
8 -</plist>
cw_monero/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted
-87
@@ -1,87 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<Scheme
3 - LastUpgradeVersion = "1300"
4 - version = "1.3">
5 - <BuildAction
6 - parallelizeBuildables = "YES"
7 - buildImplicitDependencies = "YES">
8 - <BuildActionEntries>
9 - <BuildActionEntry
10 - buildForTesting = "YES"
11 - buildForRunning = "YES"
12 - buildForProfiling = "YES"
13 - buildForArchiving = "YES"
14 - buildForAnalyzing = "YES">
15 - <BuildableReference
16 - BuildableIdentifier = "primary"
17 - BlueprintIdentifier = "33CC10EC2044A3C60003C045"
18 - BuildableName = "cw_monero_example.app"
19 - BlueprintName = "Runner"
20 - ReferencedContainer = "container:Runner.xcodeproj">
21 - </BuildableReference>
22 - </BuildActionEntry>
23 - </BuildActionEntries>
24 - </BuildAction>
25 - <TestAction
26 - buildConfiguration = "Debug"
27 - selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28 - selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29 - shouldUseLaunchSchemeArgsEnv = "YES">
30 - <MacroExpansion>
31 - <BuildableReference
32 - BuildableIdentifier = "primary"
33 - BlueprintIdentifier = "33CC10EC2044A3C60003C045"
34 - BuildableName = "cw_monero_example.app"
35 - BlueprintName = "Runner"
36 - ReferencedContainer = "container:Runner.xcodeproj">
37 - </BuildableReference>
38 - </MacroExpansion>
39 - <Testables>
40 - </Testables>
41 - </TestAction>
42 - <LaunchAction
43 - buildConfiguration = "Debug"
44 - selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
45 - selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
46 - launchStyle = "0"
47 - useCustomWorkingDirectory = "NO"
48 - ignoresPersistentStateOnLaunch = "NO"
49 - debugDocumentVersioning = "YES"
50 - debugServiceExtension = "internal"
51 - allowLocationSimulation = "YES">
52 - <BuildableProductRunnable
53 - runnableDebuggingMode = "0">
54 - <BuildableReference
55 - BuildableIdentifier = "primary"
56 - BlueprintIdentifier = "33CC10EC2044A3C60003C045"
57 - BuildableName = "cw_monero_example.app"
58 - BlueprintName = "Runner"
59 - ReferencedContainer = "container:Runner.xcodeproj">
60 - </BuildableReference>
61 - </BuildableProductRunnable>
62 - </LaunchAction>
63 - <ProfileAction
64 - buildConfiguration = "Profile"
65 - shouldUseLaunchSchemeArgsEnv = "YES"
66 - savedToolIdentifier = ""
67 - useCustomWorkingDirectory = "NO"
68 - debugDocumentVersioning = "YES">
69 - <BuildableProductRunnable
70 - runnableDebuggingMode = "0">
71 - <BuildableReference
72 - BuildableIdentifier = "primary"
73 - BlueprintIdentifier = "33CC10EC2044A3C60003C045"
74 - BuildableName = "cw_monero_example.app"
75 - BlueprintName = "Runner"
76 - ReferencedContainer = "container:Runner.xcodeproj">
77 - </BuildableReference>
78 - </BuildableProductRunnable>
79 - </ProfileAction>
80 - <AnalyzeAction
81 - buildConfiguration = "Debug">
82 - </AnalyzeAction>
83 - <ArchiveAction
84 - buildConfiguration = "Release"
85 - revealArchiveInOrganizer = "YES">
86 - </ArchiveAction>
87 -</Scheme>
cw_monero/example/macos/Runner.xcworkspace/contents.xcworkspacedata deleted
-10
@@ -1,10 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<Workspace
3 - version = "1.0">
4 - <FileRef
5 - location = "group:Runner.xcodeproj">
6 - </FileRef>
7 - <FileRef
8 - location = "group:Pods/Pods.xcodeproj">
9 - </FileRef>
10 -</Workspace>
cw_monero/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted
-8
@@ -1,8 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 -<plist version="1.0">
4 -<dict>
5 - <key>IDEDidComputeMac32BitWarning</key>
6 - <true/>
7 -</dict>
8 -</plist>
cw_monero/example/macos/Runner/AppDelegate.swift deleted
-9
@@ -1,9 +0,0 @@
1 -import Cocoa
2 -import FlutterMacOS
3 -
4 -@NSApplicationMain
5 -class AppDelegate: FlutterAppDelegate {
6 - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 - return true
8 - }
9 -}
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted
-68
@@ -1,68 +0,0 @@
1 -{
2 - "images" : [
3 - {
4 - "size" : "16x16",
5 - "idiom" : "mac",
6 - "filename" : "app_icon_16.png",
7 - "scale" : "1x"
8 - },
9 - {
10 - "size" : "16x16",
11 - "idiom" : "mac",
12 - "filename" : "app_icon_32.png",
13 - "scale" : "2x"
14 - },
15 - {
16 - "size" : "32x32",
17 - "idiom" : "mac",
18 - "filename" : "app_icon_32.png",
19 - "scale" : "1x"
20 - },
21 - {
22 - "size" : "32x32",
23 - "idiom" : "mac",
24 - "filename" : "app_icon_64.png",
25 - "scale" : "2x"
26 - },
27 - {
28 - "size" : "128x128",
29 - "idiom" : "mac",
30 - "filename" : "app_icon_128.png",
31 - "scale" : "1x"
32 - },
33 - {
34 - "size" : "128x128",
35 - "idiom" : "mac",
36 - "filename" : "app_icon_256.png",
37 - "scale" : "2x"
38 - },
39 - {
40 - "size" : "256x256",
41 - "idiom" : "mac",
42 - "filename" : "app_icon_256.png",
43 - "scale" : "1x"
44 - },
45 - {
46 - "size" : "256x256",
47 - "idiom" : "mac",
48 - "filename" : "app_icon_512.png",
49 - "scale" : "2x"
50 - },
51 - {
52 - "size" : "512x512",
53 - "idiom" : "mac",
54 - "filename" : "app_icon_512.png",
55 - "scale" : "1x"
56 - },
57 - {
58 - "size" : "512x512",
59 - "idiom" : "mac",
60 - "filename" : "app_icon_1024.png",
61 - "scale" : "2x"
62 - }
63 - ],
64 - "info" : {
65 - "version" : 1,
66 - "author" : "xcode"
67 - }
68 -}
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
Binary files a/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
Binary files a/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
Binary files a/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
Binary files a/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
Binary files a/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
Binary files a/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
Binary files a/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ
cw_monero/example/macos/Runner/Base.lproj/MainMenu.xib deleted
-343
@@ -1,343 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
3 - <dependencies>
4 - <deployment identifier="macosx"/>
5 - <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
6 - <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
7 - </dependencies>
8 - <objects>
9 - <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
10 - <connections>
11 - <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
12 - </connections>
13 - </customObject>
14 - <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
15 - <customObject id="-3" userLabel="Application" customClass="NSObject"/>
16 - <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
17 - <connections>
18 - <outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
19 - <outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
20 - </connections>
21 - </customObject>
22 - <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
23 - <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
24 - <items>
25 - <menuItem title="APP_NAME" id="1Xt-HY-uBw">
26 - <modifierMask key="keyEquivalentModifierMask"/>
27 - <menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
28 - <items>
29 - <menuItem title="About APP_NAME" id="5kV-Vb-QxS">
30 - <modifierMask key="keyEquivalentModifierMask"/>
31 - <connections>
32 - <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
33 - </connections>
34 - </menuItem>
35 - <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
36 - <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
37 - <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
38 - <menuItem title="Services" id="NMo-om-nkz">
39 - <modifierMask key="keyEquivalentModifierMask"/>
40 - <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
41 - </menuItem>
42 - <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
43 - <menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
44 - <connections>
45 - <action selector="hide:" target="-1" id="PnN-Uc-m68"/>
46 - </connections>
47 - </menuItem>
48 - <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
49 - <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
50 - <connections>
51 - <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
52 - </connections>
53 - </menuItem>
54 - <menuItem title="Show All" id="Kd2-mp-pUS">
55 - <modifierMask key="keyEquivalentModifierMask"/>
56 - <connections>
57 - <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
58 - </connections>
59 - </menuItem>
60 - <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
61 - <menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
62 - <connections>
63 - <action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
64 - </connections>
65 - </menuItem>
66 - </items>
67 - </menu>
68 - </menuItem>
69 - <menuItem title="Edit" id="5QF-Oa-p0T">
70 - <modifierMask key="keyEquivalentModifierMask"/>
71 - <menu key="submenu" title="Edit" id="W48-6f-4Dl">
72 - <items>
73 - <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
74 - <connections>
75 - <action selector="undo:" target="-1" id="M6e-cu-g7V"/>
76 - </connections>
77 - </menuItem>
78 - <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
79 - <connections>
80 - <action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
81 - </connections>
82 - </menuItem>
83 - <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
84 - <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
85 - <connections>
86 - <action selector="cut:" target="-1" id="YJe-68-I9s"/>
87 - </connections>
88 - </menuItem>
89 - <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
90 - <connections>
91 - <action selector="copy:" target="-1" id="G1f-GL-Joy"/>
92 - </connections>
93 - </menuItem>
94 - <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
95 - <connections>
96 - <action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
97 - </connections>
98 - </menuItem>
99 - <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
100 - <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
101 - <connections>
102 - <action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
103 - </connections>
104 - </menuItem>
105 - <menuItem title="Delete" id="pa3-QI-u2k">
106 - <modifierMask key="keyEquivalentModifierMask"/>
107 - <connections>
108 - <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
109 - </connections>
110 - </menuItem>
111 - <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
112 - <connections>
113 - <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
114 - </connections>
115 - </menuItem>
116 - <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
117 - <menuItem title="Find" id="4EN-yA-p0u">
118 - <modifierMask key="keyEquivalentModifierMask"/>
119 - <menu key="submenu" title="Find" id="1b7-l0-nxx">
120 - <items>
121 - <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
122 - <connections>
123 - <action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
124 - </connections>
125 - </menuItem>
126 - <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
127 - <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
128 - <connections>
129 - <action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
130 - </connections>
131 - </menuItem>
132 - <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
133 - <connections>
134 - <action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
135 - </connections>
136 - </menuItem>
137 - <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
138 - <connections>
139 - <action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
140 - </connections>
141 - </menuItem>
142 - <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
143 - <connections>
144 - <action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
145 - </connections>
146 - </menuItem>
147 - <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
148 - <connections>
149 - <action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
150 - </connections>
151 - </menuItem>
152 - </items>
153 - </menu>
154 - </menuItem>
155 - <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
156 - <modifierMask key="keyEquivalentModifierMask"/>
157 - <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
158 - <items>
159 - <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
160 - <connections>
161 - <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
162 - </connections>
163 - </menuItem>
164 - <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
165 - <connections>
166 - <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
167 - </connections>
168 - </menuItem>
169 - <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
170 - <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
171 - <modifierMask key="keyEquivalentModifierMask"/>
172 - <connections>
173 - <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
174 - </connections>
175 - </menuItem>
176 - <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
177 - <modifierMask key="keyEquivalentModifierMask"/>
178 - <connections>
179 - <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
180 - </connections>
181 - </menuItem>
182 - <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
183 - <modifierMask key="keyEquivalentModifierMask"/>
184 - <connections>
185 - <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
186 - </connections>
187 - </menuItem>
188 - </items>
189 - </menu>
190 - </menuItem>
191 - <menuItem title="Substitutions" id="9ic-FL-obx">
192 - <modifierMask key="keyEquivalentModifierMask"/>
193 - <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
194 - <items>
195 - <menuItem title="Show Substitutions" id="z6F-FW-3nz">
196 - <modifierMask key="keyEquivalentModifierMask"/>
197 - <connections>
198 - <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
199 - </connections>
200 - </menuItem>
201 - <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
202 - <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
203 - <modifierMask key="keyEquivalentModifierMask"/>
204 - <connections>
205 - <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
206 - </connections>
207 - </menuItem>
208 - <menuItem title="Smart Quotes" id="hQb-2v-fYv">
209 - <modifierMask key="keyEquivalentModifierMask"/>
210 - <connections>
211 - <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
212 - </connections>
213 - </menuItem>
214 - <menuItem title="Smart Dashes" id="rgM-f4-ycn">
215 - <modifierMask key="keyEquivalentModifierMask"/>
216 - <connections>
217 - <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
218 - </connections>
219 - </menuItem>
220 - <menuItem title="Smart Links" id="cwL-P1-jid">
221 - <modifierMask key="keyEquivalentModifierMask"/>
222 - <connections>
223 - <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
224 - </connections>
225 - </menuItem>
226 - <menuItem title="Data Detectors" id="tRr-pd-1PS">
227 - <modifierMask key="keyEquivalentModifierMask"/>
228 - <connections>
229 - <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
230 - </connections>
231 - </menuItem>
232 - <menuItem title="Text Replacement" id="HFQ-gK-NFA">
233 - <modifierMask key="keyEquivalentModifierMask"/>
234 - <connections>
235 - <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
236 - </connections>
237 - </menuItem>
238 - </items>
239 - </menu>
240 - </menuItem>
241 - <menuItem title="Transformations" id="2oI-Rn-ZJC">
242 - <modifierMask key="keyEquivalentModifierMask"/>
243 - <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
244 - <items>
245 - <menuItem title="Make Upper Case" id="vmV-6d-7jI">
246 - <modifierMask key="keyEquivalentModifierMask"/>
247 - <connections>
248 - <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
249 - </connections>
250 - </menuItem>
251 - <menuItem title="Make Lower Case" id="d9M-CD-aMd">
252 - <modifierMask key="keyEquivalentModifierMask"/>
253 - <connections>
254 - <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
255 - </connections>
256 - </menuItem>
257 - <menuItem title="Capitalize" id="UEZ-Bs-lqG">
258 - <modifierMask key="keyEquivalentModifierMask"/>
259 - <connections>
260 - <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
261 - </connections>
262 - </menuItem>
263 - </items>
264 - </menu>
265 - </menuItem>
266 - <menuItem title="Speech" id="xrE-MZ-jX0">
267 - <modifierMask key="keyEquivalentModifierMask"/>
268 - <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
269 - <items>
270 - <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
271 - <modifierMask key="keyEquivalentModifierMask"/>
272 - <connections>
273 - <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
274 - </connections>
275 - </menuItem>
276 - <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
277 - <modifierMask key="keyEquivalentModifierMask"/>
278 - <connections>
279 - <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
280 - </connections>
281 - </menuItem>
282 - </items>
283 - </menu>
284 - </menuItem>
285 - </items>
286 - </menu>
287 - </menuItem>
288 - <menuItem title="View" id="H8h-7b-M4v">
289 - <modifierMask key="keyEquivalentModifierMask"/>
290 - <menu key="submenu" title="View" id="HyV-fh-RgO">
291 - <items>
292 - <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
293 - <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
294 - <connections>
295 - <action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
296 - </connections>
297 - </menuItem>
298 - </items>
299 - </menu>
300 - </menuItem>
301 - <menuItem title="Window" id="aUF-d1-5bR">
302 - <modifierMask key="keyEquivalentModifierMask"/>
303 - <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
304 - <items>
305 - <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
306 - <connections>
307 - <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
308 - </connections>
309 - </menuItem>
310 - <menuItem title="Zoom" id="R4o-n2-Eq4">
311 - <modifierMask key="keyEquivalentModifierMask"/>
312 - <connections>
313 - <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
314 - </connections>
315 - </menuItem>
316 - <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
317 - <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
318 - <modifierMask key="keyEquivalentModifierMask"/>
319 - <connections>
320 - <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
321 - </connections>
322 - </menuItem>
323 - </items>
324 - </menu>
325 - </menuItem>
326 - <menuItem title="Help" id="EPT-qC-fAb">
327 - <modifierMask key="keyEquivalentModifierMask"/>
328 - <menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
329 - </menuItem>
330 - </items>
331 - <point key="canvasLocation" x="142" y="-258"/>
332 - </menu>
333 - <window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
334 - <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
335 - <rect key="contentRect" x="335" y="390" width="800" height="600"/>
336 - <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
337 - <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
338 - <rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
339 - <autoresizingMask key="autoresizingMask"/>
340 - </view>
341 - </window>
342 - </objects>
343 -</document>
cw_monero/example/macos/Runner/Configs/AppInfo.xcconfig deleted
-14
@@ -1,14 +0,0 @@
1 -// Application-level settings for the Runner target.
2 -//
3 -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 -// future. If not, the values below would default to using the project name when this becomes a
5 -// 'flutter create' template.
6 -
7 -// The application's name. By default this is also the title of the Flutter window.
8 -PRODUCT_NAME = cw_monero_example
9 -
10 -// The application's bundle identifier
11 -PRODUCT_BUNDLE_IDENTIFIER = com.cakewallet.cwMoneroExample
12 -
13 -// The copyright displayed in application information
14 -PRODUCT_COPYRIGHT = Copyright © 2022 com.cakewallet. All rights reserved.
cw_monero/example/macos/Runner/Configs/Debug.xcconfig deleted
-2
@@ -1,2 +0,0 @@
1 -#include "../../Flutter/Flutter-Debug.xcconfig"
2 -#include "Warnings.xcconfig"
cw_monero/example/macos/Runner/Configs/Release.xcconfig deleted
-2
@@ -1,2 +0,0 @@
1 -#include "../../Flutter/Flutter-Release.xcconfig"
2 -#include "Warnings.xcconfig"
cw_monero/example/macos/Runner/Configs/Warnings.xcconfig deleted
-13
@@ -1,13 +0,0 @@
1 -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 -GCC_WARN_UNDECLARED_SELECTOR = YES
3 -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 -CLANG_WARN_PRAGMA_PACK = YES
7 -CLANG_WARN_STRICT_PROTOTYPES = YES
8 -CLANG_WARN_COMMA = YES
9 -GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 -GCC_WARN_SHADOW = YES
13 -CLANG_WARN_UNREACHABLE_CODE = YES
cw_monero/example/macos/Runner/Info.plist deleted
-32
@@ -1,32 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 -<plist version="1.0">
4 -<dict>
5 - <key>CFBundleDevelopmentRegion</key>
6 - <string>$(DEVELOPMENT_LANGUAGE)</string>
7 - <key>CFBundleExecutable</key>
8 - <string>$(EXECUTABLE_NAME)</string>
9 - <key>CFBundleIconFile</key>
10 - <string></string>
11 - <key>CFBundleIdentifier</key>
12 - <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13 - <key>CFBundleInfoDictionaryVersion</key>
14 - <string>6.0</string>
15 - <key>CFBundleName</key>
16 - <string>$(PRODUCT_NAME)</string>
17 - <key>CFBundlePackageType</key>
18 - <string>APPL</string>
19 - <key>CFBundleShortVersionString</key>
20 - <string>$(FLUTTER_BUILD_NAME)</string>
21 - <key>CFBundleVersion</key>
22 - <string>$(FLUTTER_BUILD_NUMBER)</string>
23 - <key>LSMinimumSystemVersion</key>
24 - <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
25 - <key>NSHumanReadableCopyright</key>
26 - <string>$(PRODUCT_COPYRIGHT)</string>
27 - <key>NSMainNibFile</key>
28 - <string>MainMenu</string>
29 - <key>NSPrincipalClass</key>
30 - <string>NSApplication</string>
31 -</dict>
32 -</plist>
cw_monero/example/macos/Runner/MainFlutterWindow.swift deleted
-15
@@ -1,15 +0,0 @@
1 -import Cocoa
2 -import FlutterMacOS
3 -
4 -class MainFlutterWindow: NSWindow {
5 - override func awakeFromNib() {
6 - let flutterViewController = FlutterViewController.init()
7 - let windowFrame = self.frame
8 - self.contentViewController = flutterViewController
9 - self.setFrame(windowFrame, display: true)
10 -
11 - RegisterGeneratedPlugins(registry: flutterViewController)
12 -
13 - super.awakeFromNib()
14 - }
15 -}
cw_monero/example/macos/Runner/Release.entitlements deleted
-8
@@ -1,8 +0,0 @@
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 -<plist version="1.0">
4 -<dict>
5 - <key>com.apple.security.app-sandbox</key>
6 - <true/>
7 -</dict>
8 -</plist>
cw_monero/example/pubspec.yaml deleted
-84
@@ -1,84 +0,0 @@
1 -name: cw_monero_example
2 -description: Demonstrates how to use the cw_monero plugin.
3 -
4 -# The following line prevents the package from being accidentally published to
5 -# pub.dev using `flutter pub publish`. This is preferred for private packages.
6 -publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 -
8 -environment:
9 - sdk: '>=2.18.1 <3.0.0'
10 -
11 -# Dependencies specify other packages that your package needs in order to work.
12 -# To automatically upgrade your package dependencies to the latest versions
13 -# consider running `flutter pub upgrade --major-versions`. Alternatively,
14 -# dependencies can be manually updated by changing the version numbers below to
15 -# the latest version available on pub.dev. To see which dependencies have newer
16 -# versions available, run `flutter pub outdated`.
17 -dependencies:
18 - flutter:
19 - sdk: flutter
20 -
21 - cw_monero:
22 - # When depending on this package from a real application you should use:
23 - # cw_monero: ^x.y.z
24 - # See https://dart.dev/tools/pub/dependencies#version-constraints
25 - # The example app is bundled with the plugin so we use a path dependency on
26 - # the parent directory to use the current plugin's version.
27 - path: ../
28 -
29 - # The following adds the Cupertino Icons font to your application.
30 - # Use with the CupertinoIcons class for iOS style icons.
31 - cupertino_icons: ^1.0.2
32 -
33 -dev_dependencies:
34 - flutter_test:
35 - sdk: flutter
36 -
37 - # The "flutter_lints" package below contains a set of recommended lints to
38 - # encourage good coding practices. The lint set provided by the package is
39 - # activated in the `analysis_options.yaml` file located at the root of your
40 - # package. See that file for information about deactivating specific lint
41 - # rules and activating additional ones.
42 - flutter_lints: ^2.0.0
43 -
44 -# For information on the generic Dart part of this file, see the
45 -# following page: https://dart.dev/tools/pub/pubspec
46 -
47 -# The following section is specific to Flutter packages.
48 -flutter:
49 -
50 - # The following line ensures that the Material Icons font is
51 - # included with your application, so that you can use the icons in
52 - # the material Icons class.
53 - uses-material-design: true
54 -
55 - # To add assets to your application, add an assets section, like this:
56 - # assets:
57 - # - images/a_dot_burr.jpeg
58 - # - images/a_dot_ham.jpeg
59 -
60 - # An image asset can refer to one or more resolution-specific "variants", see
61 - # https://flutter.dev/assets-and-images/#resolution-aware
62 -
63 - # For details regarding adding assets from package dependencies, see
64 - # https://flutter.dev/assets-and-images/#from-packages
65 -
66 - # To add custom fonts to your application, add a fonts section here,
67 - # in this "flutter" section. Each entry in this list should have a
68 - # "family" key with the font family name, and a "fonts" key with a
69 - # list giving the asset and other descriptors for the font. For
70 - # example:
71 - # fonts:
72 - # - family: Schyler
73 - # fonts:
74 - # - asset: fonts/Schyler-Regular.ttf
75 - # - asset: fonts/Schyler-Italic.ttf
76 - # style: italic
77 - # - family: Trajan Pro
78 - # fonts:
79 - # - asset: fonts/TrajanPro.ttf
80 - # - asset: fonts/TrajanPro_Bold.ttf
81 - # weight: 700
82 - #
83 - # For details regarding fonts from package dependencies,
84 - # see https://flutter.dev/custom-fonts/#from-packages
cw_monero/example/test/widget_test.dart deleted
-27
@@ -1,27 +0,0 @@
1 -// This is a basic Flutter widget test.
2 -//
3 -// To perform an interaction with a widget in your test, use the WidgetTester
4 -// utility in the flutter_test package. For example, you can send tap and scroll
5 -// gestures. You can also use WidgetTester to find child widgets in the widget
6 -// tree, read text, and verify that the values of widget properties are correct.
7 -
8 -import 'package:flutter/material.dart';
9 -import 'package:flutter_test/flutter_test.dart';
10 -
11 -import 'package:cw_monero_example/main.dart';
12 -
13 -void main() {
14 - testWidgets('Verify Platform version', (WidgetTester tester) async {
15 - // Build our app and trigger a frame.
16 - await tester.pumpWidget(const MyApp());
17 -
18 - // Verify that platform version is retrieved.
19 - expect(
20 - find.byWidgetPredicate(
21 - (Widget widget) => widget is Text &&
22 - widget.data!.startsWith('Running on:'),
23 - ),
24 - findsOneWidget,
25 - );
26 - });
27 -}
cw_monero/ios/.gitignore deleted
-37
@@ -1,37 +0,0 @@
1 -.idea/
2 -.vagrant/
3 -.sconsign.dblite
4 -.svn/
5 -
6 -.DS_Store
7 -*.swp
8 -profile
9 -
10 -DerivedData/
11 -build/
12 -GeneratedPluginRegistrant.h
13 -GeneratedPluginRegistrant.m
14 -
15 -.generated/
16 -
17 -*.pbxuser
18 -*.mode1v3
19 -*.mode2v3
20 -*.perspectivev3
21 -
22 -!default.pbxuser
23 -!default.mode1v3
24 -!default.mode2v3
25 -!default.perspectivev3
26 -
27 -xcuserdata
28 -
29 -*.moved-aside
30 -
31 -*.pyc
32 -*sync/
33 -Icon?
34 -.tags*
35 -
36 -/Flutter/Generated.xcconfig
37 -/Flutter/flutter_export_environment.sh
\ No newline at end of file
cw_monero/ios/Classes/CwMoneroPlugin.h deleted
-4
@@ -1,4 +0,0 @@
1 -#import <Flutter/Flutter.h>
2 -
3 -@interface CwMoneroPlugin : NSObject<FlutterPlugin>
4 -@end
cw_monero/ios/Classes/CwMoneroPlugin.m deleted
-8
@@ -1,8 +0,0 @@
1 -#import "CwMoneroPlugin.h"
2 -#import <cw_monero/cw_monero-Swift.h>
3 -
4 -@implementation CwMoneroPlugin
5 -+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
6 - [SwiftCwMoneroPlugin registerWithRegistrar:registrar];
7 -}
8 -@end
cw_monero/ios/Classes/CwWalletListener.h deleted
-23
@@ -1,23 +0,0 @@
1 -#include <stdint.h>
2 -
3 -struct CWMoneroWalletListener;
4 -
5 -typedef int8_t (*on_new_block_callback)(uint64_t height);
6 -typedef int8_t (*on_need_to_refresh_callback)();
7 -
8 -typedef struct CWMoneroWalletListener
9 -{
10 - // on_money_spent_callback *on_money_spent;
11 - // on_money_received_callback *on_money_received;
12 - // on_unconfirmed_money_received_callback *on_unconfirmed_money_received;
13 - // on_new_block_callback *on_new_block;
14 - // on_updated_callback *on_updated;
15 - // on_refreshed_callback *on_refreshed;
16 -
17 - on_new_block_callback on_new_block;
18 -} CWMoneroWalletListener;
19 -
20 -struct TestListener {
21 - // int8_t x;
22 - on_new_block_callback on_new_block;
23 -};
\ No newline at end of file
cw_monero/ios/Classes/SwiftCwMoneroPlugin.swift deleted
-14
@@ -1,14 +0,0 @@
1 -import Flutter
2 -import UIKit
3 -
4 -public class SwiftCwMoneroPlugin: NSObject, FlutterPlugin {
5 - public static func register(with registrar: FlutterPluginRegistrar) {
6 - let channel = FlutterMethodChannel(name: "cw_monero", binaryMessenger: registrar.messenger())
7 - let instance = SwiftCwMoneroPlugin()
8 - registrar.addMethodCallDelegate(instance, channel: channel)
9 - }
10 -
11 - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
12 - result("iOS " + UIDevice.current.systemVersion)
13 - }
14 -}
cw_monero/ios/Classes/monero_api.cpp deleted
-1044
@@ -1,1044 +0,0 @@
1 -#include <stdint.h>
2 -#include "cstdlib"
3 -#include <chrono>
4 -#include <functional>
5 -#include <iostream>
6 -#include <fstream>
7 -#include <unistd.h>
8 -#include <mutex>
9 -#include <list>
10 -#include "thread"
11 -#include "CwWalletListener.h"
12 -#if __APPLE__
13 -// Fix for randomx on ios
14 -void __clear_cache(void* start, void* end) { }
15 -#include "../External/ios/include/wallet2_api.h"
16 -#else
17 -#include "../External/android/include/wallet2_api.h"
18 -#endif
19 -
20 -using namespace std::chrono_literals;
21 -#ifdef __cplusplus
22 -extern "C"
23 -{
24 -#endif
25 - const uint64_t MONERO_BLOCK_SIZE = 1000;
26 -
27 - struct Utf8Box
28 - {
29 - char *value;
30 -
31 - Utf8Box(char *_value)
32 - {
33 - value = _value;
34 - }
35 - };
36 -
37 - struct SubaddressRow
38 - {
39 - uint64_t id;
40 - char *address;
41 - char *label;
42 -
43 - SubaddressRow(std::size_t _id, char *_address, char *_label)
44 - {
45 - id = static_cast<uint64_t>(_id);
46 - address = _address;
47 - label = _label;
48 - }
49 - };
50 -
51 - struct AccountRow
52 - {
53 - uint64_t id;
54 - char *label;
55 -
56 - AccountRow(std::size_t _id, char *_label)
57 - {
58 - id = static_cast<uint64_t>(_id);
59 - label = _label;
60 - }
61 - };
62 -
63 - struct MoneroWalletListener : Monero::WalletListener
64 - {
65 - uint64_t m_height;
66 - bool m_need_to_refresh;
67 - bool m_new_transaction;
68 -
69 - MoneroWalletListener()
70 - {
71 - m_height = 0;
72 - m_need_to_refresh = false;
73 - m_new_transaction = false;
74 - }
75 -
76 - void moneySpent(const std::string &txId, uint64_t amount)
77 - {
78 - m_new_transaction = true;
79 - }
80 -
81 - void moneyReceived(const std::string &txId, uint64_t amount)
82 - {
83 - m_new_transaction = true;
84 - }
85 -
86 - void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
87 - {
88 - m_new_transaction = true;
89 - }
90 -
91 - void newBlock(uint64_t height)
92 - {
93 - m_height = height;
94 - }
95 -
96 - void updated()
97 - {
98 - m_new_transaction = true;
99 - }
100 -
101 - void refreshed()
102 - {
103 - m_need_to_refresh = true;
104 - }
105 -
106 - void resetNeedToRefresh()
107 - {
108 - m_need_to_refresh = false;
109 - }
110 -
111 - bool isNeedToRefresh()
112 - {
113 - return m_need_to_refresh;
114 - }
115 -
116 - bool isNewTransactionExist()
117 - {
118 - return m_new_transaction;
119 - }
120 -
121 - void resetIsNewTransactionExist()
122 - {
123 - m_new_transaction = false;
124 - }
125 -
126 - uint64_t height()
127 - {
128 - return m_height;
129 - }
130 - };
131 -
132 - struct TransactionInfoRow
133 - {
134 - uint64_t amount;
135 - uint64_t fee;
136 - uint64_t blockHeight;
137 - uint64_t confirmations;
138 - uint32_t subaddrAccount;
139 - int8_t direction;
140 - int8_t isPending;
141 - uint32_t subaddrIndex;
142 -
143 - char *hash;
144 - char *paymentId;
145 -
146 - int64_t datetime;
147 -
148 - TransactionInfoRow(Monero::TransactionInfo *transaction)
149 - {
150 - amount = transaction->amount();
151 - fee = transaction->fee();
152 - blockHeight = transaction->blockHeight();
153 - subaddrAccount = transaction->subaddrAccount();
154 - std::set<uint32_t>::iterator it = transaction->subaddrIndex().begin();
155 - subaddrIndex = *it;
156 - confirmations = transaction->confirmations();
157 - datetime = static_cast<int64_t>(transaction->timestamp());
158 - direction = transaction->direction();
159 - isPending = static_cast<int8_t>(transaction->isPending());
160 - std::string *hash_str = new std::string(transaction->hash());
161 - hash = strdup(hash_str->c_str());
162 - paymentId = strdup(transaction->paymentId().c_str());
163 - }
164 - };
165 -
166 - struct PendingTransactionRaw
167 - {
168 - uint64_t amount;
169 - uint64_t fee;
170 - char *hash;
171 - char *hex;
172 - char *txKey;
173 - Monero::PendingTransaction *transaction;
174 -
175 - PendingTransactionRaw(Monero::PendingTransaction *_transaction)
176 - {
177 - transaction = _transaction;
178 - amount = _transaction->amount();
179 - fee = _transaction->fee();
180 - hash = strdup(_transaction->txid()[0].c_str());
181 - hex = strdup(_transaction->hex()[0].c_str());
182 - txKey = strdup(_transaction->txKey()[0].c_str());
183 - }
184 - };
185 -
186 - struct CoinsInfoRow
187 - {
188 - uint64_t blockHeight;
189 - char *hash;
190 - uint64_t internalOutputIndex;
191 - uint64_t globalOutputIndex;
192 - bool spent;
193 - bool frozen;
194 - uint64_t spentHeight;
195 - uint64_t amount;
196 - bool rct;
197 - bool keyImageKnown;
198 - uint64_t pkIndex;
199 - uint32_t subaddrIndex;
200 - uint32_t subaddrAccount;
201 - char *address;
202 - char *addressLabel;
203 - char *keyImage;
204 - uint64_t unlockTime;
205 - bool unlocked;
206 - char *pubKey;
207 - bool coinbase;
208 - char *description;
209 -
210 - CoinsInfoRow(Monero::CoinsInfo *coinsInfo)
211 - {
212 - blockHeight = coinsInfo->blockHeight();
213 - std::string *hash_str = new std::string(coinsInfo->hash());
214 - hash = strdup(hash_str->c_str());
215 - internalOutputIndex = coinsInfo->internalOutputIndex();
216 - globalOutputIndex = coinsInfo->globalOutputIndex();
217 - spent = coinsInfo->spent();
218 - frozen = coinsInfo->frozen();
219 - spentHeight = coinsInfo->spentHeight();
220 - amount = coinsInfo->amount();
221 - rct = coinsInfo->rct();
222 - keyImageKnown = coinsInfo->keyImageKnown();
223 - pkIndex = coinsInfo->pkIndex();
224 - subaddrIndex = coinsInfo->subaddrIndex();
225 - subaddrAccount = coinsInfo->subaddrAccount();
226 - address = strdup(coinsInfo->address().c_str()) ;
227 - addressLabel = strdup(coinsInfo->addressLabel().c_str());
228 - keyImage = strdup(coinsInfo->keyImage().c_str());
229 - unlockTime = coinsInfo->unlockTime();
230 - unlocked = coinsInfo->unlocked();
231 - pubKey = strdup(coinsInfo->pubKey().c_str());
232 - coinbase = coinsInfo->coinbase();
233 - description = strdup(coinsInfo->description().c_str());
234 - }
235 -
236 - void setUnlocked(bool unlocked);
237 - };
238 -
239 - Monero::Coins *m_coins;
240 -
241 - Monero::Wallet *m_wallet;
242 - Monero::TransactionHistory *m_transaction_history;
243 - MoneroWalletListener *m_listener;
244 - Monero::Subaddress *m_subaddress;
245 - Monero::SubaddressAccount *m_account;
246 - uint64_t m_last_known_wallet_height;
247 - uint64_t m_cached_syncing_blockchain_height = 0;
248 - std::list<Monero::CoinsInfo*> m_coins_info;
249 - std::mutex store_lock;
250 - bool is_storing = false;
251 -
252 - void change_current_wallet(Monero::Wallet *wallet)
253 - {
254 - m_wallet = wallet;
255 - m_listener = nullptr;
256 -
257 -
258 - if (wallet != nullptr)
259 - {
260 - m_transaction_history = wallet->history();
261 - }
262 - else
263 - {
264 - m_transaction_history = nullptr;
265 - }
266 -
267 - if (wallet != nullptr)
268 - {
269 - m_account = wallet->subaddressAccount();
270 - }
271 - else
272 - {
273 - m_account = nullptr;
274 - }
275 -
276 - if (wallet != nullptr)
277 - {
278 - m_subaddress = wallet->subaddress();
279 - }
280 - else
281 - {
282 - m_subaddress = nullptr;
283 - }
284 -
285 - m_coins_info = std::list<Monero::CoinsInfo*>();
286 -
287 - if (wallet != nullptr)
288 - {
289 - m_coins = wallet->coins();
290 - }
291 - else
292 - {
293 - m_coins = nullptr;
294 - }
295 - }
296 -
297 - Monero::Wallet *get_current_wallet()
298 - {
299 - return m_wallet;
300 - }
301 -
302 - bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error)
303 - {
304 - Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
305 - Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
306 - Monero::Wallet *wallet = walletManager->createWallet(path, password, language, _networkType);
307 -
308 - int status;
309 - std::string errorString;
310 -
311 - wallet->statusWithErrorString(status, errorString);
312 -
313 - if (wallet->status() != Monero::Wallet::Status_Ok)
314 - {
315 - error = strdup(wallet->errorString().c_str());
316 - return false;
317 - }
318 -
319 - change_current_wallet(wallet);
320 -
321 - return true;
322 - }
323 -
324 - bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error)
325 - {
326 - Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
327 - Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->recoveryWallet(
328 - std::string(path),
329 - std::string(password),
330 - std::string(seed),
331 - _networkType,
332 - (uint64_t)restoreHeight);
333 -
334 - int status;
335 - std::string errorString;
336 -
337 - wallet->statusWithErrorString(status, errorString);
338 -
339 - if (status != Monero::Wallet::Status_Ok || !errorString.empty())
340 - {
341 - error = strdup(errorString.c_str());
342 - return false;
343 - }
344 -
345 - change_current_wallet(wallet);
346 - return true;
347 - }
348 -
349 - bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error)
350 - {
351 - Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
352 - Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createWalletFromKeys(
353 - std::string(path),
354 - std::string(password),
355 - std::string(language),
356 - _networkType,
357 - (uint64_t)restoreHeight,
358 - std::string(address),
359 - std::string(viewKey),
360 - std::string(spendKey));
361 -
362 - int status;
363 - std::string errorString;
364 -
365 - wallet->statusWithErrorString(status, errorString);
366 -
367 - if (status != Monero::Wallet::Status_Ok || !errorString.empty())
368 - {
369 - error = strdup(errorString.c_str());
370 - return false;
371 - }
372 -
373 - change_current_wallet(wallet);
374 - return true;
375 - }
376 -
377 - bool restore_wallet_from_spend_key(char *path, char *password, char *seed, char *language, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error)
378 - {
379 - Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
380 - Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createDeterministicWalletFromSpendKey(
381 - std::string(path),
382 - std::string(password),
383 - std::string(language),
384 - _networkType,
385 - (uint64_t)restoreHeight,
386 - std::string(spendKey));
387 -
388 - // Cache Raw to support Polyseed
389 - wallet->setCacheAttribute("cakewallet.seed", std::string(seed));
390 -
391 - int status;
392 - std::string errorString;
393 -
394 - wallet->statusWithErrorString(status, errorString);
395 -
396 - if (status != Monero::Wallet::Status_Ok || !errorString.empty())
397 - {
398 - error = strdup(errorString.c_str());
399 - return false;
400 - }
401 -
402 - change_current_wallet(wallet);
403 - return true;
404 - }
405 -
406 - bool load_wallet(char *path, char *password, int32_t nettype)
407 - {
408 - nice(19);
409 - Monero::NetworkType networkType = static_cast<Monero::NetworkType>(nettype);
410 - Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
411 - Monero::Wallet *wallet = walletManager->openWallet(std::string(path), std::string(password), networkType);
412 - int status;
413 - std::string errorString;
414 -
415 - wallet->statusWithErrorString(status, errorString);
416 - change_current_wallet(wallet);
417 -
418 - return !(status != Monero::Wallet::Status_Ok || !errorString.empty());
419 - }
420 -
421 - char *error_string() {
422 - return strdup(get_current_wallet()->errorString().c_str());
423 - }
424 -
425 -
426 - bool is_wallet_exist(char *path)
427 - {
428 - return Monero::WalletManagerFactory::getWalletManager()->walletExists(std::string(path));
429 - }
430 -
431 - void close_current_wallet()
432 - {
433 - Monero::WalletManagerFactory::getWalletManager()->closeWallet(get_current_wallet());
434 - change_current_wallet(nullptr);
435 - }
436 -
437 - char *get_filename()
438 - {
439 - return strdup(get_current_wallet()->filename().c_str());
440 - }
441 -
442 - char *secret_view_key()
443 - {
444 - return strdup(get_current_wallet()->secretViewKey().c_str());
445 - }
446 -
447 - char *public_view_key()
448 - {
449 - return strdup(get_current_wallet()->publicViewKey().c_str());
450 - }
451 -
452 - char *secret_spend_key()
453 - {
454 - return strdup(get_current_wallet()->secretSpendKey().c_str());
455 - }
456 -
457 - char *public_spend_key()
458 - {
459 - return strdup(get_current_wallet()->publicSpendKey().c_str());
460 - }
461 -
462 - char *get_address(uint32_t account_index, uint32_t address_index)
463 - {
464 - return strdup(get_current_wallet()->address(account_index, address_index).c_str());
465 - }
466 -
467 - char *get_cache_attribute(char *name)
468 - {
469 - return strdup(get_current_wallet()->getCacheAttribute(std::string(name)).c_str());
470 - }
471 -
472 - bool set_cache_attribute(char *name, char *value)
473 - {
474 - get_current_wallet()->setCacheAttribute(std::string(name), std::string(value));
475 - return true;
476 - }
477 -
478 - const char *seed()
479 - {
480 - std::string _rawSeed = get_current_wallet()->getCacheAttribute("cakewallet.seed");
481 - if (!_rawSeed.empty())
482 - {
483 - return strdup(_rawSeed.c_str());
484 - }
485 - return strdup(get_current_wallet()->seed().c_str());
486 - }
487 -
488 - uint64_t get_full_balance(uint32_t account_index)
489 - {
490 - return get_current_wallet()->balance(account_index);
491 - }
492 -
493 - uint64_t get_unlocked_balance(uint32_t account_index)
494 - {
495 - return get_current_wallet()->unlockedBalance(account_index);
496 - }
497 -
498 - uint64_t get_current_height()
499 - {
500 - return get_current_wallet()->blockChainHeight();
501 - }
502 -
503 - uint64_t get_node_height()
504 - {
505 - return get_current_wallet()->daemonBlockChainHeight();
506 - }
507 -
508 - bool connect_to_node(char *error)
509 - {
510 - nice(19);
511 - bool is_connected = get_current_wallet()->connectToDaemon();
512 -
513 - if (!is_connected)
514 - {
515 - error = strdup(get_current_wallet()->errorString().c_str());
516 - }
517 -
518 - return is_connected;
519 - }
520 -
521 - bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *socksProxyAddress, char *error)
522 - {
523 - nice(19);
524 - Monero::Wallet *wallet = get_current_wallet();
525 -
526 - std::string _login = "";
527 - std::string _password = "";
528 - std::string _socksProxyAddress = "";
529 -
530 - if (login != nullptr)
531 - {
532 - _login = std::string(login);
533 - }
534 -
535 - if (password != nullptr)
536 - {
537 - _password = std::string(password);
538 - }
539 -
540 - if (socksProxyAddress != nullptr)
541 - {
542 - _socksProxyAddress = std::string(socksProxyAddress);
543 - }
544 -
545 - bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet, _socksProxyAddress);
546 -
547 - if (!inited)
548 - {
549 - error = strdup(wallet->errorString().c_str());
550 - } else if (!wallet->connectToDaemon()) {
551 - error = strdup(wallet->errorString().c_str());
552 - }
553 -
554 - return inited;
555 - }
556 -
557 - bool is_connected()
558 - {
559 - return get_current_wallet()->connected();
560 - }
561 -
562 - void start_refresh()
563 - {
564 - get_current_wallet()->refreshAsync();
565 - get_current_wallet()->startRefresh();
566 - }
567 -
568 - void set_refresh_from_block_height(uint64_t height)
569 - {
570 - get_current_wallet()->setRefreshFromBlockHeight(height);
571 - }
572 -
573 - void set_recovering_from_seed(bool is_recovery)
574 - {
575 - get_current_wallet()->setRecoveringFromSeed(is_recovery);
576 - }
577 -
578 - void store(char *path)
579 - {
580 - store_lock.lock();
581 - if (is_storing) {
582 - return;
583 - }
584 -
585 - is_storing = true;
586 - get_current_wallet()->store(std::string(path));
587 - is_storing = false;
588 - store_lock.unlock();
589 - }
590 -
591 - bool set_password(char *password, Utf8Box &error) {
592 - bool is_changed = get_current_wallet()->setPassword(std::string(password));
593 -
594 - if (!is_changed) {
595 - error = Utf8Box(strdup(get_current_wallet()->errorString().c_str()));
596 - }
597 -
598 - return is_changed;
599 - }
600 -
601 - bool transaction_create(char *address, char *payment_id, char *amount,
602 - uint8_t priority_raw, uint32_t subaddr_account,
603 - char **preferred_inputs, uint32_t preferred_inputs_size,
604 - Utf8Box &error, PendingTransactionRaw &pendingTransaction)
605 - {
606 - nice(19);
607 -
608 - std::set<std::string> _preferred_inputs;
609 -
610 - for (int i = 0; i < preferred_inputs_size; i++) {
611 - _preferred_inputs.insert(std::string(*preferred_inputs));
612 - preferred_inputs++;
613 - }
614 -
615 - auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
616 - std::string _payment_id;
617 - Monero::PendingTransaction *transaction;
618 -
619 - if (payment_id != nullptr)
620 - {
621 - _payment_id = std::string(payment_id);
622 - }
623 -
624 - if (amount != nullptr)
625 - {
626 - uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
627 - transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
628 - }
629 - else
630 - {
631 - transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
632 - }
633 -
634 - int status = transaction->status();
635 -
636 - if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
637 - {
638 - error = Utf8Box(strdup(transaction->errorString().c_str()));
639 - return false;
640 - }
641 -
642 - if (m_listener != nullptr) {
643 - m_listener->m_new_transaction = true;
644 - }
645 -
646 - pendingTransaction = PendingTransactionRaw(transaction);
647 - return true;
648 - }
649 -
650 - bool transaction_create_mult_dest(char **addresses, char *payment_id, char **amounts, uint32_t size,
651 - uint8_t priority_raw, uint32_t subaddr_account,
652 - char **preferred_inputs, uint32_t preferred_inputs_size,
653 - Utf8Box &error, PendingTransactionRaw &pendingTransaction)
654 - {
655 - nice(19);
656 -
657 - std::vector<std::string> _addresses;
658 - std::vector<uint64_t> _amounts;
659 -
660 - for (int i = 0; i < size; i++) {
661 - _addresses.push_back(std::string(*addresses));
662 - _amounts.push_back(Monero::Wallet::amountFromString(std::string(*amounts)));
663 - addresses++;
664 - amounts++;
665 - }
666 -
667 - std::set<std::string> _preferred_inputs;
668 -
669 - for (int i = 0; i < preferred_inputs_size; i++) {
670 - _preferred_inputs.insert(std::string(*preferred_inputs));
671 - preferred_inputs++;
672 - }
673 -
674 - auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
675 - std::string _payment_id;
676 - Monero::PendingTransaction *transaction;
677 -
678 - if (payment_id != nullptr)
679 - {
680 - _payment_id = std::string(payment_id);
681 - }
682 -
683 - transaction = m_wallet->createTransactionMultDest(_addresses, _payment_id, _amounts, m_wallet->defaultMixin(), priority, subaddr_account);
684 -
685 - int status = transaction->status();
686 -
687 - if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
688 - {
689 - error = Utf8Box(strdup(transaction->errorString().c_str()));
690 - return false;
691 - }
692 -
693 - if (m_listener != nullptr) {
694 - m_listener->m_new_transaction = true;
695 - }
696 -
697 - pendingTransaction = PendingTransactionRaw(transaction);
698 - return true;
699 - }
700 -
701 - bool transaction_commit(PendingTransactionRaw *transaction, Utf8Box &error)
702 - {
703 - bool committed = transaction->transaction->commit();
704 -
705 - if (!committed)
706 - {
707 - error = Utf8Box(strdup(transaction->transaction->errorString().c_str()));
708 - } else if (m_listener != nullptr) {
709 - m_listener->m_new_transaction = true;
710 - }
711 -
712 - return committed;
713 - }
714 -
715 - uint64_t get_node_height_or_update(uint64_t base_eight)
716 - {
717 - if (m_cached_syncing_blockchain_height < base_eight) {
718 - m_cached_syncing_blockchain_height = base_eight;
719 - }
720 -
721 - return m_cached_syncing_blockchain_height;
722 - }
723 -
724 - uint64_t get_syncing_height()
725 - {
726 - if (m_listener == nullptr) {
727 - return 0;
728 - }
729 -
730 - uint64_t height = m_listener->height();
731 -
732 - if (height <= 1) {
733 - return 0;
734 - }
735 -
736 - if (height != m_last_known_wallet_height)
737 - {
738 - m_last_known_wallet_height = height;
739 - }
740 -
741 - return height;
742 - }
743 -
744 - uint64_t is_needed_to_refresh()
745 - {
746 - if (m_listener == nullptr) {
747 - return false;
748 - }
749 -
750 - bool should_refresh = m_listener->isNeedToRefresh();
751 -
752 - if (should_refresh) {
753 - m_listener->resetNeedToRefresh();
754 - }
755 -
756 - return should_refresh;
757 - }
758 -
759 - uint8_t is_new_transaction_exist()
760 - {
761 - if (m_listener == nullptr) {
762 - return false;
763 - }
764 -
765 - bool is_new_transaction_exist = m_listener->isNewTransactionExist();
766 -
767 - if (is_new_transaction_exist)
768 - {
769 - m_listener->resetIsNewTransactionExist();
770 - }
771 -
772 - return is_new_transaction_exist;
773 - }
774 -
775 - void set_listener()
776 - {
777 - m_last_known_wallet_height = 0;
778 -
779 - if (m_listener != nullptr)
780 - {
781 - free(m_listener);
782 - }
783 -
784 - m_listener = new MoneroWalletListener();
785 - get_current_wallet()->setListener(m_listener);
786 - }
787 -
788 - int64_t *subaddrress_get_all()
789 - {
790 - std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
791 - size_t size = _subaddresses.size();
792 - int64_t *subaddresses = (int64_t *)malloc(size * sizeof(int64_t));
793 -
794 - for (int i = 0; i < size; i++)
795 - {
796 - Monero::SubaddressRow *row = _subaddresses[i];
797 - SubaddressRow *_row = new SubaddressRow(row->getRowId(), strdup(row->getAddress().c_str()), strdup(row->getLabel().c_str()));
798 - subaddresses[i] = reinterpret_cast<int64_t>(_row);
799 - }
800 -
801 - return subaddresses;
802 - }
803 -
804 - int32_t subaddrress_size()
805 - {
806 - std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
807 - return _subaddresses.size();
808 - }
809 -
810 - void subaddress_add_row(uint32_t accountIndex, char *label)
811 - {
812 - m_subaddress->addRow(accountIndex, std::string(label));
813 - }
814 -
815 - void subaddress_set_label(uint32_t accountIndex, uint32_t addressIndex, char *label)
816 - {
817 - m_subaddress->setLabel(accountIndex, addressIndex, std::string(label));
818 - }
819 -
820 - void subaddress_refresh(uint32_t accountIndex)
821 - {
822 - m_subaddress->refresh(accountIndex);
823 - }
824 -
825 - int32_t account_size()
826 - {
827 - std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
828 - return _accocunts.size();
829 - }
830 -
831 - int64_t *account_get_all()
832 - {
833 - std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
834 - size_t size = _accocunts.size();
835 - int64_t *accocunts = (int64_t *)malloc(size * sizeof(int64_t));
836 -
837 - for (int i = 0; i < size; i++)
838 - {
839 - Monero::SubaddressAccountRow *row = _accocunts[i];
840 - AccountRow *_row = new AccountRow(row->getRowId(), strdup(row->getLabel().c_str()));
841 - accocunts[i] = reinterpret_cast<int64_t>(_row);
842 - }
843 -
844 - return accocunts;
845 - }
846 -
847 - void account_add_row(char *label)
848 - {
849 - m_account->addRow(std::string(label));
850 - }
851 -
852 - void account_set_label_row(uint32_t account_index, char *label)
853 - {
854 - m_account->setLabel(account_index, label);
855 - }
856 -
857 - void account_refresh()
858 - {
859 - m_account->refresh();
860 - }
861 -
862 - int64_t *transactions_get_all()
863 - {
864 - std::vector<Monero::TransactionInfo *> transactions = m_transaction_history->getAll();
865 - size_t size = transactions.size();
866 - int64_t *transactionAddresses = (int64_t *)malloc(size * sizeof(int64_t));
867 -
868 - for (int i = 0; i < size; i++)
869 - {
870 - Monero::TransactionInfo *row = transactions[i];
871 - TransactionInfoRow *tx = new TransactionInfoRow(row);
872 - transactionAddresses[i] = reinterpret_cast<int64_t>(tx);
873 - }
874 -
875 - return transactionAddresses;
876 - }
877 -
878 - void transactions_refresh()
879 - {
880 - m_transaction_history->refresh();
881 - }
882 -
883 - int64_t transactions_count()
884 - {
885 - return m_transaction_history->count();
886 - }
887 -
888 - TransactionInfoRow* get_transaction(char * txId)
889 - {
890 - Monero::TransactionInfo *row = m_transaction_history->transaction(std::string(txId));
891 - return new TransactionInfoRow(row);
892 - }
893 -
894 - int LedgerExchange(
895 - unsigned char *command,
896 - unsigned int cmd_len,
897 - unsigned char *response,
898 - unsigned int max_resp_len)
899 - {
900 - return -1;
901 - }
902 -
903 - int LedgerFind(char *buffer, size_t len)
904 - {
905 - return -1;
906 - }
907 -
908 - void on_startup()
909 - {
910 - Monero::Utils::onStartup();
911 - Monero::WalletManagerFactory::setLogLevel(0);
912 - }
913 -
914 - void rescan_blockchain()
915 - {
916 - m_wallet->rescanBlockchainAsync();
917 - }
918 -
919 - char * get_tx_key(char * txId)
920 - {
921 - return strdup(m_wallet->getTxKey(std::string(txId)).c_str());
922 - }
923 -
924 - char *get_subaddress_label(uint32_t accountIndex, uint32_t addressIndex)
925 - {
926 - return strdup(get_current_wallet()->getSubaddressLabel(accountIndex, addressIndex).c_str());
927 - }
928 -
929 - void set_trusted_daemon(bool arg)
930 - {
931 - m_wallet->setTrustedDaemon(arg);
932 - }
933 -
934 - bool trusted_daemon()
935 - {
936 - return m_wallet->trustedDaemon();
937 - }
938 -
939 - // Coin Control //
940 -
941 - CoinsInfoRow* coin(int index)
942 - {
943 - if (index >= 0 && index < m_coins_info.size()) {
944 - std::list<Monero::CoinsInfo*>::iterator it = m_coins_info.begin();
945 - std::advance(it, index);
946 - Monero::CoinsInfo* element = *it;
947 - std::cout << "Element at index " << index << ": " << element << std::endl;
948 - return new CoinsInfoRow(element);
949 - } else {
950 - std::cout << "Invalid index." << std::endl;
951 - return nullptr; // Return a default value (nullptr) for invalid index
952 - }
953 - }
954 -
955 - void refresh_coins(uint32_t accountIndex)
956 - {
957 - m_coins_info.clear();
958 -
959 - m_coins->refresh();
960 - for (const auto i : m_coins->getAll()) {
961 - if (i->subaddrAccount() == accountIndex && !(i->spent())) {
962 - m_coins_info.push_back(i);
963 - }
964 - }
965 - }
966 -
967 - uint64_t coins_count()
968 - {
969 - return m_coins_info.size();
970 - }
971 -
972 - CoinsInfoRow** coins_from_account(uint32_t accountIndex)
973 - {
974 - std::vector<CoinsInfoRow*> matchingCoins;
975 -
976 - for (int i = 0; i < coins_count(); i++) {
977 - CoinsInfoRow* coinInfo = coin(i);
978 - if (coinInfo->subaddrAccount == accountIndex) {
979 - matchingCoins.push_back(coinInfo);
980 - }
981 - }
982 -
983 - CoinsInfoRow** result = new CoinsInfoRow*[matchingCoins.size()];
984 - std::copy(matchingCoins.begin(), matchingCoins.end(), result);
985 - return result;
986 - }
987 -
988 - CoinsInfoRow** coins_from_txid(const char* txid, size_t* count)
989 - {
990 - std::vector<CoinsInfoRow*> matchingCoins;
991 -
992 - for (int i = 0; i < coins_count(); i++) {
993 - CoinsInfoRow* coinInfo = coin(i);
994 - if (std::string(coinInfo->hash) == txid) {
995 - matchingCoins.push_back(coinInfo);
996 - }
997 - }
998 -
999 - *count = matchingCoins.size();
1000 - CoinsInfoRow** result = new CoinsInfoRow*[*count];
1001 - std::copy(matchingCoins.begin(), matchingCoins.end(), result);
1002 - return result;
1003 - }
1004 -
1005 - CoinsInfoRow** coins_from_key_image(const char** keyimages, size_t keyimageCount, size_t* count)
1006 - {
1007 - std::vector<CoinsInfoRow*> matchingCoins;
1008 -
1009 - for (int i = 0; i < coins_count(); i++) {
1010 - CoinsInfoRow* coinsInfoRow = coin(i);
1011 - for (size_t j = 0; j < keyimageCount; j++) {
1012 - if (coinsInfoRow->keyImageKnown && std::string(coinsInfoRow->keyImage) == keyimages[j]) {
1013 - matchingCoins.push_back(coinsInfoRow);
1014 - break;
1015 - }
1016 - }
1017 - }
1018 -
1019 - *count = matchingCoins.size();
1020 - CoinsInfoRow** result = new CoinsInfoRow*[*count];
1021 - std::copy(matchingCoins.begin(), matchingCoins.end(), result);
1022 - return result;
1023 - }
1024 -
1025 - void freeze_coin(int index)
1026 - {
1027 - m_coins->setFrozen(index);
1028 - }
1029 -
1030 - void thaw_coin(int index)
1031 - {
1032 - m_coins->thaw(index);
1033 - }
1034 -
1035 - // Sign Messages //
1036 -
1037 - char *sign_message(char *message, char *address = "")
1038 - {
1039 - return strdup(get_current_wallet()->signMessage(std::string(message), std::string(address)).c_str());
1040 - }
1041 -
1042 -#ifdef __cplusplus
1043 -}
1044 -#endif
cw_monero/ios/Classes/monero_api.h deleted
-39
@@ -1,39 +0,0 @@
1 -#include <stdint.h>
2 -#include <stdio.h>
3 -#include <stdbool.h>
4 -#include "CwWalletListener.h"
5 -
6 -#ifdef __cplusplus
7 -extern "C" {
8 -#endif
9 -
10 -bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error);
11 -bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error);
12 -bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error);
13 -void load_wallet(char *path, char *password, int32_t nettype);
14 -bool is_wallet_exist(char *path);
15 -
16 -char *get_filename();
17 -const char *seed();
18 -char *get_address(uint32_t account_index, uint32_t address_index);
19 -uint64_t get_full_balance(uint32_t account_index);
20 -uint64_t get_unlocked_balance(uint32_t account_index);
21 -uint64_t get_current_height();
22 -uint64_t get_node_height();
23 -
24 -bool is_connected();
25 -
26 -bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error);
27 -bool connect_to_node(char *error);
28 -void start_refresh();
29 -void set_refresh_from_block_height(uint64_t height);
30 -void set_recovering_from_seed(bool is_recovery);
31 -void store(char *path);
32 -
33 -void set_trusted_daemon(bool arg);
34 -bool trusted_daemon();
35 -char *sign_message(char *message, char *address);
36 -
37 -#ifdef __cplusplus
38 -}
39 -#endif
cw_monero/ios/cw_monero.podspec deleted
-62
@@ -1,62 +0,0 @@
1 -#
2 -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 -# Run `pod lib lint cw_monero.podspec' to validate before publishing.
4 -#
5 -Pod::Spec.new do |s|
6 - s.name = 'cw_monero'
7 - s.version = '0.0.2'
8 - s.summary = 'CW Monero'
9 - s.description = 'Cake Wallet wrapper over Monero project.'
10 - s.homepage = 'http://cakewallet.com'
11 - s.license = { :file => '../LICENSE' }
12 - s.author = { 'CakeWallet' => 'support@cakewallet.com' }
13 - s.source = { :path => '.' }
14 - s.source_files = 'Classes/**/*'
15 - s.public_header_files = 'Classes/**/*.h, Classes/*.h, External/ios/libs/monero/include/External/ios/**/*.h'
16 - s.dependency 'Flutter'
17 - s.dependency 'cw_shared_external'
18 - s.platform = :ios, '10.0'
19 - s.swift_version = '4.0'
20 - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
21 - s.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/Classes/*.h" }
22 -
23 - s.subspec 'OpenSSL' do |openssl|
24 - openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
25 - openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
26 - openssl.libraries = 'ssl', 'crypto'
27 - openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
28 - end
29 -
30 - s.subspec 'Sodium' do |sodium|
31 - sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
32 - sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libsodium.a'
33 - sodium.libraries = 'sodium'
34 - sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
35 - end
36 -
37 - s.subspec 'Unbound' do |unbound|
38 - unbound.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
39 - unbound.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libunbound.a'
40 - unbound.libraries = 'unbound'
41 - unbound.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
42 - end
43 -
44 - s.subspec 'Boost' do |boost|
45 - boost.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h',
46 - boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libboost.a',
47 - boost.libraries = 'boost'
48 - boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
49 - end
50 -
51 - s.subspec 'Monero' do |monero|
52 - monero.preserve_paths = 'External/ios/include/**/*.h'
53 - monero.vendored_libraries = 'External/ios/lib/libmonero.a'
54 - monero.libraries = 'monero'
55 - monero.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
56 - end
57 -
58 - # s.subspec 'lmdb' do |lmdb|
59 - # lmdb.vendored_libraries = 'External/ios/lib/liblmdb.a'
60 - # lmdb.libraries = 'lmdb'
61 - # end
62 -end
cw_monero/lib/api/account_list.dart
+30 -40
@@ -1,38 +1,28 @@
1 -import 'dart:ffi';
2 -import 'package:ffi/ffi.dart';
3 -import 'package:cw_monero/api/signatures.dart';
4 -import 'package:cw_monero/api/types.dart';
5 -import 'package:cw_monero/api/monero_api.dart';
6 -import 'package:cw_monero/api/structs/account_row.dart';
7 -import 'package:flutter/foundation.dart';
1 import 'package:cw_monero/api/wallet.dart';
2 +import 'package:monero/monero.dart' as monero;
3
10 -final accountSizeNative = moneroApi
11 - .lookup<NativeFunction<account_size>>('account_size')
12 - .asFunction<SubaddressSize>();
4 +monero.wallet? wptr = null;
5
14 -final accountRefreshNative = moneroApi
15 - .lookup<NativeFunction<account_refresh>>('account_refresh')
16 - .asFunction<AccountRefresh>();
6 +int _wlptrForW = 0;
7 +monero.WalletListener? _wlptr = null;
8
18 -final accountGetAllNative = moneroApi
19 - .lookup<NativeFunction<account_get_all>>('account_get_all')
20 - .asFunction<AccountGetAll>();
9 +monero.WalletListener getWlptr() {
10 + if (wptr!.address == _wlptrForW) return _wlptr!;
11 + _wlptrForW = wptr!.address;
12 + _wlptr = monero.MONERO_cw_getWalletListener(wptr!);
13 + return _wlptr!;
14 +}
15
22 -final accountAddNewNative = moneroApi
23 - .lookup<NativeFunction<account_add_new>>('account_add_row')
24 - .asFunction<AccountAddNew>();
16
26 -final accountSetLabelNative = moneroApi
27 - .lookup<NativeFunction<account_set_label>>('account_set_label_row')
28 - .asFunction<AccountSetLabel>();
17 +monero.SubaddressAccount? subaddressAccount;
18
19 bool isUpdating = false;
20
21 void refreshAccounts() {
22 try {
23 isUpdating = true;
35 - accountRefreshNative();
24 + subaddressAccount = monero.Wallet_subaddressAccount(wptr!);
25 + monero.SubaddressAccount_refresh(subaddressAccount!);
26 isUpdating = false;
27 } catch (e) {
28 isUpdating = false;
@@ -40,26 +30,27 @@ void refreshAccounts() {
30 }
31 }
32
43 -List<AccountRow> getAllAccount() {
44 - final size = accountSizeNative();
45 - final accountAddressesPointer = accountGetAllNative();
46 - final accountAddresses = accountAddressesPointer.asTypedList(size);
47 -
48 - return accountAddresses
49 - .map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
50 - .toList();
33 +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");
38 + if (size == 0) {
39 + monero.Wallet_addSubaddressAccount(wptr!);
40 + return getAllAccount();
41 + }
42 + return List.generate(size, (index) {
43 + return monero.SubaddressAccount_getAll_byIndex(subaddressAccount!, index: index);
44 + });
45 }
46
47 void addAccountSync({required String label}) {
54 - final labelPointer = label.toNativeUtf8();
55 - accountAddNewNative(labelPointer);
56 - calloc.free(labelPointer);
48 + monero.Wallet_addSubaddressAccount(wptr!, label: label);
49 }
50
51 void setLabelForAccountSync({required int accountIndex, required String label}) {
60 - final labelPointer = label.toNativeUtf8();
61 - accountSetLabelNative(accountIndex, labelPointer);
62 - calloc.free(labelPointer);
52 + // TODO(mrcyjanek): this may be wrong function?
53 + monero.Wallet_setSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: 0, label: label);
54 }
55
56 void _addAccount(String label) => addAccountSync(label: label);
@@ -72,12 +63,11 @@ void _setLabelForAccount(Map<String, dynamic> args) {
63 }
64
65 Future<void> addAccount({required String label}) async {
75 - await compute(_addAccount, label);
66 + _addAccount(label);
67 await store();
68 }
69
70 Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
80 - await compute(
81 - _setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
71 + _setLabelForAccount({'accountIndex': accountIndex, 'label': label});
72 await store();
73 }
\ No newline at end of file
cw_monero/lib/api/coins_info.dart
+11 -29
@@ -1,35 +1,17 @@
1 -import 'dart:ffi';
2 -import 'package:cw_monero/api/signatures.dart';
3 -import 'package:cw_monero/api/structs/coins_info_row.dart';
4 -import 'package:cw_monero/api/types.dart';
5 -import 'package:cw_monero/api/monero_api.dart';
1 +import 'package:cw_monero/api/account_list.dart';
2 +import 'package:monero/monero.dart' as monero;
3
7 -final refreshCoinsNative = moneroApi
8 - .lookup<NativeFunction<refresh_coins>>('refresh_coins')
9 - .asFunction<RefreshCoins>();
4 +monero.Coins? coins = null;
5
11 -final coinsCountNative = moneroApi
12 - .lookup<NativeFunction<coins_count>>('coins_count')
13 - .asFunction<CoinsCount>();
6 +void refreshCoins(int accountIndex) {
7 + coins = monero.Wallet_coins(wptr!);
8 + monero.Coins_refresh(coins!);
9 +}
10
15 -final coinNative = moneroApi
16 - .lookup<NativeFunction<coin>>('coin')
17 - .asFunction<GetCoin>();
11 +int countOfCoins() => monero.Coins_count(coins!);
12
19 -final freezeCoinNative = moneroApi
20 - .lookup<NativeFunction<freeze_coin>>('freeze_coin')
21 - .asFunction<FreezeCoin>();
13 +monero.CoinsInfo getCoin(int index) => monero.Coins_coin(coins!, index);
14
23 -final thawCoinNative = moneroApi
24 - .lookup<NativeFunction<thaw_coin>>('thaw_coin')
25 - .asFunction<ThawCoin>();
15 +void freezeCoin(int index) => monero.Coins_setFrozen(coins!, index: index);
16
27 -void refreshCoins(int accountIndex) => refreshCoinsNative(accountIndex);
28 -
29 -int countOfCoins() => coinsCountNative();
30 -
31 -CoinsInfoRow getCoin(int index) => coinNative(index).ref;
32 -
33 -void freezeCoin(int index) => freezeCoinNative(index);
34 -
35 -void thawCoin(int index) => thawCoinNative(index);
17 +void thawCoin(int index) => monero.Coins_thaw(coins!, index: index);
cw_monero/lib/api/convert_utf8_to_string.dart deleted
-8
@@ -1,8 +0,0 @@
1 -import 'dart:ffi';
2 -import 'package:ffi/ffi.dart';
3 -
4 -String convertUTF8ToString({required Pointer<Utf8> pointer}) {
5 - final str = pointer.toDartString();
6 - calloc.free(pointer);
7 - return str;
8 -}
\ No newline at end of file
cw_monero/lib/api/monero_api.dart deleted
-6
@@ -1,6 +0,0 @@
1 -import 'dart:ffi';
2 -import 'dart:io';
3 -
4 -final DynamicLibrary moneroApi = Platform.isAndroid
5 - ? DynamicLibrary.open("libcw_monero.so")
6 - : DynamicLibrary.open("cw_monero.framework/cw_monero");
\ No newline at end of file
cw_monero/lib/api/signatures.dart deleted
-160
@@ -1,160 +0,0 @@
1 -import 'dart:ffi';
2 -import 'package:cw_monero/api/structs/coins_info_row.dart';
3 -import 'package:cw_monero/api/structs/pending_transaction.dart';
4 -import 'package:cw_monero/api/structs/transaction_info_row.dart';
5 -import 'package:cw_monero/api/structs/ut8_box.dart';
6 -import 'package:ffi/ffi.dart';
7 -
8 -typedef create_wallet = Int8 Function(
9 - Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Pointer<Utf8>);
10 -
11 -typedef restore_wallet_from_seed = Int8 Function(
12 - Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
13 -
14 -typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
15 - Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
16 -
17 -typedef restore_wallet_from_spend_key = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
18 - Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
19 -
20 -// typedef restore_wallet_from_device = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
21 -// Int32, Int64, Pointer<Utf8>);
22 -
23 -typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
24 -
25 -typedef load_wallet = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
26 -
27 -typedef error_string = Pointer<Utf8> Function();
28 -
29 -typedef get_filename = Pointer<Utf8> Function();
30 -
31 -typedef get_seed = Pointer<Utf8> Function();
32 -
33 -typedef get_address = Pointer<Utf8> Function(Int32, Int32);
34 -
35 -typedef get_full_balanace = Int64 Function(Int32);
36 -
37 -typedef get_unlocked_balanace = Int64 Function(Int32);
38 -
39 -typedef get_current_height = Int64 Function();
40 -
41 -typedef get_node_height = Int64 Function();
42 -
43 -typedef is_connected = Int8 Function();
44 -
45 -typedef setup_node = Int8 Function(
46 - Pointer<Utf8>, Pointer<Utf8>?, Pointer<Utf8>?, Int8, Int8, Pointer<Utf8>?, Pointer<Utf8>);
47 -
48 -typedef start_refresh = Void Function();
49 -
50 -typedef connect_to_node = Int8 Function();
51 -
52 -typedef set_refresh_from_block_height = Void Function(Int64);
53 -
54 -typedef set_recovering_from_seed = Void Function(Int8);
55 -
56 -typedef store_c = Void Function(Pointer<Utf8>);
57 -
58 -typedef set_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
59 -
60 -typedef set_listener = Void Function();
61 -
62 -typedef get_syncing_height = Int64 Function();
63 -
64 -typedef is_needed_to_refresh = Int8 Function();
65 -
66 -typedef is_new_transaction_exist = Int8 Function();
67 -
68 -typedef subaddrress_size = Int32 Function();
69 -
70 -typedef subaddrress_refresh = Void Function(Int32);
71 -
72 -typedef subaddress_get_all = Pointer<Int64> Function();
73 -
74 -typedef subaddress_add_new = Void Function(Int32 accountIndex, Pointer<Utf8> label);
75 -
76 -typedef subaddress_set_label = Void Function(
77 - Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
78 -
79 -typedef account_size = Int32 Function();
80 -
81 -typedef account_refresh = Void Function();
82 -
83 -typedef account_get_all = Pointer<Int64> Function();
84 -
85 -typedef account_add_new = Void Function(Pointer<Utf8> label);
86 -
87 -typedef account_set_label = Void Function(Int32 accountIndex, Pointer<Utf8> label);
88 -
89 -typedef transactions_refresh = Void Function();
90 -
91 -typedef get_transaction = Pointer<TransactionInfoRow> Function(Pointer<Utf8> txId);
92 -
93 -typedef get_tx_key = Pointer<Utf8>? Function(Pointer<Utf8> txId);
94 -
95 -typedef transactions_count = Int64 Function();
96 -
97 -typedef transactions_get_all = Pointer<Int64> Function();
98 -
99 -typedef transaction_create = Int8 Function(
100 - Pointer<Utf8> address,
101 - Pointer<Utf8> paymentId,
102 - Pointer<Utf8> amount,
103 - Int8 priorityRaw,
104 - Int32 subaddrAccount,
105 - Pointer<Pointer<Utf8>> preferredInputs,
106 - Int32 preferredInputsSize,
107 - Pointer<Utf8Box> error,
108 - Pointer<PendingTransactionRaw> pendingTransaction);
109 -
110 -typedef transaction_create_mult_dest = Int8 Function(
111 - Pointer<Pointer<Utf8>> addresses,
112 - Pointer<Utf8> paymentId,
113 - Pointer<Pointer<Utf8>> amounts,
114 - Int32 size,
115 - Int8 priorityRaw,
116 - Int32 subaddrAccount,
117 - Pointer<Pointer<Utf8>> preferredInputs,
118 - Int32 preferredInputsSize,
119 - Pointer<Utf8Box> error,
120 - Pointer<PendingTransactionRaw> pendingTransaction);
121 -
122 -typedef transaction_commit = Int8 Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
123 -
124 -typedef secret_view_key = Pointer<Utf8> Function();
125 -
126 -typedef public_view_key = Pointer<Utf8> Function();
127 -
128 -typedef secret_spend_key = Pointer<Utf8> Function();
129 -
130 -typedef public_spend_key = Pointer<Utf8> Function();
131 -
132 -typedef close_current_wallet = Void Function();
133 -
134 -typedef on_startup = Void Function();
135 -
136 -typedef rescan_blockchain = Void Function();
137 -
138 -typedef get_subaddress_label = Pointer<Utf8> Function(Int32 accountIndex, Int32 addressIndex);
139 -
140 -typedef set_trusted_daemon = Void Function(Int8 trusted);
141 -
142 -typedef trusted_daemon = Int8 Function();
143 -
144 -typedef refresh_coins = Void Function(Int32 accountIndex);
145 -
146 -typedef coins_count = Int64 Function();
147 -
148 -// typedef coins_from_txid = Pointer<CoinsInfoRow> Function(Pointer<Utf8> txid);
149 -
150 -typedef coin = Pointer<CoinsInfoRow> Function(Int32 index);
151 -
152 -typedef freeze_coin = Void Function(Int32 index);
153 -
154 -typedef thaw_coin = Void Function(Int32 index);
155 -
156 -typedef sign_message = Pointer<Utf8> Function(Pointer<Utf8> message, Pointer<Utf8> address);
157 -
158 -typedef get_cache_attribute = Pointer<Utf8> Function(Pointer<Utf8> name);
159 -
160 -typedef set_cache_attribute = Int8 Function(Pointer<Utf8> name, Pointer<Utf8> value);
cw_monero/lib/api/structs/pending_transaction.dart
-22
@@ -1,25 +1,3 @@
1 -import 'dart:ffi';
2 -import 'package:ffi/ffi.dart';
3 -
4 -class PendingTransactionRaw extends Struct {
5 - @Int64()
6 - external int amount;
7 -
8 - @Int64()
9 - external int fee;
10 -
11 - external Pointer<Utf8> hash;
12 -
13 - external Pointer<Utf8> hex;
14 -
15 - external Pointer<Utf8> txKey;
16 -
17 - String getHash() => hash.toDartString();
18 -
19 - String getHex() => hex.toDartString();
20 -
21 - String getKey() => txKey.toDartString();
22 -}
1
2 class PendingTransactionDescription {
3 PendingTransactionDescription({
cw_monero/lib/api/subaddress_list.dart
+40 -45
@@ -1,38 +1,23 @@
1 -import 'dart:ffi';
2 -import 'package:ffi/ffi.dart';
3 -import 'package:flutter/foundation.dart';
4 -import 'package:cw_monero/api/signatures.dart';
5 -import 'package:cw_monero/api/types.dart';
6 -import 'package:cw_monero/api/monero_api.dart';
7 -import 'package:cw_monero/api/structs/subaddress_row.dart';
8 -import 'package:cw_monero/api/wallet.dart';
9 -
10 -final subaddressSizeNative = moneroApi
11 - .lookup<NativeFunction<subaddrress_size>>('subaddrress_size')
12 - .asFunction<SubaddressSize>();
13 -
14 -final subaddressRefreshNative = moneroApi
15 - .lookup<NativeFunction<subaddrress_refresh>>('subaddress_refresh')
16 - .asFunction<SubaddressRefresh>();
1
18 -final subaddrressGetAllNative = moneroApi
19 - .lookup<NativeFunction<subaddress_get_all>>('subaddrress_get_all')
20 - .asFunction<SubaddressGetAll>();
2 +import 'package:cw_monero/api/account_list.dart';
3 +import 'package:cw_monero/api/wallet.dart';
4 +import 'package:monero/monero.dart' as monero;
5
22 -final subaddrressAddNewNative = moneroApi
23 - .lookup<NativeFunction<subaddress_add_new>>('subaddress_add_row')
24 - .asFunction<SubaddressAddNew>();
6 +bool isUpdating = false;
7
26 -final subaddrressSetLabelNative = moneroApi
27 - .lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
28 - .asFunction<SubaddressSetLabel>();
8 +class SubaddressInfoMetadata {
9 + SubaddressInfoMetadata({
10 + required this.accountIndex,
11 + });
12 + int accountIndex;
13 +}
14
30 -bool isUpdating = false;
15 +SubaddressInfoMetadata? subaddress = null;
16
17 void refreshSubaddresses({required int accountIndex}) {
18 try {
19 isUpdating = true;
35 - subaddressRefreshNative(accountIndex);
20 + subaddress = SubaddressInfoMetadata(accountIndex: accountIndex);
21 isUpdating = false;
22 } catch (e) {
23 isUpdating = false;
@@ -40,28 +25,39 @@ void refreshSubaddresses({required int accountIndex}) {
25 }
26 }
27
43 -List<SubaddressRow> getAllSubaddresses() {
44 - final size = subaddressSizeNative();
45 - final subaddressAddressesPointer = subaddrressGetAllNative();
46 - final subaddressAddresses = subaddressAddressesPointer.asTypedList(size);
28 +class Subaddress {
29 + Subaddress({
30 + required this.addressIndex,
31 + required this.accountIndex,
32 + });
33 + String get address => monero.Wallet_address(
34 + wptr!,
35 + accountIndex: accountIndex,
36 + addressIndex: addressIndex,
37 + );
38 + final int addressIndex;
39 + final int accountIndex;
40 + String get label => monero.Wallet_getSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex);
41 +}
42
48 - return subaddressAddresses
49 - .map((addr) => Pointer<SubaddressRow>.fromAddress(addr).ref)
50 - .toList();
43 +List<Subaddress> getAllSubaddresses() {
44 + final size = monero.Wallet_numSubaddresses(wptr!, accountIndex: subaddress!.accountIndex);
45 + return List.generate(size, (index) {
46 + return Subaddress(
47 + accountIndex: subaddress!.accountIndex,
48 + addressIndex: index,
49 + );
50 + }).reversed.toList();
51 }
52
53 void addSubaddressSync({required int accountIndex, required String label}) {
54 - final labelPointer = label.toNativeUtf8();
55 - subaddrressAddNewNative(accountIndex, labelPointer);
56 - calloc.free(labelPointer);
54 + monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex, label: label);
55 + refreshSubaddresses(accountIndex: accountIndex);
56 }
57
58 void setLabelForSubaddressSync(
59 {required int accountIndex, required int addressIndex, required String label}) {
61 - final labelPointer = label.toNativeUtf8();
62 -
63 - subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
64 - calloc.free(labelPointer);
60 + monero.Wallet_setSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex, label: label);
61 }
62
63 void _addSubaddress(Map<String, dynamic> args) {
@@ -81,14 +77,13 @@ void _setLabelForSubaddress(Map<String, dynamic> args) {
77 }
78
79 Future<void> addSubaddress({required int accountIndex, required String label}) async {
84 - await compute<Map<String, Object>, void>(
85 - _addSubaddress, {'accountIndex': accountIndex, 'label': label});
86 - await store();
80 + _addSubaddress({'accountIndex': accountIndex, 'label': label});
81 + await store();
82 }
83
84 Future<void> setLabelForSubaddress(
85 {required int accountIndex, required int addressIndex, required String label}) async {
91 - await compute<Map<String, Object>, void>(_setLabelForSubaddress, {
86 + _setLabelForSubaddress({
87 'accountIndex': accountIndex,
88 'addressIndex': addressIndex,
89 'label': label
cw_monero/lib/api/transaction_history.dart
+226 -183
@@ -1,138 +1,132 @@
1 +
2 import 'dart:ffi';
3 +import 'dart:isolate';
4
3 -import 'package:cw_monero/api/convert_utf8_to_string.dart';
5 +import 'package:cw_monero/api/account_list.dart';
6 import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
5 -import 'package:cw_monero/api/monero_api.dart';
7 import 'package:cw_monero/api/monero_output.dart';
7 -import 'package:cw_monero/api/signatures.dart';
8 import 'package:cw_monero/api/structs/pending_transaction.dart';
9 -import 'package:cw_monero/api/structs/transaction_info_row.dart';
10 -import 'package:cw_monero/api/structs/ut8_box.dart';
11 -import 'package:cw_monero/api/types.dart';
9 import 'package:ffi/ffi.dart';
13 -import 'package:flutter/foundation.dart';
14 -
15 -final transactionsRefreshNative = moneroApi
16 - .lookup<NativeFunction<transactions_refresh>>('transactions_refresh')
17 - .asFunction<TransactionsRefresh>();
18 -
19 -final transactionsCountNative = moneroApi
20 - .lookup<NativeFunction<transactions_count>>('transactions_count')
21 - .asFunction<TransactionsCount>();
22 -
23 -final transactionsGetAllNative = moneroApi
24 - .lookup<NativeFunction<transactions_get_all>>('transactions_get_all')
25 - .asFunction<TransactionsGetAll>();
26 -
27 -final transactionCreateNative = moneroApi
28 - .lookup<NativeFunction<transaction_create>>('transaction_create')
29 - .asFunction<TransactionCreate>();
10 +import 'package:monero/monero.dart' as monero;
11 +import 'package:monero/src/generated_bindings_monero.g.dart' as monero_gen;
12
31 -final transactionCreateMultDestNative = moneroApi
32 - .lookup<NativeFunction<transaction_create_mult_dest>>('transaction_create_mult_dest')
33 - .asFunction<TransactionCreateMultDest>();
34 -
35 -final transactionCommitNative = moneroApi
36 - .lookup<NativeFunction<transaction_commit>>('transaction_commit')
37 - .asFunction<TransactionCommit>();
38 -
39 -final getTxKeyNative =
40 - moneroApi.lookup<NativeFunction<get_tx_key>>('get_tx_key').asFunction<GetTxKey>();
41 -
42 -final getTransactionNative = moneroApi
43 - .lookup<NativeFunction<get_transaction>>('get_transaction')
44 - .asFunction<GetTransaction>();
13
14 String getTxKey(String txId) {
47 - final txIdPointer = txId.toNativeUtf8();
48 - final keyPointer = getTxKeyNative(txIdPointer);
49 -
50 - calloc.free(txIdPointer);
51 -
52 - if (keyPointer != null) {
53 - return convertUTF8ToString(pointer: keyPointer);
54 - }
55 -
56 - return '';
15 + return monero.Wallet_getTxKey(wptr!, txid: txId);
16 }
17
59 -void refreshTransactions() => transactionsRefreshNative();
60 -
61 -int countOfTransactions() => transactionsCountNative();
18 +monero.TransactionHistory? txhistory;
19
63 -List<TransactionInfoRow> getAllTransactions() {
64 - final size = transactionsCountNative();
65 - final transactionsPointer = transactionsGetAllNative();
66 - final transactionsAddresses = transactionsPointer.asTypedList(size);
20 +void refreshTransactions() {
21 + txhistory = monero.Wallet_history(wptr!);
22 + monero.TransactionHistory_refresh(txhistory!);
23 +}
24
68 - return transactionsAddresses
69 - .map((addr) => Pointer<TransactionInfoRow>.fromAddress(addr).ref)
70 - .toList();
25 +int countOfTransactions() => monero.TransactionHistory_count(txhistory!);
26 +
27 +List<Transaction> getAllTransactions() {
28 + List<Transaction> dummyTxs = [];
29 +
30 + txhistory = monero.Wallet_history(wptr!);
31 + monero.TransactionHistory_refresh(txhistory!);
32 + int size = countOfTransactions();
33 + final list = List.generate(size, (index) => Transaction(txInfo: monero.TransactionHistory_transaction(txhistory!, index: index)))..addAll(dummyTxs);
34 +
35 + final accts = monero.Wallet_numSubaddressAccounts(wptr!);
36 + for (var i = 0; i < accts; i++) {
37 + final fullBalance = monero.Wallet_balance(wptr!, accountIndex: i);
38 + final availBalance = monero.Wallet_unlockedBalance(wptr!, accountIndex: i);
39 + if (fullBalance > availBalance) {
40 + if (list.where((element) => element.accountIndex == i && element.isConfirmed == false).isNotEmpty) {
41 + dummyTxs.add(
42 + Transaction.dummy(
43 + displayLabel: "",
44 + description: "",
45 + fee: 0,
46 + confirmations: 0,
47 + blockheight: 0,
48 + accountIndex: i,
49 + paymentId: "",
50 + amount: fullBalance - availBalance,
51 + isSpend: false,
52 + hash: "pending",
53 + key: "pending",
54 + txInfo: Pointer.fromAddress(0),
55 + )..timeStamp = DateTime.now()
56 + );
57 + }
58 + }
59 + }
60 + list.addAll(dummyTxs);
61 + return list;
62 }
63
73 -TransactionInfoRow getTransaction(String txId) {
74 - final txIdPointer = txId.toNativeUtf8();
75 - return getTransactionNative(txIdPointer).ref;
64 +Transaction getTransaction(String txId) {
65 + return Transaction(txInfo: monero.TransactionHistory_transactionById(txhistory!, txid: txId));
66 }
67
78 -PendingTransactionDescription createTransactionSync(
68 +Future<PendingTransactionDescription> createTransactionSync(
69 {required String address,
70 required String paymentId,
71 required int priorityRaw,
72 String? amount,
73 int accountIndex = 0,
84 - List<String> preferredInputs = const []}) {
85 - final addressPointer = address.toNativeUtf8();
86 - final paymentIdPointer = paymentId.toNativeUtf8();
87 - final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr;
88 -
89 - final int preferredInputsSize = preferredInputs.length;
90 - final List<Pointer<Utf8>> preferredInputsPointers =
91 - preferredInputs.map((output) => output.toNativeUtf8()).toList();
92 - final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
93 -
94 - for (int i = 0; i < preferredInputsSize; i++) {
95 - preferredInputsPointerPointer[i] = preferredInputsPointers[i];
96 - }
97 -
98 - final errorMessagePointer = calloc<Utf8Box>();
99 - final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
100 - final created = transactionCreateNative(
101 - addressPointer,
102 - paymentIdPointer,
103 - amountPointer,
104 - priorityRaw,
105 - accountIndex,
106 - preferredInputsPointerPointer,
107 - preferredInputsSize,
108 - errorMessagePointer,
109 - pendingTransactionRawPointer) !=
110 - 0;
111 -
112 - calloc.free(preferredInputsPointerPointer);
113 -
114 - preferredInputsPointers.forEach((element) => calloc.free(element));
115 -
116 - calloc.free(addressPointer);
117 - calloc.free(paymentIdPointer);
118 -
119 - if (amountPointer != nullptr) {
120 - calloc.free(amountPointer);
121 - }
122 -
123 - if (!created) {
124 - final message = errorMessagePointer.ref.getValue();
125 - calloc.free(errorMessagePointer);
74 + List<String> preferredInputs = const []}) async {
75 +
76 + final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount);
77 +
78 + final address_ = address.toNativeUtf8();
79 + final paymentId_ = paymentId.toNativeUtf8();
80 + final preferredInputs_ = preferredInputs.join(monero.defaultSeparatorStr).toNativeUtf8();
81 +
82 + final waddr = wptr!.address;
83 + final addraddr = address_.address;
84 + final paymentIdAddr = paymentId_.address;
85 + final preferredInputsAddr = preferredInputs_.address;
86 + final spaddr = monero.defaultSeparator.address;
87 + final pendingTx = Pointer<Void>.fromAddress(await Isolate.run(() {
88 + final tx = monero_gen.MoneroC(DynamicLibrary.open(monero.libPath)).MONERO_Wallet_createTransaction(
89 + Pointer.fromAddress(waddr),
90 + Pointer.fromAddress(addraddr).cast(),
91 + Pointer.fromAddress(paymentIdAddr).cast(),
92 + amt,
93 + 1,
94 + priorityRaw,
95 + accountIndex,
96 + Pointer.fromAddress(preferredInputsAddr).cast(),
97 + Pointer.fromAddress(spaddr),
98 + );
99 + return tx.address;
100 + }));
101 + calloc.free(address_);
102 + calloc.free(paymentId_);
103 + calloc.free(preferredInputs_);
104 + final String? error = (() {
105 + final status = monero.PendingTransaction_status(pendingTx);
106 + if (status == 0) {
107 + return null;
108 + }
109 + return monero.PendingTransaction_errorString(pendingTx);
110 + })();
111 +
112 + if (error != null) {
113 + final message = error;
114 throw CreationTransactionException(message: message);
115 }
116
117 + final rAmt = monero.PendingTransaction_amount(pendingTx);
118 + final rFee = monero.PendingTransaction_fee(pendingTx);
119 + final rHash = monero.PendingTransaction_txid(pendingTx, '');
120 + final rTxKey = rHash;
121 +
122 return PendingTransactionDescription(
130 - amount: pendingTransactionRawPointer.ref.amount,
131 - fee: pendingTransactionRawPointer.ref.fee,
132 - hash: pendingTransactionRawPointer.ref.getHash(),
133 - hex: pendingTransactionRawPointer.ref.getHex(),
134 - txKey: pendingTransactionRawPointer.ref.getKey(),
135 - pointerAddress: pendingTransactionRawPointer.address);
123 + amount: rAmt,
124 + fee: rFee,
125 + hash: rHash,
126 + hex: '',
127 + txKey: rTxKey,
128 + pointerAddress: pendingTx.address,
129 + );
130 }
131
132 PendingTransactionDescription createTransactionMultDestSync(
@@ -141,84 +135,50 @@ PendingTransactionDescription createTransactionMultDestSync(
135 required int priorityRaw,
136 int accountIndex = 0,
137 List<String> preferredInputs = const []}) {
144 - final int size = outputs.length;
145 - final List<Pointer<Utf8>> addressesPointers =
146 - outputs.map((output) => output.address.toNativeUtf8()).toList();
147 - final Pointer<Pointer<Utf8>> addressesPointerPointer = calloc(size);
148 - final List<Pointer<Utf8>> amountsPointers =
149 - outputs.map((output) => output.amount.toNativeUtf8()).toList();
150 - final Pointer<Pointer<Utf8>> amountsPointerPointer = calloc(size);
151 -
152 - for (int i = 0; i < size; i++) {
153 - addressesPointerPointer[i] = addressesPointers[i];
154 - amountsPointerPointer[i] = amountsPointers[i];
155 - }
156 -
157 - final int preferredInputsSize = preferredInputs.length;
158 - final List<Pointer<Utf8>> preferredInputsPointers =
159 - preferredInputs.map((output) => output.toNativeUtf8()).toList();
160 - final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
161 -
162 - for (int i = 0; i < preferredInputsSize; i++) {
163 - preferredInputsPointerPointer[i] = preferredInputsPointers[i];
164 - }
165 -
166 - final paymentIdPointer = paymentId.toNativeUtf8();
167 - final errorMessagePointer = calloc<Utf8Box>();
168 - final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
169 - final created = transactionCreateMultDestNative(
170 - addressesPointerPointer,
171 - paymentIdPointer,
172 - amountsPointerPointer,
173 - size,
174 - priorityRaw,
175 - accountIndex,
176 - preferredInputsPointerPointer,
177 - preferredInputsSize,
178 - errorMessagePointer,
179 - pendingTransactionRawPointer) !=
180 - 0;
181 -
182 - calloc.free(addressesPointerPointer);
183 - calloc.free(amountsPointerPointer);
184 - calloc.free(preferredInputsPointerPointer);
185 -
186 - addressesPointers.forEach((element) => calloc.free(element));
187 - amountsPointers.forEach((element) => calloc.free(element));
188 - preferredInputsPointers.forEach((element) => calloc.free(element));
189 -
190 - calloc.free(paymentIdPointer);
191 -
192 - if (!created) {
193 - final message = errorMessagePointer.ref.getValue();
194 - calloc.free(errorMessagePointer);
195 - throw CreationTransactionException(message: message);
138 +
139 + final txptr = monero.Wallet_createTransactionMultDest(
140 + wptr!,
141 + dstAddr: outputs.map((e) => e.address).toList(),
142 + isSweepAll: false,
143 + amounts: outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList(),
144 + mixinCount: 0,
145 + pendingTransactionPriority: priorityRaw,
146 + subaddr_account: accountIndex,
147 + );
148 + if (monero.PendingTransaction_status(txptr) != 0) {
149 + throw CreationTransactionException(message: monero.PendingTransaction_errorString(txptr));
150 }
197 -
151 return PendingTransactionDescription(
199 - amount: pendingTransactionRawPointer.ref.amount,
200 - fee: pendingTransactionRawPointer.ref.fee,
201 - hash: pendingTransactionRawPointer.ref.getHash(),
202 - hex: pendingTransactionRawPointer.ref.getHex(),
203 - txKey: pendingTransactionRawPointer.ref.getKey(),
204 - pointerAddress: pendingTransactionRawPointer.address);
152 + amount: monero.PendingTransaction_amount(txptr),
153 + fee: monero.PendingTransaction_fee(txptr),
154 + hash: monero.PendingTransaction_txid(txptr, ''),
155 + hex: monero.PendingTransaction_txid(txptr, ''),
156 + txKey: monero.PendingTransaction_txid(txptr, ''),
157 + pointerAddress: txptr.address,
158 + );
159 }
160
161 void commitTransactionFromPointerAddress({required int address}) =>
208 - commitTransaction(transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
209 -
210 -void commitTransaction({required Pointer<PendingTransactionRaw> transactionPointer}) {
211 - final errorMessagePointer = calloc<Utf8Box>();
212 - final isCommited = transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
213 -
214 - if (!isCommited) {
215 - final message = errorMessagePointer.ref.getValue();
216 - calloc.free(errorMessagePointer);
217 - throw CreationTransactionException(message: message);
162 + commitTransaction(transactionPointer: monero.PendingTransaction.fromAddress(address));
163 +
164 +void commitTransaction({required monero.PendingTransaction transactionPointer}) {
165 +
166 + final txCommit = monero.PendingTransaction_commit(transactionPointer, filename: '', overwrite: false);
167 +
168 + final String? error = (() {
169 + final status = monero.PendingTransaction_status(transactionPointer.cast());
170 + if (status == 0) {
171 + return null;
172 + }
173 + return monero.Wallet_errorString(wptr!);
174 + })();
175 +
176 + if (error != null) {
177 + throw CreationTransactionException(message: error);
178 }
179 }
180
221 -PendingTransactionDescription _createTransactionSync(Map args) {
181 +Future<PendingTransactionDescription> _createTransactionSync(Map args) async {
182 final address = args['address'] as String;
183 final paymentId = args['paymentId'] as String;
184 final amount = args['amount'] as String?;
@@ -256,8 +216,8 @@ Future<PendingTransactionDescription> createTransaction(
216 String? amount,
217 String paymentId = '',
218 int accountIndex = 0,
259 - List<String> preferredInputs = const []}) =>
260 - compute(_createTransactionSync, {
219 + List<String> preferredInputs = const []}) async =>
220 + _createTransactionSync({
221 'address': address,
222 'paymentId': paymentId,
223 'amount': amount,
@@ -271,11 +231,94 @@ Future<PendingTransactionDescription> createTransactionMultDest(
231 required int priorityRaw,
232 String paymentId = '',
233 int accountIndex = 0,
274 - List<String> preferredInputs = const []}) =>
275 - compute(_createTransactionMultDestSync, {
234 + List<String> preferredInputs = const []}) async =>
235 + _createTransactionMultDestSync({
236 'outputs': outputs,
237 'paymentId': paymentId,
238 'priorityRaw': priorityRaw,
239 'accountIndex': accountIndex,
240 'preferredInputs': preferredInputs
241 });
242 +
243 +
244 +class Transaction {
245 + final String displayLabel;
246 + String subaddressLabel = monero.Wallet_getSubaddressLabel(wptr!, accountIndex: 0, addressIndex: 0);
247 + late final String address = monero.Wallet_address(
248 + wptr!,
249 + accountIndex: 0,
250 + addressIndex: 0,
251 + );
252 + final String description;
253 + final int fee;
254 + final int confirmations;
255 + late final bool isPending = confirmations < 10;
256 + final int blockheight;
257 + final int addressIndex = 0;
258 + final int accountIndex;
259 + final String paymentId;
260 + final int amount;
261 + final bool isSpend;
262 + late DateTime timeStamp;
263 + late final bool isConfirmed = !isPending;
264 + final String hash;
265 + final String key;
266 +
267 + Map<String, dynamic> toJson() {
268 + return {
269 + "displayLabel": displayLabel,
270 + "subaddressLabel": subaddressLabel,
271 + "address": address,
272 + "description": description,
273 + "fee": fee,
274 + "confirmations": confirmations,
275 + "isPending": isPending,
276 + "blockheight": blockheight,
277 + "accountIndex": accountIndex,
278 + "addressIndex": addressIndex,
279 + "paymentId": paymentId,
280 + "amount": amount,
281 + "isSpend": isSpend,
282 + "timeStamp": timeStamp.toIso8601String(),
283 + "isConfirmed": isConfirmed,
284 + "hash": hash,
285 + };
286 + }
287 +
288 + // S finalubAddress? subAddress;
289 + // List<Transfer> transfers = [];
290 + // final int txIndex;
291 + final monero.TransactionInfo txInfo;
292 + Transaction({
293 + required this.txInfo,
294 + }) : displayLabel = monero.TransactionInfo_label(txInfo),
295 + hash = monero.TransactionInfo_hash(txInfo),
296 + timeStamp = DateTime.fromMillisecondsSinceEpoch(
297 + monero.TransactionInfo_timestamp(txInfo) * 1000,
298 + ),
299 + isSpend = monero.TransactionInfo_direction(txInfo) ==
300 + monero.TransactionInfo_Direction.Out,
301 + amount = monero.TransactionInfo_amount(txInfo),
302 + paymentId = monero.TransactionInfo_paymentId(txInfo),
303 + accountIndex = monero.TransactionInfo_subaddrAccount(txInfo),
304 + blockheight = monero.TransactionInfo_blockHeight(txInfo),
305 + confirmations = monero.TransactionInfo_confirmations(txInfo),
306 + fee = monero.TransactionInfo_fee(txInfo),
307 + description = monero.TransactionInfo_description(txInfo),
308 + key = monero.Wallet_getTxKey(wptr!, txid: monero.TransactionInfo_hash(txInfo));
309 +
310 + Transaction.dummy({
311 + required this.displayLabel,
312 + required this.description,
313 + required this.fee,
314 + required this.confirmations,
315 + required this.blockheight,
316 + required this.accountIndex,
317 + required this.paymentId,
318 + required this.amount,
319 + required this.isSpend,
320 + required this.hash,
321 + required this.key,
322 + required this.txInfo
323 + });
324 +}
\ No newline at end of file
cw_monero/lib/api/types.dart deleted
-160
@@ -1,160 +0,0 @@
1 -import 'dart:ffi';
2 -import 'package:cw_monero/api/structs/coins_info_row.dart';
3 -import 'package:cw_monero/api/structs/pending_transaction.dart';
4 -import 'package:cw_monero/api/structs/transaction_info_row.dart';
5 -import 'package:cw_monero/api/structs/ut8_box.dart';
6 -import 'package:ffi/ffi.dart';
7 -
8 -typedef CreateWallet = int Function(
9 - Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, Pointer<Utf8>);
10 -
11 -typedef RestoreWalletFromSeed = int Function(
12 - Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
13 -
14 -typedef RestoreWalletFromKeys = int Function(Pointer<Utf8>, Pointer<Utf8>,
15 - Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
16 -
17 -typedef RestoreWalletFromSpendKey = int Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
18 - Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
19 -
20 -typedef RestoreWalletFromDevice = int Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
21 - int, int, Pointer<Utf8>);
22 -
23 -typedef IsWalletExist = int Function(Pointer<Utf8>);
24 -
25 -typedef LoadWallet = int Function(Pointer<Utf8>, Pointer<Utf8>, int);
26 -
27 -typedef ErrorString = Pointer<Utf8> Function();
28 -
29 -typedef GetFilename = Pointer<Utf8> Function();
30 -
31 -typedef GetSeed = Pointer<Utf8> Function();
32 -
33 -typedef GetAddress = Pointer<Utf8> Function(int, int);
34 -
35 -typedef GetFullBalance = int Function(int);
36 -
37 -typedef GetUnlockedBalance = int Function(int);
38 -
39 -typedef GetCurrentHeight = int Function();
40 -
41 -typedef GetNodeHeight = int Function();
42 -
43 -typedef IsConnected = int Function();
44 -
45 -typedef SetupNode = int Function(
46 - Pointer<Utf8>, Pointer<Utf8>?, Pointer<Utf8>?, int, int, Pointer<Utf8>?, Pointer<Utf8>);
47 -
48 -typedef StartRefresh = void Function();
49 -
50 -typedef ConnectToNode = int Function();
51 -
52 -typedef SetRefreshFromBlockHeight = void Function(int);
53 -
54 -typedef SetRecoveringFromSeed = void Function(int);
55 -
56 -typedef Store = void Function(Pointer<Utf8>);
57 -
58 -typedef SetPassword = int Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
59 -
60 -typedef SetListener = void Function();
61 -
62 -typedef GetSyncingHeight = int Function();
63 -
64 -typedef IsNeededToRefresh = int Function();
65 -
66 -typedef IsNewTransactionExist = int Function();
67 -
68 -typedef SubaddressSize = int Function();
69 -
70 -typedef SubaddressRefresh = void Function(int);
71 -
72 -typedef SubaddressGetAll = Pointer<Int64> Function();
73 -
74 -typedef SubaddressAddNew = void Function(int accountIndex, Pointer<Utf8> label);
75 -
76 -typedef SubaddressSetLabel = void Function(
77 - int accountIndex, int addressIndex, Pointer<Utf8> label);
78 -
79 -typedef AccountSize = int Function();
80 -
81 -typedef AccountRefresh = void Function();
82 -
83 -typedef AccountGetAll = Pointer<Int64> Function();
84 -
85 -typedef AccountAddNew = void Function(Pointer<Utf8> label);
86 -
87 -typedef AccountSetLabel = void Function(int accountIndex, Pointer<Utf8> label);
88 -
89 -typedef TransactionsRefresh = void Function();
90 -
91 -typedef GetTransaction = Pointer<TransactionInfoRow> Function(Pointer<Utf8> txId);
92 -
93 -typedef GetTxKey = Pointer<Utf8>? Function(Pointer<Utf8> txId);
94 -
95 -typedef TransactionsCount = int Function();
96 -
97 -typedef TransactionsGetAll = Pointer<Int64> Function();
98 -
99 -typedef TransactionCreate = int Function(
100 - Pointer<Utf8> address,
101 - Pointer<Utf8> paymentId,
102 - Pointer<Utf8> amount,
103 - int priorityRaw,
104 - int subaddrAccount,
105 - Pointer<Pointer<Utf8>> preferredInputs,
106 - int preferredInputsSize,
107 - Pointer<Utf8Box> error,
108 - Pointer<PendingTransactionRaw> pendingTransaction);
109 -
110 -typedef TransactionCreateMultDest = int Function(
111 - Pointer<Pointer<Utf8>> addresses,
112 - Pointer<Utf8> paymentId,
113 - Pointer<Pointer<Utf8>> amounts,
114 - int size,
115 - int priorityRaw,
116 - int subaddrAccount,
117 - Pointer<Pointer<Utf8>> preferredInputs,
118 - int preferredInputsSize,
119 - Pointer<Utf8Box> error,
120 - Pointer<PendingTransactionRaw> pendingTransaction);
121 -
122 -typedef TransactionCommit = int Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
123 -
124 -typedef SecretViewKey = Pointer<Utf8> Function();
125 -
126 -typedef PublicViewKey = Pointer<Utf8> Function();
127 -
128 -typedef SecretSpendKey = Pointer<Utf8> Function();
129 -
130 -typedef PublicSpendKey = Pointer<Utf8> Function();
131 -
132 -typedef CloseCurrentWallet = void Function();
133 -
134 -typedef OnStartup = void Function();
135 -
136 -typedef RescanBlockchainAsync = void Function();
137 -
138 -typedef GetSubaddressLabel = Pointer<Utf8> Function(
139 - int accountIndex,
140 - int addressIndex);
141 -
142 -typedef SetTrustedDaemon = void Function(int);
143 -
144 -typedef TrustedDaemon = int Function();
145 -
146 -typedef RefreshCoins = void Function(int);
147 -
148 -typedef CoinsCount = int Function();
149 -
150 -typedef GetCoin = Pointer<CoinsInfoRow> Function(int);
151 -
152 -typedef FreezeCoin = void Function(int);
153 -
154 -typedef ThawCoin = void Function(int);
155 -
156 -typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);
157 -
158 -typedef GetCacheAttribute = Pointer<Utf8> Function(Pointer<Utf8>);
159 -
160 -typedef SetCacheAttribute = int Function(Pointer<Utf8>, Pointer<Utf8>);
cw_monero/lib/api/wallet.dart
+131 -245
@@ -1,245 +1,155 @@
1 import 'dart:async';
2 import 'dart:ffi';
3 +import 'dart:isolate';
4
4 -import 'package:cw_monero/api/convert_utf8_to_string.dart';
5 +import 'package:cw_monero/api/account_list.dart';
6 import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
6 -import 'package:cw_monero/api/monero_api.dart';
7 -import 'package:cw_monero/api/signatures.dart';
8 -import 'package:cw_monero/api/structs/ut8_box.dart';
9 -import 'package:cw_monero/api/types.dart';
10 -import 'package:ffi/ffi.dart';
11 -import 'package:flutter/foundation.dart';
12 -
13 -int _boolToInt(bool value) => value ? 1 : 0;
14 -
15 -final getFileNameNative =
16 - moneroApi.lookup<NativeFunction<get_filename>>('get_filename').asFunction<GetFilename>();
17 -
18 -final getSeedNative = moneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
19 -
20 -final getAddressNative =
21 - moneroApi.lookup<NativeFunction<get_address>>('get_address').asFunction<GetAddress>();
22 -
23 -final getFullBalanceNative = moneroApi
24 - .lookup<NativeFunction<get_full_balanace>>('get_full_balance')
25 - .asFunction<GetFullBalance>();
26 -
27 -final getUnlockedBalanceNative = moneroApi
28 - .lookup<NativeFunction<get_unlocked_balanace>>('get_unlocked_balance')
29 - .asFunction<GetUnlockedBalance>();
30 -
31 -final getCurrentHeightNative = moneroApi
32 - .lookup<NativeFunction<get_current_height>>('get_current_height')
33 - .asFunction<GetCurrentHeight>();
34 -
35 -final getNodeHeightNative = moneroApi
36 - .lookup<NativeFunction<get_node_height>>('get_node_height')
37 - .asFunction<GetNodeHeight>();
38 -
39 -final isConnectedNative =
40 - moneroApi.lookup<NativeFunction<is_connected>>('is_connected').asFunction<IsConnected>();
41 -
42 -final setupNodeNative =
43 - moneroApi.lookup<NativeFunction<setup_node>>('setup_node').asFunction<SetupNode>();
44 -
45 -final startRefreshNative =
46 - moneroApi.lookup<NativeFunction<start_refresh>>('start_refresh').asFunction<StartRefresh>();
47 -
48 -final connecToNodeNative = moneroApi
49 - .lookup<NativeFunction<connect_to_node>>('connect_to_node')
50 - .asFunction<ConnectToNode>();
51 -
52 -final setRefreshFromBlockHeightNative = moneroApi
53 - .lookup<NativeFunction<set_refresh_from_block_height>>('set_refresh_from_block_height')
54 - .asFunction<SetRefreshFromBlockHeight>();
55 -
56 -final setRecoveringFromSeedNative = moneroApi
57 - .lookup<NativeFunction<set_recovering_from_seed>>('set_recovering_from_seed')
58 - .asFunction<SetRecoveringFromSeed>();
59 -
60 -final storeNative = moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
61 -
62 -final setPasswordNative =
63 - moneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
64 -
65 -final setListenerNative =
66 - moneroApi.lookup<NativeFunction<set_listener>>('set_listener').asFunction<SetListener>();
67 -
68 -final getSyncingHeightNative = moneroApi
69 - .lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
70 - .asFunction<GetSyncingHeight>();
71 -
72 -final isNeededToRefreshNative = moneroApi
73 - .lookup<NativeFunction<is_needed_to_refresh>>('is_needed_to_refresh')
74 - .asFunction<IsNeededToRefresh>();
75 -
76 -final isNewTransactionExistNative = moneroApi
77 - .lookup<NativeFunction<is_new_transaction_exist>>('is_new_transaction_exist')
78 - .asFunction<IsNewTransactionExist>();
79 -
80 -final getSecretViewKeyNative = moneroApi
81 - .lookup<NativeFunction<secret_view_key>>('secret_view_key')
82 - .asFunction<SecretViewKey>();
83 -
84 -final getPublicViewKeyNative = moneroApi
85 - .lookup<NativeFunction<public_view_key>>('public_view_key')
86 - .asFunction<PublicViewKey>();
87 -
88 -final getSecretSpendKeyNative = moneroApi
89 - .lookup<NativeFunction<secret_spend_key>>('secret_spend_key')
90 - .asFunction<SecretSpendKey>();
91 -
92 -final getPublicSpendKeyNative = moneroApi
93 - .lookup<NativeFunction<secret_view_key>>('public_spend_key')
94 - .asFunction<PublicSpendKey>();
95 -
96 -final closeCurrentWalletNative = moneroApi
97 - .lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
98 - .asFunction<CloseCurrentWallet>();
99 -
100 -final onStartupNative =
101 - moneroApi.lookup<NativeFunction<on_startup>>('on_startup').asFunction<OnStartup>();
102 -
103 -final rescanBlockchainAsyncNative = moneroApi
104 - .lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
105 - .asFunction<RescanBlockchainAsync>();
106 -
107 -final getSubaddressLabelNative = moneroApi
108 - .lookup<NativeFunction<get_subaddress_label>>('get_subaddress_label')
109 - .asFunction<GetSubaddressLabel>();
110 -
111 -final setTrustedDaemonNative = moneroApi
112 - .lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
113 - .asFunction<SetTrustedDaemon>();
114 -
115 -final trustedDaemonNative =
116 - moneroApi.lookup<NativeFunction<trusted_daemon>>('trusted_daemon').asFunction<TrustedDaemon>();
117 -
118 -final signMessageNative =
119 - moneroApi.lookup<NativeFunction<sign_message>>('sign_message').asFunction<SignMessage>();
120 -
121 -final getCacheAttributeNative = moneroApi
122 - .lookup<NativeFunction<get_cache_attribute>>('get_cache_attribute')
123 - .asFunction<GetCacheAttribute>();
124 -
125 -final setCacheAttributeNative = moneroApi
126 - .lookup<NativeFunction<set_cache_attribute>>('set_cache_attribute')
127 - .asFunction<SetCacheAttribute>();
7 +import 'package:monero/monero.dart' as monero;
8 +import 'package:mutex/mutex.dart';
9 +
10 +int getSyncingHeight() {
11 + // final height = monero.MONERO_cw_WalletListener_height(getWlptr());
12 + final h2 = monero.Wallet_blockChainHeight(wptr!);
13 + // print("height: $height / $h2");
14 + return h2;
15 +}
16
129 -int getSyncingHeight() => getSyncingHeightNative();
17 +bool isNeededToRefresh() {
18 + final ret = monero.MONERO_cw_WalletListener_isNeedToRefresh(getWlptr());
19 + monero.MONERO_cw_WalletListener_resetNeedToRefresh(getWlptr());
20 + return ret;
21 +}
22
131 -bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
23 +bool isNewTransactionExist() {
24 + final ret = monero.MONERO_cw_WalletListener_isNewTransactionExist(getWlptr());
25 + monero.MONERO_cw_WalletListener_resetIsNewTransactionExist(getWlptr());
26 + return ret;
27 +}
28
133 -bool isNewTransactionExist() => isNewTransactionExistNative() != 0;
29 +String getFilename() => monero.Wallet_filename(wptr!);
30
135 -String getFilename() => convertUTF8ToString(pointer: getFileNameNative());
31 +String getSeed() {
32 + // monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
33 + final cakepolyseed =
34 + monero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.seed");
35 + if (cakepolyseed != "") {
36 + return cakepolyseed;
37 + }
38 + final polyseed = monero.Wallet_getPolyseed(wptr!, passphrase: '');
39 + if (polyseed != "") {
40 + return polyseed;
41 + }
42 + final legacy = monero.Wallet_seed(wptr!, seedOffset: '');
43 + return legacy;
44 +}
45
137 -String getSeed() => convertUTF8ToString(pointer: getSeedNative());
46 +String getSeedLegacy(String? language) {
47 + var legacy = monero.Wallet_seed(wptr!, seedOffset: '');
48 + if (monero.Wallet_status(wptr!) != 0) {
49 + monero.Wallet_setSeedLanguage(wptr!, language: language ?? "English");
50 + legacy = monero.Wallet_seed(wptr!, seedOffset: '');
51 + }
52 + return legacy;
53 +}
54
55 String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
140 - convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
56 + monero.Wallet_address(wptr!,
57 + accountIndex: accountIndex, addressIndex: addressIndex);
58
142 -int getFullBalance({int accountIndex = 0}) => getFullBalanceNative(accountIndex);
59 +int getFullBalance({int accountIndex = 0}) =>
60 + monero.Wallet_balance(wptr!, accountIndex: accountIndex);
61
144 -int getUnlockedBalance({int accountIndex = 0}) => getUnlockedBalanceNative(accountIndex);
62 +int getUnlockedBalance({int accountIndex = 0}) =>
63 + monero.Wallet_unlockedBalance(wptr!, accountIndex: accountIndex);
64
146 -int getCurrentHeight() => getCurrentHeightNative();
65 +int getCurrentHeight() => monero.Wallet_blockChainHeight(wptr!);
66
148 -int getNodeHeightSync() => getNodeHeightNative();
67 +int getNodeHeightSync() => monero.Wallet_daemonBlockChainHeight(wptr!);
68
150 -bool isConnectedSync() => isConnectedNative() != 0;
69 +bool isConnectedSync() => monero.Wallet_connected(wptr!) != 0;
70
152 -bool setupNodeSync(
71 +Future<bool> setupNodeSync(
72 {required String address,
73 String? login,
74 String? password,
75 bool useSSL = false,
76 bool isLightWallet = false,
158 - String? socksProxyAddress}) {
159 - final addressPointer = address.toNativeUtf8();
160 - Pointer<Utf8>? loginPointer;
161 - Pointer<Utf8>? socksProxyAddressPointer;
162 - Pointer<Utf8>? passwordPointer;
163 -
164 - if (login != null) {
165 - loginPointer = login.toNativeUtf8();
166 - }
167 -
168 - if (password != null) {
169 - passwordPointer = password.toNativeUtf8();
170 - }
171 -
172 - if (socksProxyAddress != null) {
173 - socksProxyAddressPointer = socksProxyAddress.toNativeUtf8();
174 - }
175 -
176 - final errorMessagePointer = ''.toNativeUtf8();
177 - final isSetupNode = setupNodeNative(
178 - addressPointer,
179 - loginPointer,
180 - passwordPointer,
181 - _boolToInt(useSSL),
182 - _boolToInt(isLightWallet),
183 - socksProxyAddressPointer,
184 - errorMessagePointer) !=
185 - 0;
186 -
187 - calloc.free(addressPointer);
188 -
189 - if (loginPointer != null) {
190 - calloc.free(loginPointer);
191 - }
192 -
193 - if (passwordPointer != null) {
194 - calloc.free(passwordPointer);
195 - }
196 -
197 - if (!isSetupNode) {
198 - throw SetupWalletException(message: convertUTF8ToString(pointer: errorMessagePointer));
77 + String? socksProxyAddress}) async {
78 + print('''
79 +{
80 + wptr!,
81 + daemonAddress: $address,
82 + useSsl: $useSSL,
83 + proxyAddress: $socksProxyAddress ?? '',
84 + daemonUsername: $login ?? '',
85 + daemonPassword: $password ?? ''
86 +}
87 +''');
88 + final addr = wptr!.address;
89 + await Isolate.run(() {
90 + monero.Wallet_init(Pointer.fromAddress(addr),
91 + daemonAddress: address,
92 + useSsl: useSSL,
93 + proxyAddress: socksProxyAddress ?? '',
94 + daemonUsername: login ?? '',
95 + daemonPassword: password ?? '');
96 + });
97 + // monero.Wallet_init3(wptr!, argv0: '', defaultLogBaseName: 'moneroc', console: true);
98 +
99 + final status = monero.Wallet_status(wptr!);
100 +
101 + if (status != 0) {
102 + final error = monero.Wallet_errorString(wptr!);
103 + print("error: $error");
104 + throw SetupWalletException(message: error);
105 }
106
201 - return isSetupNode;
107 + return status == 0;
108 }
109
204 -void startRefreshSync() => startRefreshNative();
110 +void startRefreshSync() {
111 + monero.Wallet_refreshAsync(wptr!);
112 + monero.Wallet_startRefresh(wptr!);
113 +}
114
206 -Future<bool> connectToNode() async => connecToNodeNative() != 0;
115
208 -void setRefreshFromBlockHeight({required int height}) => setRefreshFromBlockHeightNative(height);
116 +void setRefreshFromBlockHeight({required int height}) =>
117 + monero.Wallet_setRefreshFromBlockHeight(wptr!,
118 + refresh_from_block_height: height);
119
120 void setRecoveringFromSeed({required bool isRecovery}) =>
211 - setRecoveringFromSeedNative(_boolToInt(isRecovery));
212 -
213 -void storeSync() {
214 - final pathPointer = ''.toNativeUtf8();
215 - storeNative(pathPointer);
216 - calloc.free(pathPointer);
121 + monero.Wallet_setRecoveringFromSeed(wptr!, recoveringFromSeed: isRecovery);
122 +
123 +final storeMutex = Mutex();
124 +void storeSync() async {
125 + await storeMutex.acquire();
126 + final addr = wptr!.address;
127 + await Isolate.run(() {
128 + monero.Wallet_store(Pointer.fromAddress(addr));
129 + });
130 + storeMutex.release();
131 }
132
133 void setPasswordSync(String password) {
220 - final passwordPointer = password.toNativeUtf8();
221 - final errorMessagePointer = calloc<Utf8Box>();
222 - final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
223 - calloc.free(passwordPointer);
224 -
225 - if (!changed) {
226 - final message = errorMessagePointer.ref.getValue();
227 - calloc.free(errorMessagePointer);
228 - throw Exception(message);
229 - }
134 + monero.Wallet_setPassword(wptr!, password: password);
135
231 - calloc.free(errorMessagePointer);
136 + final status = monero.Wallet_status(wptr!);
137 + if (status != 0) {
138 + throw Exception(monero.Wallet_errorString(wptr!));
139 + }
140 }
141
234 -void closeCurrentWallet() => closeCurrentWalletNative();
142 +void closeCurrentWallet() {
143 + monero.Wallet_stop(wptr!);
144 +}
145
236 -String getSecretViewKey() => convertUTF8ToString(pointer: getSecretViewKeyNative());
146 +String getSecretViewKey() => monero.Wallet_secretViewKey(wptr!);
147
238 -String getPublicViewKey() => convertUTF8ToString(pointer: getPublicViewKeyNative());
148 +String getPublicViewKey() => monero.Wallet_publicViewKey(wptr!);
149
240 -String getSecretSpendKey() => convertUTF8ToString(pointer: getSecretSpendKeyNative());
150 +String getSecretSpendKey() => monero.Wallet_secretSpendKey(wptr!);
151
242 -String getPublicSpendKey() => convertUTF8ToString(pointer: getPublicSpendKeyNative());
152 +String getPublicSpendKey() => monero.Wallet_publicSpendKey(wptr!);
153
154 class SyncListener {
155 SyncListener(this.onNewBlock, this.onNewTransaction)
@@ -267,7 +177,8 @@ class SyncListener {
177 _cachedBlockchainHeight = 0;
178 _lastKnownBlockHeight = 0;
179 _initialSyncHeight = 0;
270 - _updateSyncInfoTimer ??= Timer.periodic(Duration(milliseconds: 1200), (_) async {
180 + _updateSyncInfoTimer ??=
181 + Timer.periodic(Duration(milliseconds: 1200), (_) async {
182 if (isNewTransactionExist()) {
183 onNewTransaction();
184 }
@@ -306,18 +217,18 @@ class SyncListener {
217 void stop() => _updateSyncInfoTimer?.cancel();
218 }
219
309 -SyncListener setListeners(
310 - void Function(int, int, double) onNewBlock, void Function() onNewTransaction) {
220 +SyncListener setListeners(void Function(int, int, double) onNewBlock,
221 + void Function() onNewTransaction) {
222 final listener = SyncListener(onNewBlock, onNewTransaction);
312 - setListenerNative();
223 + // setListenerNative();
224 return listener;
225 }
226
316 -void onStartup() => onStartupNative();
227 +void onStartup() {}
228
229 void _storeSync(Object _) => storeSync();
230
320 -bool _setupNodeSync(Map<String, Object?> args) {
231 +Future<bool> _setupNodeSync(Map<String, Object?> args) async {
232 final address = args['address'] as String;
233 final login = (args['login'] ?? '') as String;
234 final password = (args['password'] ?? '') as String;
@@ -346,8 +257,8 @@ Future<void> setupNode(
257 String? password,
258 bool useSSL = false,
259 String? socksProxyAddress,
349 - bool isLightWallet = false}) =>
350 - compute<Map<String, Object?>, void>(_setupNodeSync, {
260 + bool isLightWallet = false}) async =>
261 + _setupNodeSync({
262 'address': address,
263 'login': login,
264 'password': password,
@@ -356,49 +267,24 @@ Future<void> setupNode(
267 'socksProxyAddress': socksProxyAddress
268 });
269
359 -Future<void> store() => compute<int, void>(_storeSync, 0);
270 +Future<void> store() async => _storeSync(0);
271
361 -Future<bool> isConnected() => compute(_isConnected, 0);
272 +Future<bool> isConnected() async => _isConnected(0);
273
363 -Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
274 +Future<int> getNodeHeight() async => _getNodeHeight(0);
275
365 -void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
276 +void rescanBlockchainAsync() => monero.Wallet_rescanBlockchainAsync(wptr!);
277
278 String getSubaddressLabel(int accountIndex, int addressIndex) {
368 - return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex));
279 + return monero.Wallet_getSubaddressLabel(wptr!,
280 + accountIndex: accountIndex, addressIndex: addressIndex);
281 }
282
371 -Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
283 +Future setTrustedDaemon(bool trusted) async =>
284 + monero.Wallet_setTrustedDaemon(wptr!, arg: trusted);
285
373 -Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
286 +Future<bool> trustedDaemon() async => monero.Wallet_trustedDaemon(wptr!);
287
288 String signMessage(String message, {String address = ""}) {
376 - final messagePointer = message.toNativeUtf8();
377 - final addressPointer = address.toNativeUtf8();
378 -
379 - final signature = convertUTF8ToString(pointer: signMessageNative(messagePointer, addressPointer));
380 - calloc.free(messagePointer);
381 - calloc.free(addressPointer);
382 -
383 - return signature;
384 -}
385 -
386 -bool setCacheAttribute(String name, String value) {
387 - final namePointer = name.toNativeUtf8();
388 - final valuePointer = value.toNativeUtf8();
389 -
390 - final isSet = setCacheAttributeNative(namePointer, valuePointer);
391 - calloc.free(namePointer);
392 - calloc.free(valuePointer);
393 -
394 - return isSet == 1;
395 -}
396 -
397 -String getCacheAttribute(String name) {
398 - final namePointer = name.toNativeUtf8();
399 -
400 - final value = convertUTF8ToString(pointer: getCacheAttributeNative(namePointer));
401 - calloc.free(namePointer);
402 -
403 - return value;
289 + return monero.Wallet_signMessage(wptr!, message: message, address: address);
290 }
cw_monero/lib/api/wallet_manager.dart
+150 -174
@@ -1,85 +1,50 @@
1 import 'dart:ffi';
2 +import 'dart:isolate';
3
3 -import 'package:cw_monero/api/convert_utf8_to_string.dart';
4 +import 'package:cw_monero/api/account_list.dart';
5 import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart';
6 import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
7 import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart';
8 import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart';
8 -import 'package:cw_monero/api/monero_api.dart';
9 -import 'package:cw_monero/api/signatures.dart';
10 -import 'package:cw_monero/api/types.dart';
9 import 'package:cw_monero/api/wallet.dart';
12 -import 'package:ffi/ffi.dart';
13 -import 'package:flutter/foundation.dart';
14 -
15 -final createWalletNative = moneroApi
16 - .lookup<NativeFunction<create_wallet>>('create_wallet')
17 - .asFunction<CreateWallet>();
18 -
19 -final restoreWalletFromSeedNative = moneroApi
20 - .lookup<NativeFunction<restore_wallet_from_seed>>(
21 - 'restore_wallet_from_seed')
22 - .asFunction<RestoreWalletFromSeed>();
23 -
24 -final restoreWalletFromKeysNative = moneroApi
25 - .lookup<NativeFunction<restore_wallet_from_keys>>(
26 - 'restore_wallet_from_keys')
27 - .asFunction<RestoreWalletFromKeys>();
28 -
29 -final restoreWalletFromSpendKeyNative = moneroApi
30 - .lookup<NativeFunction<restore_wallet_from_spend_key>>(
31 - 'restore_wallet_from_spend_key')
32 - .asFunction<RestoreWalletFromSpendKey>();
33 -
34 -// final restoreWalletFromDeviceNative = moneroApi
35 -// .lookup<NativeFunction<restore_wallet_from_device>>(
36 -// 'restore_wallet_from_device')
37 -// .asFunction<RestoreWalletFromDevice>();
38 -
39 -final isWalletExistNative = moneroApi
40 - .lookup<NativeFunction<is_wallet_exist>>('is_wallet_exist')
41 - .asFunction<IsWalletExist>();
42 -
43 -final loadWalletNative = moneroApi
44 - .lookup<NativeFunction<load_wallet>>('load_wallet')
45 - .asFunction<LoadWallet>();
46 -
47 -final errorStringNative = moneroApi
48 - .lookup<NativeFunction<error_string>>('error_string')
49 - .asFunction<ErrorString>();
10 +import 'package:monero/monero.dart' as monero;
11 +
12 +monero.WalletManager? _wmPtr;
13 +final monero.WalletManager wmPtr = Pointer.fromAddress((() {
14 + try {
15 + // Problems with the wallet? Crashes? Lags? this will print all calls to xmr
16 + // codebase, so it will be easier to debug what happens. At least easier
17 + // than plugging gdb in. Especially on windows/android.
18 + monero.printStarts = false;
19 + _wmPtr ??= monero.WalletManagerFactory_getWalletManager();
20 + print("ptr: $_wmPtr");
21 + } catch (e) {
22 + print(e);
23 + }
24 + return _wmPtr!.address;
25 +})());
26
27 void createWalletSync(
28 {required String path,
53 - required String password,
54 - required String language,
55 - int nettype = 0}) {
56 - final pathPointer = path.toNativeUtf8();
57 - final passwordPointer = password.toNativeUtf8();
58 - final languagePointer = language.toNativeUtf8();
59 - final errorMessagePointer = ''.toNativeUtf8();
60 - final isWalletCreated = createWalletNative(pathPointer, passwordPointer,
61 - languagePointer, nettype, errorMessagePointer) !=
62 - 0;
63 -
64 - calloc.free(pathPointer);
65 - calloc.free(passwordPointer);
66 - calloc.free(languagePointer);
67 -
68 - if (!isWalletCreated) {
69 - throw WalletCreationException(
70 - message: convertUTF8ToString(pointer: errorMessagePointer));
29 + required String password,
30 + required String language,
31 + int nettype = 0}) {
32 + wptr = monero.WalletManager_createWallet(wmPtr,
33 + path: path, password: password, language: language, networkType: 0);
34 +
35 + final status = monero.Wallet_status(wptr!);
36 + if (status != 0) {
37 + throw WalletCreationException(message: monero.Wallet_errorString(wptr!));
38 }
39 + monero.Wallet_store(wptr!, path: path);
40 + openedWalletsByPath[path] = wptr!;
41
42 + // is the line below needed?
43 // setupNodeSync(address: "node.moneroworld.com:18089");
44 }
45
46 bool isWalletExistSync({required String path}) {
77 - final pathPointer = path.toNativeUtf8();
78 - final isExist = isWalletExistNative(pathPointer) != 0;
79 -
80 - calloc.free(pathPointer);
81 -
82 - return isExist;
47 + return monero.WalletManager_walletExists(wmPtr, path);
48 }
49
50 void restoreWalletFromSeedSync(
@@ -88,27 +53,24 @@ void restoreWalletFromSeedSync(
53 required String seed,
54 int nettype = 0,
55 int restoreHeight = 0}) {
91 - final pathPointer = path.toNativeUtf8();
92 - final passwordPointer = password.toNativeUtf8();
93 - final seedPointer = seed.toNativeUtf8();
94 - final errorMessagePointer = ''.toNativeUtf8();
95 - final isWalletRestored = restoreWalletFromSeedNative(
96 - pathPointer,
97 - passwordPointer,
98 - seedPointer,
99 - nettype,
100 - restoreHeight,
101 - errorMessagePointer) !=
102 - 0;
103 -
104 - calloc.free(pathPointer);
105 - calloc.free(passwordPointer);
106 - calloc.free(seedPointer);
107 -
108 - if (!isWalletRestored) {
109 - throw WalletRestoreFromSeedException(
110 - message: convertUTF8ToString(pointer: errorMessagePointer));
56 + wptr = monero.WalletManager_recoveryWallet(
57 + wmPtr,
58 + path: path,
59 + password: password,
60 + mnemonic: seed,
61 + restoreHeight: restoreHeight,
62 + seedOffset: '',
63 + networkType: 0,
64 + );
65 +
66 + final status = monero.Wallet_status(wptr!);
67 +
68 + if (status != 0) {
69 + final error = monero.Wallet_errorString(wptr!);
70 + throw WalletRestoreFromSeedException(message: error);
71 }
72 +
73 + openedWalletsByPath[path] = wptr!;
74 }
75
76 void restoreWalletFromKeysSync(
@@ -120,76 +82,72 @@ void restoreWalletFromKeysSync(
82 required String spendKey,
83 int nettype = 0,
84 int restoreHeight = 0}) {
123 - final pathPointer = path.toNativeUtf8();
124 - final passwordPointer = password.toNativeUtf8();
125 - final languagePointer = language.toNativeUtf8();
126 - final addressPointer = address.toNativeUtf8();
127 - final viewKeyPointer = viewKey.toNativeUtf8();
128 - final spendKeyPointer = spendKey.toNativeUtf8();
129 - final errorMessagePointer = ''.toNativeUtf8();
130 - final isWalletRestored = restoreWalletFromKeysNative(
131 - pathPointer,
132 - passwordPointer,
133 - languagePointer,
134 - addressPointer,
135 - viewKeyPointer,
136 - spendKeyPointer,
137 - nettype,
138 - restoreHeight,
139 - errorMessagePointer) !=
140 - 0;
141 -
142 - calloc.free(pathPointer);
143 - calloc.free(passwordPointer);
144 - calloc.free(languagePointer);
145 - calloc.free(addressPointer);
146 - calloc.free(viewKeyPointer);
147 - calloc.free(spendKeyPointer);
148 -
149 - if (!isWalletRestored) {
85 + wptr = monero.WalletManager_createWalletFromKeys(
86 + wmPtr,
87 + path: path,
88 + password: password,
89 + restoreHeight: restoreHeight,
90 + addressString: address,
91 + viewKeyString: viewKey,
92 + spendKeyString: spendKey,
93 + nettype: 0,
94 + );
95 +
96 + final status = monero.Wallet_status(wptr!);
97 + if (status != 0) {
98 throw WalletRestoreFromKeysException(
151 - message: convertUTF8ToString(pointer: errorMessagePointer));
99 + message: monero.Wallet_errorString(wptr!));
100 }
101 +
102 + openedWalletsByPath[path] = wptr!;
103 }
104
105 void restoreWalletFromSpendKeySync(
106 {required String path,
157 - required String password,
158 - required String seed,
159 - required String language,
160 - required String spendKey,
161 - int nettype = 0,
162 - int restoreHeight = 0}) {
163 - final pathPointer = path.toNativeUtf8();
164 - final passwordPointer = password.toNativeUtf8();
165 - final seedPointer = seed.toNativeUtf8();
166 - final languagePointer = language.toNativeUtf8();
167 - final spendKeyPointer = spendKey.toNativeUtf8();
168 - final errorMessagePointer = ''.toNativeUtf8();
169 - final isWalletRestored = restoreWalletFromSpendKeyNative(
170 - pathPointer,
171 - passwordPointer,
172 - seedPointer,
173 - languagePointer,
174 - spendKeyPointer,
175 - nettype,
176 - restoreHeight,
177 - errorMessagePointer) !=
178 - 0;
179 -
180 - calloc.free(pathPointer);
181 - calloc.free(passwordPointer);
182 - calloc.free(languagePointer);
183 - calloc.free(spendKeyPointer);
107 + required String password,
108 + required String seed,
109 + required String language,
110 + required String spendKey,
111 + int nettype = 0,
112 + int restoreHeight = 0}) {
113 + // wptr = monero.WalletManager_createWalletFromKeys(
114 + // wmPtr,
115 + // path: path,
116 + // password: password,
117 + // restoreHeight: restoreHeight,
118 + // addressString: '',
119 + // spendKeyString: spendKey,
120 + // viewKeyString: '',
121 + // nettype: 0,
122 + // );
123 +
124 + wptr = monero.WalletManager_createDeterministicWalletFromSpendKey(
125 + wmPtr,
126 + path: path,
127 + password: password,
128 + language: language,
129 + spendKeyString: spendKey,
130 + newWallet: true, // TODO(mrcyjanek): safe to remove
131 + restoreHeight: restoreHeight,
132 + );
133 +
134 + final status = monero.Wallet_status(wptr!);
135 +
136 + if (status != 0) {
137 + final err = monero.Wallet_errorString(wptr!);
138 + print("err: $err");
139 + throw WalletRestoreFromKeysException(message: err);
140 + }
141 +
142 + monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
143
144 storeSync();
145
187 - if (!isWalletRestored) {
188 - throw WalletRestoreFromKeysException(
189 - message: convertUTF8ToString(pointer: errorMessagePointer));
190 - }
146 + openedWalletsByPath[path] = wptr!;
147 }
148
149 +String _lastOpenedWallet = "";
150 +
151 // void restoreMoneroWalletFromDevice(
152 // {required String path,
153 // required String password,
@@ -221,20 +179,35 @@ void restoreWalletFromSpendKeySync(
179 // }
180 // }
181
182 +Map<String, monero.wallet> openedWalletsByPath = {};
183
225 -void loadWallet({
226 - required String path,
227 - required String password,
228 - int nettype = 0}) {
229 - final pathPointer = path.toNativeUtf8();
230 - final passwordPointer = password.toNativeUtf8();
231 - final loaded = loadWalletNative(pathPointer, passwordPointer, nettype) != 0;
232 - calloc.free(pathPointer);
233 - calloc.free(passwordPointer);
234 -
235 - if (!loaded) {
236 - throw WalletOpeningException(
237 - message: convertUTF8ToString(pointer: errorStringNative()));
184 +void loadWallet(
185 + {required String path, required String password, int nettype = 0}) {
186 + if (openedWalletsByPath[path] != null) {
187 + wptr = openedWalletsByPath[path]!;
188 + return;
189 + }
190 + try {
191 + if (wptr == null || path != _lastOpenedWallet) {
192 + if (wptr != null) {
193 + final addr = wptr!.address;
194 + Isolate.run(() {
195 + monero.Wallet_store(Pointer.fromAddress(addr));
196 + });
197 + }
198 + wptr = monero.WalletManager_openWallet(wmPtr,
199 + path: path, password: password);
200 + openedWalletsByPath[path] = wptr!;
201 + _lastOpenedWallet = path;
202 + }
203 + } catch (e) {
204 + print(e);
205 + }
206 + final status = monero.Wallet_status(wptr!);
207 + if (status != 0) {
208 + final err = monero.Wallet_errorString(wptr!);
209 + print(err);
210 + throw WalletOpeningException(message: err);
211 }
212 }
213
@@ -292,23 +265,26 @@ void _restoreFromSpendKey(Map<String, dynamic> args) {
265 spendKey: spendKey);
266 }
267
295 -Future<void> _openWallet(Map<String, String> args) async =>
296 - loadWallet(path: args['path'] as String, password: args['password'] as String);
268 +Future<void> _openWallet(Map<String, String> args) async => loadWallet(
269 + path: args['path'] as String, password: args['password'] as String);
270
271 bool _isWalletExist(String path) => isWalletExistSync(path: path);
272
300 -void openWallet({required String path, required String password, int nettype = 0}) async =>
273 +void openWallet(
274 + {required String path,
275 + required String password,
276 + int nettype = 0}) async =>
277 loadWallet(path: path, password: password, nettype: nettype);
278
279 Future<void> openWalletAsync(Map<String, String> args) async =>
304 - compute(_openWallet, args);
280 + _openWallet(args);
281
282 Future<void> createWallet(
283 {required String path,
284 required String password,
285 required String language,
286 int nettype = 0}) async =>
311 - compute(_createWallet, {
287 + _createWallet({
288 'path': path,
289 'password': password,
290 'language': language,
@@ -321,7 +297,7 @@ Future<void> restoreFromSeed(
297 required String seed,
298 int nettype = 0,
299 int restoreHeight = 0}) async =>
324 - compute<Map<String, Object>, void>(_restoreFromSeed, {
300 + _restoreFromSeed({
301 'path': path,
302 'password': password,
303 'seed': seed,
@@ -338,7 +314,7 @@ Future<void> restoreFromKeys(
314 required String spendKey,
315 int nettype = 0,
316 int restoreHeight = 0}) async =>
341 - compute<Map<String, Object>, void>(_restoreFromKeys, {
317 + _restoreFromKeys({
318 'path': path,
319 'password': password,
320 'language': language,
@@ -350,14 +326,14 @@ Future<void> restoreFromKeys(
326 });
327
328 Future<void> restoreFromSpendKey(
353 - {required String path,
354 - required String password,
355 - required String seed,
356 - required String language,
357 - required String spendKey,
358 - int nettype = 0,
359 - int restoreHeight = 0}) async =>
360 - compute<Map<String, Object>, void>(_restoreFromSpendKey, {
329 + {required String path,
330 + required String password,
331 + required String seed,
332 + required String language,
333 + required String spendKey,
334 + int nettype = 0,
335 + int restoreHeight = 0}) async =>
336 + _restoreFromSpendKey({
337 'path': path,
338 'password': password,
339 'seed': seed,
@@ -367,4 +343,4 @@ Future<void> restoreFromSpendKey(
343 'restoreHeight': restoreHeight
344 });
345
370 -Future<bool> isWalletExist({required String path}) => compute(_isWalletExist, path);
346 +bool isWalletExist({required String path}) => _isWalletExist(path);
cw_monero/lib/monero_account_list.dart
+5 -6
@@ -2,7 +2,7 @@ import 'package:cw_core/monero_amount_format.dart';
2 import 'package:mobx/mobx.dart';
3 import 'package:cw_core/account.dart';
4 import 'package:cw_monero/api/account_list.dart' as account_list;
5 -import 'package:cw_monero/api/wallet.dart' as monero_wallet;
5 +import 'package:monero/monero.dart' as monero;
6
7 part 'monero_account_list.g.dart';
8
@@ -44,13 +44,12 @@ abstract class MoneroAccountListBase with Store {
44 }
45
46 List<Account> getAll() => account_list.getAllAccount().map((accountRow) {
47 - final accountIndex = accountRow.getId();
48 - final balance = monero_wallet.getFullBalance(accountIndex: accountIndex);
47 + final balance = monero.SubaddressAccountRow_getUnlockedBalance(accountRow);
48
49 return Account(
51 - id: accountRow.getId(),
52 - label: accountRow.getLabel(),
53 - balance: moneroAmountToString(amount: balance),
50 + id: monero.SubaddressAccountRow_getRowId(accountRow),
51 + label: monero.SubaddressAccountRow_getLabel(accountRow),
52 + balance: moneroAmountToString(amount: monero.Wallet_amountFromString(balance)),
53 );
54 }).toList();
55
cw_monero/lib/monero_subaddress_list.dart
+30 -19
@@ -1,8 +1,8 @@
1 -import 'package:flutter/services.dart';
2 -import 'package:mobx/mobx.dart';
1 +import 'package:cw_core/subaddress.dart';
2 import 'package:cw_monero/api/coins_info.dart';
3 import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
5 -import 'package:cw_core/subaddress.dart';
4 +import 'package:flutter/services.dart';
5 +import 'package:mobx/mobx.dart';
6
7 part 'monero_subaddress_list.g.dart';
8
@@ -50,19 +50,22 @@ abstract class MoneroSubaddressListBase with Store {
50 subaddresses = [primary] + rest.toList();
51 }
52
53 - return subaddresses.map((subaddressRow) {
53 + return subaddresses.map((s) {
54 + final address = s.address;
55 + final label = s.label;
56 + final id = s.addressIndex;
57 final hasDefaultAddressName =
55 - subaddressRow.getLabel().toLowerCase() == 'Primary account'.toLowerCase() ||
56 - subaddressRow.getLabel().toLowerCase() == 'Untitled account'.toLowerCase();
57 - final isPrimaryAddress = subaddressRow.getId() == 0 && hasDefaultAddressName;
58 + label.toLowerCase() == 'Primary account'.toLowerCase() ||
59 + label.toLowerCase() == 'Untitled account'.toLowerCase();
60 + final isPrimaryAddress = id == 0 && hasDefaultAddressName;
61 return Subaddress(
59 - id: subaddressRow.getId(),
60 - address: subaddressRow.getAddress(),
62 + id: id,
63 + address: address,
64 label: isPrimaryAddress
65 ? 'Primary address'
66 : hasDefaultAddressName
67 ? ''
65 - : subaddressRow.getLabel());
68 + : label);
69 }).toList();
70 }
71
@@ -121,8 +124,8 @@ abstract class MoneroSubaddressListBase with Store {
124 Future<List<Subaddress>> _getAllUnusedAddresses(
125 {required int accountIndex, required String label}) async {
126 final allAddresses = subaddress_list.getAllSubaddresses();
124 -
125 - if (allAddresses.isEmpty || _usedAddresses.contains(allAddresses.last.getAddress())) {
127 + final lastAddress = allAddresses.last.address;
128 + if (allAddresses.isEmpty || _usedAddresses.contains(lastAddress)) {
129 final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label);
130 if (!isAddressUnused) {
131 return await _getAllUnusedAddresses(accountIndex: accountIndex, label: label);
@@ -130,13 +133,18 @@ abstract class MoneroSubaddressListBase with Store {
133 }
134
135 return allAddresses
133 - .map((subaddressRow) => Subaddress(
134 - id: subaddressRow.getId(),
135 - address: subaddressRow.getAddress(),
136 - label: subaddressRow.getId() == 0 &&
137 - subaddressRow.getLabel().toLowerCase() == 'Primary account'.toLowerCase()
136 + .map((s) {
137 + final id = s.addressIndex;
138 + final address = s.address;
139 + final label = s.label;
140 + return Subaddress(
141 + id: id,
142 + address: address,
143 + label: id == 0 &&
144 + label.toLowerCase() == 'Primary account'.toLowerCase()
145 ? 'Primary address'
139 - : subaddressRow.getLabel()))
146 + : label);
147 + })
148 .toList();
149 }
150
@@ -145,7 +153,10 @@ abstract class MoneroSubaddressListBase with Store {
153
154 return subaddress_list
155 .getAllSubaddresses()
148 - .where((subaddressRow) => !_usedAddresses.contains(subaddressRow.getAddress()))
156 + .where((s) {
157 + final address = s.address;
158 + return !_usedAddresses.contains(address);
159 + })
160 .isNotEmpty;
161 }
162 }
cw_monero/lib/monero_wallet.dart
+159 -69
@@ -1,5 +1,7 @@
1 import 'dart:async';
2 +import 'dart:ffi';
3 import 'dart:io';
4 +import 'dart:isolate';
5
6 import 'package:cw_core/account.dart';
7 import 'package:cw_core/crypto_currency.dart';
@@ -12,15 +14,18 @@ import 'package:cw_core/node.dart';
14 import 'package:cw_core/pathForWallet.dart';
15 import 'package:cw_core/pending_transaction.dart';
16 import 'package:cw_core/sync_status.dart';
17 +import 'package:cw_core/transaction_direction.dart';
18 import 'package:cw_core/transaction_priority.dart';
19 import 'package:cw_core/unspent_coins_info.dart';
20 import 'package:cw_core/wallet_base.dart';
21 import 'package:cw_core/wallet_info.dart';
22 +import 'package:cw_monero/api/account_list.dart';
23 import 'package:cw_monero/api/coins_info.dart';
24 import 'package:cw_monero/api/monero_output.dart';
25 import 'package:cw_monero/api/structs/pending_transaction.dart';
26 import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
27 import 'package:cw_monero/api/wallet.dart' as monero_wallet;
28 +import 'package:cw_monero/api/wallet_manager.dart';
29 import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
30 import 'package:cw_monero/exceptions/monero_transaction_no_inputs_exception.dart';
31 import 'package:cw_monero/monero_transaction_creation_credentials.dart';
@@ -32,6 +37,7 @@ import 'package:cw_monero/pending_monero_transaction.dart';
37 import 'package:flutter/foundation.dart';
38 import 'package:hive/hive.dart';
39 import 'package:mobx/mobx.dart';
40 +import 'package:monero/monero.dart' as monero;
41
42 part 'monero_wallet.g.dart';
43
@@ -41,10 +47,11 @@ const MIN_RESTORE_HEIGHT = 1000;
47
48 class MoneroWallet = MoneroWalletBase with _$MoneroWallet;
49
44 -abstract class MoneroWalletBase
45 - extends WalletBase<MoneroBalance, MoneroTransactionHistory, MoneroTransactionInfo> with Store {
50 +abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
51 + MoneroTransactionHistory, MoneroTransactionInfo> with Store {
52 MoneroWalletBase(
47 - {required WalletInfo walletInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo})
53 + {required WalletInfo walletInfo,
54 + required Box<UnspentCoinsInfo> unspentCoinsInfo})
55 : balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
56 CryptoCurrency.xmr: MoneroBalance(
57 fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
@@ -60,13 +67,16 @@ abstract class MoneroWalletBase
67 transactionHistory = MoneroTransactionHistory();
68 walletAddresses = MoneroWalletAddresses(walletInfo, transactionHistory);
69
63 - _onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) {
70 + _onAccountChangeReaction =
71 + reaction((_) => walletAddresses.account, (Account? account) {
72 if (account == null) return;
73
66 - balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency, MoneroBalance>{
74 + balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency,
75 + MoneroBalance>{
76 currency: MoneroBalance(
77 fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
69 - unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id))
78 + unlockedBalance:
79 + monero_wallet.getUnlockedBalance(accountIndex: account.id))
80 });
81 _updateSubAddress(isEnabledAutoGenerateSubaddress, account: account);
82 _askForUpdateTransactionHistory();
@@ -100,6 +110,9 @@ abstract class MoneroWalletBase
110
111 @override
112 String get seed => monero_wallet.getSeed();
113 + String seedLegacy(String? language) {
114 + return monero_wallet.getSeedLegacy(language);
115 + }
116
117 @override
118 MoneroWalletKeys get keys => MoneroWalletKeys(
@@ -108,7 +121,8 @@ abstract class MoneroWalletBase
121 publicSpendKey: monero_wallet.getPublicSpendKey(),
122 publicViewKey: monero_wallet.getPublicViewKey());
123
111 - int? get restoreHeight => transactionHistory.transactions.values.firstOrNull?.height;
124 + int? get restoreHeight =>
125 + transactionHistory.transactions.values.firstOrNull?.height;
126
127 monero_wallet.SyncListener? _listener;
128 ReactionDisposer? _onAccountChangeReaction;
@@ -119,11 +133,13 @@ abstract class MoneroWalletBase
133
134 Future<void> init() async {
135 await walletAddresses.init();
122 - balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency, MoneroBalance>{
136 + balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency,
137 + MoneroBalance>{
138 currency: MoneroBalance(
124 - fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id),
125 - unlockedBalance:
126 - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id))
139 + fullBalance: monero_wallet.getFullBalance(
140 + accountIndex: walletAddresses.account!.id),
141 + unlockedBalance: monero_wallet.getUnlockedBalance(
142 + accountIndex: walletAddresses.account!.id))
143 });
144 _setListeners();
145 await updateTransactions();
@@ -132,19 +148,20 @@ abstract class MoneroWalletBase
148 monero_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
149
150 if (monero_wallet.getCurrentHeight() <= 1) {
135 - monero_wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight);
151 + monero_wallet.setRefreshFromBlockHeight(
152 + height: walletInfo.restoreHeight);
153 }
154 }
155
139 - _autoSaveTimer =
140 - Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save());
156 + _autoSaveTimer = Timer.periodic(
157 + Duration(seconds: _autoSaveInterval), (_) async => await save());
158 }
159
160 @override
161 Future<void>? updateBalance() => null;
162
163 @override
147 - void close() {
164 + void close() async {
165 _listener?.stop();
166 _onAccountChangeReaction?.reaction.dispose();
167 _autoSaveTimer?.cancel();
@@ -209,8 +226,8 @@ abstract class MoneroWalletBase
226 final inputs = <String>[];
227 final outputs = _credentials.outputs;
228 final hasMultiDestination = outputs.length > 1;
212 - final unlockedBalance =
213 - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
229 + final unlockedBalance = monero_wallet.getUnlockedBalance(
230 + accountIndex: walletAddresses.account!.id);
231 var allInputsAmount = 0;
232
233 PendingTransactionDescription pendingTransactionDescription;
@@ -232,16 +249,20 @@ abstract class MoneroWalletBase
249 final spendAllCoins = inputs.length == unspentCoins.length;
250
251 if (hasMultiDestination) {
235 - if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
236 - throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.');
252 + if (outputs.any(
253 + (item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
254 + throw MoneroTransactionCreationException(
255 + 'You do not have enough XMR to send this amount.');
256 }
257
239 - final int totalAmount =
240 - outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
258 + final int totalAmount = outputs.fold(
259 + 0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
260
242 - final estimatedFee = calculateEstimatedFee(_credentials.priority, totalAmount);
261 + final estimatedFee =
262 + calculateEstimatedFee(_credentials.priority, totalAmount);
263 if (unlockedBalance < totalAmount) {
244 - throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.');
264 + throw MoneroTransactionCreationException(
265 + 'You do not have enough XMR to send this amount.');
266 }
267
268 if (!spendAllCoins && (allInputsAmount < totalAmount + estimatedFee)) {
@@ -249,22 +270,28 @@ abstract class MoneroWalletBase
270 }
271
272 final moneroOutputs = outputs.map((output) {
252 - final outputAddress = output.isParsedAddress ? output.extractedAddress : output.address;
273 + final outputAddress =
274 + output.isParsedAddress ? output.extractedAddress : output.address;
275
276 return MoneroOutput(
255 - address: outputAddress!, amount: output.cryptoAmount!.replaceAll(',', '.'));
277 + address: outputAddress!,
278 + amount: output.cryptoAmount!.replaceAll(',', '.'));
279 }).toList();
280
258 - pendingTransactionDescription = await transaction_history.createTransactionMultDest(
259 - outputs: moneroOutputs,
260 - priorityRaw: _credentials.priority.serialize(),
261 - accountIndex: walletAddresses.account!.id,
262 - preferredInputs: inputs);
281 + pendingTransactionDescription =
282 + await transaction_history.createTransactionMultDest(
283 + outputs: moneroOutputs,
284 + priorityRaw: _credentials.priority.serialize(),
285 + accountIndex: walletAddresses.account!.id,
286 + preferredInputs: inputs);
287 } else {
288 final output = outputs.first;
265 - final address = output.isParsedAddress ? output.extractedAddress : output.address;
266 - final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
267 - final formattedAmount = output.sendAll ? null : output.formattedCryptoAmount;
289 + final address =
290 + output.isParsedAddress ? output.extractedAddress : output.address;
291 + final amount =
292 + output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
293 + final formattedAmount =
294 + output.sendAll ? null : output.formattedCryptoAmount;
295
296 if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
297 (formattedAmount == null && unlockedBalance <= 0)) {
@@ -274,19 +301,22 @@ abstract class MoneroWalletBase
301 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
302 }
303
277 - final estimatedFee = calculateEstimatedFee(_credentials.priority, formattedAmount);
304 + final estimatedFee =
305 + calculateEstimatedFee(_credentials.priority, formattedAmount);
306 if (!spendAllCoins &&
279 - ((formattedAmount != null && allInputsAmount < (formattedAmount + estimatedFee)) ||
307 + ((formattedAmount != null &&
308 + allInputsAmount < (formattedAmount + estimatedFee)) ||
309 formattedAmount == null)) {
310 throw MoneroTransactionNoInputsException(inputs.length);
311 }
312
284 - pendingTransactionDescription = await transaction_history.createTransaction(
285 - address: address!,
286 - amount: amount,
287 - priorityRaw: _credentials.priority.serialize(),
288 - accountIndex: walletAddresses.account!.id,
289 - preferredInputs: inputs);
313 + pendingTransactionDescription =
314 + await transaction_history.createTransaction(
315 + address: address!,
316 + amount: amount,
317 + priorityRaw: _credentials.priority.serialize(),
318 + accountIndex: walletAddresses.account!.id,
319 + preferredInputs: inputs);
320 }
321
322 return PendingMoneroTransaction(pendingTransactionDescription);
@@ -325,18 +355,36 @@ abstract class MoneroWalletBase
355 }
356
357 await walletAddresses.updateAddressesInBox();
328 - await backupWalletFiles(name);
358 await monero_wallet.store();
359 + try {
360 + await backupWalletFiles(name);
361 + } catch (e) {
362 + print("¯\\_(ツ)_/¯");
363 + print(e);
364 + }
365 }
366
367 @override
368 Future<void> renameWalletFiles(String newWalletName) async {
369 final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
335 -
370 + if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) {
371 + // NOTE: this is realistically only required on windows.
372 + print("closing wallet");
373 + final wmaddr = wmPtr.address;
374 + final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address;
375 + await Isolate.run(() {
376 + monero.WalletManager_closeWallet(
377 + Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
378 + });
379 + openedWalletsByPath.remove("$currentWalletDirPath/$name");
380 + print("wallet closed");
381 + }
382 try {
383 // -- rename the waller folder --
338 - final currentWalletDir = Directory(await pathForWalletDir(name: name, type: type));
339 - final newWalletDirPath = await pathForWalletDir(name: newWalletName, type: type);
384 + final currentWalletDir =
385 + Directory(await pathForWalletDir(name: name, type: type));
386 + final newWalletDirPath =
387 + await pathForWalletDir(name: newWalletName, type: type);
388 await currentWalletDir.rename(newWalletDirPath);
389
390 // -- use new waller folder to rename files with old names still --
@@ -346,7 +394,8 @@ abstract class MoneroWalletBase
394 final currentKeysFile = File('$renamedWalletPath.keys');
395 final currentAddressListFile = File('$renamedWalletPath.address.txt');
396
349 - final newWalletPath = await pathForWallet(name: newWalletName, type: type);
397 + final newWalletPath =
398 + await pathForWallet(name: newWalletName, type: type);
399
400 if (currentCacheFile.existsSync()) {
401 await currentCacheFile.rename(newWalletPath);
@@ -366,7 +415,8 @@ abstract class MoneroWalletBase
415 final currentKeysFile = File('$currentWalletPath.keys');
416 final currentAddressListFile = File('$currentWalletPath.address.txt');
417
369 - final newWalletPath = await pathForWallet(name: newWalletName, type: type);
418 + final newWalletPath =
419 + await pathForWallet(name: newWalletName, type: type);
420
421 // Copies current wallet files into new wallet name's dir and files
422 if (currentCacheFile.existsSync()) {
@@ -385,7 +435,8 @@ abstract class MoneroWalletBase
435 }
436
437 @override
388 - Future<void> changePassword(String password) async => monero_wallet.setPasswordSync(password);
438 + Future<void> changePassword(String password) async =>
439 + monero_wallet.setPasswordSync(password);
440
441 Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
442
@@ -419,10 +470,19 @@ abstract class MoneroWalletBase
470 final coinCount = countOfCoins();
471 for (var i = 0; i < coinCount; i++) {
472 final coin = getCoin(i);
422 - if (coin.spent == 0) {
423 - final unspent = MoneroUnspent.fromCoinsInfoRow(coin);
473 + final coinSpent = monero.CoinsInfo_spent(coin);
474 + if (coinSpent == false) {
475 + final unspent = MoneroUnspent(
476 + monero.CoinsInfo_address(coin),
477 + monero.CoinsInfo_hash(coin),
478 + monero.CoinsInfo_keyImage(coin),
479 + monero.CoinsInfo_amount(coin),
480 + monero.CoinsInfo_frozen(coin),
481 + monero.CoinsInfo_unlocked(coin),
482 + );
483 + // TODO: double-check the logic here
484 if (unspent.hash.isNotEmpty) {
425 - unspent.isChange = transaction_history.getTransaction(unspent.hash).direction == 1;
485 + unspent.isChange = transaction_history.getTransaction(unspent.hash).isSpend == true;
486 }
487 unspentCoins.add(unspent);
488 }
@@ -484,13 +544,15 @@ abstract class MoneroWalletBase
544 Future<void> _refreshUnspentCoinsInfo() async {
545 try {
546 final List<dynamic> keys = <dynamic>[];
487 - final currentWalletUnspentCoins = unspentCoinsInfo.values.where((element) =>
488 - element.walletId.contains(id) && element.accountIndex == walletAddresses.account!.id);
547 + final currentWalletUnspentCoins = unspentCoinsInfo.values.where(
548 + (element) =>
549 + element.walletId.contains(id) &&
550 + element.accountIndex == walletAddresses.account!.id);
551
552 if (currentWalletUnspentCoins.isNotEmpty) {
553 currentWalletUnspentCoins.forEach((element) {
492 - final existUnspentCoins =
493 - unspentCoins.where((coin) => element.keyImage!.contains(coin.keyImage!));
554 + final existUnspentCoins = unspentCoins
555 + .where((coin) => element.keyImage!.contains(coin.keyImage!));
556
557 if (existUnspentCoins.isEmpty) {
558 keys.add(element.key);
@@ -507,13 +569,15 @@ abstract class MoneroWalletBase
569 }
570
571 String getTransactionAddress(int accountIndex, int addressIndex) =>
510 - monero_wallet.getAddress(accountIndex: accountIndex, addressIndex: addressIndex);
572 + monero_wallet.getAddress(
573 + accountIndex: accountIndex, addressIndex: addressIndex);
574
575 @override
576 Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
577 transaction_history.refreshTransactions();
578 return _getAllTransactionsOfAccount(walletAddresses.account?.id)
516 - .fold<Map<String, MoneroTransactionInfo>>(<String, MoneroTransactionInfo>{},
579 + .fold<Map<String, MoneroTransactionInfo>>(
580 + <String, MoneroTransactionInfo>{},
581 (Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
582 acc[tx.id] = tx;
583 return acc;
@@ -541,11 +605,31 @@ abstract class MoneroWalletBase
605 String getSubaddressLabel(int accountIndex, int addressIndex) =>
606 monero_wallet.getSubaddressLabel(accountIndex, addressIndex);
607
544 - List<MoneroTransactionInfo> _getAllTransactionsOfAccount(int? accountIndex) => transaction_history
545 - .getAllTransactions()
546 - .map((row) => MoneroTransactionInfo.fromRow(row))
547 - .where((element) => element.accountIndex == (accountIndex ?? 0))
548 - .toList();
608 + List<MoneroTransactionInfo> _getAllTransactionsOfAccount(int? accountIndex) =>
609 + transaction_history
610 + .getAllTransactions()
611 + .map(
612 + (row) => MoneroTransactionInfo(
613 + row.hash,
614 + row.blockheight,
615 + row.isSpend
616 + ? TransactionDirection.outgoing
617 + : TransactionDirection.incoming,
618 + row.timeStamp,
619 + row.isPending,
620 + row.amount,
621 + row.accountIndex,
622 + 0,
623 + row.fee,
624 + row.confirmations,
625 + )..additionalInfo = <String, dynamic>{
626 + 'key': row.key,
627 + 'accountIndex': row.accountIndex,
628 + 'addressIndex': row.addressIndex
629 + },
630 + )
631 + .where((element) => element.accountIndex == (accountIndex ?? 0))
632 + .toList();
633
634 void _setListeners() {
635 _listener?.stop();
@@ -583,7 +667,8 @@ abstract class MoneroWalletBase
667 }
668
669 int _getHeightDistance(DateTime date) {
586 - final distance = DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
670 + final distance =
671 + DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
672 final daysTmp = (distance / 86400).round();
673 final days = daysTmp < 1 ? 1 : daysTmp;
674
@@ -611,22 +696,27 @@ abstract class MoneroWalletBase
696 balance[currency]!.unlockedBalance != unlockedBalance ||
697 balance[currency]!.frozenBalance != frozenBalance) {
698 balance[currency] = MoneroBalance(
614 - fullBalance: fullBalance, unlockedBalance: unlockedBalance, frozenBalance: frozenBalance);
699 + fullBalance: fullBalance,
700 + unlockedBalance: unlockedBalance,
701 + frozenBalance: frozenBalance);
702 }
703 }
704
618 - Future<void> _askForUpdateTransactionHistory() async => await updateTransactions();
705 + Future<void> _askForUpdateTransactionHistory() async =>
706 + await updateTransactions();
707
620 - int _getFullBalance() => monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id);
708 + int _getFullBalance() =>
709 + monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id);
710
622 - int _getUnlockedBalance() =>
623 - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
711 + int _getUnlockedBalance() => monero_wallet.getUnlockedBalance(
712 + accountIndex: walletAddresses.account!.id);
713
714 int _getFrozenBalance() {
715 var frozenBalance = 0;
716
717 for (var coin in unspentCoinsInfo.values.where((element) =>
629 - element.walletId == id && element.accountIndex == walletAddresses.account!.id)) {
718 + element.walletId == id &&
719 + element.accountIndex == walletAddresses.account!.id)) {
720 if (coin.isFrozen) frozenBalance += coin.value;
721 }
722
cw_monero/lib/monero_wallet_service.dart
+19
@@ -1,3 +1,4 @@
1 +import 'dart:ffi';
2 import 'dart:io';
3 import 'package:cw_core/monero_wallet_utils.dart';
4 import 'package:cw_core/pathForWallet.dart';
@@ -10,10 +11,12 @@ import 'package:cw_core/wallet_type.dart';
11 import 'package:cw_core/get_height_by_date.dart';
12 import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
13 import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
14 +import 'package:cw_monero/api/wallet_manager.dart';
15 import 'package:cw_monero/monero_wallet.dart';
16 import 'package:flutter/widgets.dart';
17 import 'package:hive/hive.dart';
18 import 'package:polyseed/polyseed.dart';
19 +import 'package:monero/monero.dart' as monero;
20
21 class MoneroNewWalletCredentials extends WalletCredentials {
22 MoneroNewWalletCredentials(
@@ -174,6 +177,22 @@ class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
177 @override
178 Future<void> remove(String wallet) async {
179 final path = await pathForWalletDir(name: wallet, type: getType());
180 + if (openedWalletsByPath["$path/$wallet"] != null) {
181 + // NOTE: this is realistically only required on windows.
182 + print("closing wallet");
183 + final wmaddr = wmPtr.address;
184 + final waddr = openedWalletsByPath["$path/$wallet"]!.address;
185 + // await Isolate.run(() {
186 + monero.WalletManager_closeWallet(
187 + Pointer.fromAddress(wmaddr),
188 + Pointer.fromAddress(waddr),
189 + false
190 + );
191 + // });
192 + openedWalletsByPath.remove("$path/$wallet");
193 + print("wallet closed");
194 + }
195 +
196 final file = Directory(path);
197 final isExist = file.existsSync();
198
cw_monero/macos/Classes/CwMoneroPlugin.swift deleted
-19
@@ -1,19 +0,0 @@
1 -import Cocoa
2 -import FlutterMacOS
3 -
4 -public class CwMoneroPlugin: NSObject, FlutterPlugin {
5 - public static func register(with registrar: FlutterPluginRegistrar) {
6 - let channel = FlutterMethodChannel(name: "cw_monero", binaryMessenger: registrar.messenger)
7 - let instance = CwMoneroPlugin()
8 - registrar.addMethodCallDelegate(instance, channel: channel)
9 - }
10 -
11 - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
12 - switch call.method {
13 - case "getPlatformVersion":
14 - result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString)
15 - default:
16 - result(FlutterMethodNotImplemented)
17 - }
18 - }
19 -}
cw_monero/macos/Classes/CwWalletListener.h deleted
-23
@@ -1,23 +0,0 @@
1 -#include <stdint.h>
2 -
3 -struct CWMoneroWalletListener;
4 -
5 -typedef int8_t (*on_new_block_callback)(uint64_t height);
6 -typedef int8_t (*on_need_to_refresh_callback)();
7 -
8 -typedef struct CWMoneroWalletListener
9 -{
10 - // on_money_spent_callback *on_money_spent;
11 - // on_money_received_callback *on_money_received;
12 - // on_unconfirmed_money_received_callback *on_unconfirmed_money_received;
13 - // on_new_block_callback *on_new_block;
14 - // on_updated_callback *on_updated;
15 - // on_refreshed_callback *on_refreshed;
16 -
17 - on_new_block_callback on_new_block;
18 -} CWMoneroWalletListener;
19 -
20 -struct TestListener {
21 - // int8_t x;
22 - on_new_block_callback on_new_block;
23 -};
\ No newline at end of file
cw_monero/macos/Classes/monero_api.cpp deleted
-1032
@@ -1,1032 +0,0 @@
1 -#include <stdint.h>
2 -#include "cstdlib"
3 -#include <chrono>
4 -#include <functional>
5 -#include <iostream>
6 -#include <fstream>
7 -#include <unistd.h>
8 -#include <mutex>
9 -#include <list>
10 -#include "thread"
11 -#include "CwWalletListener.h"
12 -#if __APPLE__
13 -// Fix for randomx on ios
14 -void __clear_cache(void* start, void* end) { }
15 -#include "../External/macos/include/wallet2_api.h"
16 -#else
17 -#include "../External/android/include/wallet2_api.h"
18 -#endif
19 -
20 -using namespace std::chrono_literals;
21 -#ifdef __cplusplus
22 -extern "C"
23 -{
24 -#endif
25 - const uint64_t MONERO_BLOCK_SIZE = 1000;
26 -
27 - struct Utf8Box
28 - {
29 - char *value;
30 -
31 - Utf8Box(char *_value)
32 - {
33 - value = _value;
34 - }
35 - };
36 -
37 - struct SubaddressRow
38 - {
39 - uint64_t id;
40 - char *address;
41 - char *label;
42 -
43 - SubaddressRow(std::size_t _id, char *_address, char *_label)
44 - {
45 - id = static_cast<uint64_t>(_id);
46 - address = _address;
47 - label = _label;
48 - }
49 - };
50 -
51 - struct AccountRow
52 - {
53 - uint64_t id;
54 - char *label;
55 -
56 - AccountRow(std::size_t _id, char *_label)
57 - {
58 - id = static_cast<uint64_t>(_id);
59 - label = _label;
60 - }
61 - };
62 -
63 - struct MoneroWalletListener : Monero::WalletListener
64 - {
65 - uint64_t m_height;
66 - bool m_need_to_refresh;
67 - bool m_new_transaction;
68 -
69 - MoneroWalletListener()
70 - {
71 - m_height = 0;
72 - m_need_to_refresh = false;
73 - m_new_transaction = false;
74 - }
75 -
76 - void moneySpent(const std::string &txId, uint64_t amount)
77 - {
78 - m_new_transaction = true;
79 - }
80 -
81 - void moneyReceived(const std::string &txId, uint64_t amount)
82 - {
83 - m_new_transaction = true;
84 - }
85 -
86 - void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
87 - {
88 - m_new_transaction = true;
89 - }
90 -
91 - void newBlock(uint64_t height)
92 - {
93 - m_height = height;
94 - }
95 -
96 - void updated()
97 - {
98 - m_new_transaction = true;
99 - }
100 -
101 - void refreshed()
102 - {
103 - m_need_to_refresh = true;
104 - }
105 -
106 - void resetNeedToRefresh()
107 - {
108 - m_need_to_refresh = false;
109 - }
110 -
111 - bool isNeedToRefresh()
112 - {
113 - return m_need_to_refresh;
114 - }
115 -
116 - bool isNewTransactionExist()
117 - {
118 - return m_new_transaction;
119 - }
120 -
121 - void resetIsNewTransactionExist()
122 - {
123 - m_new_transaction = false;
124 - }
125 -
126 - uint64_t height()
127 - {
128 - return m_height;
129 - }
130 - };
131 -
132 - struct TransactionInfoRow
133 - {
134 - uint64_t amount;
135 - uint64_t fee;
136 - uint64_t blockHeight;
137 - uint64_t confirmations;
138 - uint32_t subaddrAccount;
139 - int8_t direction;
140 - int8_t isPending;
141 - uint32_t subaddrIndex;
142 -
143 - char *hash;
144 - char *paymentId;
145 -
146 - int64_t datetime;
147 -
148 - TransactionInfoRow(Monero::TransactionInfo *transaction)
149 - {
150 - amount = transaction->amount();
151 - fee = transaction->fee();
152 - blockHeight = transaction->blockHeight();
153 - subaddrAccount = transaction->subaddrAccount();
154 - std::set<uint32_t>::iterator it = transaction->subaddrIndex().begin();
155 - subaddrIndex = *it;
156 - confirmations = transaction->confirmations();
157 - datetime = static_cast<int64_t>(transaction->timestamp());
158 - direction = transaction->direction();
159 - isPending = static_cast<int8_t>(transaction->isPending());
160 - std::string *hash_str = new std::string(transaction->hash());
161 - hash = strdup(hash_str->c_str());
162 - paymentId = strdup(transaction->paymentId().c_str());
163 - }
164 - };
165 -
166 - struct PendingTransactionRaw
167 - {
168 - uint64_t amount;
169 - uint64_t fee;
170 - char *hash;
171 - char *hex;
172 - char *txKey;
173 - Monero::PendingTransaction *transaction;
174 -
175 - PendingTransactionRaw(Monero::PendingTransaction *_transaction)
176 - {
177 - transaction = _transaction;
178 - amount = _transaction->amount();
179 - fee = _transaction->fee();
180 - hash = strdup(_transaction->txid()[0].c_str());
181 - hex = strdup(_transaction->hex()[0].c_str());
182 - txKey = strdup(_transaction->txKey()[0].c_str());
183 - }
184 - };
185 -
186 - struct CoinsInfoRow
187 - {
188 - uint64_t blockHeight;
189 - char *hash;
190 - uint64_t internalOutputIndex;
191 - uint64_t globalOutputIndex;
192 - bool spent;
193 - bool frozen;
194 - uint64_t spentHeight;
195 - uint64_t amount;
196 - bool rct;
197 - bool keyImageKnown;
198 - uint64_t pkIndex;
199 - uint32_t subaddrIndex;
200 - uint32_t subaddrAccount;
201 - char *address;
202 - char *addressLabel;
203 - char *keyImage;
204 - uint64_t unlockTime;
205 - bool unlocked;
206 - char *pubKey;
207 - bool coinbase;
208 - char *description;
209 -
210 - CoinsInfoRow(Monero::CoinsInfo *coinsInfo)
211 - {
212 - blockHeight = coinsInfo->blockHeight();
213 - std::string *hash_str = new std::string(coinsInfo->hash());
214 - hash = strdup(hash_str->c_str());
215 - internalOutputIndex = coinsInfo->internalOutputIndex();
216 - globalOutputIndex = coinsInfo->globalOutputIndex();
217 - spent = coinsInfo->spent();
218 - frozen = coinsInfo->frozen();
219 - spentHeight = coinsInfo->spentHeight();
220 - amount = coinsInfo->amount();
221 - rct = coinsInfo->rct();
222 - keyImageKnown = coinsInfo->keyImageKnown();
223 - pkIndex = coinsInfo->pkIndex();
224 - subaddrIndex = coinsInfo->subaddrIndex();
225 - subaddrAccount = coinsInfo->subaddrAccount();
226 - address = strdup(coinsInfo->address().c_str()) ;
227 - addressLabel = strdup(coinsInfo->addressLabel().c_str());
228 - keyImage = strdup(coinsInfo->keyImage().c_str());
229 - unlockTime = coinsInfo->unlockTime();
230 - unlocked = coinsInfo->unlocked();
231 - pubKey = strdup(coinsInfo->pubKey().c_str());
232 - coinbase = coinsInfo->coinbase();
233 - description = strdup(coinsInfo->description().c_str());
234 - }
235 -
236 - void setUnlocked(bool unlocked);
237 - };
238 -
239 - Monero::Coins *m_coins;
240 -
241 - Monero::Wallet *m_wallet;
242 - Monero::TransactionHistory *m_transaction_history;
243 - MoneroWalletListener *m_listener;
244 - Monero::Subaddress *m_subaddress;
245 - Monero::SubaddressAccount *m_account;
246 - uint64_t m_last_known_wallet_height;
247 - uint64_t m_cached_syncing_blockchain_height = 0;
248 - std::list<Monero::CoinsInfo*> m_coins_info;
249 - std::mutex store_lock;
250 - bool is_storing = false;
251 -
252 - void change_current_wallet(Monero::Wallet *wallet)
253 - {
254 - m_wallet = wallet;
255 - m_listener = nullptr;
256 -
257 -
258 - if (wallet != nullptr)
259 - {
260 - m_transaction_history = wallet->history();
261 - }
262 - else
263 - {
264 - m_transaction_history = nullptr;
265 - }
266 -
267 - if (wallet != nullptr)
268 - {
269 - m_account = wallet->subaddressAccount();
270 - }
271 - else
272 - {
273 - m_account = nullptr;
274 - }
275 -
276 - if (wallet != nullptr)
277 - {
278 - m_subaddress = wallet->subaddress();
279 - }
280 - else
281 - {
282 - m_subaddress = nullptr;
283 - }
284 -
285 - m_coins_info = std::list<Monero::CoinsInfo*>();
286 -
287 - if (wallet != nullptr)
288 - {
289 - m_coins = wallet->coins();
290 - }
291 - else
292 - {
293 - m_coins = nullptr;
294 - }
295 - }
296 -
297 - Monero::Wallet *get_current_wallet()
298 - {
299 - return m_wallet;
300 - }
301 -
302 - bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error)
303 - {
304 - Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
305 - Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
306 - Monero::Wallet *wallet = walletManager->createWallet(path, password, language, _networkType);
307 -
308 - int status;
309 - std::string errorString;
310 -
311 - wallet->statusWithErrorString(status, errorString);
312 -
313 - if (wallet->status() != Monero::Wallet::Status_Ok)
314 - {
315 - error = strdup(wallet->errorString().c_str());
316 - return false;
317 - }
318 -
319 - change_current_wallet(wallet);
320 -
321 - return true;
322 - }
323 -
324 - bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error)
325 - {
326 - Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
327 - Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->recoveryWallet(
328 - std::string(path),
329 - std::string(password),
330 - std::string(seed),
331 - _networkType,
332 - (uint64_t)restoreHeight);
333 -
334 - int status;
335 - std::string errorString;
336 -
337 - wallet->statusWithErrorString(status, errorString);
338 -
339 - if (status != Monero::Wallet::Status_Ok || !errorString.empty())
340 - {
341 - error = strdup(errorString.c_str());
342 - return false;
343 - }
344 -
345 - change_current_wallet(wallet);
346 - return true;
347 - }
348 -
349 - bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error)
350 - {
351 - Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
352 - Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createWalletFromKeys(
353 - std::string(path),
354 - std::string(password),
355 - std::string(language),
356 - _networkType,
357 - (uint64_t)restoreHeight,
358 - std::string(address),
359 - std::string(viewKey),
360 - std::string(spendKey));
361 -
362 - int status;
363 - std::string errorString;
364 -
365 - wallet->statusWithErrorString(status, errorString);
366 -
367 - if (status != Monero::Wallet::Status_Ok || !errorString.empty())
368 - {
369 - error = strdup(errorString.c_str());
370 - return false;
371 - }
372 -
373 - change_current_wallet(wallet);
374 - return true;
375 - }
376 -
377 - bool restore_wallet_from_spend_key(char *path, char *password, char *seed, char *language, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error)
378 - {
379 - Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
380 - Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createDeterministicWalletFromSpendKey(
381 - std::string(path),
382 - std::string(password),
383 - std::string(language),
384 - _networkType,
385 - (uint64_t)restoreHeight,
386 - std::string(spendKey));
387 -
388 - // Cache Raw to support Polyseed
389 - wallet->setCacheAttribute("cakewallet.seed", std::string(seed));
390 -
391 - int status;
392 - std::string errorString;
393 -
394 - wallet->statusWithErrorString(status, errorString);
395 -
396 - if (status != Monero::Wallet::Status_Ok || !errorString.empty())
397 - {
398 - error = strdup(errorString.c_str());
399 - return false;
400 - }
401 -
402 - change_current_wallet(wallet);
403 - return true;
404 - }
405 -
406 - bool load_wallet(char *path, char *password, int32_t nettype)
407 - {
408 - nice(19);
409 - Monero::NetworkType networkType = static_cast<Monero::NetworkType>(nettype);
410 - Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
411 - Monero::Wallet *wallet = walletManager->openWallet(std::string(path), std::string(password), networkType);
412 - int status;
413 - std::string errorString;
414 -
415 - wallet->statusWithErrorString(status, errorString);
416 - change_current_wallet(wallet);
417 -
418 - return !(status != Monero::Wallet::Status_Ok || !errorString.empty());
419 - }
420 -
421 - char *error_string() {
422 - return strdup(get_current_wallet()->errorString().c_str());
423 - }
424 -
425 -
426 - bool is_wallet_exist(char *path)
427 - {
428 - return Monero::WalletManagerFactory::getWalletManager()->walletExists(std::string(path));
429 - }
430 -
431 - void close_current_wallet()
432 - {
433 - Monero::WalletManagerFactory::getWalletManager()->closeWallet(get_current_wallet());
434 - change_current_wallet(nullptr);
435 - }
436 -
437 - char *get_filename()
438 - {
439 - return strdup(get_current_wallet()->filename().c_str());
440 - }
441 -
442 - char *secret_view_key()
443 - {
444 - return strdup(get_current_wallet()->secretViewKey().c_str());
445 - }
446 -
447 - char *public_view_key()
448 - {
449 - return strdup(get_current_wallet()->publicViewKey().c_str());
450 - }
451 -
452 - char *secret_spend_key()
453 - {
454 - return strdup(get_current_wallet()->secretSpendKey().c_str());
455 - }
456 -
457 - char *public_spend_key()
458 - {
459 - return strdup(get_current_wallet()->publicSpendKey().c_str());
460 - }
461 -
462 - char *get_address(uint32_t account_index, uint32_t address_index)
463 - {
464 - return strdup(get_current_wallet()->address(account_index, address_index).c_str());
465 - }
466 -
467 -
468 - const char *seed()
469 - {
470 - std::string _rawSeed = get_current_wallet()->getCacheAttribute("cakewallet.seed");
471 - if (!_rawSeed.empty())
472 - {
473 - return strdup(_rawSeed.c_str());
474 - }
475 - return strdup(get_current_wallet()->seed().c_str());
476 - }
477 -
478 - uint64_t get_full_balance(uint32_t account_index)
479 - {
480 - return get_current_wallet()->balance(account_index);
481 - }
482 -
483 - uint64_t get_unlocked_balance(uint32_t account_index)
484 - {
485 - return get_current_wallet()->unlockedBalance(account_index);
486 - }
487 -
488 - uint64_t get_current_height()
489 - {
490 - return get_current_wallet()->blockChainHeight();
491 - }
492 -
493 - uint64_t get_node_height()
494 - {
495 - return get_current_wallet()->daemonBlockChainHeight();
496 - }
497 -
498 - bool connect_to_node(char *error)
499 - {
500 - nice(19);
501 - bool is_connected = get_current_wallet()->connectToDaemon();
502 -
503 - if (!is_connected)
504 - {
505 - error = strdup(get_current_wallet()->errorString().c_str());
506 - }
507 -
508 - return is_connected;
509 - }
510 -
511 - bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *socksProxyAddress, char *error)
512 - {
513 - nice(19);
514 - Monero::Wallet *wallet = get_current_wallet();
515 -
516 - std::string _login = "";
517 - std::string _password = "";
518 - std::string _socksProxyAddress = "";
519 -
520 - if (login != nullptr)
521 - {
522 - _login = std::string(login);
523 - }
524 -
525 - if (password != nullptr)
526 - {
527 - _password = std::string(password);
528 - }
529 -
530 - if (socksProxyAddress != nullptr)
531 - {
532 - _socksProxyAddress = std::string(socksProxyAddress);
533 - }
534 -
535 - bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet, _socksProxyAddress);
536 -
537 - if (!inited)
538 - {
539 - error = strdup(wallet->errorString().c_str());
540 - } else if (!wallet->connectToDaemon()) {
541 - error = strdup(wallet->errorString().c_str());
542 - }
543 -
544 - return inited;
545 - }
546 -
547 - bool is_connected()
548 - {
549 - return get_current_wallet()->connected();
550 - }
551 -
552 - void start_refresh()
553 - {
554 - get_current_wallet()->refreshAsync();
555 - get_current_wallet()->startRefresh();
556 - }
557 -
558 - void set_refresh_from_block_height(uint64_t height)
559 - {
560 - get_current_wallet()->setRefreshFromBlockHeight(height);
561 - }
562 -
563 - void set_recovering_from_seed(bool is_recovery)
564 - {
565 - get_current_wallet()->setRecoveringFromSeed(is_recovery);
566 - }
567 -
568 - void store(char *path)
569 - {
570 - store_lock.lock();
571 - if (is_storing) {
572 - return;
573 - }
574 -
575 - is_storing = true;
576 - get_current_wallet()->store(std::string(path));
577 - is_storing = false;
578 - store_lock.unlock();
579 - }
580 -
581 - bool set_password(char *password, Utf8Box &error) {
582 - bool is_changed = get_current_wallet()->setPassword(std::string(password));
583 -
584 - if (!is_changed) {
585 - error = Utf8Box(strdup(get_current_wallet()->errorString().c_str()));
586 - }
587 -
588 - return is_changed;
589 - }
590 -
591 - bool transaction_create(char *address, char *payment_id, char *amount,
592 - uint8_t priority_raw, uint32_t subaddr_account,
593 - char **preferred_inputs, uint32_t preferred_inputs_size,
594 - Utf8Box &error, PendingTransactionRaw &pendingTransaction)
595 - {
596 - nice(19);
597 -
598 - std::set<std::string> _preferred_inputs;
599 -
600 - for (int i = 0; i < preferred_inputs_size; i++) {
601 - _preferred_inputs.insert(std::string(*preferred_inputs));
602 - preferred_inputs++;
603 - }
604 -
605 - auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
606 - std::string _payment_id;
607 - Monero::PendingTransaction *transaction;
608 -
609 - if (payment_id != nullptr)
610 - {
611 - _payment_id = std::string(payment_id);
612 - }
613 -
614 - if (amount != nullptr)
615 - {
616 - uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
617 - transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
618 - }
619 - else
620 - {
621 - transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
622 - }
623 -
624 - int status = transaction->status();
625 -
626 - if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
627 - {
628 - error = Utf8Box(strdup(transaction->errorString().c_str()));
629 - return false;
630 - }
631 -
632 - if (m_listener != nullptr) {
633 - m_listener->m_new_transaction = true;
634 - }
635 -
636 - pendingTransaction = PendingTransactionRaw(transaction);
637 - return true;
638 - }
639 -
640 - bool transaction_create_mult_dest(char **addresses, char *payment_id, char **amounts, uint32_t size,
641 - uint8_t priority_raw, uint32_t subaddr_account,
642 - char **preferred_inputs, uint32_t preferred_inputs_size,
643 - Utf8Box &error, PendingTransactionRaw &pendingTransaction)
644 - {
645 - nice(19);
646 -
647 - std::vector<std::string> _addresses;
648 - std::vector<uint64_t> _amounts;
649 -
650 - for (int i = 0; i < size; i++) {
651 - _addresses.push_back(std::string(*addresses));
652 - _amounts.push_back(Monero::Wallet::amountFromString(std::string(*amounts)));
653 - addresses++;
654 - amounts++;
655 - }
656 -
657 - std::set<std::string> _preferred_inputs;
658 -
659 - for (int i = 0; i < preferred_inputs_size; i++) {
660 - _preferred_inputs.insert(std::string(*preferred_inputs));
661 - preferred_inputs++;
662 - }
663 -
664 - auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
665 - std::string _payment_id;
666 - Monero::PendingTransaction *transaction;
667 -
668 - if (payment_id != nullptr)
669 - {
670 - _payment_id = std::string(payment_id);
671 - }
672 -
673 - transaction = m_wallet->createTransactionMultDest(_addresses, _payment_id, _amounts, m_wallet->defaultMixin(), priority, subaddr_account);
674 -
675 - int status = transaction->status();
676 -
677 - if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
678 - {
679 - error = Utf8Box(strdup(transaction->errorString().c_str()));
680 - return false;
681 - }
682 -
683 - if (m_listener != nullptr) {
684 - m_listener->m_new_transaction = true;
685 - }
686 -
687 - pendingTransaction = PendingTransactionRaw(transaction);
688 - return true;
689 - }
690 -
691 - bool transaction_commit(PendingTransactionRaw *transaction, Utf8Box &error)
692 - {
693 - bool committed = transaction->transaction->commit();
694 -
695 - if (!committed)
696 - {
697 - error = Utf8Box(strdup(transaction->transaction->errorString().c_str()));
698 - } else if (m_listener != nullptr) {
699 - m_listener->m_new_transaction = true;
700 - }
701 -
702 - return committed;
703 - }
704 -
705 - uint64_t get_node_height_or_update(uint64_t base_eight)
706 - {
707 - if (m_cached_syncing_blockchain_height < base_eight) {
708 - m_cached_syncing_blockchain_height = base_eight;
709 - }
710 -
711 - return m_cached_syncing_blockchain_height;
712 - }
713 -
714 - uint64_t get_syncing_height()
715 - {
716 - if (m_listener == nullptr) {
717 - return 0;
718 - }
719 -
720 - uint64_t height = m_listener->height();
721 -
722 - if (height <= 1) {
723 - return 0;
724 - }
725 -
726 - if (height != m_last_known_wallet_height)
727 - {
728 - m_last_known_wallet_height = height;
729 - }
730 -
731 - return height;
732 - }
733 -
734 - uint64_t is_needed_to_refresh()
735 - {
736 - if (m_listener == nullptr) {
737 - return false;
738 - }
739 -
740 - bool should_refresh = m_listener->isNeedToRefresh();
741 -
742 - if (should_refresh) {
743 - m_listener->resetNeedToRefresh();
744 - }
745 -
746 - return should_refresh;
747 - }
748 -
749 - uint8_t is_new_transaction_exist()
750 - {
751 - if (m_listener == nullptr) {
752 - return false;
753 - }
754 -
755 - bool is_new_transaction_exist = m_listener->isNewTransactionExist();
756 -
757 - if (is_new_transaction_exist)
758 - {
759 - m_listener->resetIsNewTransactionExist();
760 - }
761 -
762 - return is_new_transaction_exist;
763 - }
764 -
765 - void set_listener()
766 - {
767 - m_last_known_wallet_height = 0;
768 -
769 - if (m_listener != nullptr)
770 - {
771 - free(m_listener);
772 - }
773 -
774 - m_listener = new MoneroWalletListener();
775 - get_current_wallet()->setListener(m_listener);
776 - }
777 -
778 - int64_t *subaddrress_get_all()
779 - {
780 - std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
781 - size_t size = _subaddresses.size();
782 - int64_t *subaddresses = (int64_t *)malloc(size * sizeof(int64_t));
783 -
784 - for (int i = 0; i < size; i++)
785 - {
786 - Monero::SubaddressRow *row = _subaddresses[i];
787 - SubaddressRow *_row = new SubaddressRow(row->getRowId(), strdup(row->getAddress().c_str()), strdup(row->getLabel().c_str()));
788 - subaddresses[i] = reinterpret_cast<int64_t>(_row);
789 - }
790 -
791 - return subaddresses;
792 - }
793 -
794 - int32_t subaddrress_size()
795 - {
796 - std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
797 - return _subaddresses.size();
798 - }
799 -
800 - void subaddress_add_row(uint32_t accountIndex, char *label)
801 - {
802 - m_subaddress->addRow(accountIndex, std::string(label));
803 - }
804 -
805 - void subaddress_set_label(uint32_t accountIndex, uint32_t addressIndex, char *label)
806 - {
807 - m_subaddress->setLabel(accountIndex, addressIndex, std::string(label));
808 - }
809 -
810 - void subaddress_refresh(uint32_t accountIndex)
811 - {
812 - m_subaddress->refresh(accountIndex);
813 - }
814 -
815 - int32_t account_size()
816 - {
817 - std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
818 - return _accocunts.size();
819 - }
820 -
821 - int64_t *account_get_all()
822 - {
823 - std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
824 - size_t size = _accocunts.size();
825 - int64_t *accocunts = (int64_t *)malloc(size * sizeof(int64_t));
826 -
827 - for (int i = 0; i < size; i++)
828 - {
829 - Monero::SubaddressAccountRow *row = _accocunts[i];
830 - AccountRow *_row = new AccountRow(row->getRowId(), strdup(row->getLabel().c_str()));
831 - accocunts[i] = reinterpret_cast<int64_t>(_row);
832 - }
833 -
834 - return accocunts;
835 - }
836 -
837 - void account_add_row(char *label)
838 - {
839 - m_account->addRow(std::string(label));
840 - }
841 -
842 - void account_set_label_row(uint32_t account_index, char *label)
843 - {
844 - m_account->setLabel(account_index, label);
845 - }
846 -
847 - void account_refresh()
848 - {
849 - m_account->refresh();
850 - }
851 -
852 - int64_t *transactions_get_all()
853 - {
854 - std::vector<Monero::TransactionInfo *> transactions = m_transaction_history->getAll();
855 - size_t size = transactions.size();
856 - int64_t *transactionAddresses = (int64_t *)malloc(size * sizeof(int64_t));
857 -
858 - for (int i = 0; i < size; i++)
859 - {
860 - Monero::TransactionInfo *row = transactions[i];
861 - TransactionInfoRow *tx = new TransactionInfoRow(row);
862 - transactionAddresses[i] = reinterpret_cast<int64_t>(tx);
863 - }
864 -
865 - return transactionAddresses;
866 - }
867 -
868 - void transactions_refresh()
869 - {
870 - m_transaction_history->refresh();
871 - }
872 -
873 - int64_t transactions_count()
874 - {
875 - return m_transaction_history->count();
876 - }
877 -
878 - TransactionInfoRow* get_transaction(char * txId)
879 - {
880 - Monero::TransactionInfo *row = m_transaction_history->transaction(std::string(txId));
881 - return new TransactionInfoRow(row);
882 - }
883 -
884 - int LedgerExchange(
885 - unsigned char *command,
886 - unsigned int cmd_len,
887 - unsigned char *response,
888 - unsigned int max_resp_len)
889 - {
890 - return -1;
891 - }
892 -
893 - int LedgerFind(char *buffer, size_t len)
894 - {
895 - return -1;
896 - }
897 -
898 - void on_startup()
899 - {
900 - Monero::Utils::onStartup();
901 - Monero::WalletManagerFactory::setLogLevel(0);
902 - }
903 -
904 - void rescan_blockchain()
905 - {
906 - m_wallet->rescanBlockchainAsync();
907 - }
908 -
909 - char * get_tx_key(char * txId)
910 - {
911 - return strdup(m_wallet->getTxKey(std::string(txId)).c_str());
912 - }
913 -
914 - char *get_subaddress_label(uint32_t accountIndex, uint32_t addressIndex)
915 - {
916 - return strdup(get_current_wallet()->getSubaddressLabel(accountIndex, addressIndex).c_str());
917 - }
918 -
919 - void set_trusted_daemon(bool arg)
920 - {
921 - m_wallet->setTrustedDaemon(arg);
922 - }
923 -
924 - bool trusted_daemon()
925 - {
926 - return m_wallet->trustedDaemon();
927 - }
928 -
929 - CoinsInfoRow* coin(int index)
930 - {
931 - if (index >= 0 && index < m_coins_info.size()) {
932 - std::list<Monero::CoinsInfo*>::iterator it = m_coins_info.begin();
933 - std::advance(it, index);
934 - Monero::CoinsInfo* element = *it;
935 - std::cout << "Element at index " << index << ": " << element << std::endl;
936 - return new CoinsInfoRow(element);
937 - } else {
938 - std::cout << "Invalid index." << std::endl;
939 - return nullptr; // Return a default value (nullptr) for invalid index
940 - }
941 - }
942 -
943 - void refresh_coins(uint32_t accountIndex)
944 - {
945 - m_coins_info.clear();
946 -
947 - m_coins->refresh();
948 - for (const auto i : m_coins->getAll()) {
949 - if (i->subaddrAccount() == accountIndex && !(i->spent())) {
950 - m_coins_info.push_back(i);
951 - }
952 - }
953 - }
954 -
955 - uint64_t coins_count()
956 - {
957 - return m_coins_info.size();
958 - }
959 -
960 - CoinsInfoRow** coins_from_account(uint32_t accountIndex)
961 - {
962 - std::vector<CoinsInfoRow*> matchingCoins;
963 -
964 - for (int i = 0; i < coins_count(); i++) {
965 - CoinsInfoRow* coinInfo = coin(i);
966 - if (coinInfo->subaddrAccount == accountIndex) {
967 - matchingCoins.push_back(coinInfo);
968 - }
969 - }
970 -
971 - CoinsInfoRow** result = new CoinsInfoRow*[matchingCoins.size()];
972 - std::copy(matchingCoins.begin(), matchingCoins.end(), result);
973 - return result;
974 - }
975 -
976 - CoinsInfoRow** coins_from_txid(const char* txid, size_t* count)
977 - {
978 - std::vector<CoinsInfoRow*> matchingCoins;
979 -
980 - for (int i = 0; i < coins_count(); i++) {
981 - CoinsInfoRow* coinInfo = coin(i);
982 - if (std::string(coinInfo->hash) == txid) {
983 - matchingCoins.push_back(coinInfo);
984 - }
985 - }
986 -
987 - *count = matchingCoins.size();
988 - CoinsInfoRow** result = new CoinsInfoRow*[*count];
989 - std::copy(matchingCoins.begin(), matchingCoins.end(), result);
990 - return result;
991 - }
992 -
993 - CoinsInfoRow** coins_from_key_image(const char** keyimages, size_t keyimageCount, size_t* count)
994 - {
995 - std::vector<CoinsInfoRow*> matchingCoins;
996 -
997 - for (int i = 0; i < coins_count(); i++) {
998 - CoinsInfoRow* coinsInfoRow = coin(i);
999 - for (size_t j = 0; j < keyimageCount; j++) {
1000 - if (coinsInfoRow->keyImageKnown && std::string(coinsInfoRow->keyImage) == keyimages[j]) {
1001 - matchingCoins.push_back(coinsInfoRow);
1002 - break;
1003 - }
1004 - }
1005 - }
1006 -
1007 - *count = matchingCoins.size();
1008 - CoinsInfoRow** result = new CoinsInfoRow*[*count];
1009 - std::copy(matchingCoins.begin(), matchingCoins.end(), result);
1010 - return result;
1011 - }
1012 -
1013 - void freeze_coin(int index)
1014 - {
1015 - m_coins->setFrozen(index);
1016 - }
1017 -
1018 - void thaw_coin(int index)
1019 - {
1020 - m_coins->thaw(index);
1021 - }
1022 -
1023 - // Sign Messages //
1024 -
1025 - char *sign_message(char *message, char *address = "")
1026 - {
1027 - return strdup(get_current_wallet()->signMessage(std::string(message), std::string(address)).c_str());
1028 - }
1029 -
1030 -#ifdef __cplusplus
1031 -}
1032 -#endif
cw_monero/macos/Classes/monero_api.h deleted
-39
@@ -1,39 +0,0 @@
1 -#include <stdint.h>
2 -#include <stdio.h>
3 -#include <stdbool.h>
4 -#include "CwWalletListener.h"
5 -
6 -#ifdef __cplusplus
7 -extern "C" {
8 -#endif
9 -
10 -bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error);
11 -bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error);
12 -bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error);
13 -void load_wallet(char *path, char *password, int32_t nettype);
14 -bool is_wallet_exist(char *path);
15 -
16 -char *get_filename();
17 -const char *seed();
18 -char *get_address(uint32_t account_index, uint32_t address_index);
19 -uint64_t get_full_balance(uint32_t account_index);
20 -uint64_t get_unlocked_balance(uint32_t account_index);
21 -uint64_t get_current_height();
22 -uint64_t get_node_height();
23 -
24 -bool is_connected();
25 -
26 -bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error);
27 -bool connect_to_node(char *error);
28 -void start_refresh();
29 -void set_refresh_from_block_height(uint64_t height);
30 -void set_recovering_from_seed(bool is_recovery);
31 -void store(char *path);
32 -
33 -void set_trusted_daemon(bool arg);
34 -bool trusted_daemon();
35 -char *sign_message(char *message, char *address);
36 -
37 -#ifdef __cplusplus
38 -}
39 -#endif
cw_monero/macos/cw_monero_base.podspec deleted
-56
@@ -1,56 +0,0 @@
1 -#
2 -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 -# Run `pod lib lint cw_monero.podspec` to validate before publishing.
4 -#
5 -Pod::Spec.new do |s|
6 - s.name = 'cw_monero'
7 - s.version = '0.0.1'
8 - s.summary = 'CW Monero'
9 - s.description = 'Cake Wallet wrapper over Monero project.'
10 - s.homepage = 'http://cakewallet.com'
11 - s.license = { :file => '../LICENSE' }
12 - s.author = { 'CakeWallet' => 'support@cakewallet.com' }
13 - s.source = { :path => '.' }
14 - s.source_files = 'Classes/**/*'
15 - s.dependency 'FlutterMacOS'
16 - s.public_header_files = 'Classes/**/*.h, Classes/*.h, External/macos/libs/monero/include/External/ios/**/*.h'
17 - s.platform = :osx, '10.11'
18 - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => '#___VALID_ARCHS___#', 'ENABLE_BITCODE' => 'NO' }
19 - s.swift_version = '5.0'
20 - s.libraries = 'iconv'
21 -
22 - s.subspec 'OpenSSL' do |openssl|
23 - openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/macos/include/**/*.h'
24 - openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/macos/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
25 - openssl.libraries = 'ssl', 'crypto'
26 - openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include/**" }
27 - end
28 -
29 - s.subspec 'Sodium' do |sodium|
30 - sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/macos/include/**/*.h'
31 - sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/macos/lib/libsodium.a'
32 - sodium.libraries = 'sodium'
33 - sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include/**" }
34 - end
35 -
36 - s.subspec 'Unbound' do |unbound|
37 - unbound.preserve_paths = '../../../../../cw_shared_external/ios/External/macos/include/**/*.h'
38 - unbound.vendored_libraries = '../../../../../cw_shared_external/ios/External/macos/lib/libunbound.a'
39 - unbound.libraries = 'unbound'
40 - unbound.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include/**" }
41 - end
42 -
43 - s.subspec 'Boost' do |boost|
44 - boost.preserve_paths = '../../../../../cw_shared_external/ios/External/macos/include/**/*.h',
45 - boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/macos/lib/libboost.a',
46 - boost.libraries = 'boost'
47 - boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include/**" }
48 - end
49 -
50 - s.subspec 'Monero' do |monero|
51 - monero.preserve_paths = 'External/macos/include/**/*.h'
52 - monero.vendored_libraries = 'External/macos/lib/libmonero.a'
53 - monero.libraries = 'monero'
54 - monero.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include" }
55 - end
56 -end
cw_monero/pubspec.lock
+21 -4
@@ -204,10 +204,10 @@ packages:
204 dependency: "direct main"
205 description:
206 name: ffi
207 - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
207 + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
208 url: "https://pub.dev"
209 source: hosted
210 - version: "2.0.1"
210 + version: "2.1.0"
211 file:
212 dependency: transitive
213 description:
@@ -434,6 +434,23 @@ packages:
434 url: "https://pub.dev"
435 source: hosted
436 version: "2.1.1"
437 + monero:
438 + dependency: "direct main"
439 + description:
440 + path: "."
441 + ref: d46753eca865e9e56c2f0ef6fe485c42e11982c5
442 + resolved-ref: d46753eca865e9e56c2f0ef6fe485c42e11982c5
443 + url: "https://github.com/mrcyjanek/monero.dart"
444 + source: git
445 + version: "0.0.0"
446 + mutex:
447 + dependency: "direct main"
448 + description:
449 + name: mutex
450 + sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2"
451 + url: "https://pub.dev"
452 + source: hosted
453 + version: "3.1.0"
454 package_config:
455 dependency: transitive
456 description:
@@ -526,10 +543,10 @@ packages:
543 dependency: "direct main"
544 description:
545 name: polyseed
529 - sha256: "9b48ec535b10863f78f6354ec983b4cc0c88ca69ff48fee469d0fd1954b01d4f"
546 + sha256: a340962242d7917b0f3e6bd02c4acc3f90eae8ff766f1244f793ae7a6414dd68
547 url: "https://pub.dev"
548 source: hosted
532 - version: "0.0.2"
549 + version: "0.0.4"
550 pool:
551 dependency: transitive
552 description:
cw_monero/pubspec.yaml
+6 -10
@@ -6,7 +6,7 @@ author: Cake Wallet
6 homepage: https://cakewallet.com
7
8 environment:
9 - sdk: ">=2.17.5 <3.0.0"
9 + sdk: ">=2.19.0 <3.0.0"
10 flutter: ">=1.20.0"
11
12 dependencies:
@@ -22,6 +22,11 @@ dependencies:
22 polyseed: ^0.0.5
23 cw_core:
24 path: ../cw_core
25 + monero:
26 + git:
27 + url: https://github.com/mrcyjanek/monero.dart
28 + ref: d46753eca865e9e56c2f0ef6fe485c42e11982c5
29 + mutex: ^3.1.0
30
31 dev_dependencies:
32 flutter_test:
@@ -43,16 +48,7 @@ flutter:
48 # The androidPackage and pluginClass identifiers should not ordinarily
49 # be modified. They are used by the tooling to maintain consistency when
50 # adding or updating assets for this project.
46 - plugin:
47 - platforms:
48 - android:
49 - package: com.cakewallet.monero
50 - pluginClass: CwMoneroPlugin
51 - ios:
52 - pluginClass: CwMoneroPlugin
51
54 - macos:
55 - pluginClass: CwMoneroPlugin
52
53 # To add assets to your plugin package, add an assets section, like this:
54 # assets:
cw_monero/test/cw_monero_method_channel_test.dart deleted
-24
@@ -1,24 +0,0 @@
1 -import 'package:flutter/services.dart';
2 -import 'package:flutter_test/flutter_test.dart';
3 -import 'package:cw_monero/cw_monero_method_channel.dart';
4 -
5 -void main() {
6 - MethodChannelCwMonero platform = MethodChannelCwMonero();
7 - const MethodChannel channel = MethodChannel('cw_monero');
8 -
9 - TestWidgetsFlutterBinding.ensureInitialized();
10 -
11 - setUp(() {
12 - channel.setMockMethodCallHandler((MethodCall methodCall) async {
13 - return '42';
14 - });
15 - });
16 -
17 - tearDown(() {
18 - channel.setMockMethodCallHandler(null);
19 - });
20 -
21 - test('getPlatformVersion', () async {
22 - expect(await platform.getPlatformVersion(), '42');
23 - });
24 -}
cw_monero/test/cw_monero_test.dart deleted
-29
@@ -1,29 +0,0 @@
1 -import 'package:flutter_test/flutter_test.dart';
2 -import 'package:cw_monero/cw_monero.dart';
3 -import 'package:cw_monero/cw_monero_platform_interface.dart';
4 -import 'package:cw_monero/cw_monero_method_channel.dart';
5 -import 'package:plugin_platform_interface/plugin_platform_interface.dart';
6 -
7 -class MockCwMoneroPlatform
8 - with MockPlatformInterfaceMixin
9 - implements CwMoneroPlatform {
10 -
11 - @override
12 - Future<String?> getPlatformVersion() => Future.value('42');
13 -}
14 -
15 -void main() {
16 - final CwMoneroPlatform initialPlatform = CwMoneroPlatform.instance;
17 -
18 - test('$MethodChannelCwMonero is the default instance', () {
19 - expect(initialPlatform, isInstanceOf<MethodChannelCwMonero>());
20 - });
21 -
22 - test('getPlatformVersion', () async {
23 - CwMonero cwMoneroPlugin = CwMonero();
24 - MockCwMoneroPlatform fakePlatform = MockCwMoneroPlatform();
25 - CwMoneroPlatform.instance = fakePlatform;
26 -
27 - expect(await cwMoneroPlugin.getPlatformVersion(), '42');
28 - });
29 -}
cw_wownero/.gitignore new
+5
@@ -0,0 +1,5 @@
1 +.DS_Store
2 +.dart_tool/
3 +
4 +.packages
5 +.pub/
cw_wownero/.metadata new
+30
@@ -0,0 +1,30 @@
1 +# This file tracks properties of this Flutter project.
2 +# Used by Flutter tool to assess capabilities and perform upgrades etc.
3 +#
4 +# This file should be version controlled.
5 +
6 +version:
7 + revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
8 + channel: stable
9 +
10 +project_type: plugin
11 +
12 +# Tracks metadata for the flutter migrate command
13 +migration:
14 + platforms:
15 + - platform: root
16 + create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
17 + base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
18 + - platform: macos
19 + create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
20 + base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
21 +
22 + # User provided section
23 +
24 + # List of Local paths (relative to this file) that should be
25 + # ignored by the migrate tool.
26 + #
27 + # Files that are not part of the templates will be ignored by default.
28 + unmanaged_files:
29 + - 'lib/main.dart'
30 + - 'ios/Runner.xcodeproj/project.pbxproj'
cw_wownero/CHANGELOG.md new
+3
@@ -0,0 +1,3 @@
1 +## 0.0.1
2 +
3 +* TODO: Describe initial release.
cw_wownero/LICENSE new
+21
@@ -0,0 +1,21 @@
1 +MIT License
2 +
3 +Copyright (c) 2020 Cake Technologies LLC
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
\ No newline at end of file
cw_wownero/README.md new
+5
@@ -0,0 +1,5 @@
1 +# cw_wownero
2 +
3 +This project is part of Cake Wallet app.
4 +
5 +Copyright (c) 2020 Cake Technologies LLC.
\ No newline at end of file
cw_wownero/analysis_options.yaml new
+4
@@ -0,0 +1,4 @@
1 +include: package:flutter_lints/flutter.yaml
2 +
3 +# Additional information about this file can be found at
4 +# https://dart.dev/guides/language/analysis-options
cw_wownero/lib/api/account_list.dart new
+72
@@ -0,0 +1,72 @@
1 +import 'package:cw_wownero/api/wallet.dart';
2 +import 'package:monero/wownero.dart' as wownero;
3 +
4 +wownero.wallet? wptr = null;
5 +
6 +int _wlptrForW = 0;
7 +wownero.WalletListener? _wlptr = null;
8 +
9 +wownero.WalletListener getWlptr() {
10 + if (wptr!.address == _wlptrForW) return _wlptr!;
11 + _wlptrForW = wptr!.address;
12 + _wlptr = wownero.WOWNERO_cw_getWalletListener(wptr!);
13 + return _wlptr!;
14 +}
15 +
16 +
17 +wownero.SubaddressAccount? subaddressAccount;
18 +
19 +bool isUpdating = false;
20 +
21 +void refreshAccounts() {
22 + try {
23 + isUpdating = true;
24 + subaddressAccount = wownero.Wallet_subaddressAccount(wptr!);
25 + wownero.SubaddressAccount_refresh(subaddressAccount!);
26 + isUpdating = false;
27 + } catch (e) {
28 + isUpdating = false;
29 + rethrow;
30 + }
31 +}
32 +
33 +List<wownero.SubaddressAccountRow> getAllAccount() {
34 + // final size = wownero.Wallet_numSubaddressAccounts(wptr!);
35 + refreshAccounts();
36 + int size = wownero.SubaddressAccount_getAll_size(subaddressAccount!);
37 + if (size == 0) {
38 + wownero.Wallet_addSubaddressAccount(wptr!);
39 + return getAllAccount();
40 + }
41 + return List.generate(size, (index) {
42 + return wownero.SubaddressAccount_getAll_byIndex(subaddressAccount!, index: index);
43 + });
44 +}
45 +
46 +void addAccountSync({required String label}) {
47 + wownero.Wallet_addSubaddressAccount(wptr!, label: label);
48 +}
49 +
50 +void setLabelForAccountSync({required int accountIndex, required String label}) {
51 + // TODO(mrcyjanek): this may be wrong function?
52 + wownero.Wallet_setSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: 0, label: label);
53 +}
54 +
55 +void _addAccount(String label) => addAccountSync(label: label);
56 +
57 +void _setLabelForAccount(Map<String, dynamic> args) {
58 + final label = args['label'] as String;
59 + final accountIndex = args['accountIndex'] as int;
60 +
61 + setLabelForAccountSync(label: label, accountIndex: accountIndex);
62 +}
63 +
64 +Future<void> addAccount({required String label}) async {
65 + _addAccount(label);
66 + await store();
67 +}
68 +
69 +Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
70 + _setLabelForAccount({'accountIndex': accountIndex, 'label': label});
71 + await store();
72 +}
\ No newline at end of file
cw_wownero/lib/api/coins_info.dart new
+17
@@ -0,0 +1,17 @@
1 +import 'package:cw_wownero/api/account_list.dart';
2 +import 'package:monero/wownero.dart' as wownero;
3 +
4 +wownero.Coins? coins = null;
5 +
6 +void refreshCoins(int accountIndex) {
7 + coins = wownero.Wallet_coins(wptr!);
8 + wownero.Coins_refresh(coins!);
9 +}
10 +
11 +int countOfCoins() => wownero.Coins_count(coins!);
12 +
13 +wownero.CoinsInfo getCoin(int index) => wownero.Coins_coin(coins!, index);
14 +
15 +void freezeCoin(int index) => wownero.Coins_setFrozen(coins!, index: index);
16 +
17 +void thawCoin(int index) => wownero.Coins_thaw(coins!, index: index);
cw_wownero/lib/api/exceptions/connection_to_node_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class ConnectionToNodeException implements Exception {
2 + ConnectionToNodeException({required this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_wownero/lib/api/exceptions/creation_transaction_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class CreationTransactionException implements Exception {
2 + CreationTransactionException({required this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_wownero/lib/api/exceptions/setup_wallet_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class SetupWalletException implements Exception {
2 + SetupWalletException({required this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_wownero/lib/api/exceptions/wallet_creation_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class WalletCreationException implements Exception {
2 + WalletCreationException({required this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_wownero/lib/api/exceptions/wallet_opening_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class WalletOpeningException implements Exception {
2 + WalletOpeningException({required this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_wownero/lib/api/exceptions/wallet_restore_from_keys_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class WalletRestoreFromKeysException implements Exception {
2 + WalletRestoreFromKeysException({required this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_wownero/lib/api/exceptions/wallet_restore_from_seed_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class WalletRestoreFromSeedException implements Exception {
2 + WalletRestoreFromSeedException({required this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_wownero/lib/api/structs/account_row.dart new
+12
@@ -0,0 +1,12 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class AccountRow extends Struct {
5 + @Int64()
6 + external int id;
7 +
8 + external Pointer<Utf8> label;
9 +
10 + String getLabel() => label.toDartString();
11 + int getId() => id;
12 +}
cw_wownero/lib/api/structs/coins_info_row.dart new
+73
@@ -0,0 +1,73 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class CoinsInfoRow extends Struct {
5 + @Int64()
6 + external int blockHeight;
7 +
8 + external Pointer<Utf8> hash;
9 +
10 + @Uint64()
11 + external int internalOutputIndex;
12 +
13 + @Uint64()
14 + external int globalOutputIndex;
15 +
16 + @Int8()
17 + external int spent;
18 +
19 + @Int8()
20 + external int frozen;
21 +
22 + @Uint64()
23 + external int spentHeight;
24 +
25 + @Uint64()
26 + external int amount;
27 +
28 + @Int8()
29 + external int rct;
30 +
31 + @Int8()
32 + external int keyImageKnown;
33 +
34 + @Uint64()
35 + external int pkIndex;
36 +
37 + @Uint32()
38 + external int subaddrIndex;
39 +
40 + @Uint32()
41 + external int subaddrAccount;
42 +
43 + external Pointer<Utf8> address;
44 +
45 + external Pointer<Utf8> addressLabel;
46 +
47 + external Pointer<Utf8> keyImage;
48 +
49 + @Uint64()
50 + external int unlockTime;
51 +
52 + @Int8()
53 + external int unlocked;
54 +
55 + external Pointer<Utf8> pubKey;
56 +
57 + @Int8()
58 + external int coinbase;
59 +
60 + external Pointer<Utf8> description;
61 +
62 + String getHash() => hash.toDartString();
63 +
64 + String getAddress() => address.toDartString();
65 +
66 + String getAddressLabel() => addressLabel.toDartString();
67 +
68 + String getKeyImage() => keyImage.toDartString();
69 +
70 + String getPubKey() => pubKey.toDartString();
71 +
72 + String getDescription() => description.toDartString();
73 +}
cw_wownero/lib/api/structs/pending_transaction.dart new
+17
@@ -0,0 +1,17 @@
1 +
2 +class PendingTransactionDescription {
3 + PendingTransactionDescription({
4 + required this.amount,
5 + required this.fee,
6 + required this.hash,
7 + required this.hex,
8 + required this.txKey,
9 + required this.pointerAddress});
10 +
11 + final int amount;
12 + final int fee;
13 + final String hash;
14 + final String hex;
15 + final String txKey;
16 + final int pointerAddress;
17 +}
\ No newline at end of file
cw_wownero/lib/api/structs/subaddress_row.dart new
+15
@@ -0,0 +1,15 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class SubaddressRow extends Struct {
5 + @Int64()
6 + external int id;
7 +
8 + external Pointer<Utf8> address;
9 +
10 + external Pointer<Utf8> label;
11 +
12 + String getLabel() => label.toDartString();
13 + String getAddress() => address.toDartString();
14 + int getId() => id;
15 +}
\ No newline at end of file
cw_wownero/lib/api/structs/transaction_info_row.dart new
+41
@@ -0,0 +1,41 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class TransactionInfoRow extends Struct {
5 + @Uint64()
6 + external int amount;
7 +
8 + @Uint64()
9 + external int fee;
10 +
11 + @Uint64()
12 + external int blockHeight;
13 +
14 + @Uint64()
15 + external int confirmations;
16 +
17 + @Uint32()
18 + external int subaddrAccount;
19 +
20 + @Int8()
21 + external int direction;
22 +
23 + @Int8()
24 + external int isPending;
25 +
26 + @Uint32()
27 + external int subaddrIndex;
28 +
29 + external Pointer<Utf8> hash;
30 +
31 + external Pointer<Utf8> paymentId;
32 +
33 + @Int64()
34 + external int datetime;
35 +
36 + int getDatetime() => datetime;
37 + int getAmount() => amount >= 0 ? amount : amount * -1;
38 + bool getIsPending() => isPending != 0;
39 + String getHash() => hash.toDartString();
40 + String getPaymentId() => paymentId.toDartString();
41 +}
cw_wownero/lib/api/structs/ut8_box.dart new
+8
@@ -0,0 +1,8 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class Utf8Box extends Struct {
5 + external Pointer<Utf8> value;
6 +
7 + String getValue() => value.toDartString();
8 +}
cw_wownero/lib/api/subaddress_list.dart new
+91
@@ -0,0 +1,91 @@
1 +import 'package:cw_wownero/api/account_list.dart';
2 +import 'package:cw_wownero/api/wallet.dart';
3 +import 'package:monero/wownero.dart' as wownero;
4 +
5 +bool isUpdating = false;
6 +
7 +class SubaddressInfoMetadata {
8 + SubaddressInfoMetadata({
9 + required this.accountIndex,
10 + });
11 + int accountIndex;
12 +}
13 +
14 +SubaddressInfoMetadata? subaddress = null;
15 +
16 +void refreshSubaddresses({required int accountIndex}) {
17 + try {
18 + isUpdating = true;
19 + subaddress = SubaddressInfoMetadata(accountIndex: accountIndex);
20 + isUpdating = false;
21 + } catch (e) {
22 + isUpdating = false;
23 + rethrow;
24 + }
25 +}
26 +
27 +class Subaddress {
28 + Subaddress({
29 + required this.addressIndex,
30 + required this.accountIndex,
31 + });
32 + String get address => wownero.Wallet_address(
33 + wptr!,
34 + accountIndex: accountIndex,
35 + addressIndex: addressIndex,
36 + );
37 + final int addressIndex;
38 + final int accountIndex;
39 + String get label => wownero.Wallet_getSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex);
40 +}
41 +
42 +List<Subaddress> getAllSubaddresses() {
43 + final size = wownero.Wallet_numSubaddresses(wptr!, accountIndex: subaddress!.accountIndex);
44 + return List.generate(size, (index) {
45 + return Subaddress(
46 + accountIndex: subaddress!.accountIndex,
47 + addressIndex: index,
48 + );
49 + }).reversed.toList();
50 +}
51 +
52 +void addSubaddressSync({required int accountIndex, required String label}) {
53 + wownero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex, label: label);
54 + refreshSubaddresses(accountIndex: accountIndex);
55 +}
56 +
57 +void setLabelForSubaddressSync(
58 + {required int accountIndex, required int addressIndex, required String label}) {
59 + wownero.Wallet_setSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex, label: label);
60 +}
61 +
62 +void _addSubaddress(Map<String, dynamic> args) {
63 + final label = args['label'] as String;
64 + final accountIndex = args['accountIndex'] as int;
65 +
66 + addSubaddressSync(accountIndex: accountIndex, label: label);
67 +}
68 +
69 +void _setLabelForSubaddress(Map<String, dynamic> args) {
70 + final label = args['label'] as String;
71 + final accountIndex = args['accountIndex'] as int;
72 + final addressIndex = args['addressIndex'] as int;
73 +
74 + setLabelForSubaddressSync(
75 + accountIndex: accountIndex, addressIndex: addressIndex, label: label);
76 +}
77 +
78 +Future<void> addSubaddress({required int accountIndex, required String label}) async {
79 + _addSubaddress({'accountIndex': accountIndex, 'label': label});
80 + await store();
81 +}
82 +
83 +Future<void> setLabelForSubaddress(
84 + {required int accountIndex, required int addressIndex, required String label}) async {
85 + _setLabelForSubaddress({
86 + 'accountIndex': accountIndex,
87 + 'addressIndex': addressIndex,
88 + 'label': label
89 + });
90 + await store();
91 +}
cw_wownero/lib/api/transaction_history.dart new
+324
@@ -0,0 +1,324 @@
1 +import 'dart:ffi';
2 +import 'dart:isolate';
3 +
4 +import 'package:cw_wownero/api/account_list.dart';
5 +import 'package:cw_wownero/api/exceptions/creation_transaction_exception.dart';
6 +import 'package:cw_wownero/api/wownero_output.dart';
7 +import 'package:cw_wownero/api/structs/pending_transaction.dart';
8 +import 'package:ffi/ffi.dart';
9 +import 'package:monero/wownero.dart' as wownero;
10 +import 'package:monero/src/generated_bindings_wownero.g.dart' as wownero_gen;
11 +
12 +
13 +String getTxKey(String txId) {
14 + return wownero.Wallet_getTxKey(wptr!, txid: txId);
15 +}
16 +
17 +wownero.TransactionHistory? txhistory;
18 +
19 +void refreshTransactions() {
20 + txhistory = wownero.Wallet_history(wptr!);
21 + wownero.TransactionHistory_refresh(txhistory!);
22 +}
23 +
24 +int countOfTransactions() => wownero.TransactionHistory_count(txhistory!);
25 +
26 +List<Transaction> getAllTransactions() {
27 + List<Transaction> dummyTxs = [];
28 +
29 + txhistory = wownero.Wallet_history(wptr!);
30 + wownero.TransactionHistory_refresh(txhistory!);
31 + int size = countOfTransactions();
32 + final list = List.generate(size, (index) => Transaction(txInfo: wownero.TransactionHistory_transaction(txhistory!, index: index)))..addAll(dummyTxs);
33 +
34 + final accts = wownero.Wallet_numSubaddressAccounts(wptr!);
35 + for (var i = 0; i < accts; i++) {
36 + final fullBalance = wownero.Wallet_balance(wptr!, accountIndex: i);
37 + final availBalance = wownero.Wallet_unlockedBalance(wptr!, accountIndex: i);
38 + if (fullBalance > availBalance) {
39 + if (list.where((element) => element.accountIndex == i && element.isConfirmed == false).isNotEmpty) {
40 + dummyTxs.add(
41 + Transaction.dummy(
42 + displayLabel: "",
43 + description: "",
44 + fee: 0,
45 + confirmations: 0,
46 + blockheight: 0,
47 + accountIndex: i,
48 + paymentId: "",
49 + amount: fullBalance - availBalance,
50 + isSpend: false,
51 + hash: "pending",
52 + key: "pending",
53 + txInfo: Pointer.fromAddress(0),
54 + )..timeStamp = DateTime.now()
55 + );
56 + }
57 + }
58 + }
59 + list.addAll(dummyTxs);
60 + return list;
61 +}
62 +
63 +// TODO(mrcyjanek): ...
64 +Transaction getTransaction(String txId) {
65 + return Transaction(txInfo: wownero.TransactionHistory_transactionById(txhistory!, txid: txId));
66 +}
67 +
68 +Future<PendingTransactionDescription> createTransactionSync(
69 + {required String address,
70 + required String paymentId,
71 + required int priorityRaw,
72 + String? amount,
73 + int accountIndex = 0,
74 + List<String> preferredInputs = const []}) async {
75 +
76 + final amt = amount == null ? 0 : wownero.Wallet_amountFromString(amount);
77 +
78 + final address_ = address.toNativeUtf8();
79 + final paymentId_ = paymentId.toNativeUtf8();
80 + final preferredInputs_ = preferredInputs.join(wownero.defaultSeparatorStr).toNativeUtf8();
81 +
82 + final waddr = wptr!.address;
83 + final addraddr = address_.address;
84 + final paymentIdAddr = paymentId_.address;
85 + final preferredInputsAddr = preferredInputs_.address;
86 + final spaddr = wownero.defaultSeparator.address;
87 + final pendingTx = Pointer<Void>.fromAddress(await Isolate.run(() {
88 + final tx = wownero_gen.WowneroC(DynamicLibrary.open(wownero.libPath)).WOWNERO_Wallet_createTransaction(
89 + Pointer.fromAddress(waddr),
90 + Pointer.fromAddress(addraddr).cast(),
91 + Pointer.fromAddress(paymentIdAddr).cast(),
92 + amt,
93 + 1,
94 + priorityRaw,
95 + accountIndex,
96 + Pointer.fromAddress(preferredInputsAddr).cast(),
97 + Pointer.fromAddress(spaddr),
98 + );
99 + return tx.address;
100 + }));
101 + calloc.free(address_);
102 + calloc.free(paymentId_);
103 + calloc.free(preferredInputs_);
104 + final String? error = (() {
105 + final status = wownero.PendingTransaction_status(pendingTx);
106 + if (status == 0) {
107 + return null;
108 + }
109 + return wownero.PendingTransaction_errorString(pendingTx);
110 + })();
111 +
112 + if (error != null) {
113 + final message = error;
114 + throw CreationTransactionException(message: message);
115 + }
116 +
117 + final rAmt = wownero.PendingTransaction_amount(pendingTx);
118 + final rFee = wownero.PendingTransaction_fee(pendingTx);
119 + final rHash = wownero.PendingTransaction_txid(pendingTx, '');
120 + final rTxKey = rHash;
121 +
122 + return PendingTransactionDescription(
123 + amount: rAmt,
124 + fee: rFee,
125 + hash: rHash,
126 + hex: '',
127 + txKey: rTxKey,
128 + pointerAddress: pendingTx.address,
129 + );
130 +}
131 +
132 +PendingTransactionDescription createTransactionMultDestSync(
133 + {required List<WowneroOutput> outputs,
134 + required String paymentId,
135 + required int priorityRaw,
136 + int accountIndex = 0,
137 + List<String> preferredInputs = const []}) {
138 +
139 + final txptr = wownero.Wallet_createTransactionMultDest(
140 + wptr!,
141 + dstAddr: outputs.map((e) => e.address).toList(),
142 + isSweepAll: false,
143 + amounts: outputs.map((e) => wownero.Wallet_amountFromString(e.amount)).toList(),
144 + mixinCount: 0,
145 + pendingTransactionPriority: priorityRaw,
146 + subaddr_account: accountIndex,
147 + );
148 + if (wownero.PendingTransaction_status(txptr) != 0) {
149 + throw CreationTransactionException(message: wownero.PendingTransaction_errorString(txptr));
150 + }
151 + return PendingTransactionDescription(
152 + amount: wownero.PendingTransaction_amount(txptr),
153 + fee: wownero.PendingTransaction_fee(txptr),
154 + hash: wownero.PendingTransaction_txid(txptr, ''),
155 + hex: wownero.PendingTransaction_txid(txptr, ''),
156 + txKey: wownero.PendingTransaction_txid(txptr, ''),
157 + pointerAddress: txptr.address,
158 + );
159 +}
160 +
161 +void commitTransactionFromPointerAddress({required int address}) =>
162 + commitTransaction(transactionPointer: wownero.PendingTransaction.fromAddress(address));
163 +
164 +void commitTransaction({required wownero.PendingTransaction transactionPointer}) {
165 +
166 + final txCommit = wownero.PendingTransaction_commit(transactionPointer, filename: '', overwrite: false);
167 +
168 + final String? error = (() {
169 + final status = wownero.PendingTransaction_status(transactionPointer.cast());
170 + if (status == 0) {
171 + return null;
172 + }
173 + return wownero.Wallet_errorString(wptr!);
174 + })();
175 +
176 + if (error != null) {
177 + throw CreationTransactionException(message: error);
178 + }
179 +}
180 +
181 +Future<PendingTransactionDescription> _createTransactionSync(Map args) async {
182 + final address = args['address'] as String;
183 + final paymentId = args['paymentId'] as String;
184 + final amount = args['amount'] as String?;
185 + final priorityRaw = args['priorityRaw'] as int;
186 + final accountIndex = args['accountIndex'] as int;
187 + final preferredInputs = args['preferredInputs'] as List<String>;
188 +
189 + return createTransactionSync(
190 + address: address,
191 + paymentId: paymentId,
192 + amount: amount,
193 + priorityRaw: priorityRaw,
194 + accountIndex: accountIndex,
195 + preferredInputs: preferredInputs);
196 +}
197 +
198 +PendingTransactionDescription _createTransactionMultDestSync(Map args) {
199 + final outputs = args['outputs'] as List<WowneroOutput>;
200 + final paymentId = args['paymentId'] as String;
201 + final priorityRaw = args['priorityRaw'] as int;
202 + final accountIndex = args['accountIndex'] as int;
203 + final preferredInputs = args['preferredInputs'] as List<String>;
204 +
205 + return createTransactionMultDestSync(
206 + outputs: outputs,
207 + paymentId: paymentId,
208 + priorityRaw: priorityRaw,
209 + accountIndex: accountIndex,
210 + preferredInputs: preferredInputs);
211 +}
212 +
213 +Future<PendingTransactionDescription> createTransaction(
214 + {required String address,
215 + required int priorityRaw,
216 + String? amount,
217 + String paymentId = '',
218 + int accountIndex = 0,
219 + List<String> preferredInputs = const []}) async =>
220 + _createTransactionSync({
221 + 'address': address,
222 + 'paymentId': paymentId,
223 + 'amount': amount,
224 + 'priorityRaw': priorityRaw,
225 + 'accountIndex': accountIndex,
226 + 'preferredInputs': preferredInputs
227 + });
228 +
229 +Future<PendingTransactionDescription> createTransactionMultDest(
230 + {required List<WowneroOutput> outputs,
231 + required int priorityRaw,
232 + String paymentId = '',
233 + int accountIndex = 0,
234 + List<String> preferredInputs = const []}) async =>
235 + _createTransactionMultDestSync({
236 + 'outputs': outputs,
237 + 'paymentId': paymentId,
238 + 'priorityRaw': priorityRaw,
239 + 'accountIndex': accountIndex,
240 + 'preferredInputs': preferredInputs
241 + });
242 +
243 +
244 +class Transaction {
245 + final String displayLabel;
246 + String subaddressLabel = wownero.Wallet_getSubaddressLabel(wptr!, accountIndex: 0, addressIndex: 0);
247 + late final String address = wownero.Wallet_address(
248 + wptr!,
249 + accountIndex: 0,
250 + addressIndex: 0,
251 + );
252 + final String description;
253 + final int fee;
254 + final int confirmations;
255 + late final bool isPending = confirmations < 3;
256 + final int blockheight;
257 + final int addressIndex = 0;
258 + final int accountIndex;
259 + final String paymentId;
260 + final int amount;
261 + final bool isSpend;
262 + late DateTime timeStamp;
263 + late final bool isConfirmed = !isPending;
264 + final String hash;
265 + final String key;
266 +
267 + Map<String, dynamic> toJson() {
268 + return {
269 + "displayLabel": displayLabel,
270 + "subaddressLabel": subaddressLabel,
271 + "address": address,
272 + "description": description,
273 + "fee": fee,
274 + "confirmations": confirmations,
275 + "isPending": isPending,
276 + "blockheight": blockheight,
277 + "accountIndex": accountIndex,
278 + "addressIndex": addressIndex,
279 + "paymentId": paymentId,
280 + "amount": amount,
281 + "isSpend": isSpend,
282 + "timeStamp": timeStamp.toIso8601String(),
283 + "isConfirmed": isConfirmed,
284 + "hash": hash,
285 + };
286 + }
287 +
288 + // S finalubAddress? subAddress;
289 + // List<Transfer> transfers = [];
290 + // final int txIndex;
291 + final wownero.TransactionInfo txInfo;
292 + Transaction({
293 + required this.txInfo,
294 + }) : displayLabel = wownero.TransactionInfo_label(txInfo),
295 + hash = wownero.TransactionInfo_hash(txInfo),
296 + timeStamp = DateTime.fromMillisecondsSinceEpoch(
297 + wownero.TransactionInfo_timestamp(txInfo) * 1000,
298 + ),
299 + isSpend = wownero.TransactionInfo_direction(txInfo) ==
300 + wownero.TransactionInfo_Direction.Out,
301 + amount = wownero.TransactionInfo_amount(txInfo),
302 + paymentId = wownero.TransactionInfo_paymentId(txInfo),
303 + accountIndex = wownero.TransactionInfo_subaddrAccount(txInfo),
304 + blockheight = wownero.TransactionInfo_blockHeight(txInfo),
305 + confirmations = wownero.TransactionInfo_confirmations(txInfo),
306 + fee = wownero.TransactionInfo_fee(txInfo),
307 + description = wownero.TransactionInfo_description(txInfo),
308 + key = wownero.Wallet_getTxKey(wptr!, txid: wownero.TransactionInfo_hash(txInfo));
309 +
310 + Transaction.dummy({
311 + required this.displayLabel,
312 + required this.description,
313 + required this.fee,
314 + required this.confirmations,
315 + required this.blockheight,
316 + required this.accountIndex,
317 + required this.paymentId,
318 + required this.amount,
319 + required this.isSpend,
320 + required this.hash,
321 + required this.key,
322 + required this.txInfo
323 + });
324 +}
\ No newline at end of file
cw_wownero/lib/api/wallet.dart new
+295
@@ -0,0 +1,295 @@
1 +import 'dart:async';
2 +import 'dart:ffi';
3 +import 'dart:isolate';
4 +
5 +import 'package:cw_wownero/api/account_list.dart';
6 +import 'package:cw_wownero/api/exceptions/setup_wallet_exception.dart';
7 +import 'package:monero/wownero.dart' as wownero;
8 +import 'package:mutex/mutex.dart';
9 +
10 +int getSyncingHeight() {
11 + // final height = wownero.WOWNERO_cw_WalletListener_height(getWlptr());
12 + final h2 = wownero.Wallet_blockChainHeight(wptr!);
13 + // print("height: $height / $h2");
14 + return h2;
15 +}
16 +
17 +bool isNeededToRefresh() {
18 + // final ret = wownero.WOWNERO_cw_WalletListener_isNeedToRefresh(getWlptr());
19 + // wownero.WOWNERO_cw_WalletListener_resetNeedToRefresh(getWlptr());
20 + return true;
21 +}
22 +
23 +bool isNewTransactionExist() {
24 + // final ret =
25 + // wownero.WOWNERO_cw_WalletListener_isNewTransactionExist(getWlptr());
26 + // wownero.WOWNERO_cw_WalletListener_resetIsNewTransactionExist(getWlptr());
27 + // NOTE: I don't know why wownero is being funky, but
28 + return true;
29 +}
30 +
31 +String getFilename() => wownero.Wallet_filename(wptr!);
32 +
33 +String getSeed() {
34 + // wownero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
35 + final cakepolyseed =
36 + wownero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.seed");
37 + if (cakepolyseed != "") {
38 + return cakepolyseed;
39 + }
40 + final polyseed = wownero.Wallet_getPolyseed(wptr!, passphrase: '');
41 + if (polyseed != "") {
42 + return polyseed;
43 + }
44 + final legacy = wownero.Wallet_seed(wptr!, seedOffset: '');
45 + return legacy;
46 +}
47 +
48 +String getSeedLegacy(String? language) {
49 + var legacy = wownero.Wallet_seed(wptr!, seedOffset: '');
50 + if (wownero.Wallet_status(wptr!) != 0) {
51 + wownero.Wallet_setSeedLanguage(wptr!, language: language ?? "English");
52 + legacy = wownero.Wallet_seed(wptr!, seedOffset: '');
53 + }
54 + return legacy;
55 +}
56 +
57 +String getAddress({int accountIndex = 0, int addressIndex = 1}) =>
58 + wownero.Wallet_address(wptr!,
59 + accountIndex: accountIndex, addressIndex: addressIndex);
60 +
61 +int getFullBalance({int accountIndex = 0}) =>
62 + wownero.Wallet_balance(wptr!, accountIndex: accountIndex);
63 +
64 +int getUnlockedBalance({int accountIndex = 0}) =>
65 + wownero.Wallet_unlockedBalance(wptr!, accountIndex: accountIndex);
66 +
67 +int getCurrentHeight() => wownero.Wallet_blockChainHeight(wptr!);
68 +
69 +int getNodeHeightSync() => wownero.Wallet_daemonBlockChainHeight(wptr!);
70 +
71 +bool isConnectedSync() => wownero.Wallet_connected(wptr!) != 0;
72 +
73 +Future<bool> setupNodeSync(
74 + {required String address,
75 + String? login,
76 + String? password,
77 + bool useSSL = false,
78 + bool isLightWallet = false,
79 + String? socksProxyAddress}) async {
80 + print('''
81 +{
82 + wptr!,
83 + daemonAddress: $address,
84 + useSsl: $useSSL,
85 + proxyAddress: $socksProxyAddress ?? '',
86 + daemonUsername: $login ?? '',
87 + daemonPassword: $password ?? ''
88 +}
89 +''');
90 + final addr = wptr!.address;
91 + await Isolate.run(() {
92 + wownero.Wallet_init(Pointer.fromAddress(addr),
93 + daemonAddress: address,
94 + useSsl: useSSL,
95 + proxyAddress: socksProxyAddress ?? '',
96 + daemonUsername: login ?? '',
97 + daemonPassword: password ?? '');
98 + });
99 + // wownero.Wallet_init3(wptr!, argv0: '', defaultLogBaseName: 'wowneroc', console: true);
100 +
101 + final status = wownero.Wallet_status(wptr!);
102 +
103 + if (status != 0) {
104 + final error = wownero.Wallet_errorString(wptr!);
105 + print("error: $error");
106 + throw SetupWalletException(message: error);
107 + }
108 +
109 + return status == 0;
110 +}
111 +
112 +void startRefreshSync() {
113 + wownero.Wallet_refreshAsync(wptr!);
114 + wownero.Wallet_startRefresh(wptr!);
115 +}
116 +
117 +Future<bool> connectToNode() async {
118 + return true;
119 +}
120 +
121 +void setRefreshFromBlockHeight({required int height}) =>
122 + wownero.Wallet_setRefreshFromBlockHeight(wptr!,
123 + refresh_from_block_height: height);
124 +
125 +void setRecoveringFromSeed({required bool isRecovery}) =>
126 + wownero.Wallet_setRecoveringFromSeed(wptr!, recoveringFromSeed: isRecovery);
127 +
128 +final storeMutex = Mutex();
129 +void storeSync() async {
130 + await storeMutex.acquire();
131 + final addr = wptr!.address;
132 + Isolate.run(() {
133 + wownero.Wallet_store(Pointer.fromAddress(addr));
134 + });
135 + storeMutex.release();
136 +}
137 +
138 +void setPasswordSync(String password) {
139 + wownero.Wallet_setPassword(wptr!, password: password);
140 +
141 + final status = wownero.Wallet_status(wptr!);
142 + if (status != 0) {
143 + throw Exception(wownero.Wallet_errorString(wptr!));
144 + }
145 +}
146 +
147 +void closeCurrentWallet() {
148 + wownero.Wallet_stop(wptr!);
149 +}
150 +
151 +String getSecretViewKey() => wownero.Wallet_secretViewKey(wptr!);
152 +
153 +String getPublicViewKey() => wownero.Wallet_publicViewKey(wptr!);
154 +
155 +String getSecretSpendKey() => wownero.Wallet_secretSpendKey(wptr!);
156 +
157 +String getPublicSpendKey() => wownero.Wallet_publicSpendKey(wptr!);
158 +
159 +class SyncListener {
160 + SyncListener(this.onNewBlock, this.onNewTransaction)
161 + : _cachedBlockchainHeight = 0,
162 + _lastKnownBlockHeight = 0,
163 + _initialSyncHeight = 0;
164 +
165 + void Function(int, int, double) onNewBlock;
166 + void Function() onNewTransaction;
167 +
168 + Timer? _updateSyncInfoTimer;
169 + int _cachedBlockchainHeight;
170 + int _lastKnownBlockHeight;
171 + int _initialSyncHeight;
172 +
173 + Future<int> getNodeHeightOrUpdate(int baseHeight) async {
174 + if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) {
175 + _cachedBlockchainHeight = await getNodeHeight();
176 + }
177 +
178 + return _cachedBlockchainHeight;
179 + }
180 +
181 + void start() {
182 + _cachedBlockchainHeight = 0;
183 + _lastKnownBlockHeight = 0;
184 + _initialSyncHeight = 0;
185 + _updateSyncInfoTimer ??=
186 + Timer.periodic(Duration(milliseconds: 1200), (_) async {
187 + if (isNewTransactionExist()) {
188 + onNewTransaction();
189 + }
190 +
191 + var syncHeight = getSyncingHeight();
192 +
193 + if (syncHeight <= 0) {
194 + syncHeight = getCurrentHeight();
195 + }
196 +
197 + if (_initialSyncHeight <= 0) {
198 + _initialSyncHeight = syncHeight;
199 + }
200 +
201 + final bchHeight = await getNodeHeightOrUpdate(syncHeight);
202 +
203 + if (_lastKnownBlockHeight == syncHeight) {
204 + return;
205 + }
206 +
207 + _lastKnownBlockHeight = syncHeight;
208 + final track = bchHeight - _initialSyncHeight;
209 + final diff = track - (bchHeight - syncHeight);
210 + final ptc = diff <= 0 ? 0.0 : diff / track;
211 + final left = bchHeight - syncHeight;
212 +
213 + if (syncHeight < 0 || left < 0) {
214 + return;
215 + }
216 +
217 + // 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
218 + onNewBlock.call(syncHeight, left, ptc);
219 + });
220 + }
221 +
222 + void stop() => _updateSyncInfoTimer?.cancel();
223 +}
224 +
225 +SyncListener setListeners(void Function(int, int, double) onNewBlock,
226 + void Function() onNewTransaction) {
227 + final listener = SyncListener(onNewBlock, onNewTransaction);
228 + // setListenerNative();
229 + return listener;
230 +}
231 +
232 +void onStartup() {}
233 +
234 +void _storeSync(Object _) => storeSync();
235 +
236 +Future<bool> _setupNodeSync(Map<String, Object?> args) async {
237 + final address = args['address'] as String;
238 + final login = (args['login'] ?? '') as String;
239 + final password = (args['password'] ?? '') as String;
240 + final useSSL = args['useSSL'] as bool;
241 + final isLightWallet = args['isLightWallet'] as bool;
242 + final socksProxyAddress = (args['socksProxyAddress'] ?? '') as String;
243 +
244 + return setupNodeSync(
245 + address: address,
246 + login: login,
247 + password: password,
248 + useSSL: useSSL,
249 + isLightWallet: isLightWallet,
250 + socksProxyAddress: socksProxyAddress);
251 +}
252 +
253 +bool _isConnected(Object _) => isConnectedSync();
254 +
255 +int _getNodeHeight(Object _) => getNodeHeightSync();
256 +
257 +void startRefresh() => startRefreshSync();
258 +
259 +Future<void> setupNode(
260 + {required String address,
261 + String? login,
262 + String? password,
263 + bool useSSL = false,
264 + String? socksProxyAddress,
265 + bool isLightWallet = false}) async =>
266 + _setupNodeSync({
267 + 'address': address,
268 + 'login': login,
269 + 'password': password,
270 + 'useSSL': useSSL,
271 + 'isLightWallet': isLightWallet,
272 + 'socksProxyAddress': socksProxyAddress
273 + });
274 +
275 +Future<void> store() async => _storeSync(0);
276 +
277 +Future<bool> isConnected() async => _isConnected(0);
278 +
279 +Future<int> getNodeHeight() async => _getNodeHeight(0);
280 +
281 +void rescanBlockchainAsync() => wownero.Wallet_rescanBlockchainAsync(wptr!);
282 +
283 +String getSubaddressLabel(int accountIndex, int addressIndex) {
284 + return wownero.Wallet_getSubaddressLabel(wptr!,
285 + accountIndex: accountIndex, addressIndex: addressIndex);
286 +}
287 +
288 +Future setTrustedDaemon(bool trusted) async =>
289 + wownero.Wallet_setTrustedDaemon(wptr!, arg: trusted);
290 +
291 +Future<bool> trustedDaemon() async => wownero.Wallet_trustedDaemon(wptr!);
292 +
293 +String signMessage(String message, {String address = ""}) {
294 + return wownero.Wallet_signMessage(wptr!, message: message, address: address);
295 +}
cw_wownero/lib/api/wallet_manager.dart new
+359
@@ -0,0 +1,359 @@
1 +import 'dart:ffi';
2 +import 'dart:isolate';
3 +
4 +import 'package:cw_wownero/api/account_list.dart';
5 +import 'package:cw_wownero/api/exceptions/wallet_creation_exception.dart';
6 +import 'package:cw_wownero/api/exceptions/wallet_opening_exception.dart';
7 +import 'package:cw_wownero/api/exceptions/wallet_restore_from_keys_exception.dart';
8 +import 'package:cw_wownero/api/exceptions/wallet_restore_from_seed_exception.dart';
9 +import 'package:cw_wownero/api/wallet.dart';
10 +import 'package:monero/wownero.dart' as wownero;
11 +
12 +wownero.WalletManager? _wmPtr;
13 +final wownero.WalletManager wmPtr = Pointer.fromAddress((() {
14 + try {
15 + // Problems with the wallet? Crashes? Lags? this will print all calls to wow
16 + // codebase, so it will be easier to debug what happens. At least easier
17 + // than plugging gdb in. Especially on windows/android.
18 + wownero.printStarts = false;
19 + _wmPtr ??= wownero.WalletManagerFactory_getWalletManager();
20 + print("ptr: $_wmPtr");
21 + } catch (e) {
22 + print(e);
23 + }
24 + return _wmPtr!.address;
25 +})());
26 +
27 +void createWalletSync(
28 + {required String path,
29 + required String password,
30 + required String language,
31 + int nettype = 0}) {
32 + wptr = wownero.WalletManager_createWallet(wmPtr,
33 + path: path, password: password, language: language, networkType: 0);
34 +
35 + final status = wownero.Wallet_status(wptr!);
36 + if (status != 0) {
37 + throw WalletCreationException(message: wownero.Wallet_errorString(wptr!));
38 + }
39 + wownero.Wallet_store(wptr!, path: path);
40 + openedWalletsByPath[path] = wptr!;
41 +
42 + // is the line below needed?
43 + // setupNodeSync(address: "node.wowneroworld.com:18089");
44 +}
45 +
46 +bool isWalletExistSync({required String path}) {
47 + return wownero.WalletManager_walletExists(wmPtr, path);
48 +}
49 +
50 +void restoreWalletFromSeedSync(
51 + {required String path,
52 + required String password,
53 + required String seed,
54 + int nettype = 0,
55 + int restoreHeight = 0}) {
56 + if (seed.split(" ").length == 14) {
57 + wptr = wownero.WOWNERO_deprecated_restore14WordSeed(
58 + path: path,
59 + password: password,
60 + language: seed, // I KNOW - this is supposed to be called seed
61 + networkType: 0,
62 + );
63 +
64 + setRefreshFromBlockHeight(
65 + height: wownero.WOWNERO_deprecated_14WordSeedHeight(seed: seed),
66 + );
67 + } else {
68 + wptr = wownero.WalletManager_recoveryWallet(
69 + wmPtr,
70 + path: path,
71 + password: password,
72 + mnemonic: seed,
73 + restoreHeight: restoreHeight,
74 + seedOffset: '',
75 + networkType: 0,
76 + );
77 + }
78 +
79 + final status = wownero.Wallet_status(wptr!);
80 +
81 + if (status != 0) {
82 + final error = wownero.Wallet_errorString(wptr!);
83 + throw WalletRestoreFromSeedException(message: error);
84 + }
85 +
86 + openedWalletsByPath[path] = wptr!;
87 +}
88 +
89 +void restoreWalletFromKeysSync(
90 + {required String path,
91 + required String password,
92 + required String language,
93 + required String address,
94 + required String viewKey,
95 + required String spendKey,
96 + int nettype = 0,
97 + int restoreHeight = 0}) {
98 + wptr = wownero.WalletManager_createWalletFromKeys(
99 + wmPtr,
100 + path: path,
101 + password: password,
102 + restoreHeight: restoreHeight,
103 + addressString: address,
104 + viewKeyString: viewKey,
105 + spendKeyString: spendKey,
106 + nettype: 0,
107 + );
108 +
109 + final status = wownero.Wallet_status(wptr!);
110 + if (status != 0) {
111 + throw WalletRestoreFromKeysException(
112 + message: wownero.Wallet_errorString(wptr!));
113 + }
114 +
115 + openedWalletsByPath[path] = wptr!;
116 +}
117 +
118 +void restoreWalletFromSpendKeySync(
119 + {required String path,
120 + required String password,
121 + required String seed,
122 + required String language,
123 + required String spendKey,
124 + int nettype = 0,
125 + int restoreHeight = 0}) {
126 + // wptr = wownero.WalletManager_createWalletFromKeys(
127 + // wmPtr,
128 + // path: path,
129 + // password: password,
130 + // restoreHeight: restoreHeight,
131 + // addressString: '',
132 + // spendKeyString: spendKey,
133 + // viewKeyString: '',
134 + // nettype: 0,
135 + // );
136 +
137 + wptr = wownero.WalletManager_createDeterministicWalletFromSpendKey(
138 + wmPtr,
139 + path: path,
140 + password: password,
141 + language: language,
142 + spendKeyString: spendKey,
143 + newWallet: true, // TODO(mrcyjanek): safe to remove
144 + restoreHeight: restoreHeight,
145 + );
146 +
147 + final status = wownero.Wallet_status(wptr!);
148 +
149 + if (status != 0) {
150 + final err = wownero.Wallet_errorString(wptr!);
151 + print("err: $err");
152 + throw WalletRestoreFromKeysException(message: err);
153 + }
154 +
155 + wownero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
156 +
157 + storeSync();
158 +
159 + openedWalletsByPath[path] = wptr!;
160 +}
161 +
162 +String _lastOpenedWallet = "";
163 +
164 +// void restoreWowneroWalletFromDevice(
165 +// {required String path,
166 +// required String password,
167 +// required String deviceName,
168 +// int nettype = 0,
169 +// int restoreHeight = 0}) {
170 +//
171 +// final pathPointer = path.toNativeUtf8();
172 +// final passwordPointer = password.toNativeUtf8();
173 +// final deviceNamePointer = deviceName.toNativeUtf8();
174 +// final errorMessagePointer = ''.toNativeUtf8();
175 +//
176 +// final isWalletRestored = restoreWalletFromDeviceNative(
177 +// pathPointer,
178 +// passwordPointer,
179 +// deviceNamePointer,
180 +// nettype,
181 +// restoreHeight,
182 +// errorMessagePointer) != 0;
183 +//
184 +// calloc.free(pathPointer);
185 +// calloc.free(passwordPointer);
186 +//
187 +// storeSync();
188 +//
189 +// if (!isWalletRestored) {
190 +// throw WalletRestoreFromKeysException(
191 +// message: convertUTF8ToString(pointer: errorMessagePointer));
192 +// }
193 +// }
194 +
195 +Map<String, wownero.wallet> openedWalletsByPath = {};
196 +
197 +void loadWallet(
198 + {required String path, required String password, int nettype = 0}) {
199 + if (openedWalletsByPath[path] != null) {
200 + wptr = openedWalletsByPath[path]!;
201 + return;
202 + }
203 + try {
204 + if (wptr == null || path != _lastOpenedWallet) {
205 + if (wptr != null) {
206 + final addr = wptr!.address;
207 + Isolate.run(() {
208 + wownero.Wallet_store(Pointer.fromAddress(addr));
209 + });
210 + }
211 + wptr = wownero.WalletManager_openWallet(wmPtr,
212 + path: path, password: password);
213 + openedWalletsByPath[path] = wptr!;
214 + _lastOpenedWallet = path;
215 + }
216 + } catch (e) {
217 + print(e);
218 + }
219 + final status = wownero.Wallet_status(wptr!);
220 + if (status != 0) {
221 + final err = wownero.Wallet_errorString(wptr!);
222 + print(err);
223 + throw WalletOpeningException(message: err);
224 + }
225 +}
226 +
227 +void _createWallet(Map<String, dynamic> args) {
228 + final path = args['path'] as String;
229 + final password = args['password'] as String;
230 + final language = args['language'] as String;
231 +
232 + createWalletSync(path: path, password: password, language: language);
233 +}
234 +
235 +void _restoreFromSeed(Map<String, dynamic> args) {
236 + final path = args['path'] as String;
237 + final password = args['password'] as String;
238 + final seed = args['seed'] as String;
239 + final restoreHeight = args['restoreHeight'] as int;
240 +
241 + restoreWalletFromSeedSync(
242 + path: path, password: password, seed: seed, restoreHeight: restoreHeight);
243 +}
244 +
245 +void _restoreFromKeys(Map<String, dynamic> args) {
246 + final path = args['path'] as String;
247 + final password = args['password'] as String;
248 + final language = args['language'] as String;
249 + final restoreHeight = args['restoreHeight'] as int;
250 + final address = args['address'] as String;
251 + final viewKey = args['viewKey'] as String;
252 + final spendKey = args['spendKey'] as String;
253 +
254 + restoreWalletFromKeysSync(
255 + path: path,
256 + password: password,
257 + language: language,
258 + restoreHeight: restoreHeight,
259 + address: address,
260 + viewKey: viewKey,
261 + spendKey: spendKey);
262 +}
263 +
264 +void _restoreFromSpendKey(Map<String, dynamic> args) {
265 + final path = args['path'] as String;
266 + final password = args['password'] as String;
267 + final seed = args['seed'] as String;
268 + final language = args['language'] as String;
269 + final spendKey = args['spendKey'] as String;
270 + final restoreHeight = args['restoreHeight'] as int;
271 +
272 + restoreWalletFromSpendKeySync(
273 + path: path,
274 + password: password,
275 + seed: seed,
276 + language: language,
277 + restoreHeight: restoreHeight,
278 + spendKey: spendKey);
279 +}
280 +
281 +Future<void> _openWallet(Map<String, String> args) async => loadWallet(
282 + path: args['path'] as String, password: args['password'] as String);
283 +
284 +Future<bool> _isWalletExist(String path) async => isWalletExistSync(path: path);
285 +
286 +void openWallet(
287 + {required String path,
288 + required String password,
289 + int nettype = 0}) async =>
290 + loadWallet(path: path, password: password, nettype: nettype);
291 +
292 +Future<void> openWalletAsync(Map<String, String> args) async =>
293 + _openWallet(args);
294 +
295 +Future<void> createWallet(
296 + {required String path,
297 + required String password,
298 + required String language,
299 + int nettype = 0}) async =>
300 + _createWallet({
301 + 'path': path,
302 + 'password': password,
303 + 'language': language,
304 + 'nettype': nettype
305 + });
306 +
307 +Future<void> restoreFromSeed(
308 + {required String path,
309 + required String password,
310 + required String seed,
311 + int nettype = 0,
312 + int restoreHeight = 0}) async =>
313 + _restoreFromSeed({
314 + 'path': path,
315 + 'password': password,
316 + 'seed': seed,
317 + 'nettype': nettype,
318 + 'restoreHeight': restoreHeight
319 + });
320 +
321 +Future<void> restoreFromKeys(
322 + {required String path,
323 + required String password,
324 + required String language,
325 + required String address,
326 + required String viewKey,
327 + required String spendKey,
328 + int nettype = 0,
329 + int restoreHeight = 0}) async =>
330 + _restoreFromKeys({
331 + 'path': path,
332 + 'password': password,
333 + 'language': language,
334 + 'address': address,
335 + 'viewKey': viewKey,
336 + 'spendKey': spendKey,
337 + 'nettype': nettype,
338 + 'restoreHeight': restoreHeight
339 + });
340 +
341 +Future<void> restoreFromSpendKey(
342 + {required String path,
343 + required String password,
344 + required String seed,
345 + required String language,
346 + required String spendKey,
347 + int nettype = 0,
348 + int restoreHeight = 0}) async =>
349 + _restoreFromSpendKey({
350 + 'path': path,
351 + 'password': password,
352 + 'seed': seed,
353 + 'language': language,
354 + 'spendKey': spendKey,
355 + 'nettype': nettype,
356 + 'restoreHeight': restoreHeight
357 + });
358 +
359 +Future<bool> isWalletExist({required String path}) => _isWalletExist(path);
cw_wownero/lib/api/wownero_output.dart new
+6
@@ -0,0 +1,6 @@
1 +class WowneroOutput {
2 + WowneroOutput({required this.address, required this.amount});
3 +
4 + final String address;
5 + final String amount;
6 +}
\ No newline at end of file
cw_wownero/lib/cw_wownero.dart new
+8
@@ -0,0 +1,8 @@
1 +
2 +import 'cw_wownero_platform_interface.dart';
3 +
4 +class CwWownero {
5 + Future<String?> getPlatformVersion() {
6 + return CwWowneroPlatform.instance.getPlatformVersion();
7 + }
8 +}
cw_wownero/lib/cw_wownero_method_channel.dart new
+17
@@ -0,0 +1,17 @@
1 +import 'package:flutter/foundation.dart';
2 +import 'package:flutter/services.dart';
3 +
4 +import 'cw_wownero_platform_interface.dart';
5 +
6 +/// An implementation of [CwWowneroPlatform] that uses method channels.
7 +class MethodChannelCwWownero extends CwWowneroPlatform {
8 + /// The method channel used to interact with the native platform.
9 + @visibleForTesting
10 + final methodChannel = const MethodChannel('cw_wownero');
11 +
12 + @override
13 + Future<String?> getPlatformVersion() async {
14 + final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
15 + return version;
16 + }
17 +}
cw_wownero/lib/cw_wownero_platform_interface.dart new
+29
@@ -0,0 +1,29 @@
1 +import 'package:plugin_platform_interface/plugin_platform_interface.dart';
2 +
3 +import 'cw_wownero_method_channel.dart';
4 +
5 +abstract class CwWowneroPlatform extends PlatformInterface {
6 + /// Constructs a CwWowneroPlatform.
7 + CwWowneroPlatform() : super(token: _token);
8 +
9 + static final Object _token = Object();
10 +
11 + static CwWowneroPlatform _instance = MethodChannelCwWownero();
12 +
13 + /// The default instance of [CwWowneroPlatform] to use.
14 + ///
15 + /// Defaults to [MethodChannelCwWownero].
16 + static CwWowneroPlatform get instance => _instance;
17 +
18 + /// Platform-specific implementations should set this with their own
19 + /// platform-specific class that extends [CwWowneroPlatform] when
20 + /// they register themselves.
21 + static set instance(CwWowneroPlatform instance) {
22 + PlatformInterface.verifyToken(instance, _token);
23 + _instance = instance;
24 + }
25 +
26 + Future<String?> getPlatformVersion() {
27 + throw UnimplementedError('platformVersion() has not been implemented.');
28 + }
29 +}
cw_wownero/lib/exceptions/wownero_transaction_creation_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class WowneroTransactionCreationException implements Exception {
2 + WowneroTransactionCreationException(this.message);
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_wownero/lib/exceptions/wownero_transaction_no_inputs_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class WowneroTransactionNoInputsException implements Exception {
2 + WowneroTransactionNoInputsException(this.inputsSize);
3 +
4 + int inputsSize;
5 +
6 + @override
7 + String toString() => 'Not enough inputs ($inputsSize) selected. Please select more under Coin Control';
8 +}
cw_wownero/lib/mnemonics/chinese_simplified.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class ChineseSimplifiedMnemonics {
2 + static const words = [
3 + "的",
4 + "一",
5 + "是",
6 + "在",
7 + "不",
8 + "了",
9 + "有",
10 + "和",
11 + "人",
12 + "这",
13 + "中",
14 + "大",
15 + "为",
16 + "上",
17 + "个",
18 + "国",
19 + "我",
20 + "以",
21 + "要",
22 + "他",
23 + "时",
24 + "来",
25 + "用",
26 + "们",
27 + "生",
28 + "到",
29 + "作",
30 + "地",
31 + "于",
32 + "出",
33 + "就",
34 + "分",
35 + "对",
36 + "成",
37 + "会",
38 + "可",
39 + "主",
40 + "发",
41 + "年",
42 + "动",
43 + "同",
44 + "工",
45 + "也",
46 + "能",
47 + "下",
48 + "过",
49 + "子",
50 + "说",
51 + "产",
52 + "种",
53 + "面",
54 + "而",
55 + "方",
56 + "后",
57 + "多",
58 + "定",
59 + "行",
60 + "学",
61 + "法",
62 + "所",
63 + "民",
64 + "得",
65 + "经",
66 + "十",
67 + "三",
68 + "之",
69 + "进",
70 + "着",
71 + "等",
72 + "部",
73 + "度",
74 + "家",
75 + "电",
76 + "力",
77 + "里",
78 + "如",
79 + "水",
80 + "化",
81 + "高",
82 + "自",
83 + "二",
84 + "理",
85 + "起",
86 + "小",
87 + "物",
88 + "现",
89 + "实",
90 + "加",
91 + "量",
92 + "都",
93 + "两",
94 + "体",
95 + "制",
96 + "机",
97 + "当",
98 + "使",
99 + "点",
100 + "从",
101 + "业",
102 + "本",
103 + "去",
104 + "把",
105 + "性",
106 + "好",
107 + "应",
108 + "开",
109 + "它",
110 + "合",
111 + "还",
112 + "因",
113 + "由",
114 + "其",
115 + "些",
116 + "然",
117 + "前",
118 + "外",
119 + "天",
120 + "政",
121 + "四",
122 + "日",
123 + "那",
124 + "社",
125 + "义",
126 + "事",
127 + "平",
128 + "形",
129 + "相",
130 + "全",
131 + "表",
132 + "间",
133 + "样",
134 + "与",
135 + "关",
136 + "各",
137 + "重",
138 + "新",
139 + "线",
140 + "内",
141 + "数",
142 + "正",
143 + "心",
144 + "反",
145 + "你",
146 + "明",
147 + "看",
148 + "原",
149 + "又",
150 + "么",
151 + "利",
152 + "比",
153 + "或",
154 + "但",
155 + "质",
156 + "气",
157 + "第",
158 + "向",
159 + "道",
160 + "命",
161 + "此",
162 + "变",
163 + "条",
164 + "只",
165 + "没",
166 + "结",
167 + "解",
168 + "问",
169 + "意",
170 + "建",
171 + "月",
172 + "公",
173 + "无",
174 + "系",
175 + "军",
176 + "很",
177 + "情",
178 + "者",
179 + "最",
180 + "立",
181 + "代",
182 + "想",
183 + "已",
184 + "通",
185 + "并",
186 + "提",
187 + "直",
188 + "题",
189 + "党",
190 + "程",
191 + "展",
192 + "五",
193 + "果",
194 + "料",
195 + "象",
196 + "员",
197 + "革",
198 + "位",
199 + "入",
200 + "常",
201 + "文",
202 + "总",
203 + "次",
204 + "品",
205 + "式",
206 + "活",
207 + "设",
208 + "及",
209 + "管",
210 + "特",
211 + "件",
212 + "长",
213 + "求",
214 + "老",
215 + "头",
216 + "基",
217 + "资",
218 + "边",
219 + "流",
220 + "路",
221 + "级",
222 + "少",
223 + "图",
224 + "山",
225 + "统",
226 + "接",
227 + "知",
228 + "较",
229 + "将",
230 + "组",
231 + "见",
232 + "计",
233 + "别",
234 + "她",
235 + "手",
236 + "角",
237 + "期",
238 + "根",
239 + "论",
240 + "运",
241 + "农",
242 + "指",
243 + "几",
244 + "九",
245 + "区",
246 + "强",
247 + "放",
248 + "决",
249 + "西",
250 + "被",
251 + "干",
252 + "做",
253 + "必",
254 + "战",
255 + "先",
256 + "回",
257 + "则",
258 + "任",
259 + "取",
260 + "据",
261 + "处",
262 + "队",
263 + "南",
264 + "给",
265 + "色",
266 + "光",
267 + "门",
268 + "即",
269 + "保",
270 + "治",
271 + "北",
272 + "造",
273 + "百",
274 + "规",
275 + "热",
276 + "领",
277 + "七",
278 + "海",
279 + "口",
280 + "东",
281 + "导",
282 + "器",
283 + "压",
284 + "志",
285 + "世",
286 + "金",
287 + "增",
288 + "争",
289 + "济",
290 + "阶",
291 + "油",
292 + "思",
293 + "术",
294 + "极",
295 + "交",
296 + "受",
297 + "联",
298 + "什",
299 + "认",
300 + "六",
301 + "共",
302 + "权",
303 + "收",
304 + "证",
305 + "改",
306 + "清",
307 + "美",
308 + "再",
309 + "采",
310 + "转",
311 + "更",
312 + "单",
313 + "风",
314 + "切",
315 + "打",
316 + "白",
317 + "教",
318 + "速",
319 + "花",
320 + "带",
321 + "安",
322 + "场",
323 + "身",
324 + "车",
325 + "例",
326 + "真",
327 + "务",
328 + "具",
329 + "万",
330 + "每",
331 + "目",
332 + "至",
333 + "达",
334 + "走",
335 + "积",
336 + "示",
337 + "议",
338 + "声",
339 + "报",
340 + "斗",
341 + "完",
342 + "类",
343 + "八",
344 + "离",
345 + "华",
346 + "名",
347 + "确",
348 + "才",
349 + "科",
350 + "张",
351 + "信",
352 + "马",
353 + "节",
354 + "话",
355 + "米",
356 + "整",
357 + "空",
358 + "元",
359 + "况",
360 + "今",
361 + "集",
362 + "温",
363 + "传",
364 + "土",
365 + "许",
366 + "步",
367 + "群",
368 + "广",
369 + "石",
370 + "记",
371 + "需",
372 + "段",
373 + "研",
374 + "界",
375 + "拉",
376 + "林",
377 + "律",
378 + "叫",
379 + "且",
380 + "究",
381 + "观",
382 + "越",
383 + "织",
384 + "装",
385 + "影",
386 + "算",
387 + "低",
388 + "持",
389 + "音",
390 + "众",
391 + "书",
392 + "布",
393 + "复",
394 + "容",
395 + "儿",
396 + "须",
397 + "际",
398 + "商",
399 + "非",
400 + "验",
401 + "连",
402 + "断",
403 + "深",
404 + "难",
405 + "近",
406 + "矿",
407 + "千",
408 + "周",
409 + "委",
410 + "素",
411 + "技",
412 + "备",
413 + "半",
414 + "办",
415 + "青",
416 + "省",
417 + "列",
418 + "习",
419 + "响",
420 + "约",
421 + "支",
422 + "般",
423 + "史",
424 + "感",
425 + "劳",
426 + "便",
427 + "团",
428 + "往",
429 + "酸",
430 + "历",
431 + "市",
432 + "克",
433 + "何",
434 + "除",
435 + "消",
436 + "构",
437 + "府",
438 + "称",
439 + "太",
440 + "准",
441 + "精",
442 + "值",
443 + "号",
444 + "率",
445 + "族",
446 + "维",
447 + "划",
448 + "选",
449 + "标",
450 + "写",
451 + "存",
452 + "候",
453 + "毛",
454 + "亲",
455 + "快",
456 + "效",
457 + "斯",
458 + "院",
459 + "查",
460 + "江",
461 + "型",
462 + "眼",
463 + "王",
464 + "按",
465 + "格",
466 + "养",
467 + "易",
468 + "置",
469 + "派",
470 + "层",
471 + "片",
472 + "始",
473 + "却",
474 + "专",
475 + "状",
476 + "育",
477 + "厂",
478 + "京",
479 + "识",
480 + "适",
481 + "属",
482 + "圆",
483 + "包",
484 + "火",
485 + "住",
486 + "调",
487 + "满",
488 + "县",
489 + "局",
490 + "照",
491 + "参",
492 + "红",
493 + "细",
494 + "引",
495 + "听",
496 + "该",
497 + "铁",
498 + "价",
499 + "严",
500 + "首",
501 + "底",
502 + "液",
503 + "官",
504 + "德",
505 + "随",
506 + "病",
507 + "苏",
508 + "失",
509 + "尔",
510 + "死",
511 + "讲",
512 + "配",
513 + "女",
514 + "黄",
515 + "推",
516 + "显",
517 + "谈",
518 + "罪",
519 + "神",
520 + "艺",
521 + "呢",
522 + "席",
523 + "含",
524 + "企",
525 + "望",
526 + "密",
527 + "批",
528 + "营",
529 + "项",
530 + "防",
531 + "举",
532 + "球",
533 + "英",
534 + "氧",
535 + "势",
536 + "告",
537 + "李",
538 + "台",
539 + "落",
540 + "木",
541 + "帮",
542 + "轮",
543 + "破",
544 + "亚",
545 + "师",
546 + "围",
547 + "注",
548 + "远",
549 + "字",
550 + "材",
551 + "排",
552 + "供",
553 + "河",
554 + "态",
555 + "封",
556 + "另",
557 + "施",
558 + "减",
559 + "树",
560 + "溶",
561 + "怎",
562 + "止",
563 + "案",
564 + "言",
565 + "士",
566 + "均",
567 + "武",
568 + "固",
569 + "叶",
570 + "鱼",
571 + "波",
572 + "视",
573 + "仅",
574 + "费",
575 + "紧",
576 + "爱",
577 + "左",
578 + "章",
579 + "早",
580 + "朝",
581 + "害",
582 + "续",
583 + "轻",
584 + "服",
585 + "试",
586 + "食",
587 + "充",
588 + "兵",
589 + "源",
590 + "判",
591 + "护",
592 + "司",
593 + "足",
594 + "某",
595 + "练",
596 + "差",
597 + "致",
598 + "板",
599 + "田",
600 + "降",
601 + "黑",
602 + "犯",
603 + "负",
604 + "击",
605 + "范",
606 + "继",
607 + "兴",
608 + "似",
609 + "余",
610 + "坚",
611 + "曲",
612 + "输",
613 + "修",
614 + "故",
615 + "城",
616 + "夫",
617 + "够",
618 + "送",
619 + "笔",
620 + "船",
621 + "占",
622 + "右",
623 + "财",
624 + "吃",
625 + "富",
626 + "春",
627 + "职",
628 + "觉",
629 + "汉",
630 + "画",
631 + "功",
632 + "巴",
633 + "跟",
634 + "虽",
635 + "杂",
636 + "飞",
637 + "检",
638 + "吸",
639 + "助",
640 + "升",
641 + "阳",
642 + "互",
643 + "初",
644 + "创",
645 + "抗",
646 + "考",
647 + "投",
648 + "坏",
649 + "策",
650 + "古",
651 + "径",
652 + "换",
653 + "未",
654 + "跑",
655 + "留",
656 + "钢",
657 + "曾",
658 + "端",
659 + "责",
660 + "站",
661 + "简",
662 + "述",
663 + "钱",
664 + "副",
665 + "尽",
666 + "帝",
667 + "射",
668 + "草",
669 + "冲",
670 + "承",
671 + "独",
672 + "令",
673 + "限",
674 + "阿",
675 + "宣",
676 + "环",
677 + "双",
678 + "请",
679 + "超",
680 + "微",
681 + "让",
682 + "控",
683 + "州",
684 + "良",
685 + "轴",
686 + "找",
687 + "否",
688 + "纪",
689 + "益",
690 + "依",
691 + "优",
692 + "顶",
693 + "础",
694 + "载",
695 + "倒",
696 + "房",
697 + "突",
698 + "坐",
699 + "粉",
700 + "敌",
701 + "略",
702 + "客",
703 + "袁",
704 + "冷",
705 + "胜",
706 + "绝",
707 + "析",
708 + "块",
709 + "剂",
710 + "测",
711 + "丝",
712 + "协",
713 + "诉",
714 + "念",
715 + "陈",
716 + "仍",
717 + "罗",
718 + "盐",
719 + "友",
720 + "洋",
721 + "错",
722 + "苦",
723 + "夜",
724 + "刑",
725 + "移",
726 + "频",
727 + "逐",
728 + "靠",
729 + "混",
730 + "母",
731 + "短",
732 + "皮",
733 + "终",
734 + "聚",
735 + "汽",
736 + "村",
737 + "云",
738 + "哪",
739 + "既",
740 + "距",
741 + "卫",
742 + "停",
743 + "烈",
744 + "央",
745 + "察",
746 + "烧",
747 + "迅",
748 + "境",
749 + "若",
750 + "印",
751 + "洲",
752 + "刻",
753 + "括",
754 + "激",
755 + "孔",
756 + "搞",
757 + "甚",
758 + "室",
759 + "待",
760 + "核",
761 + "校",
762 + "散",
763 + "侵",
764 + "吧",
765 + "甲",
766 + "游",
767 + "久",
768 + "菜",
769 + "味",
770 + "旧",
771 + "模",
772 + "湖",
773 + "货",
774 + "损",
775 + "预",
776 + "阻",
777 + "毫",
778 + "普",
779 + "稳",
780 + "乙",
781 + "妈",
782 + "植",
783 + "息",
784 + "扩",
785 + "银",
786 + "语",
787 + "挥",
788 + "酒",
789 + "守",
790 + "拿",
791 + "序",
792 + "纸",
793 + "医",
794 + "缺",
795 + "雨",
796 + "吗",
797 + "针",
798 + "刘",
799 + "啊",
800 + "急",
801 + "唱",
802 + "误",
803 + "训",
804 + "愿",
805 + "审",
806 + "附",
807 + "获",
808 + "茶",
809 + "鲜",
810 + "粮",
811 + "斤",
812 + "孩",
813 + "脱",
814 + "硫",
815 + "肥",
816 + "善",
817 + "龙",
818 + "演",
819 + "父",
820 + "渐",
821 + "血",
822 + "欢",
823 + "械",
824 + "掌",
825 + "歌",
826 + "沙",
827 + "刚",
828 + "攻",
829 + "谓",
830 + "盾",
831 + "讨",
832 + "晚",
833 + "粒",
834 + "乱",
835 + "燃",
836 + "矛",
837 + "乎",
838 + "杀",
839 + "药",
840 + "宁",
841 + "鲁",
842 + "贵",
843 + "钟",
844 + "煤",
845 + "读",
846 + "班",
847 + "伯",
848 + "香",
849 + "介",
850 + "迫",
851 + "句",
852 + "丰",
853 + "培",
854 + "握",
855 + "兰",
856 + "担",
857 + "弦",
858 + "蛋",
859 + "沉",
860 + "假",
861 + "穿",
862 + "执",
863 + "答",
864 + "乐",
865 + "谁",
866 + "顺",
867 + "烟",
868 + "缩",
869 + "征",
870 + "脸",
871 + "喜",
872 + "松",
873 + "脚",
874 + "困",
875 + "异",
876 + "免",
877 + "背",
878 + "星",
879 + "福",
880 + "买",
881 + "染",
882 + "井",
883 + "概",
884 + "慢",
885 + "怕",
886 + "磁",
887 + "倍",
888 + "祖",
889 + "皇",
890 + "促",
891 + "静",
892 + "补",
893 + "评",
894 + "翻",
895 + "肉",
896 + "践",
897 + "尼",
898 + "衣",
899 + "宽",
900 + "扬",
901 + "棉",
902 + "希",
903 + "伤",
904 + "操",
905 + "垂",
906 + "秋",
907 + "宜",
908 + "氢",
909 + "套",
910 + "督",
911 + "振",
912 + "架",
913 + "亮",
914 + "末",
915 + "宪",
916 + "庆",
917 + "编",
918 + "牛",
919 + "触",
920 + "映",
921 + "雷",
922 + "销",
923 + "诗",
924 + "座",
925 + "居",
926 + "抓",
927 + "裂",
928 + "胞",
929 + "呼",
930 + "娘",
931 + "景",
932 + "威",
933 + "绿",
934 + "晶",
935 + "厚",
936 + "盟",
937 + "衡",
938 + "鸡",
939 + "孙",
940 + "延",
941 + "危",
942 + "胶",
943 + "屋",
944 + "乡",
945 + "临",
946 + "陆",
947 + "顾",
948 + "掉",
949 + "呀",
950 + "灯",
951 + "岁",
952 + "措",
953 + "束",
954 + "耐",
955 + "剧",
956 + "玉",
957 + "赵",
958 + "跳",
959 + "哥",
960 + "季",
961 + "课",
962 + "凯",
963 + "胡",
964 + "额",
965 + "款",
966 + "绍",
967 + "卷",
968 + "齐",
969 + "伟",
970 + "蒸",
971 + "殖",
972 + "永",
973 + "宗",
974 + "苗",
975 + "川",
976 + "炉",
977 + "岩",
978 + "弱",
979 + "零",
980 + "杨",
981 + "奏",
982 + "沿",
983 + "露",
984 + "杆",
985 + "探",
986 + "滑",
987 + "镇",
988 + "饭",
989 + "浓",
990 + "航",
991 + "怀",
992 + "赶",
993 + "库",
994 + "夺",
995 + "伊",
996 + "灵",
997 + "税",
998 + "途",
999 + "灭",
1000 + "赛",
1001 + "归",
1002 + "召",
1003 + "鼓",
1004 + "播",
1005 + "盘",
1006 + "裁",
1007 + "险",
1008 + "康",
1009 + "唯",
1010 + "录",
1011 + "菌",
1012 + "纯",
1013 + "借",
1014 + "糖",
1015 + "盖",
1016 + "横",
1017 + "符",
1018 + "私",
1019 + "努",
1020 + "堂",
1021 + "域",
1022 + "枪",
1023 + "润",
1024 + "幅",
1025 + "哈",
1026 + "竟",
1027 + "熟",
1028 + "虫",
1029 + "泽",
1030 + "脑",
1031 + "壤",
1032 + "碳",
1033 + "欧",
1034 + "遍",
1035 + "侧",
1036 + "寨",
1037 + "敢",
1038 + "彻",
1039 + "虑",
1040 + "斜",
1041 + "薄",
1042 + "庭",
1043 + "纳",
1044 + "弹",
1045 + "饲",
1046 + "伸",
1047 + "折",
1048 + "麦",
1049 + "湿",
1050 + "暗",
1051 + "荷",
1052 + "瓦",
1053 + "塞",
1054 + "床",
1055 + "筑",
1056 + "恶",
1057 + "户",
1058 + "访",
1059 + "塔",
1060 + "奇",
1061 + "透",
1062 + "梁",
1063 + "刀",
1064 + "旋",
1065 + "迹",
1066 + "卡",
1067 + "氯",
1068 + "遇",
1069 + "份",
1070 + "毒",
1071 + "泥",
1072 + "退",
1073 + "洗",
1074 + "摆",
1075 + "灰",
1076 + "彩",
1077 + "卖",
1078 + "耗",
1079 + "夏",
1080 + "择",
1081 + "忙",
1082 + "铜",
1083 + "献",
1084 + "硬",
1085 + "予",
1086 + "繁",
1087 + "圈",
1088 + "雪",
1089 + "函",
1090 + "亦",
1091 + "抽",
1092 + "篇",
1093 + "阵",
1094 + "阴",
1095 + "丁",
1096 + "尺",
1097 + "追",
1098 + "堆",
1099 + "雄",
1100 + "迎",
1101 + "泛",
1102 + "爸",
1103 + "楼",
1104 + "避",
1105 + "谋",
1106 + "吨",
1107 + "野",
1108 + "猪",
1109 + "旗",
1110 + "累",
1111 + "偏",
1112 + "典",
1113 + "馆",
1114 + "索",
1115 + "秦",
1116 + "脂",
1117 + "潮",
1118 + "爷",
1119 + "豆",
1120 + "忽",
1121 + "托",
1122 + "惊",
1123 + "塑",
1124 + "遗",
1125 + "愈",
1126 + "朱",
1127 + "替",
1128 + "纤",
1129 + "粗",
1130 + "倾",
1131 + "尚",
1132 + "痛",
1133 + "楚",
1134 + "谢",
1135 + "奋",
1136 + "购",
1137 + "磨",
1138 + "君",
1139 + "池",
1140 + "旁",
1141 + "碎",
1142 + "骨",
1143 + "监",
1144 + "捕",
1145 + "弟",
1146 + "暴",
1147 + "割",
1148 + "贯",
1149 + "殊",
1150 + "释",
1151 + "词",
1152 + "亡",
1153 + "壁",
1154 + "顿",
1155 + "宝",
1156 + "午",
1157 + "尘",
1158 + "闻",
1159 + "揭",
1160 + "炮",
1161 + "残",
1162 + "冬",
1163 + "桥",
1164 + "妇",
1165 + "警",
1166 + "综",
1167 + "招",
1168 + "吴",
1169 + "付",
1170 + "浮",
1171 + "遭",
1172 + "徐",
1173 + "您",
1174 + "摇",
1175 + "谷",
1176 + "赞",
1177 + "箱",
1178 + "隔",
1179 + "订",
1180 + "男",
1181 + "吹",
1182 + "园",
1183 + "纷",
1184 + "唐",
1185 + "败",
1186 + "宋",
1187 + "玻",
1188 + "巨",
1189 + "耕",
1190 + "坦",
1191 + "荣",
1192 + "闭",
1193 + "湾",
1194 + "键",
1195 + "凡",
1196 + "驻",
1197 + "锅",
1198 + "救",
1199 + "恩",
1200 + "剥",
1201 + "凝",
1202 + "碱",
1203 + "齿",
1204 + "截",
1205 + "炼",
1206 + "麻",
1207 + "纺",
1208 + "禁",
1209 + "废",
1210 + "盛",
1211 + "版",
1212 + "缓",
1213 + "净",
1214 + "睛",
1215 + "昌",
1216 + "婚",
1217 + "涉",
1218 + "筒",
1219 + "嘴",
1220 + "插",
1221 + "岸",
1222 + "朗",
1223 + "庄",
1224 + "街",
1225 + "藏",
1226 + "姑",
1227 + "贸",
1228 + "腐",
1229 + "奴",
1230 + "啦",
1231 + "惯",
1232 + "乘",
1233 + "伙",
1234 + "恢",
1235 + "匀",
1236 + "纱",
1237 + "扎",
1238 + "辩",
1239 + "耳",
1240 + "彪",
1241 + "臣",
1242 + "亿",
1243 + "璃",
1244 + "抵",
1245 + "脉",
1246 + "秀",
1247 + "萨",
1248 + "俄",
1249 + "网",
1250 + "舞",
1251 + "店",
1252 + "喷",
1253 + "纵",
1254 + "寸",
1255 + "汗",
1256 + "挂",
1257 + "洪",
1258 + "贺",
1259 + "闪",
1260 + "柬",
1261 + "爆",
1262 + "烯",
1263 + "津",
1264 + "稻",
1265 + "墙",
1266 + "软",
1267 + "勇",
1268 + "像",
1269 + "滚",
1270 + "厘",
1271 + "蒙",
1272 + "芳",
1273 + "肯",
1274 + "坡",
1275 + "柱",
1276 + "荡",
1277 + "腿",
1278 + "仪",
1279 + "旅",
1280 + "尾",
1281 + "轧",
1282 + "冰",
1283 + "贡",
1284 + "登",
1285 + "黎",
1286 + "削",
1287 + "钻",
1288 + "勒",
1289 + "逃",
1290 + "障",
1291 + "氨",
1292 + "郭",
1293 + "峰",
1294 + "币",
1295 + "港",
1296 + "伏",
1297 + "轨",
1298 + "亩",
1299 + "毕",
1300 + "擦",
1301 + "莫",
1302 + "刺",
1303 + "浪",
1304 + "秘",
1305 + "援",
1306 + "株",
1307 + "健",
1308 + "售",
1309 + "股",
1310 + "岛",
1311 + "甘",
1312 + "泡",
1313 + "睡",
1314 + "童",
1315 + "铸",
1316 + "汤",
1317 + "阀",
1318 + "休",
1319 + "汇",
1320 + "舍",
1321 + "牧",
1322 + "绕",
1323 + "炸",
1324 + "哲",
1325 + "磷",
1326 + "绩",
1327 + "朋",
1328 + "淡",
1329 + "尖",
1330 + "启",
1331 + "陷",
1332 + "柴",
1333 + "呈",
1334 + "徒",
1335 + "颜",
1336 + "泪",
1337 + "稍",
1338 + "忘",
1339 + "泵",
1340 + "蓝",
1341 + "拖",
1342 + "洞",
1343 + "授",
1344 + "镜",
1345 + "辛",
1346 + "壮",
1347 + "锋",
1348 + "贫",
1349 + "虚",
1350 + "弯",
1351 + "摩",
1352 + "泰",
1353 + "幼",
1354 + "廷",
1355 + "尊",
1356 + "窗",
1357 + "纲",
1358 + "弄",
1359 + "隶",
1360 + "疑",
1361 + "氏",
1362 + "宫",
1363 + "姐",
1364 + "震",
1365 + "瑞",
1366 + "怪",
1367 + "尤",
1368 + "琴",
1369 + "循",
1370 + "描",
1371 + "膜",
1372 + "违",
1373 + "夹",
1374 + "腰",
1375 + "缘",
1376 + "珠",
1377 + "穷",
1378 + "森",
1379 + "枝",
1380 + "竹",
1381 + "沟",
1382 + "催",
1383 + "绳",
1384 + "忆",
1385 + "邦",
1386 + "剩",
1387 + "幸",
1388 + "浆",
1389 + "栏",
1390 + "拥",
1391 + "牙",
1392 + "贮",
1393 + "礼",
1394 + "滤",
1395 + "钠",
1396 + "纹",
1397 + "罢",
1398 + "拍",
1399 + "咱",
1400 + "喊",
1401 + "袖",
1402 + "埃",
1403 + "勤",
1404 + "罚",
1405 + "焦",
1406 + "潜",
1407 + "伍",
1408 + "墨",
1409 + "欲",
1410 + "缝",
1411 + "姓",
1412 + "刊",
1413 + "饱",
1414 + "仿",
1415 + "奖",
1416 + "铝",
1417 + "鬼",
1418 + "丽",
1419 + "跨",
1420 + "默",
1421 + "挖",
1422 + "链",
1423 + "扫",
1424 + "喝",
1425 + "袋",
1426 + "炭",
1427 + "污",
1428 + "幕",
1429 + "诸",
1430 + "弧",
1431 + "励",
1432 + "梅",
1433 + "奶",
1434 + "洁",
1435 + "灾",
1436 + "舟",
1437 + "鉴",
1438 + "苯",
1439 + "讼",
1440 + "抱",
1441 + "毁",
1442 + "懂",
1443 + "寒",
1444 + "智",
1445 + "埔",
1446 + "寄",
1447 + "届",
1448 + "跃",
1449 + "渡",
1450 + "挑",
1451 + "丹",
1452 + "艰",
1453 + "贝",
1454 + "碰",
1455 + "拔",
1456 + "爹",
1457 + "戴",
1458 + "码",
1459 + "梦",
1460 + "芽",
1461 + "熔",
1462 + "赤",
1463 + "渔",
1464 + "哭",
1465 + "敬",
1466 + "颗",
1467 + "奔",
1468 + "铅",
1469 + "仲",
1470 + "虎",
1471 + "稀",
1472 + "妹",
1473 + "乏",
1474 + "珍",
1475 + "申",
1476 + "桌",
1477 + "遵",
1478 + "允",
1479 + "隆",
1480 + "螺",
1481 + "仓",
1482 + "魏",
1483 + "锐",
1484 + "晓",
1485 + "氮",
1486 + "兼",
1487 + "隐",
1488 + "碍",
1489 + "赫",
1490 + "拨",
1491 + "忠",
1492 + "肃",
1493 + "缸",
1494 + "牵",
1495 + "抢",
1496 + "博",
1497 + "巧",
1498 + "壳",
1499 + "兄",
1500 + "杜",
1501 + "讯",
1502 + "诚",
1503 + "碧",
1504 + "祥",
1505 + "柯",
1506 + "页",
1507 + "巡",
1508 + "矩",
1509 + "悲",
1510 + "灌",
1511 + "龄",
1512 + "伦",
1513 + "票",
1514 + "寻",
1515 + "桂",
1516 + "铺",
1517 + "圣",
1518 + "恐",
1519 + "恰",
1520 + "郑",
1521 + "趣",
1522 + "抬",
1523 + "荒",
1524 + "腾",
1525 + "贴",
1526 + "柔",
1527 + "滴",
1528 + "猛",
1529 + "阔",
1530 + "辆",
1531 + "妻",
1532 + "填",
1533 + "撤",
1534 + "储",
1535 + "签",
1536 + "闹",
1537 + "扰",
1538 + "紫",
1539 + "砂",
1540 + "递",
1541 + "戏",
1542 + "吊",
1543 + "陶",
1544 + "伐",
1545 + "喂",
1546 + "疗",
1547 + "瓶",
1548 + "婆",
1549 + "抚",
1550 + "臂",
1551 + "摸",
1552 + "忍",
1553 + "虾",
1554 + "蜡",
1555 + "邻",
1556 + "胸",
1557 + "巩",
1558 + "挤",
1559 + "偶",
1560 + "弃",
1561 + "槽",
1562 + "劲",
1563 + "乳",
1564 + "邓",
1565 + "吉",
1566 + "仁",
1567 + "烂",
1568 + "砖",
1569 + "租",
1570 + "乌",
1571 + "舰",
1572 + "伴",
1573 + "瓜",
1574 + "浅",
1575 + "丙",
1576 + "暂",
1577 + "燥",
1578 + "橡",
1579 + "柳",
1580 + "迷",
1581 + "暖",
1582 + "牌",
1583 + "秧",
1584 + "胆",
1585 + "详",
1586 + "簧",
1587 + "踏",
1588 + "瓷",
1589 + "谱",
1590 + "呆",
1591 + "宾",
1592 + "糊",
1593 + "洛",
1594 + "辉",
1595 + "愤",
1596 + "竞",
1597 + "隙",
1598 + "怒",
1599 + "粘",
1600 + "乃",
1601 + "绪",
1602 + "肩",
1603 + "籍",
1604 + "敏",
1605 + "涂",
1606 + "熙",
1607 + "皆",
1608 + "侦",
1609 + "悬",
1610 + "掘",
1611 + "享",
1612 + "纠",
1613 + "醒",
1614 + "狂",
1615 + "锁",
1616 + "淀",
1617 + "恨",
1618 + "牲",
1619 + "霸",
1620 + "爬",
1621 + "赏",
1622 + "逆",
1623 + "玩",
1624 + "陵",
1625 + "祝",
1626 + "秒",
1627 + "浙",
1628 + "貌"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mnemonics/dutch.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class DutchMnemonics {
2 + static const words = [
3 + "aalglad",
4 + "aalscholver",
5 + "aambeeld",
6 + "aangeef",
7 + "aanlandig",
8 + "aanvaard",
9 + "aanwakker",
10 + "aapmens",
11 + "aarten",
12 + "abdicatie",
13 + "abnormaal",
14 + "abrikoos",
15 + "accu",
16 + "acuut",
17 + "adjudant",
18 + "admiraal",
19 + "advies",
20 + "afbidding",
21 + "afdracht",
22 + "affaire",
23 + "affiche",
24 + "afgang",
25 + "afkick",
26 + "afknap",
27 + "aflees",
28 + "afmijner",
29 + "afname",
30 + "afpreekt",
31 + "afrader",
32 + "afspeel",
33 + "aftocht",
34 + "aftrek",
35 + "afzijdig",
36 + "ahornboom",
37 + "aktetas",
38 + "akzo",
39 + "alchemist",
40 + "alcohol",
41 + "aldaar",
42 + "alexander",
43 + "alfabet",
44 + "alfredo",
45 + "alice",
46 + "alikruik",
47 + "allrisk",
48 + "altsax",
49 + "alufolie",
50 + "alziend",
51 + "amai",
52 + "ambacht",
53 + "ambieer",
54 + "amina",
55 + "amnestie",
56 + "amok",
57 + "ampul",
58 + "amuzikaal",
59 + "angela",
60 + "aniek",
61 + "antje",
62 + "antwerpen",
63 + "anya",
64 + "aorta",
65 + "apache",
66 + "apekool",
67 + "appelaar",
68 + "arganolie",
69 + "argeloos",
70 + "armoede",
71 + "arrenslee",
72 + "artritis",
73 + "arubaan",
74 + "asbak",
75 + "ascii",
76 + "asgrauw",
77 + "asjes",
78 + "asml",
79 + "aspunt",
80 + "asurn",
81 + "asveld",
82 + "aterling",
83 + "atomair",
84 + "atrium",
85 + "atsma",
86 + "atypisch",
87 + "auping",
88 + "aura",
89 + "avifauna",
90 + "axiaal",
91 + "azoriaan",
92 + "azteek",
93 + "azuur",
94 + "bachelor",
95 + "badderen",
96 + "badhotel",
97 + "badmantel",
98 + "badsteden",
99 + "balie",
100 + "ballans",
101 + "balvers",
102 + "bamibal",
103 + "banneling",
104 + "barracuda",
105 + "basaal",
106 + "batelaan",
107 + "batje",
108 + "beambte",
109 + "bedlamp",
110 + "bedwelmd",
111 + "befaamd",
112 + "begierd",
113 + "begraaf",
114 + "behield",
115 + "beijaard",
116 + "bejaagd",
117 + "bekaaid",
118 + "beks",
119 + "bektas",
120 + "belaad",
121 + "belboei",
122 + "belderbos",
123 + "beloerd",
124 + "beluchten",
125 + "bemiddeld",
126 + "benadeeld",
127 + "benijd",
128 + "berechten",
129 + "beroemd",
130 + "besef",
131 + "besseling",
132 + "best",
133 + "betichten",
134 + "bevind",
135 + "bevochten",
136 + "bevraagd",
137 + "bewust",
138 + "bidplaats",
139 + "biefstuk",
140 + "biemans",
141 + "biezen",
142 + "bijbaan",
143 + "bijeenkom",
144 + "bijfiguur",
145 + "bijkaart",
146 + "bijlage",
147 + "bijpaard",
148 + "bijtgaar",
149 + "bijweg",
150 + "bimmel",
151 + "binck",
152 + "bint",
153 + "biobak",
154 + "biotisch",
155 + "biseks",
156 + "bistro",
157 + "bitter",
158 + "bitumen",
159 + "bizar",
160 + "blad",
161 + "bleken",
162 + "blender",
163 + "bleu",
164 + "blief",
165 + "blijven",
166 + "blozen",
167 + "bock",
168 + "boef",
169 + "boei",
170 + "boks",
171 + "bolder",
172 + "bolus",
173 + "bolvormig",
174 + "bomaanval",
175 + "bombarde",
176 + "bomma",
177 + "bomtapijt",
178 + "bookmaker",
179 + "boos",
180 + "borg",
181 + "bosbes",
182 + "boshuizen",
183 + "bosloop",
184 + "botanicus",
185 + "bougie",
186 + "bovag",
187 + "boxspring",
188 + "braad",
189 + "brasem",
190 + "brevet",
191 + "brigade",
192 + "brinckman",
193 + "bruid",
194 + "budget",
195 + "buffel",
196 + "buks",
197 + "bulgaar",
198 + "buma",
199 + "butaan",
200 + "butler",
201 + "buuf",
202 + "cactus",
203 + "cafeetje",
204 + "camcorder",
205 + "cannabis",
206 + "canyon",
207 + "capoeira",
208 + "capsule",
209 + "carkit",
210 + "casanova",
211 + "catalaan",
212 + "ceintuur",
213 + "celdeling",
214 + "celplasma",
215 + "cement",
216 + "censeren",
217 + "ceramisch",
218 + "cerberus",
219 + "cerebraal",
220 + "cesium",
221 + "cirkel",
222 + "citeer",
223 + "civiel",
224 + "claxon",
225 + "clenbuterol",
226 + "clicheren",
227 + "clijsen",
228 + "coalitie",
229 + "coassistentschap",
230 + "coaxiaal",
231 + "codetaal",
232 + "cofinanciering",
233 + "cognac",
234 + "coltrui",
235 + "comfort",
236 + "commandant",
237 + "condensaat",
238 + "confectie",
239 + "conifeer",
240 + "convector",
241 + "copier",
242 + "corfu",
243 + "correct",
244 + "coup",
245 + "couvert",
246 + "creatie",
247 + "credit",
248 + "crematie",
249 + "cricket",
250 + "croupier",
251 + "cruciaal",
252 + "cruijff",
253 + "cuisine",
254 + "culemborg",
255 + "culinair",
256 + "curve",
257 + "cyrano",
258 + "dactylus",
259 + "dading",
260 + "dagblind",
261 + "dagje",
262 + "daglicht",
263 + "dagprijs",
264 + "dagranden",
265 + "dakdekker",
266 + "dakpark",
267 + "dakterras",
268 + "dalgrond",
269 + "dambord",
270 + "damkat",
271 + "damlengte",
272 + "damman",
273 + "danenberg",
274 + "debbie",
275 + "decibel",
276 + "defect",
277 + "deformeer",
278 + "degelijk",
279 + "degradant",
280 + "dejonghe",
281 + "dekken",
282 + "deppen",
283 + "derek",
284 + "derf",
285 + "derhalve",
286 + "detineren",
287 + "devalueer",
288 + "diaken",
289 + "dicht",
290 + "dictaat",
291 + "dief",
292 + "digitaal",
293 + "dijbreuk",
294 + "dijkmans",
295 + "dimbaar",
296 + "dinsdag",
297 + "diode",
298 + "dirigeer",
299 + "disbalans",
300 + "dobermann",
301 + "doenbaar",
302 + "doerak",
303 + "dogma",
304 + "dokhaven",
305 + "dokwerker",
306 + "doling",
307 + "dolphijn",
308 + "dolven",
309 + "dombo",
310 + "dooraderd",
311 + "dopeling",
312 + "doping",
313 + "draderig",
314 + "drama",
315 + "drenkbak",
316 + "dreumes",
317 + "drol",
318 + "drug",
319 + "duaal",
320 + "dublin",
321 + "duplicaat",
322 + "durven",
323 + "dusdanig",
324 + "dutchbat",
325 + "dutje",
326 + "dutten",
327 + "duur",
328 + "duwwerk",
329 + "dwaal",
330 + "dweil",
331 + "dwing",
332 + "dyslexie",
333 + "ecostroom",
334 + "ecotaks",
335 + "educatie",
336 + "eeckhout",
337 + "eede",
338 + "eemland",
339 + "eencellig",
340 + "eeneiig",
341 + "eenruiter",
342 + "eenwinter",
343 + "eerenberg",
344 + "eerrover",
345 + "eersel",
346 + "eetmaal",
347 + "efteling",
348 + "egaal",
349 + "egtberts",
350 + "eickhoff",
351 + "eidooier",
352 + "eiland",
353 + "eind",
354 + "eisden",
355 + "ekster",
356 + "elburg",
357 + "elevatie",
358 + "elfkoppig",
359 + "elfrink",
360 + "elftal",
361 + "elimineer",
362 + "elleboog",
363 + "elma",
364 + "elodie",
365 + "elsa",
366 + "embleem",
367 + "embolie",
368 + "emoe",
369 + "emonds",
370 + "emplooi",
371 + "enduro",
372 + "enfin",
373 + "engageer",
374 + "entourage",
375 + "entstof",
376 + "epileer",
377 + "episch",
378 + "eppo",
379 + "erasmus",
380 + "erboven",
381 + "erebaan",
382 + "erelijst",
383 + "ereronden",
384 + "ereteken",
385 + "erfhuis",
386 + "erfwet",
387 + "erger",
388 + "erica",
389 + "ermitage",
390 + "erna",
391 + "ernie",
392 + "erts",
393 + "ertussen",
394 + "eruitzien",
395 + "ervaar",
396 + "erven",
397 + "erwt",
398 + "esbeek",
399 + "escort",
400 + "esdoorn",
401 + "essing",
402 + "etage",
403 + "eter",
404 + "ethanol",
405 + "ethicus",
406 + "etholoog",
407 + "eufonisch",
408 + "eurocent",
409 + "evacuatie",
410 + "exact",
411 + "examen",
412 + "executant",
413 + "exen",
414 + "exit",
415 + "exogeen",
416 + "exotherm",
417 + "expeditie",
418 + "expletief",
419 + "expres",
420 + "extase",
421 + "extinctie",
422 + "faal",
423 + "faam",
424 + "fabel",
425 + "facultair",
426 + "fakir",
427 + "fakkel",
428 + "faliekant",
429 + "fallisch",
430 + "famke",
431 + "fanclub",
432 + "fase",
433 + "fatsoen",
434 + "fauna",
435 + "federaal",
436 + "feedback",
437 + "feest",
438 + "feilbaar",
439 + "feitelijk",
440 + "felblauw",
441 + "figurante",
442 + "fiod",
443 + "fitheid",
444 + "fixeer",
445 + "flap",
446 + "fleece",
447 + "fleur",
448 + "flexibel",
449 + "flits",
450 + "flos",
451 + "flow",
452 + "fluweel",
453 + "foezelen",
454 + "fokkelman",
455 + "fokpaard",
456 + "fokvee",
457 + "folder",
458 + "follikel",
459 + "folmer",
460 + "folteraar",
461 + "fooi",
462 + "foolen",
463 + "forfait",
464 + "forint",
465 + "formule",
466 + "fornuis",
467 + "fosfaat",
468 + "foxtrot",
469 + "foyer",
470 + "fragiel",
471 + "frater",
472 + "freak",
473 + "freddie",
474 + "fregat",
475 + "freon",
476 + "frijnen",
477 + "fructose",
478 + "frunniken",
479 + "fuiven",
480 + "funshop",
481 + "furieus",
482 + "fysica",
483 + "gadget",
484 + "galder",
485 + "galei",
486 + "galg",
487 + "galvlieg",
488 + "galzuur",
489 + "ganesh",
490 + "gaswet",
491 + "gaza",
492 + "gazelle",
493 + "geaaid",
494 + "gebiecht",
495 + "gebufferd",
496 + "gedijd",
497 + "geef",
498 + "geflanst",
499 + "gefreesd",
500 + "gegaan",
501 + "gegijzeld",
502 + "gegniffel",
503 + "gegraaid",
504 + "gehikt",
505 + "gehobbeld",
506 + "gehucht",
507 + "geiser",
508 + "geiten",
509 + "gekaakt",
510 + "gekheid",
511 + "gekijf",
512 + "gekmakend",
513 + "gekocht",
514 + "gekskap",
515 + "gekte",
516 + "gelubberd",
517 + "gemiddeld",
518 + "geordend",
519 + "gepoederd",
520 + "gepuft",
521 + "gerda",
522 + "gerijpt",
523 + "geseald",
524 + "geshockt",
525 + "gesierd",
526 + "geslaagd",
527 + "gesnaaid",
528 + "getracht",
529 + "getwijfel",
530 + "geuit",
531 + "gevecht",
532 + "gevlagd",
533 + "gewicht",
534 + "gezaagd",
535 + "gezocht",
536 + "ghanees",
537 + "giebelen",
538 + "giechel",
539 + "giepmans",
540 + "gips",
541 + "giraal",
542 + "gistachtig",
543 + "gitaar",
544 + "glaasje",
545 + "gletsjer",
546 + "gleuf",
547 + "glibberen",
548 + "glijbaan",
549 + "gloren",
550 + "gluipen",
551 + "gluren",
552 + "gluur",
553 + "gnoe",
554 + "goddelijk",
555 + "godgans",
556 + "godschalk",
557 + "godzalig",
558 + "goeierd",
559 + "gogme",
560 + "goklustig",
561 + "gokwereld",
562 + "gonggrijp",
563 + "gonje",
564 + "goor",
565 + "grabbel",
566 + "graf",
567 + "graveer",
568 + "grif",
569 + "grolleman",
570 + "grom",
571 + "groosman",
572 + "grubben",
573 + "gruijs",
574 + "grut",
575 + "guacamole",
576 + "guido",
577 + "guppy",
578 + "haazen",
579 + "hachelijk",
580 + "haex",
581 + "haiku",
582 + "hakhout",
583 + "hakken",
584 + "hanegem",
585 + "hans",
586 + "hanteer",
587 + "harrie",
588 + "hazebroek",
589 + "hedonist",
590 + "heil",
591 + "heineken",
592 + "hekhuis",
593 + "hekman",
594 + "helbig",
595 + "helga",
596 + "helwegen",
597 + "hengelaar",
598 + "herkansen",
599 + "hermafrodiet",
600 + "hertaald",
601 + "hiaat",
602 + "hikspoors",
603 + "hitachi",
604 + "hitparade",
605 + "hobo",
606 + "hoeve",
607 + "holocaust",
608 + "hond",
609 + "honnepon",
610 + "hoogacht",
611 + "hotelbed",
612 + "hufter",
613 + "hugo",
614 + "huilbier",
615 + "hulk",
616 + "humus",
617 + "huwbaar",
618 + "huwelijk",
619 + "hype",
620 + "iconisch",
621 + "idema",
622 + "ideogram",
623 + "idolaat",
624 + "ietje",
625 + "ijker",
626 + "ijkheid",
627 + "ijklijn",
628 + "ijkmaat",
629 + "ijkwezen",
630 + "ijmuiden",
631 + "ijsbox",
632 + "ijsdag",
633 + "ijselijk",
634 + "ijskoud",
635 + "ilse",
636 + "immuun",
637 + "impliceer",
638 + "impuls",
639 + "inbijten",
640 + "inbuigen",
641 + "indijken",
642 + "induceer",
643 + "indy",
644 + "infecteer",
645 + "inhaak",
646 + "inkijk",
647 + "inluiden",
648 + "inmijnen",
649 + "inoefenen",
650 + "inpolder",
651 + "inrijden",
652 + "inslaan",
653 + "invitatie",
654 + "inwaaien",
655 + "ionisch",
656 + "isaac",
657 + "isolatie",
658 + "isotherm",
659 + "isra",
660 + "italiaan",
661 + "ivoor",
662 + "jacobs",
663 + "jakob",
664 + "jammen",
665 + "jampot",
666 + "jarig",
667 + "jehova",
668 + "jenever",
669 + "jezus",
670 + "joana",
671 + "jobdienst",
672 + "josua",
673 + "joule",
674 + "juich",
675 + "jurk",
676 + "juut",
677 + "kaas",
678 + "kabelaar",
679 + "kabinet",
680 + "kagenaar",
681 + "kajuit",
682 + "kalebas",
683 + "kalm",
684 + "kanjer",
685 + "kapucijn",
686 + "karregat",
687 + "kart",
688 + "katvanger",
689 + "katwijk",
690 + "kegelaar",
691 + "keiachtig",
692 + "keizer",
693 + "kenletter",
694 + "kerdijk",
695 + "keus",
696 + "kevlar",
697 + "kezen",
698 + "kickback",
699 + "kieviet",
700 + "kijken",
701 + "kikvors",
702 + "kilheid",
703 + "kilobit",
704 + "kilsdonk",
705 + "kipschnitzel",
706 + "kissebis",
707 + "klad",
708 + "klagelijk",
709 + "klak",
710 + "klapbaar",
711 + "klaver",
712 + "klene",
713 + "klets",
714 + "klijnhout",
715 + "klit",
716 + "klok",
717 + "klonen",
718 + "klotefilm",
719 + "kluif",
720 + "klumper",
721 + "klus",
722 + "knabbel",
723 + "knagen",
724 + "knaven",
725 + "kneedbaar",
726 + "knmi",
727 + "knul",
728 + "knus",
729 + "kokhals",
730 + "komiek",
731 + "komkommer",
732 + "kompaan",
733 + "komrij",
734 + "komvormig",
735 + "koning",
736 + "kopbal",
737 + "kopklep",
738 + "kopnagel",
739 + "koppejan",
740 + "koptekst",
741 + "kopwand",
742 + "koraal",
743 + "kosmisch",
744 + "kostbaar",
745 + "kram",
746 + "kraneveld",
747 + "kras",
748 + "kreling",
749 + "krengen",
750 + "kribbe",
751 + "krik",
752 + "kruid",
753 + "krulbol",
754 + "kuijper",
755 + "kuipbank",
756 + "kuit",
757 + "kuiven",
758 + "kutsmoes",
759 + "kuub",
760 + "kwak",
761 + "kwatong",
762 + "kwetsbaar",
763 + "kwezelaar",
764 + "kwijnen",
765 + "kwik",
766 + "kwinkslag",
767 + "kwitantie",
768 + "lading",
769 + "lakbeits",
770 + "lakken",
771 + "laklaag",
772 + "lakmoes",
773 + "lakwijk",
774 + "lamheid",
775 + "lamp",
776 + "lamsbout",
777 + "lapmiddel",
778 + "larve",
779 + "laser",
780 + "latijn",
781 + "latuw",
782 + "lawaai",
783 + "laxeerpil",
784 + "lebberen",
785 + "ledeboer",
786 + "leefbaar",
787 + "leeman",
788 + "lefdoekje",
789 + "lefhebber",
790 + "legboor",
791 + "legsel",
792 + "leguaan",
793 + "leiplaat",
794 + "lekdicht",
795 + "lekrijden",
796 + "leksteen",
797 + "lenen",
798 + "leraar",
799 + "lesbienne",
800 + "leugenaar",
801 + "leut",
802 + "lexicaal",
803 + "lezing",
804 + "lieten",
805 + "liggeld",
806 + "lijdzaam",
807 + "lijk",
808 + "lijmstang",
809 + "lijnschip",
810 + "likdoorn",
811 + "likken",
812 + "liksteen",
813 + "limburg",
814 + "link",
815 + "linoleum",
816 + "lipbloem",
817 + "lipman",
818 + "lispelen",
819 + "lissabon",
820 + "litanie",
821 + "liturgie",
822 + "lochem",
823 + "loempia",
824 + "loesje",
825 + "logheid",
826 + "lonen",
827 + "lonneke",
828 + "loom",
829 + "loos",
830 + "losbaar",
831 + "loslaten",
832 + "losplaats",
833 + "loting",
834 + "lotnummer",
835 + "lots",
836 + "louie",
837 + "lourdes",
838 + "louter",
839 + "lowbudget",
840 + "luijten",
841 + "luikenaar",
842 + "luilak",
843 + "luipaard",
844 + "luizenbos",
845 + "lulkoek",
846 + "lumen",
847 + "lunzen",
848 + "lurven",
849 + "lutjeboer",
850 + "luttel",
851 + "lutz",
852 + "luuk",
853 + "luwte",
854 + "luyendijk",
855 + "lyceum",
856 + "lynx",
857 + "maakbaar",
858 + "magdalena",
859 + "malheid",
860 + "manchet",
861 + "manfred",
862 + "manhaftig",
863 + "mank",
864 + "mantel",
865 + "marion",
866 + "marxist",
867 + "masmeijer",
868 + "massaal",
869 + "matsen",
870 + "matverf",
871 + "matze",
872 + "maude",
873 + "mayonaise",
874 + "mechanica",
875 + "meifeest",
876 + "melodie",
877 + "meppelink",
878 + "midvoor",
879 + "midweeks",
880 + "midzomer",
881 + "miezel",
882 + "mijnraad",
883 + "minus",
884 + "mirck",
885 + "mirte",
886 + "mispakken",
887 + "misraden",
888 + "miswassen",
889 + "mitella",
890 + "moker",
891 + "molecule",
892 + "mombakkes",
893 + "moonen",
894 + "mopperaar",
895 + "moraal",
896 + "morgana",
897 + "mormel",
898 + "mosselaar",
899 + "motregen",
900 + "mouw",
901 + "mufheid",
902 + "mutueel",
903 + "muzelman",
904 + "naaidoos",
905 + "naald",
906 + "nadeel",
907 + "nadruk",
908 + "nagy",
909 + "nahon",
910 + "naima",
911 + "nairobi",
912 + "napalm",
913 + "napels",
914 + "napijn",
915 + "napoleon",
916 + "narigheid",
917 + "narratief",
918 + "naseizoen",
919 + "nasibal",
920 + "navigatie",
921 + "nawijn",
922 + "negatief",
923 + "nekletsel",
924 + "nekwervel",
925 + "neolatijn",
926 + "neonataal",
927 + "neptunus",
928 + "nerd",
929 + "nest",
930 + "neuzelaar",
931 + "nihiliste",
932 + "nijenhuis",
933 + "nijging",
934 + "nijhoff",
935 + "nijl",
936 + "nijptang",
937 + "nippel",
938 + "nokkenas",
939 + "noordam",
940 + "noren",
941 + "normaal",
942 + "nottelman",
943 + "notulant",
944 + "nout",
945 + "nuance",
946 + "nuchter",
947 + "nudorp",
948 + "nulde",
949 + "nullijn",
950 + "nulmeting",
951 + "nunspeet",
952 + "nylon",
953 + "obelisk",
954 + "object",
955 + "oblie",
956 + "obsceen",
957 + "occlusie",
958 + "oceaan",
959 + "ochtend",
960 + "ockhuizen",
961 + "oerdom",
962 + "oergezond",
963 + "oerlaag",
964 + "oester",
965 + "okhuijsen",
966 + "olifant",
967 + "olijfboer",
968 + "omaans",
969 + "ombudsman",
970 + "omdat",
971 + "omdijken",
972 + "omdoen",
973 + "omgebouwd",
974 + "omkeer",
975 + "omkomen",
976 + "ommegaand",
977 + "ommuren",
978 + "omroep",
979 + "omruil",
980 + "omslaan",
981 + "omsmeden",
982 + "omvaar",
983 + "onaardig",
984 + "onedel",
985 + "onenig",
986 + "onheilig",
987 + "onrecht",
988 + "onroerend",
989 + "ontcijfer",
990 + "onthaal",
991 + "ontvallen",
992 + "ontzadeld",
993 + "onzacht",
994 + "onzin",
995 + "onzuiver",
996 + "oogappel",
997 + "ooibos",
998 + "ooievaar",
999 + "ooit",
1000 + "oorarts",
1001 + "oorhanger",
1002 + "oorijzer",
1003 + "oorklep",
1004 + "oorschelp",
1005 + "oorworm",
1006 + "oorzaak",
1007 + "opdagen",
1008 + "opdien",
1009 + "opdweilen",
1010 + "opel",
1011 + "opgebaard",
1012 + "opinie",
1013 + "opjutten",
1014 + "opkijken",
1015 + "opklaar",
1016 + "opkuisen",
1017 + "opkwam",
1018 + "opnaaien",
1019 + "opossum",
1020 + "opsieren",
1021 + "opsmeer",
1022 + "optreden",
1023 + "opvijzel",
1024 + "opvlammen",
1025 + "opwind",
1026 + "oraal",
1027 + "orchidee",
1028 + "orkest",
1029 + "ossuarium",
1030 + "ostendorf",
1031 + "oublie",
1032 + "oudachtig",
1033 + "oudbakken",
1034 + "oudnoors",
1035 + "oudshoorn",
1036 + "oudtante",
1037 + "oven",
1038 + "over",
1039 + "oxidant",
1040 + "pablo",
1041 + "pacht",
1042 + "paktafel",
1043 + "pakzadel",
1044 + "paljas",
1045 + "panharing",
1046 + "papfles",
1047 + "paprika",
1048 + "parochie",
1049 + "paus",
1050 + "pauze",
1051 + "paviljoen",
1052 + "peek",
1053 + "pegel",
1054 + "peigeren",
1055 + "pekela",
1056 + "pendant",
1057 + "penibel",
1058 + "pepmiddel",
1059 + "peptalk",
1060 + "periferie",
1061 + "perron",
1062 + "pessarium",
1063 + "peter",
1064 + "petfles",
1065 + "petgat",
1066 + "peuk",
1067 + "pfeifer",
1068 + "picknick",
1069 + "pief",
1070 + "pieneman",
1071 + "pijlkruid",
1072 + "pijnacker",
1073 + "pijpelink",
1074 + "pikdonker",
1075 + "pikeer",
1076 + "pilaar",
1077 + "pionier",
1078 + "pipet",
1079 + "piscine",
1080 + "pissebed",
1081 + "pitchen",
1082 + "pixel",
1083 + "plamuren",
1084 + "plan",
1085 + "plausibel",
1086 + "plegen",
1087 + "plempen",
1088 + "pleonasme",
1089 + "plezant",
1090 + "podoloog",
1091 + "pofmouw",
1092 + "pokdalig",
1093 + "ponywagen",
1094 + "popachtig",
1095 + "popidool",
1096 + "porren",
1097 + "positie",
1098 + "potten",
1099 + "pralen",
1100 + "prezen",
1101 + "prijzen",
1102 + "privaat",
1103 + "proef",
1104 + "prooi",
1105 + "prozawerk",
1106 + "pruik",
1107 + "prul",
1108 + "publiceer",
1109 + "puck",
1110 + "puilen",
1111 + "pukkelig",
1112 + "pulveren",
1113 + "pupil",
1114 + "puppy",
1115 + "purmerend",
1116 + "pustjens",
1117 + "putemmer",
1118 + "puzzelaar",
1119 + "queenie",
1120 + "quiche",
1121 + "raam",
1122 + "raar",
1123 + "raat",
1124 + "raes",
1125 + "ralf",
1126 + "rally",
1127 + "ramona",
1128 + "ramselaar",
1129 + "ranonkel",
1130 + "rapen",
1131 + "rapunzel",
1132 + "rarekiek",
1133 + "rarigheid",
1134 + "rattenhol",
1135 + "ravage",
1136 + "reactie",
1137 + "recreant",
1138 + "redacteur",
1139 + "redster",
1140 + "reewild",
1141 + "regie",
1142 + "reijnders",
1143 + "rein",
1144 + "replica",
1145 + "revanche",
1146 + "rigide",
1147 + "rijbaan",
1148 + "rijdansen",
1149 + "rijgen",
1150 + "rijkdom",
1151 + "rijles",
1152 + "rijnwijn",
1153 + "rijpma",
1154 + "rijstafel",
1155 + "rijtaak",
1156 + "rijzwepen",
1157 + "rioleer",
1158 + "ripdeal",
1159 + "riphagen",
1160 + "riskant",
1161 + "rits",
1162 + "rivaal",
1163 + "robbedoes",
1164 + "robot",
1165 + "rockact",
1166 + "rodijk",
1167 + "rogier",
1168 + "rohypnol",
1169 + "rollaag",
1170 + "rolpaal",
1171 + "roltafel",
1172 + "roof",
1173 + "roon",
1174 + "roppen",
1175 + "rosbief",
1176 + "rosharig",
1177 + "rosielle",
1178 + "rotan",
1179 + "rotleven",
1180 + "rotten",
1181 + "rotvaart",
1182 + "royaal",
1183 + "royeer",
1184 + "rubato",
1185 + "ruby",
1186 + "ruche",
1187 + "rudge",
1188 + "ruggetje",
1189 + "rugnummer",
1190 + "rugpijn",
1191 + "rugtitel",
1192 + "rugzak",
1193 + "ruilbaar",
1194 + "ruis",
1195 + "ruit",
1196 + "rukwind",
1197 + "rulijs",
1198 + "rumoeren",
1199 + "rumsdorp",
1200 + "rumtaart",
1201 + "runnen",
1202 + "russchen",
1203 + "ruwkruid",
1204 + "saboteer",
1205 + "saksisch",
1206 + "salade",
1207 + "salpeter",
1208 + "sambabal",
1209 + "samsam",
1210 + "satelliet",
1211 + "satineer",
1212 + "saus",
1213 + "scampi",
1214 + "scarabee",
1215 + "scenario",
1216 + "schobben",
1217 + "schubben",
1218 + "scout",
1219 + "secessie",
1220 + "secondair",
1221 + "seculair",
1222 + "sediment",
1223 + "seeland",
1224 + "settelen",
1225 + "setwinst",
1226 + "sheriff",
1227 + "shiatsu",
1228 + "siciliaan",
1229 + "sidderaal",
1230 + "sigma",
1231 + "sijben",
1232 + "silvana",
1233 + "simkaart",
1234 + "sinds",
1235 + "situatie",
1236 + "sjaak",
1237 + "sjardijn",
1238 + "sjezen",
1239 + "sjor",
1240 + "skinhead",
1241 + "skylab",
1242 + "slamixen",
1243 + "sleijpen",
1244 + "slijkerig",
1245 + "slordig",
1246 + "slowaak",
1247 + "sluieren",
1248 + "smadelijk",
1249 + "smiecht",
1250 + "smoel",
1251 + "smos",
1252 + "smukken",
1253 + "snackcar",
1254 + "snavel",
1255 + "sneaker",
1256 + "sneu",
1257 + "snijdbaar",
1258 + "snit",
1259 + "snorder",
1260 + "soapbox",
1261 + "soetekouw",
1262 + "soigneren",
1263 + "sojaboon",
1264 + "solo",
1265 + "solvabel",
1266 + "somber",
1267 + "sommatie",
1268 + "soort",
1269 + "soppen",
1270 + "sopraan",
1271 + "soundbar",
1272 + "spanen",
1273 + "spawater",
1274 + "spijgat",
1275 + "spinaal",
1276 + "spionage",
1277 + "spiraal",
1278 + "spleet",
1279 + "splijt",
1280 + "spoed",
1281 + "sporen",
1282 + "spul",
1283 + "spuug",
1284 + "spuw",
1285 + "stalen",
1286 + "standaard",
1287 + "star",
1288 + "stefan",
1289 + "stencil",
1290 + "stijf",
1291 + "stil",
1292 + "stip",
1293 + "stopdas",
1294 + "stoten",
1295 + "stoven",
1296 + "straat",
1297 + "strobbe",
1298 + "strubbel",
1299 + "stucadoor",
1300 + "stuif",
1301 + "stukadoor",
1302 + "subhoofd",
1303 + "subregent",
1304 + "sudoku",
1305 + "sukade",
1306 + "sulfaat",
1307 + "surinaams",
1308 + "suus",
1309 + "syfilis",
1310 + "symboliek",
1311 + "sympathie",
1312 + "synagoge",
1313 + "synchroon",
1314 + "synergie",
1315 + "systeem",
1316 + "taanderij",
1317 + "tabak",
1318 + "tachtig",
1319 + "tackelen",
1320 + "taiwanees",
1321 + "talman",
1322 + "tamheid",
1323 + "tangaslip",
1324 + "taps",
1325 + "tarkan",
1326 + "tarwe",
1327 + "tasman",
1328 + "tatjana",
1329 + "taxameter",
1330 + "teil",
1331 + "teisman",
1332 + "telbaar",
1333 + "telco",
1334 + "telganger",
1335 + "telstar",
1336 + "tenant",
1337 + "tepel",
1338 + "terzet",
1339 + "testament",
1340 + "ticket",
1341 + "tiesinga",
1342 + "tijdelijk",
1343 + "tika",
1344 + "tiksel",
1345 + "tilleman",
1346 + "timbaal",
1347 + "tinsteen",
1348 + "tiplijn",
1349 + "tippelaar",
1350 + "tjirpen",
1351 + "toezeggen",
1352 + "tolbaas",
1353 + "tolgeld",
1354 + "tolhek",
1355 + "tolo",
1356 + "tolpoort",
1357 + "toltarief",
1358 + "tolvrij",
1359 + "tomaat",
1360 + "tondeuse",
1361 + "toog",
1362 + "tooi",
1363 + "toonbaar",
1364 + "toos",
1365 + "topclub",
1366 + "toppen",
1367 + "toptalent",
1368 + "topvrouw",
1369 + "toque",
1370 + "torment",
1371 + "tornado",
1372 + "tosti",
1373 + "totdat",
1374 + "toucheer",
1375 + "toulouse",
1376 + "tournedos",
1377 + "tout",
1378 + "trabant",
1379 + "tragedie",
1380 + "trailer",
1381 + "traject",
1382 + "traktaat",
1383 + "trauma",
1384 + "tray",
1385 + "trechter",
1386 + "tred",
1387 + "tref",
1388 + "treur",
1389 + "troebel",
1390 + "tros",
1391 + "trucage",
1392 + "truffel",
1393 + "tsaar",
1394 + "tucht",
1395 + "tuenter",
1396 + "tuitelig",
1397 + "tukje",
1398 + "tuktuk",
1399 + "tulp",
1400 + "tuma",
1401 + "tureluurs",
1402 + "twijfel",
1403 + "twitteren",
1404 + "tyfoon",
1405 + "typograaf",
1406 + "ugandees",
1407 + "uiachtig",
1408 + "uier",
1409 + "uisnipper",
1410 + "ultiem",
1411 + "unitair",
1412 + "uranium",
1413 + "urbaan",
1414 + "urendag",
1415 + "ursula",
1416 + "uurcirkel",
1417 + "uurglas",
1418 + "uzelf",
1419 + "vaat",
1420 + "vakantie",
1421 + "vakleraar",
1422 + "valbijl",
1423 + "valpartij",
1424 + "valreep",
1425 + "valuatie",
1426 + "vanmiddag",
1427 + "vanonder",
1428 + "varaan",
1429 + "varken",
1430 + "vaten",
1431 + "veenbes",
1432 + "veeteler",
1433 + "velgrem",
1434 + "vellekoop",
1435 + "velvet",
1436 + "veneberg",
1437 + "venlo",
1438 + "vent",
1439 + "venusberg",
1440 + "venw",
1441 + "veredeld",
1442 + "verf",
1443 + "verhaaf",
1444 + "vermaak",
1445 + "vernaaid",
1446 + "verraad",
1447 + "vers",
1448 + "veruit",
1449 + "verzaagd",
1450 + "vetachtig",
1451 + "vetlok",
1452 + "vetmesten",
1453 + "veto",
1454 + "vetrek",
1455 + "vetstaart",
1456 + "vetten",
1457 + "veurink",
1458 + "viaduct",
1459 + "vibrafoon",
1460 + "vicariaat",
1461 + "vieux",
1462 + "vieveen",
1463 + "vijfvoud",
1464 + "villa",
1465 + "vilt",
1466 + "vimmetje",
1467 + "vindbaar",
1468 + "vips",
1469 + "virtueel",
1470 + "visdieven",
1471 + "visee",
1472 + "visie",
1473 + "vlaag",
1474 + "vleugel",
1475 + "vmbo",
1476 + "vocht",
1477 + "voesenek",
1478 + "voicemail",
1479 + "voip",
1480 + "volg",
1481 + "vork",
1482 + "vorselaar",
1483 + "voyeur",
1484 + "vracht",
1485 + "vrekkig",
1486 + "vreten",
1487 + "vrije",
1488 + "vrozen",
1489 + "vrucht",
1490 + "vucht",
1491 + "vugt",
1492 + "vulkaan",
1493 + "vulmiddel",
1494 + "vulva",
1495 + "vuren",
1496 + "waas",
1497 + "wacht",
1498 + "wadvogel",
1499 + "wafel",
1500 + "waffel",
1501 + "walhalla",
1502 + "walnoot",
1503 + "walraven",
1504 + "wals",
1505 + "walvis",
1506 + "wandaad",
1507 + "wanen",
1508 + "wanmolen",
1509 + "want",
1510 + "warklomp",
1511 + "warm",
1512 + "wasachtig",
1513 + "wasteil",
1514 + "watt",
1515 + "webhandel",
1516 + "weblog",
1517 + "webpagina",
1518 + "webzine",
1519 + "wedereis",
1520 + "wedstrijd",
1521 + "weeda",
1522 + "weert",
1523 + "wegmaaien",
1524 + "wegscheer",
1525 + "wekelijks",
1526 + "wekken",
1527 + "wekroep",
1528 + "wektoon",
1529 + "weldaad",
1530 + "welwater",
1531 + "wendbaar",
1532 + "wenkbrauw",
1533 + "wens",
1534 + "wentelaar",
1535 + "wervel",
1536 + "wesseling",
1537 + "wetboek",
1538 + "wetmatig",
1539 + "whirlpool",
1540 + "wijbrands",
1541 + "wijdbeens",
1542 + "wijk",
1543 + "wijnbes",
1544 + "wijting",
1545 + "wild",
1546 + "wimpelen",
1547 + "wingebied",
1548 + "winplaats",
1549 + "winter",
1550 + "winzucht",
1551 + "wipstaart",
1552 + "wisgerhof",
1553 + "withaar",
1554 + "witmaker",
1555 + "wokkel",
1556 + "wolf",
1557 + "wonenden",
1558 + "woning",
1559 + "worden",
1560 + "worp",
1561 + "wortel",
1562 + "wrat",
1563 + "wrijf",
1564 + "wringen",
1565 + "yoghurt",
1566 + "ypsilon",
1567 + "zaaijer",
1568 + "zaak",
1569 + "zacharias",
1570 + "zakelijk",
1571 + "zakkam",
1572 + "zakwater",
1573 + "zalf",
1574 + "zalig",
1575 + "zaniken",
1576 + "zebracode",
1577 + "zeeblauw",
1578 + "zeef",
1579 + "zeegaand",
1580 + "zeeuw",
1581 + "zege",
1582 + "zegje",
1583 + "zeil",
1584 + "zesbaans",
1585 + "zesenhalf",
1586 + "zeskantig",
1587 + "zesmaal",
1588 + "zetbaas",
1589 + "zetpil",
1590 + "zeulen",
1591 + "ziezo",
1592 + "zigzag",
1593 + "zijaltaar",
1594 + "zijbeuk",
1595 + "zijlijn",
1596 + "zijmuur",
1597 + "zijn",
1598 + "zijwaarts",
1599 + "zijzelf",
1600 + "zilt",
1601 + "zimmerman",
1602 + "zinledig",
1603 + "zinnelijk",
1604 + "zionist",
1605 + "zitdag",
1606 + "zitruimte",
1607 + "zitzak",
1608 + "zoal",
1609 + "zodoende",
1610 + "zoekbots",
1611 + "zoem",
1612 + "zoiets",
1613 + "zojuist",
1614 + "zondaar",
1615 + "zotskap",
1616 + "zottebol",
1617 + "zucht",
1618 + "zuivel",
1619 + "zulk",
1620 + "zult",
1621 + "zuster",
1622 + "zuur",
1623 + "zweedijk",
1624 + "zwendel",
1625 + "zwepen",
1626 + "zwiep",
1627 + "zwijmel",
1628 + "zworen"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mnemonics/english.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class EnglishMnemonics {
2 + static const words = [
3 + "abbey",
4 + "abducts",
5 + "ability",
6 + "ablaze",
7 + "abnormal",
8 + "abort",
9 + "abrasive",
10 + "absorb",
11 + "abyss",
12 + "academy",
13 + "aces",
14 + "aching",
15 + "acidic",
16 + "acoustic",
17 + "acquire",
18 + "across",
19 + "actress",
20 + "acumen",
21 + "adapt",
22 + "addicted",
23 + "adept",
24 + "adhesive",
25 + "adjust",
26 + "adopt",
27 + "adrenalin",
28 + "adult",
29 + "adventure",
30 + "aerial",
31 + "afar",
32 + "affair",
33 + "afield",
34 + "afloat",
35 + "afoot",
36 + "afraid",
37 + "after",
38 + "against",
39 + "agenda",
40 + "aggravate",
41 + "agile",
42 + "aglow",
43 + "agnostic",
44 + "agony",
45 + "agreed",
46 + "ahead",
47 + "aided",
48 + "ailments",
49 + "aimless",
50 + "airport",
51 + "aisle",
52 + "ajar",
53 + "akin",
54 + "alarms",
55 + "album",
56 + "alchemy",
57 + "alerts",
58 + "algebra",
59 + "alkaline",
60 + "alley",
61 + "almost",
62 + "aloof",
63 + "alpine",
64 + "already",
65 + "also",
66 + "altitude",
67 + "alumni",
68 + "always",
69 + "amaze",
70 + "ambush",
71 + "amended",
72 + "amidst",
73 + "ammo",
74 + "amnesty",
75 + "among",
76 + "amply",
77 + "amused",
78 + "anchor",
79 + "android",
80 + "anecdote",
81 + "angled",
82 + "ankle",
83 + "annoyed",
84 + "answers",
85 + "antics",
86 + "anvil",
87 + "anxiety",
88 + "anybody",
89 + "apart",
90 + "apex",
91 + "aphid",
92 + "aplomb",
93 + "apology",
94 + "apply",
95 + "apricot",
96 + "aptitude",
97 + "aquarium",
98 + "arbitrary",
99 + "archer",
100 + "ardent",
101 + "arena",
102 + "argue",
103 + "arises",
104 + "army",
105 + "around",
106 + "arrow",
107 + "arsenic",
108 + "artistic",
109 + "ascend",
110 + "ashtray",
111 + "aside",
112 + "asked",
113 + "asleep",
114 + "aspire",
115 + "assorted",
116 + "asylum",
117 + "athlete",
118 + "atlas",
119 + "atom",
120 + "atrium",
121 + "attire",
122 + "auburn",
123 + "auctions",
124 + "audio",
125 + "august",
126 + "aunt",
127 + "austere",
128 + "autumn",
129 + "avatar",
130 + "avidly",
131 + "avoid",
132 + "awakened",
133 + "awesome",
134 + "awful",
135 + "awkward",
136 + "awning",
137 + "awoken",
138 + "axes",
139 + "axis",
140 + "axle",
141 + "aztec",
142 + "azure",
143 + "baby",
144 + "bacon",
145 + "badge",
146 + "baffles",
147 + "bagpipe",
148 + "bailed",
149 + "bakery",
150 + "balding",
151 + "bamboo",
152 + "banjo",
153 + "baptism",
154 + "basin",
155 + "batch",
156 + "bawled",
157 + "bays",
158 + "because",
159 + "beer",
160 + "befit",
161 + "begun",
162 + "behind",
163 + "being",
164 + "below",
165 + "bemused",
166 + "benches",
167 + "berries",
168 + "bested",
169 + "betting",
170 + "bevel",
171 + "beware",
172 + "beyond",
173 + "bias",
174 + "bicycle",
175 + "bids",
176 + "bifocals",
177 + "biggest",
178 + "bikini",
179 + "bimonthly",
180 + "binocular",
181 + "biology",
182 + "biplane",
183 + "birth",
184 + "biscuit",
185 + "bite",
186 + "biweekly",
187 + "blender",
188 + "blip",
189 + "bluntly",
190 + "boat",
191 + "bobsled",
192 + "bodies",
193 + "bogeys",
194 + "boil",
195 + "boldly",
196 + "bomb",
197 + "border",
198 + "boss",
199 + "both",
200 + "bounced",
201 + "bovine",
202 + "bowling",
203 + "boxes",
204 + "boyfriend",
205 + "broken",
206 + "brunt",
207 + "bubble",
208 + "buckets",
209 + "budget",
210 + "buffet",
211 + "bugs",
212 + "building",
213 + "bulb",
214 + "bumper",
215 + "bunch",
216 + "business",
217 + "butter",
218 + "buying",
219 + "buzzer",
220 + "bygones",
221 + "byline",
222 + "bypass",
223 + "cabin",
224 + "cactus",
225 + "cadets",
226 + "cafe",
227 + "cage",
228 + "cajun",
229 + "cake",
230 + "calamity",
231 + "camp",
232 + "candy",
233 + "casket",
234 + "catch",
235 + "cause",
236 + "cavernous",
237 + "cease",
238 + "cedar",
239 + "ceiling",
240 + "cell",
241 + "cement",
242 + "cent",
243 + "certain",
244 + "chlorine",
245 + "chrome",
246 + "cider",
247 + "cigar",
248 + "cinema",
249 + "circle",
250 + "cistern",
251 + "citadel",
252 + "civilian",
253 + "claim",
254 + "click",
255 + "clue",
256 + "coal",
257 + "cobra",
258 + "cocoa",
259 + "code",
260 + "coexist",
261 + "coffee",
262 + "cogs",
263 + "cohesive",
264 + "coils",
265 + "colony",
266 + "comb",
267 + "cool",
268 + "copy",
269 + "corrode",
270 + "costume",
271 + "cottage",
272 + "cousin",
273 + "cowl",
274 + "criminal",
275 + "cube",
276 + "cucumber",
277 + "cuddled",
278 + "cuffs",
279 + "cuisine",
280 + "cunning",
281 + "cupcake",
282 + "custom",
283 + "cycling",
284 + "cylinder",
285 + "cynical",
286 + "dabbing",
287 + "dads",
288 + "daft",
289 + "dagger",
290 + "daily",
291 + "damp",
292 + "dangerous",
293 + "dapper",
294 + "darted",
295 + "dash",
296 + "dating",
297 + "dauntless",
298 + "dawn",
299 + "daytime",
300 + "dazed",
301 + "debut",
302 + "decay",
303 + "dedicated",
304 + "deepest",
305 + "deftly",
306 + "degrees",
307 + "dehydrate",
308 + "deity",
309 + "dejected",
310 + "delayed",
311 + "demonstrate",
312 + "dented",
313 + "deodorant",
314 + "depth",
315 + "desk",
316 + "devoid",
317 + "dewdrop",
318 + "dexterity",
319 + "dialect",
320 + "dice",
321 + "diet",
322 + "different",
323 + "digit",
324 + "dilute",
325 + "dime",
326 + "dinner",
327 + "diode",
328 + "diplomat",
329 + "directed",
330 + "distance",
331 + "ditch",
332 + "divers",
333 + "dizzy",
334 + "doctor",
335 + "dodge",
336 + "does",
337 + "dogs",
338 + "doing",
339 + "dolphin",
340 + "domestic",
341 + "donuts",
342 + "doorway",
343 + "dormant",
344 + "dosage",
345 + "dotted",
346 + "double",
347 + "dove",
348 + "down",
349 + "dozen",
350 + "dreams",
351 + "drinks",
352 + "drowning",
353 + "drunk",
354 + "drying",
355 + "dual",
356 + "dubbed",
357 + "duckling",
358 + "dude",
359 + "duets",
360 + "duke",
361 + "dullness",
362 + "dummy",
363 + "dunes",
364 + "duplex",
365 + "duration",
366 + "dusted",
367 + "duties",
368 + "dwarf",
369 + "dwelt",
370 + "dwindling",
371 + "dying",
372 + "dynamite",
373 + "dyslexic",
374 + "each",
375 + "eagle",
376 + "earth",
377 + "easy",
378 + "eating",
379 + "eavesdrop",
380 + "eccentric",
381 + "echo",
382 + "eclipse",
383 + "economics",
384 + "ecstatic",
385 + "eden",
386 + "edgy",
387 + "edited",
388 + "educated",
389 + "eels",
390 + "efficient",
391 + "eggs",
392 + "egotistic",
393 + "eight",
394 + "either",
395 + "eject",
396 + "elapse",
397 + "elbow",
398 + "eldest",
399 + "eleven",
400 + "elite",
401 + "elope",
402 + "else",
403 + "eluded",
404 + "emails",
405 + "ember",
406 + "emerge",
407 + "emit",
408 + "emotion",
409 + "empty",
410 + "emulate",
411 + "energy",
412 + "enforce",
413 + "enhanced",
414 + "enigma",
415 + "enjoy",
416 + "enlist",
417 + "enmity",
418 + "enough",
419 + "enraged",
420 + "ensign",
421 + "entrance",
422 + "envy",
423 + "epoxy",
424 + "equip",
425 + "erase",
426 + "erected",
427 + "erosion",
428 + "error",
429 + "eskimos",
430 + "espionage",
431 + "essential",
432 + "estate",
433 + "etched",
434 + "eternal",
435 + "ethics",
436 + "etiquette",
437 + "evaluate",
438 + "evenings",
439 + "evicted",
440 + "evolved",
441 + "examine",
442 + "excess",
443 + "exhale",
444 + "exit",
445 + "exotic",
446 + "exquisite",
447 + "extra",
448 + "exult",
449 + "fabrics",
450 + "factual",
451 + "fading",
452 + "fainted",
453 + "faked",
454 + "fall",
455 + "family",
456 + "fancy",
457 + "farming",
458 + "fatal",
459 + "faulty",
460 + "fawns",
461 + "faxed",
462 + "fazed",
463 + "feast",
464 + "february",
465 + "federal",
466 + "feel",
467 + "feline",
468 + "females",
469 + "fences",
470 + "ferry",
471 + "festival",
472 + "fetches",
473 + "fever",
474 + "fewest",
475 + "fiat",
476 + "fibula",
477 + "fictional",
478 + "fidget",
479 + "fierce",
480 + "fifteen",
481 + "fight",
482 + "films",
483 + "firm",
484 + "fishing",
485 + "fitting",
486 + "five",
487 + "fixate",
488 + "fizzle",
489 + "fleet",
490 + "flippant",
491 + "flying",
492 + "foamy",
493 + "focus",
494 + "foes",
495 + "foggy",
496 + "foiled",
497 + "folding",
498 + "fonts",
499 + "foolish",
500 + "fossil",
501 + "fountain",
502 + "fowls",
503 + "foxes",
504 + "foyer",
505 + "framed",
506 + "friendly",
507 + "frown",
508 + "fruit",
509 + "frying",
510 + "fudge",
511 + "fuel",
512 + "fugitive",
513 + "fully",
514 + "fuming",
515 + "fungal",
516 + "furnished",
517 + "fuselage",
518 + "future",
519 + "fuzzy",
520 + "gables",
521 + "gadget",
522 + "gags",
523 + "gained",
524 + "galaxy",
525 + "gambit",
526 + "gang",
527 + "gasp",
528 + "gather",
529 + "gauze",
530 + "gave",
531 + "gawk",
532 + "gaze",
533 + "gearbox",
534 + "gecko",
535 + "geek",
536 + "gels",
537 + "gemstone",
538 + "general",
539 + "geometry",
540 + "germs",
541 + "gesture",
542 + "getting",
543 + "geyser",
544 + "ghetto",
545 + "ghost",
546 + "giant",
547 + "giddy",
548 + "gifts",
549 + "gigantic",
550 + "gills",
551 + "gimmick",
552 + "ginger",
553 + "girth",
554 + "giving",
555 + "glass",
556 + "gleeful",
557 + "glide",
558 + "gnaw",
559 + "gnome",
560 + "goat",
561 + "goblet",
562 + "godfather",
563 + "goes",
564 + "goggles",
565 + "going",
566 + "goldfish",
567 + "gone",
568 + "goodbye",
569 + "gopher",
570 + "gorilla",
571 + "gossip",
572 + "gotten",
573 + "gourmet",
574 + "governing",
575 + "gown",
576 + "greater",
577 + "grunt",
578 + "guarded",
579 + "guest",
580 + "guide",
581 + "gulp",
582 + "gumball",
583 + "guru",
584 + "gusts",
585 + "gutter",
586 + "guys",
587 + "gymnast",
588 + "gypsy",
589 + "gyrate",
590 + "habitat",
591 + "hacksaw",
592 + "haggled",
593 + "hairy",
594 + "hamburger",
595 + "happens",
596 + "hashing",
597 + "hatchet",
598 + "haunted",
599 + "having",
600 + "hawk",
601 + "haystack",
602 + "hazard",
603 + "hectare",
604 + "hedgehog",
605 + "heels",
606 + "hefty",
607 + "height",
608 + "hemlock",
609 + "hence",
610 + "heron",
611 + "hesitate",
612 + "hexagon",
613 + "hickory",
614 + "hiding",
615 + "highway",
616 + "hijack",
617 + "hiker",
618 + "hills",
619 + "himself",
620 + "hinder",
621 + "hippo",
622 + "hire",
623 + "history",
624 + "hitched",
625 + "hive",
626 + "hoax",
627 + "hobby",
628 + "hockey",
629 + "hoisting",
630 + "hold",
631 + "honked",
632 + "hookup",
633 + "hope",
634 + "hornet",
635 + "hospital",
636 + "hotel",
637 + "hounded",
638 + "hover",
639 + "howls",
640 + "hubcaps",
641 + "huddle",
642 + "huge",
643 + "hull",
644 + "humid",
645 + "hunter",
646 + "hurried",
647 + "husband",
648 + "huts",
649 + "hybrid",
650 + "hydrogen",
651 + "hyper",
652 + "iceberg",
653 + "icing",
654 + "icon",
655 + "identity",
656 + "idiom",
657 + "idled",
658 + "idols",
659 + "igloo",
660 + "ignore",
661 + "iguana",
662 + "illness",
663 + "imagine",
664 + "imbalance",
665 + "imitate",
666 + "impel",
667 + "inactive",
668 + "inbound",
669 + "incur",
670 + "industrial",
671 + "inexact",
672 + "inflamed",
673 + "ingested",
674 + "initiate",
675 + "injury",
676 + "inkling",
677 + "inline",
678 + "inmate",
679 + "innocent",
680 + "inorganic",
681 + "input",
682 + "inquest",
683 + "inroads",
684 + "insult",
685 + "intended",
686 + "inundate",
687 + "invoke",
688 + "inwardly",
689 + "ionic",
690 + "irate",
691 + "iris",
692 + "irony",
693 + "irritate",
694 + "island",
695 + "isolated",
696 + "issued",
697 + "italics",
698 + "itches",
699 + "items",
700 + "itinerary",
701 + "itself",
702 + "ivory",
703 + "jabbed",
704 + "jackets",
705 + "jaded",
706 + "jagged",
707 + "jailed",
708 + "jamming",
709 + "january",
710 + "jargon",
711 + "jaunt",
712 + "javelin",
713 + "jaws",
714 + "jazz",
715 + "jeans",
716 + "jeers",
717 + "jellyfish",
718 + "jeopardy",
719 + "jerseys",
720 + "jester",
721 + "jetting",
722 + "jewels",
723 + "jigsaw",
724 + "jingle",
725 + "jittery",
726 + "jive",
727 + "jobs",
728 + "jockey",
729 + "jogger",
730 + "joining",
731 + "joking",
732 + "jolted",
733 + "jostle",
734 + "journal",
735 + "joyous",
736 + "jubilee",
737 + "judge",
738 + "juggled",
739 + "juicy",
740 + "jukebox",
741 + "july",
742 + "jump",
743 + "junk",
744 + "jury",
745 + "justice",
746 + "juvenile",
747 + "kangaroo",
748 + "karate",
749 + "keep",
750 + "kennel",
751 + "kept",
752 + "kernels",
753 + "kettle",
754 + "keyboard",
755 + "kickoff",
756 + "kidneys",
757 + "king",
758 + "kiosk",
759 + "kisses",
760 + "kitchens",
761 + "kiwi",
762 + "knapsack",
763 + "knee",
764 + "knife",
765 + "knowledge",
766 + "knuckle",
767 + "koala",
768 + "laboratory",
769 + "ladder",
770 + "lagoon",
771 + "lair",
772 + "lakes",
773 + "lamb",
774 + "language",
775 + "laptop",
776 + "large",
777 + "last",
778 + "later",
779 + "launching",
780 + "lava",
781 + "lawsuit",
782 + "layout",
783 + "lazy",
784 + "lectures",
785 + "ledge",
786 + "leech",
787 + "left",
788 + "legion",
789 + "leisure",
790 + "lemon",
791 + "lending",
792 + "leopard",
793 + "lesson",
794 + "lettuce",
795 + "lexicon",
796 + "liar",
797 + "library",
798 + "licks",
799 + "lids",
800 + "lied",
801 + "lifestyle",
802 + "light",
803 + "likewise",
804 + "lilac",
805 + "limits",
806 + "linen",
807 + "lion",
808 + "lipstick",
809 + "liquid",
810 + "listen",
811 + "lively",
812 + "loaded",
813 + "lobster",
814 + "locker",
815 + "lodge",
816 + "lofty",
817 + "logic",
818 + "loincloth",
819 + "long",
820 + "looking",
821 + "lopped",
822 + "lordship",
823 + "losing",
824 + "lottery",
825 + "loudly",
826 + "love",
827 + "lower",
828 + "loyal",
829 + "lucky",
830 + "luggage",
831 + "lukewarm",
832 + "lullaby",
833 + "lumber",
834 + "lunar",
835 + "lurk",
836 + "lush",
837 + "luxury",
838 + "lymph",
839 + "lynx",
840 + "lyrics",
841 + "macro",
842 + "madness",
843 + "magically",
844 + "mailed",
845 + "major",
846 + "makeup",
847 + "malady",
848 + "mammal",
849 + "maps",
850 + "masterful",
851 + "match",
852 + "maul",
853 + "maverick",
854 + "maximum",
855 + "mayor",
856 + "maze",
857 + "meant",
858 + "mechanic",
859 + "medicate",
860 + "meeting",
861 + "megabyte",
862 + "melting",
863 + "memoir",
864 + "menu",
865 + "merger",
866 + "mesh",
867 + "metro",
868 + "mews",
869 + "mice",
870 + "midst",
871 + "mighty",
872 + "mime",
873 + "mirror",
874 + "misery",
875 + "mittens",
876 + "mixture",
877 + "moat",
878 + "mobile",
879 + "mocked",
880 + "mohawk",
881 + "moisture",
882 + "molten",
883 + "moment",
884 + "money",
885 + "moon",
886 + "mops",
887 + "morsel",
888 + "mostly",
889 + "motherly",
890 + "mouth",
891 + "movement",
892 + "mowing",
893 + "much",
894 + "muddy",
895 + "muffin",
896 + "mugged",
897 + "mullet",
898 + "mumble",
899 + "mundane",
900 + "muppet",
901 + "mural",
902 + "musical",
903 + "muzzle",
904 + "myriad",
905 + "mystery",
906 + "myth",
907 + "nabbing",
908 + "nagged",
909 + "nail",
910 + "names",
911 + "nanny",
912 + "napkin",
913 + "narrate",
914 + "nasty",
915 + "natural",
916 + "nautical",
917 + "navy",
918 + "nearby",
919 + "necklace",
920 + "needed",
921 + "negative",
922 + "neither",
923 + "neon",
924 + "nephew",
925 + "nerves",
926 + "nestle",
927 + "network",
928 + "neutral",
929 + "never",
930 + "newt",
931 + "nexus",
932 + "nibs",
933 + "niche",
934 + "niece",
935 + "nifty",
936 + "nightly",
937 + "nimbly",
938 + "nineteen",
939 + "nirvana",
940 + "nitrogen",
941 + "nobody",
942 + "nocturnal",
943 + "nodes",
944 + "noises",
945 + "nomad",
946 + "noodles",
947 + "northern",
948 + "nostril",
949 + "noted",
950 + "nouns",
951 + "novelty",
952 + "nowhere",
953 + "nozzle",
954 + "nuance",
955 + "nucleus",
956 + "nudged",
957 + "nugget",
958 + "nuisance",
959 + "null",
960 + "number",
961 + "nuns",
962 + "nurse",
963 + "nutshell",
964 + "nylon",
965 + "oaks",
966 + "oars",
967 + "oasis",
968 + "oatmeal",
969 + "obedient",
970 + "object",
971 + "obliged",
972 + "obnoxious",
973 + "observant",
974 + "obtains",
975 + "obvious",
976 + "occur",
977 + "ocean",
978 + "october",
979 + "odds",
980 + "odometer",
981 + "offend",
982 + "often",
983 + "oilfield",
984 + "ointment",
985 + "okay",
986 + "older",
987 + "olive",
988 + "olympics",
989 + "omega",
990 + "omission",
991 + "omnibus",
992 + "onboard",
993 + "oncoming",
994 + "oneself",
995 + "ongoing",
996 + "onion",
997 + "online",
998 + "onslaught",
999 + "onto",
1000 + "onward",
1001 + "oozed",
1002 + "opacity",
1003 + "opened",
1004 + "opposite",
1005 + "optical",
1006 + "opus",
1007 + "orange",
1008 + "orbit",
1009 + "orchid",
1010 + "orders",
1011 + "organs",
1012 + "origin",
1013 + "ornament",
1014 + "orphans",
1015 + "oscar",
1016 + "ostrich",
1017 + "otherwise",
1018 + "otter",
1019 + "ouch",
1020 + "ought",
1021 + "ounce",
1022 + "ourselves",
1023 + "oust",
1024 + "outbreak",
1025 + "oval",
1026 + "oven",
1027 + "owed",
1028 + "owls",
1029 + "owner",
1030 + "oxidant",
1031 + "oxygen",
1032 + "oyster",
1033 + "ozone",
1034 + "pact",
1035 + "paddles",
1036 + "pager",
1037 + "pairing",
1038 + "palace",
1039 + "pamphlet",
1040 + "pancakes",
1041 + "paper",
1042 + "paradise",
1043 + "pastry",
1044 + "patio",
1045 + "pause",
1046 + "pavements",
1047 + "pawnshop",
1048 + "payment",
1049 + "peaches",
1050 + "pebbles",
1051 + "peculiar",
1052 + "pedantic",
1053 + "peeled",
1054 + "pegs",
1055 + "pelican",
1056 + "pencil",
1057 + "people",
1058 + "pepper",
1059 + "perfect",
1060 + "pests",
1061 + "petals",
1062 + "phase",
1063 + "pheasants",
1064 + "phone",
1065 + "phrases",
1066 + "physics",
1067 + "piano",
1068 + "picked",
1069 + "pierce",
1070 + "pigment",
1071 + "piloted",
1072 + "pimple",
1073 + "pinched",
1074 + "pioneer",
1075 + "pipeline",
1076 + "pirate",
1077 + "pistons",
1078 + "pitched",
1079 + "pivot",
1080 + "pixels",
1081 + "pizza",
1082 + "playful",
1083 + "pledge",
1084 + "pliers",
1085 + "plotting",
1086 + "plus",
1087 + "plywood",
1088 + "poaching",
1089 + "pockets",
1090 + "podcast",
1091 + "poetry",
1092 + "point",
1093 + "poker",
1094 + "polar",
1095 + "ponies",
1096 + "pool",
1097 + "popular",
1098 + "portents",
1099 + "possible",
1100 + "potato",
1101 + "pouch",
1102 + "poverty",
1103 + "powder",
1104 + "pram",
1105 + "present",
1106 + "pride",
1107 + "problems",
1108 + "pruned",
1109 + "prying",
1110 + "psychic",
1111 + "public",
1112 + "puck",
1113 + "puddle",
1114 + "puffin",
1115 + "pulp",
1116 + "pumpkins",
1117 + "punch",
1118 + "puppy",
1119 + "purged",
1120 + "push",
1121 + "putty",
1122 + "puzzled",
1123 + "pylons",
1124 + "pyramid",
1125 + "python",
1126 + "queen",
1127 + "quick",
1128 + "quote",
1129 + "rabbits",
1130 + "racetrack",
1131 + "radar",
1132 + "rafts",
1133 + "rage",
1134 + "railway",
1135 + "raking",
1136 + "rally",
1137 + "ramped",
1138 + "randomly",
1139 + "rapid",
1140 + "rarest",
1141 + "rash",
1142 + "rated",
1143 + "ravine",
1144 + "rays",
1145 + "razor",
1146 + "react",
1147 + "rebel",
1148 + "recipe",
1149 + "reduce",
1150 + "reef",
1151 + "refer",
1152 + "regular",
1153 + "reheat",
1154 + "reinvest",
1155 + "rejoices",
1156 + "rekindle",
1157 + "relic",
1158 + "remedy",
1159 + "renting",
1160 + "reorder",
1161 + "repent",
1162 + "request",
1163 + "reruns",
1164 + "rest",
1165 + "return",
1166 + "reunion",
1167 + "revamp",
1168 + "rewind",
1169 + "rhino",
1170 + "rhythm",
1171 + "ribbon",
1172 + "richly",
1173 + "ridges",
1174 + "rift",
1175 + "rigid",
1176 + "rims",
1177 + "ringing",
1178 + "riots",
1179 + "ripped",
1180 + "rising",
1181 + "ritual",
1182 + "river",
1183 + "roared",
1184 + "robot",
1185 + "rockets",
1186 + "rodent",
1187 + "rogue",
1188 + "roles",
1189 + "romance",
1190 + "roomy",
1191 + "roped",
1192 + "roster",
1193 + "rotate",
1194 + "rounded",
1195 + "rover",
1196 + "rowboat",
1197 + "royal",
1198 + "ruby",
1199 + "rudely",
1200 + "ruffled",
1201 + "rugged",
1202 + "ruined",
1203 + "ruling",
1204 + "rumble",
1205 + "runway",
1206 + "rural",
1207 + "rustled",
1208 + "ruthless",
1209 + "sabotage",
1210 + "sack",
1211 + "sadness",
1212 + "safety",
1213 + "saga",
1214 + "sailor",
1215 + "sake",
1216 + "salads",
1217 + "sample",
1218 + "sanity",
1219 + "sapling",
1220 + "sarcasm",
1221 + "sash",
1222 + "satin",
1223 + "saucepan",
1224 + "saved",
1225 + "sawmill",
1226 + "saxophone",
1227 + "sayings",
1228 + "scamper",
1229 + "scenic",
1230 + "school",
1231 + "science",
1232 + "scoop",
1233 + "scrub",
1234 + "scuba",
1235 + "seasons",
1236 + "second",
1237 + "sedan",
1238 + "seeded",
1239 + "segments",
1240 + "seismic",
1241 + "selfish",
1242 + "semifinal",
1243 + "sensible",
1244 + "september",
1245 + "sequence",
1246 + "serving",
1247 + "session",
1248 + "setup",
1249 + "seventh",
1250 + "sewage",
1251 + "shackles",
1252 + "shelter",
1253 + "shipped",
1254 + "shocking",
1255 + "shrugged",
1256 + "shuffled",
1257 + "shyness",
1258 + "siblings",
1259 + "sickness",
1260 + "sidekick",
1261 + "sieve",
1262 + "sifting",
1263 + "sighting",
1264 + "silk",
1265 + "simplest",
1266 + "sincerely",
1267 + "sipped",
1268 + "siren",
1269 + "situated",
1270 + "sixteen",
1271 + "sizes",
1272 + "skater",
1273 + "skew",
1274 + "skirting",
1275 + "skulls",
1276 + "skydive",
1277 + "slackens",
1278 + "sleepless",
1279 + "slid",
1280 + "slower",
1281 + "slug",
1282 + "smash",
1283 + "smelting",
1284 + "smidgen",
1285 + "smog",
1286 + "smuggled",
1287 + "snake",
1288 + "sneeze",
1289 + "sniff",
1290 + "snout",
1291 + "snug",
1292 + "soapy",
1293 + "sober",
1294 + "soccer",
1295 + "soda",
1296 + "software",
1297 + "soggy",
1298 + "soil",
1299 + "solved",
1300 + "somewhere",
1301 + "sonic",
1302 + "soothe",
1303 + "soprano",
1304 + "sorry",
1305 + "southern",
1306 + "sovereign",
1307 + "sowed",
1308 + "soya",
1309 + "space",
1310 + "speedy",
1311 + "sphere",
1312 + "spiders",
1313 + "splendid",
1314 + "spout",
1315 + "sprig",
1316 + "spud",
1317 + "spying",
1318 + "square",
1319 + "stacking",
1320 + "stellar",
1321 + "stick",
1322 + "stockpile",
1323 + "strained",
1324 + "stunning",
1325 + "stylishly",
1326 + "subtly",
1327 + "succeed",
1328 + "suddenly",
1329 + "suede",
1330 + "suffice",
1331 + "sugar",
1332 + "suitcase",
1333 + "sulking",
1334 + "summon",
1335 + "sunken",
1336 + "superior",
1337 + "surfer",
1338 + "sushi",
1339 + "suture",
1340 + "swagger",
1341 + "swept",
1342 + "swiftly",
1343 + "sword",
1344 + "swung",
1345 + "syllabus",
1346 + "symptoms",
1347 + "syndrome",
1348 + "syringe",
1349 + "system",
1350 + "taboo",
1351 + "tacit",
1352 + "tadpoles",
1353 + "tagged",
1354 + "tail",
1355 + "taken",
1356 + "talent",
1357 + "tamper",
1358 + "tanks",
1359 + "tapestry",
1360 + "tarnished",
1361 + "tasked",
1362 + "tattoo",
1363 + "taunts",
1364 + "tavern",
1365 + "tawny",
1366 + "taxi",
1367 + "teardrop",
1368 + "technical",
1369 + "tedious",
1370 + "teeming",
1371 + "tell",
1372 + "template",
1373 + "tender",
1374 + "tepid",
1375 + "tequila",
1376 + "terminal",
1377 + "testing",
1378 + "tether",
1379 + "textbook",
1380 + "thaw",
1381 + "theatrics",
1382 + "thirsty",
1383 + "thorn",
1384 + "threaten",
1385 + "thumbs",
1386 + "thwart",
1387 + "ticket",
1388 + "tidy",
1389 + "tiers",
1390 + "tiger",
1391 + "tilt",
1392 + "timber",
1393 + "tinted",
1394 + "tipsy",
1395 + "tirade",
1396 + "tissue",
1397 + "titans",
1398 + "toaster",
1399 + "tobacco",
1400 + "today",
1401 + "toenail",
1402 + "toffee",
1403 + "together",
1404 + "toilet",
1405 + "token",
1406 + "tolerant",
1407 + "tomorrow",
1408 + "tonic",
1409 + "toolbox",
1410 + "topic",
1411 + "torch",
1412 + "tossed",
1413 + "total",
1414 + "touchy",
1415 + "towel",
1416 + "toxic",
1417 + "toyed",
1418 + "trash",
1419 + "trendy",
1420 + "tribal",
1421 + "trolling",
1422 + "truth",
1423 + "trying",
1424 + "tsunami",
1425 + "tubes",
1426 + "tucks",
1427 + "tudor",
1428 + "tuesday",
1429 + "tufts",
1430 + "tugs",
1431 + "tuition",
1432 + "tulips",
1433 + "tumbling",
1434 + "tunnel",
1435 + "turnip",
1436 + "tusks",
1437 + "tutor",
1438 + "tuxedo",
1439 + "twang",
1440 + "tweezers",
1441 + "twice",
1442 + "twofold",
1443 + "tycoon",
1444 + "typist",
1445 + "tyrant",
1446 + "ugly",
1447 + "ulcers",
1448 + "ultimate",
1449 + "umbrella",
1450 + "umpire",
1451 + "unafraid",
1452 + "unbending",
1453 + "uncle",
1454 + "under",
1455 + "uneven",
1456 + "unfit",
1457 + "ungainly",
1458 + "unhappy",
1459 + "union",
1460 + "unjustly",
1461 + "unknown",
1462 + "unlikely",
1463 + "unmask",
1464 + "unnoticed",
1465 + "unopened",
1466 + "unplugs",
1467 + "unquoted",
1468 + "unrest",
1469 + "unsafe",
1470 + "until",
1471 + "unusual",
1472 + "unveil",
1473 + "unwind",
1474 + "unzip",
1475 + "upbeat",
1476 + "upcoming",
1477 + "update",
1478 + "upgrade",
1479 + "uphill",
1480 + "upkeep",
1481 + "upload",
1482 + "upon",
1483 + "upper",
1484 + "upright",
1485 + "upstairs",
1486 + "uptight",
1487 + "upwards",
1488 + "urban",
1489 + "urchins",
1490 + "urgent",
1491 + "usage",
1492 + "useful",
1493 + "usher",
1494 + "using",
1495 + "usual",
1496 + "utensils",
1497 + "utility",
1498 + "utmost",
1499 + "utopia",
1500 + "uttered",
1501 + "vacation",
1502 + "vague",
1503 + "vain",
1504 + "value",
1505 + "vampire",
1506 + "vane",
1507 + "vapidly",
1508 + "vary",
1509 + "vastness",
1510 + "vats",
1511 + "vaults",
1512 + "vector",
1513 + "veered",
1514 + "vegan",
1515 + "vehicle",
1516 + "vein",
1517 + "velvet",
1518 + "venomous",
1519 + "verification",
1520 + "vessel",
1521 + "veteran",
1522 + "vexed",
1523 + "vials",
1524 + "vibrate",
1525 + "victim",
1526 + "video",
1527 + "viewpoint",
1528 + "vigilant",
1529 + "viking",
1530 + "village",
1531 + "vinegar",
1532 + "violin",
1533 + "vipers",
1534 + "virtual",
1535 + "visited",
1536 + "vitals",
1537 + "vivid",
1538 + "vixen",
1539 + "vocal",
1540 + "vogue",
1541 + "voice",
1542 + "volcano",
1543 + "vortex",
1544 + "voted",
1545 + "voucher",
1546 + "vowels",
1547 + "voyage",
1548 + "vulture",
1549 + "wade",
1550 + "waffle",
1551 + "wagtail",
1552 + "waist",
1553 + "waking",
1554 + "wallets",
1555 + "wanted",
1556 + "warped",
1557 + "washing",
1558 + "water",
1559 + "waveform",
1560 + "waxing",
1561 + "wayside",
1562 + "weavers",
1563 + "website",
1564 + "wedge",
1565 + "weekday",
1566 + "weird",
1567 + "welders",
1568 + "went",
1569 + "wept",
1570 + "were",
1571 + "western",
1572 + "wetsuit",
1573 + "whale",
1574 + "when",
1575 + "whipped",
1576 + "whole",
1577 + "wickets",
1578 + "width",
1579 + "wield",
1580 + "wife",
1581 + "wiggle",
1582 + "wildly",
1583 + "winter",
1584 + "wipeout",
1585 + "wiring",
1586 + "wise",
1587 + "withdrawn",
1588 + "wives",
1589 + "wizard",
1590 + "wobbly",
1591 + "woes",
1592 + "woken",
1593 + "wolf",
1594 + "womanly",
1595 + "wonders",
1596 + "woozy",
1597 + "worry",
1598 + "wounded",
1599 + "woven",
1600 + "wrap",
1601 + "wrist",
1602 + "wrong",
1603 + "yacht",
1604 + "yahoo",
1605 + "yanks",
1606 + "yard",
1607 + "yawning",
1608 + "yearbook",
1609 + "yellow",
1610 + "yesterday",
1611 + "yeti",
1612 + "yields",
1613 + "yodel",
1614 + "yoga",
1615 + "younger",
1616 + "yoyo",
1617 + "zapped",
1618 + "zeal",
1619 + "zebra",
1620 + "zero",
1621 + "zesty",
1622 + "zigzags",
1623 + "zinger",
1624 + "zippers",
1625 + "zodiac",
1626 + "zombie",
1627 + "zones",
1628 + "zoom"
1629 + ];
1630 +}
cw_wownero/lib/mnemonics/french.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class FrenchMnemonics {
2 + static const words = [
3 + "abandon",
4 + "abattre",
5 + "aboi",
6 + "abolir",
7 + "aborder",
8 + "abri",
9 + "absence",
10 + "absolu",
11 + "abuser",
12 + "acacia",
13 + "acajou",
14 + "accent",
15 + "accord",
16 + "accrocher",
17 + "accuser",
18 + "acerbe",
19 + "achat",
20 + "acheter",
21 + "acide",
22 + "acier",
23 + "acquis",
24 + "acte",
25 + "action",
26 + "adage",
27 + "adepte",
28 + "adieu",
29 + "admettre",
30 + "admis",
31 + "adorer",
32 + "adresser",
33 + "aduler",
34 + "affaire",
35 + "affirmer",
36 + "afin",
37 + "agacer",
38 + "agent",
39 + "agir",
40 + "agiter",
41 + "agonie",
42 + "agrafe",
43 + "agrume",
44 + "aider",
45 + "aigle",
46 + "aigre",
47 + "aile",
48 + "ailleurs",
49 + "aimant",
50 + "aimer",
51 + "ainsi",
52 + "aise",
53 + "ajouter",
54 + "alarme",
55 + "album",
56 + "alcool",
57 + "alerte",
58 + "algue",
59 + "alibi",
60 + "aller",
61 + "allumer",
62 + "alors",
63 + "amande",
64 + "amener",
65 + "amie",
66 + "amorcer",
67 + "amour",
68 + "ample",
69 + "amuser",
70 + "ananas",
71 + "ancien",
72 + "anglais",
73 + "angoisse",
74 + "animal",
75 + "anneau",
76 + "annoncer",
77 + "apercevoir",
78 + "apparence",
79 + "appel",
80 + "apporter",
81 + "apprendre",
82 + "appuyer",
83 + "arbre",
84 + "arcade",
85 + "arceau",
86 + "arche",
87 + "ardeur",
88 + "argent",
89 + "argile",
90 + "aride",
91 + "arme",
92 + "armure",
93 + "arracher",
94 + "arriver",
95 + "article",
96 + "asile",
97 + "aspect",
98 + "assaut",
99 + "assez",
100 + "assister",
101 + "assurer",
102 + "astre",
103 + "astuce",
104 + "atlas",
105 + "atroce",
106 + "attacher",
107 + "attente",
108 + "attirer",
109 + "aube",
110 + "aucun",
111 + "audace",
112 + "auparavant",
113 + "auquel",
114 + "aurore",
115 + "aussi",
116 + "autant",
117 + "auteur",
118 + "autoroute",
119 + "autre",
120 + "aval",
121 + "avant",
122 + "avec",
123 + "avenir",
124 + "averse",
125 + "aveu",
126 + "avide",
127 + "avion",
128 + "avis",
129 + "avoir",
130 + "avouer",
131 + "avril",
132 + "azote",
133 + "azur",
134 + "badge",
135 + "bagage",
136 + "bague",
137 + "bain",
138 + "baisser",
139 + "balai",
140 + "balcon",
141 + "balise",
142 + "balle",
143 + "bambou",
144 + "banane",
145 + "banc",
146 + "bandage",
147 + "banjo",
148 + "banlieue",
149 + "bannir",
150 + "banque",
151 + "baobab",
152 + "barbe",
153 + "barque",
154 + "barrer",
155 + "bassine",
156 + "bataille",
157 + "bateau",
158 + "battre",
159 + "baver",
160 + "bavoir",
161 + "bazar",
162 + "beau",
163 + "beige",
164 + "berger",
165 + "besoin",
166 + "beurre",
167 + "biais",
168 + "biceps",
169 + "bidule",
170 + "bien",
171 + "bijou",
172 + "bilan",
173 + "billet",
174 + "blanc",
175 + "blason",
176 + "bleu",
177 + "bloc",
178 + "blond",
179 + "bocal",
180 + "boire",
181 + "boiserie",
182 + "boiter",
183 + "bonbon",
184 + "bondir",
185 + "bonheur",
186 + "bordure",
187 + "borgne",
188 + "borner",
189 + "bosse",
190 + "bouche",
191 + "bouder",
192 + "bouger",
193 + "boule",
194 + "bourse",
195 + "bout",
196 + "boxe",
197 + "brader",
198 + "braise",
199 + "branche",
200 + "braquer",
201 + "bras",
202 + "brave",
203 + "brebis",
204 + "brevet",
205 + "brider",
206 + "briller",
207 + "brin",
208 + "brique",
209 + "briser",
210 + "broche",
211 + "broder",
212 + "bronze",
213 + "brosser",
214 + "brouter",
215 + "bruit",
216 + "brute",
217 + "budget",
218 + "buffet",
219 + "bulle",
220 + "bureau",
221 + "buriner",
222 + "buste",
223 + "buter",
224 + "butiner",
225 + "cabas",
226 + "cabinet",
227 + "cabri",
228 + "cacao",
229 + "cacher",
230 + "cadeau",
231 + "cadre",
232 + "cage",
233 + "caisse",
234 + "caler",
235 + "calme",
236 + "camarade",
237 + "camion",
238 + "campagne",
239 + "canal",
240 + "canif",
241 + "capable",
242 + "capot",
243 + "carat",
244 + "caresser",
245 + "carie",
246 + "carpe",
247 + "cartel",
248 + "casier",
249 + "casque",
250 + "casserole",
251 + "cause",
252 + "cavale",
253 + "cave",
254 + "ceci",
255 + "cela",
256 + "celui",
257 + "cendre",
258 + "cent",
259 + "cependant",
260 + "cercle",
261 + "cerise",
262 + "cerner",
263 + "certes",
264 + "cerveau",
265 + "cesser",
266 + "chacun",
267 + "chair",
268 + "chaleur",
269 + "chamois",
270 + "chanson",
271 + "chaque",
272 + "charge",
273 + "chasse",
274 + "chat",
275 + "chaud",
276 + "chef",
277 + "chemin",
278 + "cheveu",
279 + "chez",
280 + "chicane",
281 + "chien",
282 + "chiffre",
283 + "chiner",
284 + "chiot",
285 + "chlore",
286 + "choc",
287 + "choix",
288 + "chose",
289 + "chou",
290 + "chute",
291 + "cibler",
292 + "cidre",
293 + "ciel",
294 + "cigale",
295 + "cinq",
296 + "cintre",
297 + "cirage",
298 + "cirque",
299 + "ciseau",
300 + "citation",
301 + "citer",
302 + "citron",
303 + "civet",
304 + "clairon",
305 + "clan",
306 + "classe",
307 + "clavier",
308 + "clef",
309 + "climat",
310 + "cloche",
311 + "cloner",
312 + "clore",
313 + "clos",
314 + "clou",
315 + "club",
316 + "cobra",
317 + "cocon",
318 + "coiffer",
319 + "coin",
320 + "colline",
321 + "colon",
322 + "combat",
323 + "comme",
324 + "compte",
325 + "conclure",
326 + "conduire",
327 + "confier",
328 + "connu",
329 + "conseil",
330 + "contre",
331 + "convenir",
332 + "copier",
333 + "cordial",
334 + "cornet",
335 + "corps",
336 + "cosmos",
337 + "coton",
338 + "couche",
339 + "coude",
340 + "couler",
341 + "coupure",
342 + "cour",
343 + "couteau",
344 + "couvrir",
345 + "crabe",
346 + "crainte",
347 + "crampe",
348 + "cran",
349 + "creuser",
350 + "crever",
351 + "crier",
352 + "crime",
353 + "crin",
354 + "crise",
355 + "crochet",
356 + "croix",
357 + "cruel",
358 + "cuisine",
359 + "cuite",
360 + "culot",
361 + "culte",
362 + "cumul",
363 + "cure",
364 + "curieux",
365 + "cuve",
366 + "dame",
367 + "danger",
368 + "dans",
369 + "davantage",
370 + "debout",
371 + "dedans",
372 + "dehors",
373 + "delta",
374 + "demain",
375 + "demeurer",
376 + "demi",
377 + "dense",
378 + "dent",
379 + "depuis",
380 + "dernier",
381 + "descendre",
382 + "dessus",
383 + "destin",
384 + "dette",
385 + "deuil",
386 + "deux",
387 + "devant",
388 + "devenir",
389 + "devin",
390 + "devoir",
391 + "dicton",
392 + "dieu",
393 + "difficile",
394 + "digestion",
395 + "digue",
396 + "diluer",
397 + "dimanche",
398 + "dinde",
399 + "diode",
400 + "dire",
401 + "diriger",
402 + "discours",
403 + "disposer",
404 + "distance",
405 + "divan",
406 + "divers",
407 + "docile",
408 + "docteur",
409 + "dodu",
410 + "dogme",
411 + "doigt",
412 + "dominer",
413 + "donation",
414 + "donjon",
415 + "donner",
416 + "dopage",
417 + "dorer",
418 + "dormir",
419 + "doseur",
420 + "douane",
421 + "double",
422 + "douche",
423 + "douleur",
424 + "doute",
425 + "doux",
426 + "douzaine",
427 + "draguer",
428 + "drame",
429 + "drap",
430 + "dresser",
431 + "droit",
432 + "duel",
433 + "dune",
434 + "duper",
435 + "durant",
436 + "durcir",
437 + "durer",
438 + "eaux",
439 + "effacer",
440 + "effet",
441 + "effort",
442 + "effrayant",
443 + "elle",
444 + "embrasser",
445 + "emmener",
446 + "emparer",
447 + "empire",
448 + "employer",
449 + "emporter",
450 + "enclos",
451 + "encore",
452 + "endive",
453 + "endormir",
454 + "endroit",
455 + "enduit",
456 + "enfant",
457 + "enfermer",
458 + "enfin",
459 + "enfler",
460 + "enfoncer",
461 + "enfuir",
462 + "engager",
463 + "engin",
464 + "enjeu",
465 + "enlever",
466 + "ennemi",
467 + "ennui",
468 + "ensemble",
469 + "ensuite",
470 + "entamer",
471 + "entendre",
472 + "entier",
473 + "entourer",
474 + "entre",
475 + "envelopper",
476 + "envie",
477 + "envoyer",
478 + "erreur",
479 + "escalier",
480 + "espace",
481 + "espoir",
482 + "esprit",
483 + "essai",
484 + "essor",
485 + "essuyer",
486 + "estimer",
487 + "exact",
488 + "examiner",
489 + "excuse",
490 + "exemple",
491 + "exiger",
492 + "exil",
493 + "exister",
494 + "exode",
495 + "expliquer",
496 + "exposer",
497 + "exprimer",
498 + "extase",
499 + "fable",
500 + "facette",
501 + "facile",
502 + "fade",
503 + "faible",
504 + "faim",
505 + "faire",
506 + "fait",
507 + "falloir",
508 + "famille",
509 + "faner",
510 + "farce",
511 + "farine",
512 + "fatigue",
513 + "faucon",
514 + "faune",
515 + "faute",
516 + "faux",
517 + "faveur",
518 + "favori",
519 + "faxer",
520 + "feinter",
521 + "femme",
522 + "fendre",
523 + "fente",
524 + "ferme",
525 + "festin",
526 + "feuille",
527 + "feutre",
528 + "fiable",
529 + "fibre",
530 + "ficher",
531 + "fier",
532 + "figer",
533 + "figure",
534 + "filet",
535 + "fille",
536 + "filmer",
537 + "fils",
538 + "filtre",
539 + "final",
540 + "finesse",
541 + "finir",
542 + "fiole",
543 + "firme",
544 + "fixe",
545 + "flacon",
546 + "flair",
547 + "flamme",
548 + "flan",
549 + "flaque",
550 + "fleur",
551 + "flocon",
552 + "flore",
553 + "flot",
554 + "flou",
555 + "fluide",
556 + "fluor",
557 + "flux",
558 + "focus",
559 + "foin",
560 + "foire",
561 + "foison",
562 + "folie",
563 + "fonction",
564 + "fondre",
565 + "fonte",
566 + "force",
567 + "forer",
568 + "forger",
569 + "forme",
570 + "fort",
571 + "fosse",
572 + "fouet",
573 + "fouine",
574 + "foule",
575 + "four",
576 + "foyer",
577 + "frais",
578 + "franc",
579 + "frapper",
580 + "freiner",
581 + "frimer",
582 + "friser",
583 + "frite",
584 + "froid",
585 + "froncer",
586 + "fruit",
587 + "fugue",
588 + "fuir",
589 + "fuite",
590 + "fumer",
591 + "fureur",
592 + "furieux",
593 + "fuser",
594 + "fusil",
595 + "futile",
596 + "futur",
597 + "gagner",
598 + "gain",
599 + "gala",
600 + "galet",
601 + "galop",
602 + "gamme",
603 + "gant",
604 + "garage",
605 + "garde",
606 + "garer",
607 + "gauche",
608 + "gaufre",
609 + "gaule",
610 + "gaver",
611 + "gazon",
612 + "geler",
613 + "genou",
614 + "genre",
615 + "gens",
616 + "gercer",
617 + "germer",
618 + "geste",
619 + "gibier",
620 + "gicler",
621 + "gilet",
622 + "girafe",
623 + "givre",
624 + "glace",
625 + "glisser",
626 + "globe",
627 + "gloire",
628 + "gluant",
629 + "gober",
630 + "golf",
631 + "gommer",
632 + "gorge",
633 + "gosier",
634 + "goutte",
635 + "grain",
636 + "gramme",
637 + "grand",
638 + "gras",
639 + "grave",
640 + "gredin",
641 + "griffure",
642 + "griller",
643 + "gris",
644 + "gronder",
645 + "gros",
646 + "grotte",
647 + "groupe",
648 + "grue",
649 + "guerrier",
650 + "guetter",
651 + "guider",
652 + "guise",
653 + "habiter",
654 + "hache",
655 + "haie",
656 + "haine",
657 + "halte",
658 + "hamac",
659 + "hanche",
660 + "hangar",
661 + "hanter",
662 + "haras",
663 + "hareng",
664 + "harpe",
665 + "hasard",
666 + "hausse",
667 + "haut",
668 + "havre",
669 + "herbe",
670 + "heure",
671 + "hibou",
672 + "hier",
673 + "histoire",
674 + "hiver",
675 + "hochet",
676 + "homme",
677 + "honneur",
678 + "honte",
679 + "horde",
680 + "horizon",
681 + "hormone",
682 + "houle",
683 + "housse",
684 + "hublot",
685 + "huile",
686 + "huit",
687 + "humain",
688 + "humble",
689 + "humide",
690 + "humour",
691 + "hurler",
692 + "idole",
693 + "igloo",
694 + "ignorer",
695 + "illusion",
696 + "image",
697 + "immense",
698 + "immobile",
699 + "imposer",
700 + "impression",
701 + "incapable",
702 + "inconnu",
703 + "index",
704 + "indiquer",
705 + "infime",
706 + "injure",
707 + "inox",
708 + "inspirer",
709 + "instant",
710 + "intention",
711 + "intime",
712 + "inutile",
713 + "inventer",
714 + "inviter",
715 + "iode",
716 + "iris",
717 + "issue",
718 + "ivre",
719 + "jade",
720 + "jadis",
721 + "jamais",
722 + "jambe",
723 + "janvier",
724 + "jardin",
725 + "jauge",
726 + "jaunisse",
727 + "jeter",
728 + "jeton",
729 + "jeudi",
730 + "jeune",
731 + "joie",
732 + "joindre",
733 + "joli",
734 + "joueur",
735 + "journal",
736 + "judo",
737 + "juge",
738 + "juillet",
739 + "juin",
740 + "jument",
741 + "jungle",
742 + "jupe",
743 + "jupon",
744 + "jurer",
745 + "juron",
746 + "jury",
747 + "jusque",
748 + "juste",
749 + "kayak",
750 + "ketchup",
751 + "kilo",
752 + "kiwi",
753 + "koala",
754 + "label",
755 + "lacet",
756 + "lacune",
757 + "laine",
758 + "laisse",
759 + "lait",
760 + "lame",
761 + "lancer",
762 + "lande",
763 + "laque",
764 + "lard",
765 + "largeur",
766 + "larme",
767 + "larve",
768 + "lasso",
769 + "laver",
770 + "lendemain",
771 + "lentement",
772 + "lequel",
773 + "lettre",
774 + "leur",
775 + "lever",
776 + "levure",
777 + "liane",
778 + "libre",
779 + "lien",
780 + "lier",
781 + "lieutenant",
782 + "ligne",
783 + "ligoter",
784 + "liguer",
785 + "limace",
786 + "limer",
787 + "limite",
788 + "lingot",
789 + "lion",
790 + "lire",
791 + "lisser",
792 + "litre",
793 + "livre",
794 + "lobe",
795 + "local",
796 + "logis",
797 + "loin",
798 + "loisir",
799 + "long",
800 + "loque",
801 + "lors",
802 + "lotus",
803 + "louer",
804 + "loup",
805 + "lourd",
806 + "louve",
807 + "loyer",
808 + "lubie",
809 + "lucide",
810 + "lueur",
811 + "luge",
812 + "luire",
813 + "lundi",
814 + "lune",
815 + "lustre",
816 + "lutin",
817 + "lutte",
818 + "luxe",
819 + "machine",
820 + "madame",
821 + "magie",
822 + "magnifique",
823 + "magot",
824 + "maigre",
825 + "main",
826 + "mairie",
827 + "maison",
828 + "malade",
829 + "malheur",
830 + "malin",
831 + "manche",
832 + "manger",
833 + "manier",
834 + "manoir",
835 + "manquer",
836 + "marche",
837 + "mardi",
838 + "marge",
839 + "mariage",
840 + "marquer",
841 + "mars",
842 + "masque",
843 + "masse",
844 + "matin",
845 + "mauvais",
846 + "meilleur",
847 + "melon",
848 + "membre",
849 + "menacer",
850 + "mener",
851 + "mensonge",
852 + "mentir",
853 + "menu",
854 + "merci",
855 + "merlu",
856 + "mesure",
857 + "mettre",
858 + "meuble",
859 + "meunier",
860 + "meute",
861 + "miche",
862 + "micro",
863 + "midi",
864 + "miel",
865 + "miette",
866 + "mieux",
867 + "milieu",
868 + "mille",
869 + "mimer",
870 + "mince",
871 + "mineur",
872 + "ministre",
873 + "minute",
874 + "mirage",
875 + "miroir",
876 + "miser",
877 + "mite",
878 + "mixte",
879 + "mobile",
880 + "mode",
881 + "module",
882 + "moins",
883 + "mois",
884 + "moment",
885 + "momie",
886 + "monde",
887 + "monsieur",
888 + "monter",
889 + "moquer",
890 + "moral",
891 + "morceau",
892 + "mordre",
893 + "morose",
894 + "morse",
895 + "mortier",
896 + "morue",
897 + "motif",
898 + "motte",
899 + "moudre",
900 + "moule",
901 + "mourir",
902 + "mousse",
903 + "mouton",
904 + "mouvement",
905 + "moyen",
906 + "muer",
907 + "muette",
908 + "mugir",
909 + "muguet",
910 + "mulot",
911 + "multiple",
912 + "munir",
913 + "muret",
914 + "muse",
915 + "musique",
916 + "muter",
917 + "nacre",
918 + "nager",
919 + "nain",
920 + "naissance",
921 + "narine",
922 + "narrer",
923 + "naseau",
924 + "nasse",
925 + "nation",
926 + "nature",
927 + "naval",
928 + "navet",
929 + "naviguer",
930 + "navrer",
931 + "neige",
932 + "nerf",
933 + "nerveux",
934 + "neuf",
935 + "neutre",
936 + "neuve",
937 + "neveu",
938 + "niche",
939 + "nier",
940 + "niveau",
941 + "noble",
942 + "noce",
943 + "nocif",
944 + "noir",
945 + "nomade",
946 + "nombre",
947 + "nommer",
948 + "nord",
949 + "norme",
950 + "notaire",
951 + "notice",
952 + "notre",
953 + "nouer",
954 + "nougat",
955 + "nourrir",
956 + "nous",
957 + "nouveau",
958 + "novice",
959 + "noyade",
960 + "noyer",
961 + "nuage",
962 + "nuance",
963 + "nuire",
964 + "nuit",
965 + "nulle",
966 + "nuque",
967 + "oasis",
968 + "objet",
969 + "obliger",
970 + "obscur",
971 + "observer",
972 + "obtenir",
973 + "obus",
974 + "occasion",
975 + "occuper",
976 + "ocre",
977 + "octet",
978 + "odeur",
979 + "odorat",
980 + "offense",
981 + "officier",
982 + "offrir",
983 + "ogive",
984 + "oiseau",
985 + "olive",
986 + "ombre",
987 + "onctueux",
988 + "onduler",
989 + "ongle",
990 + "onze",
991 + "opter",
992 + "option",
993 + "orageux",
994 + "oral",
995 + "orange",
996 + "orbite",
997 + "ordinaire",
998 + "ordre",
999 + "oreille",
1000 + "organe",
1001 + "orgie",
1002 + "orgueil",
1003 + "orient",
1004 + "origan",
1005 + "orner",
1006 + "orteil",
1007 + "ortie",
1008 + "oser",
1009 + "osselet",
1010 + "otage",
1011 + "otarie",
1012 + "ouate",
1013 + "oublier",
1014 + "ouest",
1015 + "ours",
1016 + "outil",
1017 + "outre",
1018 + "ouvert",
1019 + "ouvrir",
1020 + "ovale",
1021 + "ozone",
1022 + "pacte",
1023 + "page",
1024 + "paille",
1025 + "pain",
1026 + "paire",
1027 + "paix",
1028 + "palace",
1029 + "palissade",
1030 + "palmier",
1031 + "palpiter",
1032 + "panda",
1033 + "panneau",
1034 + "papa",
1035 + "papier",
1036 + "paquet",
1037 + "parc",
1038 + "pardi",
1039 + "parfois",
1040 + "parler",
1041 + "parmi",
1042 + "parole",
1043 + "partir",
1044 + "parvenir",
1045 + "passer",
1046 + "pastel",
1047 + "patin",
1048 + "patron",
1049 + "paume",
1050 + "pause",
1051 + "pauvre",
1052 + "paver",
1053 + "pavot",
1054 + "payer",
1055 + "pays",
1056 + "peau",
1057 + "peigne",
1058 + "peinture",
1059 + "pelage",
1060 + "pelote",
1061 + "pencher",
1062 + "pendre",
1063 + "penser",
1064 + "pente",
1065 + "percer",
1066 + "perdu",
1067 + "perle",
1068 + "permettre",
1069 + "personne",
1070 + "perte",
1071 + "peser",
1072 + "pesticide",
1073 + "petit",
1074 + "peuple",
1075 + "peur",
1076 + "phase",
1077 + "photo",
1078 + "phrase",
1079 + "piano",
1080 + "pied",
1081 + "pierre",
1082 + "pieu",
1083 + "pile",
1084 + "pilier",
1085 + "pilote",
1086 + "pilule",
1087 + "piment",
1088 + "pincer",
1089 + "pinson",
1090 + "pinte",
1091 + "pion",
1092 + "piquer",
1093 + "pirate",
1094 + "pire",
1095 + "piste",
1096 + "piton",
1097 + "pitre",
1098 + "pivot",
1099 + "pizza",
1100 + "placer",
1101 + "plage",
1102 + "plaire",
1103 + "plan",
1104 + "plaque",
1105 + "plat",
1106 + "plein",
1107 + "pleurer",
1108 + "pliage",
1109 + "plier",
1110 + "plonger",
1111 + "plot",
1112 + "pluie",
1113 + "plume",
1114 + "plus",
1115 + "pneu",
1116 + "poche",
1117 + "podium",
1118 + "poids",
1119 + "poil",
1120 + "point",
1121 + "poire",
1122 + "poison",
1123 + "poitrine",
1124 + "poivre",
1125 + "police",
1126 + "pollen",
1127 + "pomme",
1128 + "pompier",
1129 + "poncer",
1130 + "pondre",
1131 + "pont",
1132 + "portion",
1133 + "poser",
1134 + "position",
1135 + "possible",
1136 + "poste",
1137 + "potage",
1138 + "potin",
1139 + "pouce",
1140 + "poudre",
1141 + "poulet",
1142 + "poumon",
1143 + "poupe",
1144 + "pour",
1145 + "pousser",
1146 + "poutre",
1147 + "pouvoir",
1148 + "prairie",
1149 + "premier",
1150 + "prendre",
1151 + "presque",
1152 + "preuve",
1153 + "prier",
1154 + "primeur",
1155 + "prince",
1156 + "prison",
1157 + "priver",
1158 + "prix",
1159 + "prochain",
1160 + "produire",
1161 + "profond",
1162 + "proie",
1163 + "projet",
1164 + "promener",
1165 + "prononcer",
1166 + "propre",
1167 + "prose",
1168 + "prouver",
1169 + "prune",
1170 + "public",
1171 + "puce",
1172 + "pudeur",
1173 + "puiser",
1174 + "pull",
1175 + "pulpe",
1176 + "puma",
1177 + "punir",
1178 + "purge",
1179 + "putois",
1180 + "quand",
1181 + "quartier",
1182 + "quasi",
1183 + "quatre",
1184 + "quel",
1185 + "question",
1186 + "queue",
1187 + "quiche",
1188 + "quille",
1189 + "quinze",
1190 + "quitter",
1191 + "quoi",
1192 + "rabais",
1193 + "raboter",
1194 + "race",
1195 + "racheter",
1196 + "racine",
1197 + "racler",
1198 + "raconter",
1199 + "radar",
1200 + "radio",
1201 + "rafale",
1202 + "rage",
1203 + "ragot",
1204 + "raideur",
1205 + "raie",
1206 + "rail",
1207 + "raison",
1208 + "ramasser",
1209 + "ramener",
1210 + "rampe",
1211 + "rance",
1212 + "rang",
1213 + "rapace",
1214 + "rapide",
1215 + "rapport",
1216 + "rarement",
1217 + "rasage",
1218 + "raser",
1219 + "rasoir",
1220 + "rassurer",
1221 + "rater",
1222 + "ratio",
1223 + "rature",
1224 + "ravage",
1225 + "ravir",
1226 + "rayer",
1227 + "rayon",
1228 + "rebond",
1229 + "recevoir",
1230 + "recherche",
1231 + "record",
1232 + "reculer",
1233 + "redevenir",
1234 + "refuser",
1235 + "regard",
1236 + "regretter",
1237 + "rein",
1238 + "rejeter",
1239 + "rejoindre",
1240 + "relation",
1241 + "relever",
1242 + "religion",
1243 + "remarquer",
1244 + "remettre",
1245 + "remise",
1246 + "remonter",
1247 + "remplir",
1248 + "remuer",
1249 + "rencontre",
1250 + "rendre",
1251 + "renier",
1252 + "renoncer",
1253 + "rentrer",
1254 + "renverser",
1255 + "repas",
1256 + "repli",
1257 + "reposer",
1258 + "reproche",
1259 + "requin",
1260 + "respect",
1261 + "ressembler",
1262 + "reste",
1263 + "retard",
1264 + "retenir",
1265 + "retirer",
1266 + "retour",
1267 + "retrouver",
1268 + "revenir",
1269 + "revoir",
1270 + "revue",
1271 + "rhume",
1272 + "ricaner",
1273 + "riche",
1274 + "rideau",
1275 + "ridicule",
1276 + "rien",
1277 + "rigide",
1278 + "rincer",
1279 + "rire",
1280 + "risquer",
1281 + "rituel",
1282 + "rivage",
1283 + "rive",
1284 + "robe",
1285 + "robot",
1286 + "robuste",
1287 + "rocade",
1288 + "roche",
1289 + "rodeur",
1290 + "rogner",
1291 + "roman",
1292 + "rompre",
1293 + "ronce",
1294 + "rondeur",
1295 + "ronger",
1296 + "roque",
1297 + "rose",
1298 + "rosir",
1299 + "rotation",
1300 + "rotule",
1301 + "roue",
1302 + "rouge",
1303 + "rouler",
1304 + "route",
1305 + "ruban",
1306 + "rubis",
1307 + "ruche",
1308 + "rude",
1309 + "ruelle",
1310 + "ruer",
1311 + "rugby",
1312 + "rugir",
1313 + "ruine",
1314 + "rumeur",
1315 + "rural",
1316 + "ruse",
1317 + "rustre",
1318 + "sable",
1319 + "sabot",
1320 + "sabre",
1321 + "sacre",
1322 + "sage",
1323 + "saint",
1324 + "saisir",
1325 + "salade",
1326 + "salive",
1327 + "salle",
1328 + "salon",
1329 + "salto",
1330 + "salut",
1331 + "salve",
1332 + "samba",
1333 + "sandale",
1334 + "sanguin",
1335 + "sapin",
1336 + "sarcasme",
1337 + "satisfaire",
1338 + "sauce",
1339 + "sauf",
1340 + "sauge",
1341 + "saule",
1342 + "sauna",
1343 + "sauter",
1344 + "sauver",
1345 + "savoir",
1346 + "science",
1347 + "scoop",
1348 + "score",
1349 + "second",
1350 + "secret",
1351 + "secte",
1352 + "seigneur",
1353 + "sein",
1354 + "seize",
1355 + "selle",
1356 + "selon",
1357 + "semaine",
1358 + "sembler",
1359 + "semer",
1360 + "semis",
1361 + "sensuel",
1362 + "sentir",
1363 + "sept",
1364 + "serpe",
1365 + "serrer",
1366 + "sertir",
1367 + "service",
1368 + "seuil",
1369 + "seulement",
1370 + "short",
1371 + "sien",
1372 + "sigle",
1373 + "signal",
1374 + "silence",
1375 + "silo",
1376 + "simple",
1377 + "singe",
1378 + "sinon",
1379 + "sinus",
1380 + "sioux",
1381 + "sirop",
1382 + "site",
1383 + "situation",
1384 + "skier",
1385 + "snob",
1386 + "sobre",
1387 + "social",
1388 + "socle",
1389 + "sodium",
1390 + "soigner",
1391 + "soir",
1392 + "soixante",
1393 + "soja",
1394 + "solaire",
1395 + "soldat",
1396 + "soleil",
1397 + "solide",
1398 + "solo",
1399 + "solvant",
1400 + "sombre",
1401 + "somme",
1402 + "somnoler",
1403 + "sondage",
1404 + "songeur",
1405 + "sonner",
1406 + "sorte",
1407 + "sosie",
1408 + "sottise",
1409 + "souci",
1410 + "soudain",
1411 + "souffrir",
1412 + "souhaiter",
1413 + "soulever",
1414 + "soumettre",
1415 + "soupe",
1416 + "sourd",
1417 + "soustraire",
1418 + "soutenir",
1419 + "souvent",
1420 + "soyeux",
1421 + "spectacle",
1422 + "sport",
1423 + "stade",
1424 + "stagiaire",
1425 + "stand",
1426 + "star",
1427 + "statue",
1428 + "stock",
1429 + "stop",
1430 + "store",
1431 + "style",
1432 + "suave",
1433 + "subir",
1434 + "sucre",
1435 + "suer",
1436 + "suffire",
1437 + "suie",
1438 + "suite",
1439 + "suivre",
1440 + "sujet",
1441 + "sulfite",
1442 + "supposer",
1443 + "surf",
1444 + "surprendre",
1445 + "surtout",
1446 + "surveiller",
1447 + "tabac",
1448 + "table",
1449 + "tabou",
1450 + "tache",
1451 + "tacler",
1452 + "tacot",
1453 + "tact",
1454 + "taie",
1455 + "taille",
1456 + "taire",
1457 + "talon",
1458 + "talus",
1459 + "tandis",
1460 + "tango",
1461 + "tanin",
1462 + "tant",
1463 + "taper",
1464 + "tapis",
1465 + "tard",
1466 + "tarif",
1467 + "tarot",
1468 + "tarte",
1469 + "tasse",
1470 + "taureau",
1471 + "taux",
1472 + "taverne",
1473 + "taxer",
1474 + "taxi",
1475 + "tellement",
1476 + "temple",
1477 + "tendre",
1478 + "tenir",
1479 + "tenter",
1480 + "tenu",
1481 + "terme",
1482 + "ternir",
1483 + "terre",
1484 + "test",
1485 + "texte",
1486 + "thym",
1487 + "tibia",
1488 + "tiers",
1489 + "tige",
1490 + "tipi",
1491 + "tique",
1492 + "tirer",
1493 + "tissu",
1494 + "titre",
1495 + "toast",
1496 + "toge",
1497 + "toile",
1498 + "toiser",
1499 + "toiture",
1500 + "tomber",
1501 + "tome",
1502 + "tonne",
1503 + "tonte",
1504 + "toque",
1505 + "torse",
1506 + "tortue",
1507 + "totem",
1508 + "toucher",
1509 + "toujours",
1510 + "tour",
1511 + "tousser",
1512 + "tout",
1513 + "toux",
1514 + "trace",
1515 + "train",
1516 + "trame",
1517 + "tranquille",
1518 + "travail",
1519 + "trembler",
1520 + "trente",
1521 + "tribu",
1522 + "trier",
1523 + "trio",
1524 + "tripe",
1525 + "triste",
1526 + "troc",
1527 + "trois",
1528 + "tromper",
1529 + "tronc",
1530 + "trop",
1531 + "trotter",
1532 + "trouer",
1533 + "truc",
1534 + "truite",
1535 + "tuba",
1536 + "tuer",
1537 + "tuile",
1538 + "turbo",
1539 + "tutu",
1540 + "tuyau",
1541 + "type",
1542 + "union",
1543 + "unique",
1544 + "unir",
1545 + "unisson",
1546 + "untel",
1547 + "urne",
1548 + "usage",
1549 + "user",
1550 + "usiner",
1551 + "usure",
1552 + "utile",
1553 + "vache",
1554 + "vague",
1555 + "vaincre",
1556 + "valeur",
1557 + "valoir",
1558 + "valser",
1559 + "valve",
1560 + "vampire",
1561 + "vaseux",
1562 + "vaste",
1563 + "veau",
1564 + "veille",
1565 + "veine",
1566 + "velours",
1567 + "velu",
1568 + "vendre",
1569 + "venir",
1570 + "vent",
1571 + "venue",
1572 + "verbe",
1573 + "verdict",
1574 + "version",
1575 + "vertige",
1576 + "verve",
1577 + "veste",
1578 + "veto",
1579 + "vexer",
1580 + "vice",
1581 + "victime",
1582 + "vide",
1583 + "vieil",
1584 + "vieux",
1585 + "vigie",
1586 + "vigne",
1587 + "ville",
1588 + "vingt",
1589 + "violent",
1590 + "virer",
1591 + "virus",
1592 + "visage",
1593 + "viser",
1594 + "visite",
1595 + "visuel",
1596 + "vitamine",
1597 + "vitrine",
1598 + "vivant",
1599 + "vivre",
1600 + "vocal",
1601 + "vodka",
1602 + "vogue",
1603 + "voici",
1604 + "voile",
1605 + "voir",
1606 + "voisin",
1607 + "voiture",
1608 + "volaille",
1609 + "volcan",
1610 + "voler",
1611 + "volt",
1612 + "votant",
1613 + "votre",
1614 + "vouer",
1615 + "vouloir",
1616 + "vous",
1617 + "voyage",
1618 + "voyou",
1619 + "vrac",
1620 + "vrai",
1621 + "yacht",
1622 + "yeti",
1623 + "yeux",
1624 + "yoga",
1625 + "zeste",
1626 + "zinc",
1627 + "zone",
1628 + "zoom"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mnemonics/german.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class GermanMnemonics {
2 + static const words = [
3 + "Abakus",
4 + "Abart",
5 + "abbilden",
6 + "Abbruch",
7 + "Abdrift",
8 + "Abendrot",
9 + "Abfahrt",
10 + "abfeuern",
11 + "Abflug",
12 + "abfragen",
13 + "Abglanz",
14 + "abhärten",
15 + "abheben",
16 + "Abhilfe",
17 + "Abitur",
18 + "Abkehr",
19 + "Ablauf",
20 + "ablecken",
21 + "Ablösung",
22 + "Abnehmer",
23 + "abnutzen",
24 + "Abonnent",
25 + "Abrasion",
26 + "Abrede",
27 + "abrüsten",
28 + "Absicht",
29 + "Absprung",
30 + "Abstand",
31 + "absuchen",
32 + "Abteil",
33 + "Abundanz",
34 + "abwarten",
35 + "Abwurf",
36 + "Abzug",
37 + "Achse",
38 + "Achtung",
39 + "Acker",
40 + "Aderlass",
41 + "Adler",
42 + "Admiral",
43 + "Adresse",
44 + "Affe",
45 + "Affront",
46 + "Afrika",
47 + "Aggregat",
48 + "Agilität",
49 + "ähneln",
50 + "Ahnung",
51 + "Ahorn",
52 + "Akazie",
53 + "Akkord",
54 + "Akrobat",
55 + "Aktfoto",
56 + "Aktivist",
57 + "Albatros",
58 + "Alchimie",
59 + "Alemanne",
60 + "Alibi",
61 + "Alkohol",
62 + "Allee",
63 + "Allüre",
64 + "Almosen",
65 + "Almweide",
66 + "Aloe",
67 + "Alpaka",
68 + "Alpental",
69 + "Alphabet",
70 + "Alpinist",
71 + "Alraune",
72 + "Altbier",
73 + "Alter",
74 + "Altflöte",
75 + "Altruist",
76 + "Alublech",
77 + "Aludose",
78 + "Amateur",
79 + "Amazonas",
80 + "Ameise",
81 + "Amnesie",
82 + "Amok",
83 + "Ampel",
84 + "Amphibie",
85 + "Ampulle",
86 + "Amsel",
87 + "Amulett",
88 + "Anakonda",
89 + "Analogie",
90 + "Ananas",
91 + "Anarchie",
92 + "Anatomie",
93 + "Anbau",
94 + "Anbeginn",
95 + "anbieten",
96 + "Anblick",
97 + "ändern",
98 + "andocken",
99 + "Andrang",
100 + "anecken",
101 + "Anflug",
102 + "Anfrage",
103 + "Anführer",
104 + "Angebot",
105 + "Angler",
106 + "Anhalter",
107 + "Anhöhe",
108 + "Animator",
109 + "Anis",
110 + "Anker",
111 + "ankleben",
112 + "Ankunft",
113 + "Anlage",
114 + "anlocken",
115 + "Anmut",
116 + "Annahme",
117 + "Anomalie",
118 + "Anonymus",
119 + "Anorak",
120 + "anpeilen",
121 + "Anrecht",
122 + "Anruf",
123 + "Ansage",
124 + "Anschein",
125 + "Ansicht",
126 + "Ansporn",
127 + "Anteil",
128 + "Antlitz",
129 + "Antrag",
130 + "Antwort",
131 + "Anwohner",
132 + "Aorta",
133 + "Apfel",
134 + "Appetit",
135 + "Applaus",
136 + "Aquarium",
137 + "Arbeit",
138 + "Arche",
139 + "Argument",
140 + "Arktis",
141 + "Armband",
142 + "Aroma",
143 + "Asche",
144 + "Askese",
145 + "Asphalt",
146 + "Asteroid",
147 + "Ästhetik",
148 + "Astronom",
149 + "Atelier",
150 + "Athlet",
151 + "Atlantik",
152 + "Atmung",
153 + "Audienz",
154 + "aufatmen",
155 + "Auffahrt",
156 + "aufholen",
157 + "aufregen",
158 + "Aufsatz",
159 + "Auftritt",
160 + "Aufwand",
161 + "Augapfel",
162 + "Auktion",
163 + "Ausbruch",
164 + "Ausflug",
165 + "Ausgabe",
166 + "Aushilfe",
167 + "Ausland",
168 + "Ausnahme",
169 + "Aussage",
170 + "Autobahn",
171 + "Avocado",
172 + "Axthieb",
173 + "Bach",
174 + "backen",
175 + "Badesee",
176 + "Bahnhof",
177 + "Balance",
178 + "Balkon",
179 + "Ballett",
180 + "Balsam",
181 + "Banane",
182 + "Bandage",
183 + "Bankett",
184 + "Barbar",
185 + "Barde",
186 + "Barett",
187 + "Bargeld",
188 + "Barkasse",
189 + "Barriere",
190 + "Bart",
191 + "Bass",
192 + "Bastler",
193 + "Batterie",
194 + "Bauch",
195 + "Bauer",
196 + "Bauholz",
197 + "Baujahr",
198 + "Baum",
199 + "Baustahl",
200 + "Bauteil",
201 + "Bauweise",
202 + "Bazar",
203 + "beachten",
204 + "Beatmung",
205 + "beben",
206 + "Becher",
207 + "Becken",
208 + "bedanken",
209 + "beeilen",
210 + "beenden",
211 + "Beere",
212 + "befinden",
213 + "Befreier",
214 + "Begabung",
215 + "Begierde",
216 + "begrüßen",
217 + "Beiboot",
218 + "Beichte",
219 + "Beifall",
220 + "Beigabe",
221 + "Beil",
222 + "Beispiel",
223 + "Beitrag",
224 + "beizen",
225 + "bekommen",
226 + "beladen",
227 + "Beleg",
228 + "bellen",
229 + "belohnen",
230 + "Bemalung",
231 + "Bengel",
232 + "Benutzer",
233 + "Benzin",
234 + "beraten",
235 + "Bereich",
236 + "Bergluft",
237 + "Bericht",
238 + "Bescheid",
239 + "Besitz",
240 + "besorgen",
241 + "Bestand",
242 + "Besuch",
243 + "betanken",
244 + "beten",
245 + "betören",
246 + "Bett",
247 + "Beule",
248 + "Beute",
249 + "Bewegung",
250 + "bewirken",
251 + "Bewohner",
252 + "bezahlen",
253 + "Bezug",
254 + "biegen",
255 + "Biene",
256 + "Bierzelt",
257 + "bieten",
258 + "Bikini",
259 + "Bildung",
260 + "Billard",
261 + "binden",
262 + "Biobauer",
263 + "Biologe",
264 + "Bionik",
265 + "Biotop",
266 + "Birke",
267 + "Bison",
268 + "Bitte",
269 + "Biwak",
270 + "Bizeps",
271 + "blasen",
272 + "Blatt",
273 + "Blauwal",
274 + "Blende",
275 + "Blick",
276 + "Blitz",
277 + "Blockade",
278 + "Blödelei",
279 + "Blondine",
280 + "Blues",
281 + "Blume",
282 + "Blut",
283 + "Bodensee",
284 + "Bogen",
285 + "Boje",
286 + "Bollwerk",
287 + "Bonbon",
288 + "Bonus",
289 + "Boot",
290 + "Bordarzt",
291 + "Börse",
292 + "Böschung",
293 + "Boudoir",
294 + "Boxkampf",
295 + "Boykott",
296 + "Brahms",
297 + "Brandung",
298 + "Brauerei",
299 + "Brecher",
300 + "Breitaxt",
301 + "Bremse",
302 + "brennen",
303 + "Brett",
304 + "Brief",
305 + "Brigade",
306 + "Brillanz",
307 + "bringen",
308 + "brodeln",
309 + "Brosche",
310 + "Brötchen",
311 + "Brücke",
312 + "Brunnen",
313 + "Brüste",
314 + "Brutofen",
315 + "Buch",
316 + "Büffel",
317 + "Bugwelle",
318 + "Bühne",
319 + "Buletten",
320 + "Bullauge",
321 + "Bumerang",
322 + "bummeln",
323 + "Buntglas",
324 + "Bürde",
325 + "Burgherr",
326 + "Bursche",
327 + "Busen",
328 + "Buslinie",
329 + "Bussard",
330 + "Butangas",
331 + "Butter",
332 + "Cabrio",
333 + "campen",
334 + "Captain",
335 + "Cartoon",
336 + "Cello",
337 + "Chalet",
338 + "Charisma",
339 + "Chefarzt",
340 + "Chiffon",
341 + "Chipsatz",
342 + "Chirurg",
343 + "Chor",
344 + "Chronik",
345 + "Chuzpe",
346 + "Clubhaus",
347 + "Cockpit",
348 + "Codewort",
349 + "Cognac",
350 + "Coladose",
351 + "Computer",
352 + "Coupon",
353 + "Cousin",
354 + "Cracking",
355 + "Crash",
356 + "Curry",
357 + "Dach",
358 + "Dackel",
359 + "daddeln",
360 + "daliegen",
361 + "Dame",
362 + "Dammbau",
363 + "Dämon",
364 + "Dampflok",
365 + "Dank",
366 + "Darm",
367 + "Datei",
368 + "Datsche",
369 + "Datteln",
370 + "Datum",
371 + "Dauer",
372 + "Daunen",
373 + "Deckel",
374 + "Decoder",
375 + "Defekt",
376 + "Degen",
377 + "Dehnung",
378 + "Deiche",
379 + "Dekade",
380 + "Dekor",
381 + "Delfin",
382 + "Demut",
383 + "denken",
384 + "Deponie",
385 + "Design",
386 + "Desktop",
387 + "Dessert",
388 + "Detail",
389 + "Detektiv",
390 + "Dezibel",
391 + "Diadem",
392 + "Diagnose",
393 + "Dialekt",
394 + "Diamant",
395 + "Dichter",
396 + "Dickicht",
397 + "Diesel",
398 + "Diktat",
399 + "Diplom",
400 + "Direktor",
401 + "Dirne",
402 + "Diskurs",
403 + "Distanz",
404 + "Docht",
405 + "Dohle",
406 + "Dolch",
407 + "Domäne",
408 + "Donner",
409 + "Dorade",
410 + "Dorf",
411 + "Dörrobst",
412 + "Dorsch",
413 + "Dossier",
414 + "Dozent",
415 + "Drachen",
416 + "Draht",
417 + "Drama",
418 + "Drang",
419 + "Drehbuch",
420 + "Dreieck",
421 + "Dressur",
422 + "Drittel",
423 + "Drossel",
424 + "Druck",
425 + "Duell",
426 + "Duft",
427 + "Düne",
428 + "Dünung",
429 + "dürfen",
430 + "Duschbad",
431 + "Düsenjet",
432 + "Dynamik",
433 + "Ebbe",
434 + "Echolot",
435 + "Echse",
436 + "Eckball",
437 + "Edding",
438 + "Edelweiß",
439 + "Eden",
440 + "Edition",
441 + "Efeu",
442 + "Effekte",
443 + "Egoismus",
444 + "Ehre",
445 + "Eiablage",
446 + "Eiche",
447 + "Eidechse",
448 + "Eidotter",
449 + "Eierkopf",
450 + "Eigelb",
451 + "Eiland",
452 + "Eilbote",
453 + "Eimer",
454 + "einatmen",
455 + "Einband",
456 + "Eindruck",
457 + "Einfall",
458 + "Eingang",
459 + "Einkauf",
460 + "einladen",
461 + "Einöde",
462 + "Einrad",
463 + "Eintopf",
464 + "Einwurf",
465 + "Einzug",
466 + "Eisbär",
467 + "Eisen",
468 + "Eishöhle",
469 + "Eismeer",
470 + "Eiweiß",
471 + "Ekstase",
472 + "Elan",
473 + "Elch",
474 + "Elefant",
475 + "Eleganz",
476 + "Element",
477 + "Elfe",
478 + "Elite",
479 + "Elixier",
480 + "Ellbogen",
481 + "Eloquenz",
482 + "Emigrant",
483 + "Emission",
484 + "Emotion",
485 + "Empathie",
486 + "Empfang",
487 + "Endzeit",
488 + "Energie",
489 + "Engpass",
490 + "Enkel",
491 + "Enklave",
492 + "Ente",
493 + "entheben",
494 + "Entität",
495 + "entladen",
496 + "Entwurf",
497 + "Episode",
498 + "Epoche",
499 + "erachten",
500 + "Erbauer",
501 + "erblühen",
502 + "Erdbeere",
503 + "Erde",
504 + "Erdgas",
505 + "Erdkunde",
506 + "Erdnuss",
507 + "Erdöl",
508 + "Erdteil",
509 + "Ereignis",
510 + "Eremit",
511 + "erfahren",
512 + "Erfolg",
513 + "erfreuen",
514 + "erfüllen",
515 + "Ergebnis",
516 + "erhitzen",
517 + "erkalten",
518 + "erkennen",
519 + "erleben",
520 + "Erlösung",
521 + "ernähren",
522 + "erneuern",
523 + "Ernte",
524 + "Eroberer",
525 + "eröffnen",
526 + "Erosion",
527 + "Erotik",
528 + "Erpel",
529 + "erraten",
530 + "Erreger",
531 + "erröten",
532 + "Ersatz",
533 + "Erstflug",
534 + "Ertrag",
535 + "Eruption",
536 + "erwarten",
537 + "erwidern",
538 + "Erzbau",
539 + "Erzeuger",
540 + "erziehen",
541 + "Esel",
542 + "Eskimo",
543 + "Eskorte",
544 + "Espe",
545 + "Espresso",
546 + "essen",
547 + "Etage",
548 + "Etappe",
549 + "Etat",
550 + "Ethik",
551 + "Etikett",
552 + "Etüde",
553 + "Eule",
554 + "Euphorie",
555 + "Europa",
556 + "Everest",
557 + "Examen",
558 + "Exil",
559 + "Exodus",
560 + "Extrakt",
561 + "Fabel",
562 + "Fabrik",
563 + "Fachmann",
564 + "Fackel",
565 + "Faden",
566 + "Fagott",
567 + "Fahne",
568 + "Faible",
569 + "Fairness",
570 + "Fakt",
571 + "Fakultät",
572 + "Falke",
573 + "Fallobst",
574 + "Fälscher",
575 + "Faltboot",
576 + "Familie",
577 + "Fanclub",
578 + "Fanfare",
579 + "Fangarm",
580 + "Fantasie",
581 + "Farbe",
582 + "Farmhaus",
583 + "Farn",
584 + "Fasan",
585 + "Faser",
586 + "Fassung",
587 + "fasten",
588 + "Faulheit",
589 + "Fauna",
590 + "Faust",
591 + "Favorit",
592 + "Faxgerät",
593 + "Fazit",
594 + "fechten",
595 + "Federboa",
596 + "Fehler",
597 + "Feier",
598 + "Feige",
599 + "feilen",
600 + "Feinripp",
601 + "Feldbett",
602 + "Felge",
603 + "Fellpony",
604 + "Felswand",
605 + "Ferien",
606 + "Ferkel",
607 + "Fernweh",
608 + "Ferse",
609 + "Fest",
610 + "Fettnapf",
611 + "Feuer",
612 + "Fiasko",
613 + "Fichte",
614 + "Fiktion",
615 + "Film",
616 + "Filter",
617 + "Filz",
618 + "Finanzen",
619 + "Findling",
620 + "Finger",
621 + "Fink",
622 + "Finnwal",
623 + "Fisch",
624 + "Fitness",
625 + "Fixpunkt",
626 + "Fixstern",
627 + "Fjord",
628 + "Flachbau",
629 + "Flagge",
630 + "Flamenco",
631 + "Flanke",
632 + "Flasche",
633 + "Flaute",
634 + "Fleck",
635 + "Flegel",
636 + "flehen",
637 + "Fleisch",
638 + "fliegen",
639 + "Flinte",
640 + "Flirt",
641 + "Flocke",
642 + "Floh",
643 + "Floskel",
644 + "Floß",
645 + "Flöte",
646 + "Flugzeug",
647 + "Flunder",
648 + "Flusstal",
649 + "Flutung",
650 + "Fockmast",
651 + "Fohlen",
652 + "Föhnlage",
653 + "Fokus",
654 + "folgen",
655 + "Foliant",
656 + "Folklore",
657 + "Fontäne",
658 + "Förde",
659 + "Forelle",
660 + "Format",
661 + "Forscher",
662 + "Fortgang",
663 + "Forum",
664 + "Fotograf",
665 + "Frachter",
666 + "Fragment",
667 + "Fraktion",
668 + "fräsen",
669 + "Frauenpo",
670 + "Freak",
671 + "Fregatte",
672 + "Freiheit",
673 + "Freude",
674 + "Frieden",
675 + "Frohsinn",
676 + "Frosch",
677 + "Frucht",
678 + "Frühjahr",
679 + "Fuchs",
680 + "Fügung",
681 + "fühlen",
682 + "Füller",
683 + "Fundbüro",
684 + "Funkboje",
685 + "Funzel",
686 + "Furnier",
687 + "Fürsorge",
688 + "Fusel",
689 + "Fußbad",
690 + "Futteral",
691 + "Gabelung",
692 + "gackern",
693 + "Gage",
694 + "gähnen",
695 + "Galaxie",
696 + "Galeere",
697 + "Galopp",
698 + "Gameboy",
699 + "Gamsbart",
700 + "Gandhi",
701 + "Gang",
702 + "Garage",
703 + "Gardine",
704 + "Garküche",
705 + "Garten",
706 + "Gasthaus",
707 + "Gattung",
708 + "gaukeln",
709 + "Gazelle",
710 + "Gebäck",
711 + "Gebirge",
712 + "Gebräu",
713 + "Geburt",
714 + "Gedanke",
715 + "Gedeck",
716 + "Gedicht",
717 + "Gefahr",
718 + "Gefieder",
719 + "Geflügel",
720 + "Gefühl",
721 + "Gegend",
722 + "Gehirn",
723 + "Gehöft",
724 + "Gehweg",
725 + "Geige",
726 + "Geist",
727 + "Gelage",
728 + "Geld",
729 + "Gelenk",
730 + "Gelübde",
731 + "Gemälde",
732 + "Gemeinde",
733 + "Gemüse",
734 + "genesen",
735 + "Genuss",
736 + "Gepäck",
737 + "Geranie",
738 + "Gericht",
739 + "Germane",
740 + "Geruch",
741 + "Gesang",
742 + "Geschenk",
743 + "Gesetz",
744 + "Gesindel",
745 + "Gesöff",
746 + "Gespan",
747 + "Gestade",
748 + "Gesuch",
749 + "Getier",
750 + "Getränk",
751 + "Getümmel",
752 + "Gewand",
753 + "Geweih",
754 + "Gewitter",
755 + "Gewölbe",
756 + "Geysir",
757 + "Giftzahn",
758 + "Gipfel",
759 + "Giraffe",
760 + "Gitarre",
761 + "glänzen",
762 + "Glasauge",
763 + "Glatze",
764 + "Gleis",
765 + "Globus",
766 + "Glück",
767 + "glühen",
768 + "Glutofen",
769 + "Goldzahn",
770 + "Gondel",
771 + "gönnen",
772 + "Gottheit",
773 + "graben",
774 + "Grafik",
775 + "Grashalm",
776 + "Graugans",
777 + "greifen",
778 + "Grenze",
779 + "grillen",
780 + "Groschen",
781 + "Grotte",
782 + "Grube",
783 + "Grünalge",
784 + "Gruppe",
785 + "gruseln",
786 + "Gulasch",
787 + "Gummibär",
788 + "Gurgel",
789 + "Gürtel",
790 + "Güterzug",
791 + "Haarband",
792 + "Habicht",
793 + "hacken",
794 + "hadern",
795 + "Hafen",
796 + "Hagel",
797 + "Hähnchen",
798 + "Haifisch",
799 + "Haken",
800 + "Halbaffe",
801 + "Halsader",
802 + "halten",
803 + "Halunke",
804 + "Handbuch",
805 + "Hanf",
806 + "Harfe",
807 + "Harnisch",
808 + "härten",
809 + "Harz",
810 + "Hasenohr",
811 + "Haube",
812 + "hauchen",
813 + "Haupt",
814 + "Haut",
815 + "Havarie",
816 + "Hebamme",
817 + "hecheln",
818 + "Heck",
819 + "Hedonist",
820 + "Heiler",
821 + "Heimat",
822 + "Heizung",
823 + "Hektik",
824 + "Held",
825 + "helfen",
826 + "Helium",
827 + "Hemd",
828 + "hemmen",
829 + "Hengst",
830 + "Herd",
831 + "Hering",
832 + "Herkunft",
833 + "Hermelin",
834 + "Herrchen",
835 + "Herzdame",
836 + "Heulboje",
837 + "Hexe",
838 + "Hilfe",
839 + "Himbeere",
840 + "Himmel",
841 + "Hingabe",
842 + "hinhören",
843 + "Hinweis",
844 + "Hirsch",
845 + "Hirte",
846 + "Hitzkopf",
847 + "Hobel",
848 + "Hochform",
849 + "Hocker",
850 + "hoffen",
851 + "Hofhund",
852 + "Hofnarr",
853 + "Höhenzug",
854 + "Hohlraum",
855 + "Hölle",
856 + "Holzboot",
857 + "Honig",
858 + "Honorar",
859 + "horchen",
860 + "Hörprobe",
861 + "Höschen",
862 + "Hotel",
863 + "Hubraum",
864 + "Hufeisen",
865 + "Hügel",
866 + "huldigen",
867 + "Hülle",
868 + "Humbug",
869 + "Hummer",
870 + "Humor",
871 + "Hund",
872 + "Hunger",
873 + "Hupe",
874 + "Hürde",
875 + "Hurrikan",
876 + "Hydrant",
877 + "Hypnose",
878 + "Ibis",
879 + "Idee",
880 + "Idiot",
881 + "Igel",
882 + "Illusion",
883 + "Imitat",
884 + "impfen",
885 + "Import",
886 + "Inferno",
887 + "Ingwer",
888 + "Inhalte",
889 + "Inland",
890 + "Insekt",
891 + "Ironie",
892 + "Irrfahrt",
893 + "Irrtum",
894 + "Isolator",
895 + "Istwert",
896 + "Jacke",
897 + "Jade",
898 + "Jagdhund",
899 + "Jäger",
900 + "Jaguar",
901 + "Jahr",
902 + "Jähzorn",
903 + "Jazzfest",
904 + "Jetpilot",
905 + "jobben",
906 + "Jochbein",
907 + "jodeln",
908 + "Jodsalz",
909 + "Jolle",
910 + "Journal",
911 + "Jubel",
912 + "Junge",
913 + "Junimond",
914 + "Jupiter",
915 + "Jutesack",
916 + "Juwel",
917 + "Kabarett",
918 + "Kabine",
919 + "Kabuff",
920 + "Käfer",
921 + "Kaffee",
922 + "Kahlkopf",
923 + "Kaimauer",
924 + "Kajüte",
925 + "Kaktus",
926 + "Kaliber",
927 + "Kaltluft",
928 + "Kamel",
929 + "kämmen",
930 + "Kampagne",
931 + "Kanal",
932 + "Känguru",
933 + "Kanister",
934 + "Kanone",
935 + "Kante",
936 + "Kanu",
937 + "kapern",
938 + "Kapitän",
939 + "Kapuze",
940 + "Karneval",
941 + "Karotte",
942 + "Käsebrot",
943 + "Kasper",
944 + "Kastanie",
945 + "Katalog",
946 + "Kathode",
947 + "Katze",
948 + "kaufen",
949 + "Kaugummi",
950 + "Kauz",
951 + "Kehle",
952 + "Keilerei",
953 + "Keksdose",
954 + "Kellner",
955 + "Keramik",
956 + "Kerze",
957 + "Kessel",
958 + "Kette",
959 + "keuchen",
960 + "kichern",
961 + "Kielboot",
962 + "Kindheit",
963 + "Kinnbart",
964 + "Kinosaal",
965 + "Kiosk",
966 + "Kissen",
967 + "Klammer",
968 + "Klang",
969 + "Klapprad",
970 + "Klartext",
971 + "kleben",
972 + "Klee",
973 + "Kleinod",
974 + "Klima",
975 + "Klingel",
976 + "Klippe",
977 + "Klischee",
978 + "Kloster",
979 + "Klugheit",
980 + "Klüngel",
981 + "kneten",
982 + "Knie",
983 + "Knöchel",
984 + "knüpfen",
985 + "Kobold",
986 + "Kochbuch",
987 + "Kohlrabi",
988 + "Koje",
989 + "Kokosöl",
990 + "Kolibri",
991 + "Kolumne",
992 + "Kombüse",
993 + "Komiker",
994 + "kommen",
995 + "Konto",
996 + "Konzept",
997 + "Kopfkino",
998 + "Kordhose",
999 + "Korken",
1000 + "Korsett",
1001 + "Kosename",
1002 + "Krabbe",
1003 + "Krach",
1004 + "Kraft",
1005 + "Krähe",
1006 + "Kralle",
1007 + "Krapfen",
1008 + "Krater",
1009 + "kraulen",
1010 + "Kreuz",
1011 + "Krokodil",
1012 + "Kröte",
1013 + "Kugel",
1014 + "Kuhhirt",
1015 + "Kühnheit",
1016 + "Künstler",
1017 + "Kurort",
1018 + "Kurve",
1019 + "Kurzfilm",
1020 + "kuscheln",
1021 + "küssen",
1022 + "Kutter",
1023 + "Labor",
1024 + "lachen",
1025 + "Lackaffe",
1026 + "Ladeluke",
1027 + "Lagune",
1028 + "Laib",
1029 + "Lakritze",
1030 + "Lammfell",
1031 + "Land",
1032 + "Langmut",
1033 + "Lappalie",
1034 + "Last",
1035 + "Laterne",
1036 + "Latzhose",
1037 + "Laubsäge",
1038 + "laufen",
1039 + "Laune",
1040 + "Lausbub",
1041 + "Lavasee",
1042 + "Leben",
1043 + "Leder",
1044 + "Leerlauf",
1045 + "Lehm",
1046 + "Lehrer",
1047 + "leihen",
1048 + "Lektüre",
1049 + "Lenker",
1050 + "Lerche",
1051 + "Leseecke",
1052 + "Leuchter",
1053 + "Lexikon",
1054 + "Libelle",
1055 + "Libido",
1056 + "Licht",
1057 + "Liebe",
1058 + "liefern",
1059 + "Liftboy",
1060 + "Limonade",
1061 + "Lineal",
1062 + "Linoleum",
1063 + "List",
1064 + "Liveband",
1065 + "Lobrede",
1066 + "locken",
1067 + "Löffel",
1068 + "Logbuch",
1069 + "Logik",
1070 + "Lohn",
1071 + "Loipe",
1072 + "Lokal",
1073 + "Lorbeer",
1074 + "Lösung",
1075 + "löten",
1076 + "Lottofee",
1077 + "Löwe",
1078 + "Luchs",
1079 + "Luder",
1080 + "Luftpost",
1081 + "Luke",
1082 + "Lümmel",
1083 + "Lunge",
1084 + "lutschen",
1085 + "Luxus",
1086 + "Macht",
1087 + "Magazin",
1088 + "Magier",
1089 + "Magnet",
1090 + "mähen",
1091 + "Mahlzeit",
1092 + "Mahnmal",
1093 + "Maibaum",
1094 + "Maisbrei",
1095 + "Makel",
1096 + "malen",
1097 + "Mammut",
1098 + "Maniküre",
1099 + "Mantel",
1100 + "Marathon",
1101 + "Marder",
1102 + "Marine",
1103 + "Marke",
1104 + "Marmor",
1105 + "Märzluft",
1106 + "Maske",
1107 + "Maßanzug",
1108 + "Maßkrug",
1109 + "Mastkorb",
1110 + "Material",
1111 + "Matratze",
1112 + "Mauerbau",
1113 + "Maulkorb",
1114 + "Mäuschen",
1115 + "Mäzen",
1116 + "Medium",
1117 + "Meinung",
1118 + "melden",
1119 + "Melodie",
1120 + "Mensch",
1121 + "Merkmal",
1122 + "Messe",
1123 + "Metall",
1124 + "Meteor",
1125 + "Methode",
1126 + "Metzger",
1127 + "Mieze",
1128 + "Milchkuh",
1129 + "Mimose",
1130 + "Minirock",
1131 + "Minute",
1132 + "mischen",
1133 + "Missetat",
1134 + "mitgehen",
1135 + "Mittag",
1136 + "Mixtape",
1137 + "Möbel",
1138 + "Modul",
1139 + "mögen",
1140 + "Möhre",
1141 + "Molch",
1142 + "Moment",
1143 + "Monat",
1144 + "Mondflug",
1145 + "Monitor",
1146 + "Monokini",
1147 + "Monster",
1148 + "Monument",
1149 + "Moorhuhn",
1150 + "Moos",
1151 + "Möpse",
1152 + "Moral",
1153 + "Mörtel",
1154 + "Motiv",
1155 + "Motorrad",
1156 + "Möwe",
1157 + "Mühe",
1158 + "Mulatte",
1159 + "Müller",
1160 + "Mumie",
1161 + "Mund",
1162 + "Münze",
1163 + "Muschel",
1164 + "Muster",
1165 + "Mythos",
1166 + "Nabel",
1167 + "Nachtzug",
1168 + "Nackedei",
1169 + "Nagel",
1170 + "Nähe",
1171 + "Nähnadel",
1172 + "Namen",
1173 + "Narbe",
1174 + "Narwal",
1175 + "Nasenbär",
1176 + "Natur",
1177 + "Nebel",
1178 + "necken",
1179 + "Neffe",
1180 + "Neigung",
1181 + "Nektar",
1182 + "Nenner",
1183 + "Neptun",
1184 + "Nerz",
1185 + "Nessel",
1186 + "Nestbau",
1187 + "Netz",
1188 + "Neubau",
1189 + "Neuerung",
1190 + "Neugier",
1191 + "nicken",
1192 + "Niere",
1193 + "Nilpferd",
1194 + "nisten",
1195 + "Nocke",
1196 + "Nomade",
1197 + "Nordmeer",
1198 + "Notdurft",
1199 + "Notstand",
1200 + "Notwehr",
1201 + "Nudismus",
1202 + "Nuss",
1203 + "Nutzhanf",
1204 + "Oase",
1205 + "Obdach",
1206 + "Oberarzt",
1207 + "Objekt",
1208 + "Oboe",
1209 + "Obsthain",
1210 + "Ochse",
1211 + "Odyssee",
1212 + "Ofenholz",
1213 + "öffnen",
1214 + "Ohnmacht",
1215 + "Ohrfeige",
1216 + "Ohrwurm",
1217 + "Ökologie",
1218 + "Oktave",
1219 + "Ölberg",
1220 + "Olive",
1221 + "Ölkrise",
1222 + "Omelett",
1223 + "Onkel",
1224 + "Oper",
1225 + "Optiker",
1226 + "Orange",
1227 + "Orchidee",
1228 + "ordnen",
1229 + "Orgasmus",
1230 + "Orkan",
1231 + "Ortskern",
1232 + "Ortung",
1233 + "Ostasien",
1234 + "Ozean",
1235 + "Paarlauf",
1236 + "Packeis",
1237 + "paddeln",
1238 + "Paket",
1239 + "Palast",
1240 + "Pandabär",
1241 + "Panik",
1242 + "Panorama",
1243 + "Panther",
1244 + "Papagei",
1245 + "Papier",
1246 + "Paprika",
1247 + "Paradies",
1248 + "Parka",
1249 + "Parodie",
1250 + "Partner",
1251 + "Passant",
1252 + "Patent",
1253 + "Patzer",
1254 + "Pause",
1255 + "Pavian",
1256 + "Pedal",
1257 + "Pegel",
1258 + "peilen",
1259 + "Perle",
1260 + "Person",
1261 + "Pfad",
1262 + "Pfau",
1263 + "Pferd",
1264 + "Pfleger",
1265 + "Physik",
1266 + "Pier",
1267 + "Pilotwal",
1268 + "Pinzette",
1269 + "Piste",
1270 + "Plakat",
1271 + "Plankton",
1272 + "Platin",
1273 + "Plombe",
1274 + "plündern",
1275 + "Pobacke",
1276 + "Pokal",
1277 + "polieren",
1278 + "Popmusik",
1279 + "Porträt",
1280 + "Posaune",
1281 + "Postamt",
1282 + "Pottwal",
1283 + "Pracht",
1284 + "Pranke",
1285 + "Preis",
1286 + "Primat",
1287 + "Prinzip",
1288 + "Protest",
1289 + "Proviant",
1290 + "Prüfung",
1291 + "Pubertät",
1292 + "Pudding",
1293 + "Pullover",
1294 + "Pulsader",
1295 + "Punkt",
1296 + "Pute",
1297 + "Putsch",
1298 + "Puzzle",
1299 + "Python",
1300 + "quaken",
1301 + "Qualle",
1302 + "Quark",
1303 + "Quellsee",
1304 + "Querkopf",
1305 + "Quitte",
1306 + "Quote",
1307 + "Rabauke",
1308 + "Rache",
1309 + "Radclub",
1310 + "Radhose",
1311 + "Radio",
1312 + "Radtour",
1313 + "Rahmen",
1314 + "Rampe",
1315 + "Randlage",
1316 + "Ranzen",
1317 + "Rapsöl",
1318 + "Raserei",
1319 + "rasten",
1320 + "Rasur",
1321 + "Rätsel",
1322 + "Raubtier",
1323 + "Raumzeit",
1324 + "Rausch",
1325 + "Reaktor",
1326 + "Realität",
1327 + "Rebell",
1328 + "Rede",
1329 + "Reetdach",
1330 + "Regatta",
1331 + "Regen",
1332 + "Rehkitz",
1333 + "Reifen",
1334 + "Reim",
1335 + "Reise",
1336 + "Reizung",
1337 + "Rekord",
1338 + "Relevanz",
1339 + "Rennboot",
1340 + "Respekt",
1341 + "Restmüll",
1342 + "retten",
1343 + "Reue",
1344 + "Revolte",
1345 + "Rhetorik",
1346 + "Rhythmus",
1347 + "Richtung",
1348 + "Riegel",
1349 + "Rindvieh",
1350 + "Rippchen",
1351 + "Ritter",
1352 + "Robbe",
1353 + "Roboter",
1354 + "Rockband",
1355 + "Rohdaten",
1356 + "Roller",
1357 + "Roman",
1358 + "röntgen",
1359 + "Rose",
1360 + "Rosskur",
1361 + "Rost",
1362 + "Rotahorn",
1363 + "Rotglut",
1364 + "Rotznase",
1365 + "Rubrik",
1366 + "Rückweg",
1367 + "Rufmord",
1368 + "Ruhe",
1369 + "Ruine",
1370 + "Rumpf",
1371 + "Runde",
1372 + "Rüstung",
1373 + "rütteln",
1374 + "Saaltür",
1375 + "Saatguts",
1376 + "Säbel",
1377 + "Sachbuch",
1378 + "Sack",
1379 + "Saft",
1380 + "sagen",
1381 + "Sahneeis",
1382 + "Salat",
1383 + "Salbe",
1384 + "Salz",
1385 + "Sammlung",
1386 + "Samt",
1387 + "Sandbank",
1388 + "Sanftmut",
1389 + "Sardine",
1390 + "Satire",
1391 + "Sattel",
1392 + "Satzbau",
1393 + "Sauerei",
1394 + "Saum",
1395 + "Säure",
1396 + "Schall",
1397 + "Scheitel",
1398 + "Schiff",
1399 + "Schlager",
1400 + "Schmied",
1401 + "Schnee",
1402 + "Scholle",
1403 + "Schrank",
1404 + "Schulbus",
1405 + "Schwan",
1406 + "Seeadler",
1407 + "Seefahrt",
1408 + "Seehund",
1409 + "Seeufer",
1410 + "segeln",
1411 + "Sehnerv",
1412 + "Seide",
1413 + "Seilzug",
1414 + "Senf",
1415 + "Sessel",
1416 + "Seufzer",
1417 + "Sexgott",
1418 + "Sichtung",
1419 + "Signal",
1420 + "Silber",
1421 + "singen",
1422 + "Sinn",
1423 + "Sirup",
1424 + "Sitzbank",
1425 + "Skandal",
1426 + "Skikurs",
1427 + "Skipper",
1428 + "Skizze",
1429 + "Smaragd",
1430 + "Socke",
1431 + "Sohn",
1432 + "Sommer",
1433 + "Songtext",
1434 + "Sorte",
1435 + "Spagat",
1436 + "Spannung",
1437 + "Spargel",
1438 + "Specht",
1439 + "Speiseöl",
1440 + "Spiegel",
1441 + "Sport",
1442 + "spülen",
1443 + "Stadtbus",
1444 + "Stall",
1445 + "Stärke",
1446 + "Stativ",
1447 + "staunen",
1448 + "Stern",
1449 + "Stiftung",
1450 + "Stollen",
1451 + "Strömung",
1452 + "Sturm",
1453 + "Substanz",
1454 + "Südalpen",
1455 + "Sumpf",
1456 + "surfen",
1457 + "Tabak",
1458 + "Tafel",
1459 + "Tagebau",
1460 + "takeln",
1461 + "Taktung",
1462 + "Talsohle",
1463 + "Tand",
1464 + "Tanzbär",
1465 + "Tapir",
1466 + "Tarantel",
1467 + "Tarnname",
1468 + "Tasse",
1469 + "Tatnacht",
1470 + "Tatsache",
1471 + "Tatze",
1472 + "Taube",
1473 + "tauchen",
1474 + "Taufpate",
1475 + "Taumel",
1476 + "Teelicht",
1477 + "Teich",
1478 + "teilen",
1479 + "Tempo",
1480 + "Tenor",
1481 + "Terrasse",
1482 + "Testflug",
1483 + "Theater",
1484 + "Thermik",
1485 + "ticken",
1486 + "Tiefflug",
1487 + "Tierart",
1488 + "Tigerhai",
1489 + "Tinte",
1490 + "Tischler",
1491 + "toben",
1492 + "Toleranz",
1493 + "Tölpel",
1494 + "Tonband",
1495 + "Topf",
1496 + "Topmodel",
1497 + "Torbogen",
1498 + "Torlinie",
1499 + "Torte",
1500 + "Tourist",
1501 + "Tragesel",
1502 + "trampeln",
1503 + "Trapez",
1504 + "Traum",
1505 + "treffen",
1506 + "Trennung",
1507 + "Treue",
1508 + "Trick",
1509 + "trimmen",
1510 + "Trödel",
1511 + "Trost",
1512 + "Trumpf",
1513 + "tüfteln",
1514 + "Turban",
1515 + "Turm",
1516 + "Übermut",
1517 + "Ufer",
1518 + "Uhrwerk",
1519 + "umarmen",
1520 + "Umbau",
1521 + "Umfeld",
1522 + "Umgang",
1523 + "Umsturz",
1524 + "Unart",
1525 + "Unfug",
1526 + "Unimog",
1527 + "Unruhe",
1528 + "Unwucht",
1529 + "Uranerz",
1530 + "Urlaub",
1531 + "Urmensch",
1532 + "Utopie",
1533 + "Vakuum",
1534 + "Valuta",
1535 + "Vandale",
1536 + "Vase",
1537 + "Vektor",
1538 + "Ventil",
1539 + "Verb",
1540 + "Verdeck",
1541 + "Verfall",
1542 + "Vergaser",
1543 + "verhexen",
1544 + "Verlag",
1545 + "Vers",
1546 + "Vesper",
1547 + "Vieh",
1548 + "Viereck",
1549 + "Vinyl",
1550 + "Virus",
1551 + "Vitrine",
1552 + "Vollblut",
1553 + "Vorbote",
1554 + "Vorrat",
1555 + "Vorsicht",
1556 + "Vulkan",
1557 + "Wachstum",
1558 + "Wade",
1559 + "Wagemut",
1560 + "Wahlen",
1561 + "Wahrheit",
1562 + "Wald",
1563 + "Walhai",
1564 + "Wallach",
1565 + "Walnuss",
1566 + "Walzer",
1567 + "wandeln",
1568 + "Wanze",
1569 + "wärmen",
1570 + "Warnruf",
1571 + "Wäsche",
1572 + "Wasser",
1573 + "Weberei",
1574 + "wechseln",
1575 + "Wegegeld",
1576 + "wehren",
1577 + "Weiher",
1578 + "Weinglas",
1579 + "Weißbier",
1580 + "Weitwurf",
1581 + "Welle",
1582 + "Weltall",
1583 + "Werkbank",
1584 + "Werwolf",
1585 + "Wetter",
1586 + "wiehern",
1587 + "Wildgans",
1588 + "Wind",
1589 + "Wohl",
1590 + "Wohnort",
1591 + "Wolf",
1592 + "Wollust",
1593 + "Wortlaut",
1594 + "Wrack",
1595 + "Wunder",
1596 + "Wurfaxt",
1597 + "Wurst",
1598 + "Yacht",
1599 + "Yeti",
1600 + "Zacke",
1601 + "Zahl",
1602 + "zähmen",
1603 + "Zahnfee",
1604 + "Zäpfchen",
1605 + "Zaster",
1606 + "Zaumzeug",
1607 + "Zebra",
1608 + "zeigen",
1609 + "Zeitlupe",
1610 + "Zellkern",
1611 + "Zeltdach",
1612 + "Zensor",
1613 + "Zerfall",
1614 + "Zeug",
1615 + "Ziege",
1616 + "Zielfoto",
1617 + "Zimteis",
1618 + "Zobel",
1619 + "Zollhund",
1620 + "Zombie",
1621 + "Zöpfe",
1622 + "Zucht",
1623 + "Zufahrt",
1624 + "Zugfahrt",
1625 + "Zugvogel",
1626 + "Zündung",
1627 + "Zweck",
1628 + "Zyklop"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mnemonics/italian.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class ItalianMnemonics {
2 + static const words = [
3 + "abbinare",
4 + "abbonato",
5 + "abisso",
6 + "abitare",
7 + "abominio",
8 + "accadere",
9 + "accesso",
10 + "acciaio",
11 + "accordo",
12 + "accumulo",
13 + "acido",
14 + "acqua",
15 + "acrobata",
16 + "acustico",
17 + "adattare",
18 + "addetto",
19 + "addio",
20 + "addome",
21 + "adeguato",
22 + "aderire",
23 + "adorare",
24 + "adottare",
25 + "adozione",
26 + "adulto",
27 + "aereo",
28 + "aerobica",
29 + "affare",
30 + "affetto",
31 + "affidare",
32 + "affogato",
33 + "affronto",
34 + "africano",
35 + "afrodite",
36 + "agenzia",
37 + "aggancio",
38 + "aggeggio",
39 + "aggiunta",
40 + "agio",
41 + "agire",
42 + "agitare",
43 + "aglio",
44 + "agnello",
45 + "agosto",
46 + "aiutare",
47 + "albero",
48 + "albo",
49 + "alce",
50 + "alchimia",
51 + "alcool",
52 + "alfabeto",
53 + "algebra",
54 + "alimento",
55 + "allarme",
56 + "alleanza",
57 + "allievo",
58 + "alloggio",
59 + "alluce",
60 + "alpi",
61 + "alterare",
62 + "altro",
63 + "aluminio",
64 + "amante",
65 + "amarezza",
66 + "ambiente",
67 + "ambrosia",
68 + "america",
69 + "amico",
70 + "ammalare",
71 + "ammirare",
72 + "amnesia",
73 + "amnistia",
74 + "amore",
75 + "ampliare",
76 + "amputare",
77 + "analisi",
78 + "anamnesi",
79 + "ananas",
80 + "anarchia",
81 + "anatra",
82 + "anca",
83 + "ancorato",
84 + "andare",
85 + "androide",
86 + "aneddoto",
87 + "anello",
88 + "angelo",
89 + "angolino",
90 + "anguilla",
91 + "anidride",
92 + "anima",
93 + "annegare",
94 + "anno",
95 + "annuncio",
96 + "anomalia",
97 + "antenna",
98 + "anticipo",
99 + "aperto",
100 + "apostolo",
101 + "appalto",
102 + "appello",
103 + "appiglio",
104 + "applauso",
105 + "appoggio",
106 + "appurare",
107 + "aprile",
108 + "aquila",
109 + "arabo",
110 + "arachidi",
111 + "aragosta",
112 + "arancia",
113 + "arbitrio",
114 + "archivio",
115 + "arco",
116 + "argento",
117 + "argilla",
118 + "aria",
119 + "ariete",
120 + "arma",
121 + "armonia",
122 + "aroma",
123 + "arrivare",
124 + "arrosto",
125 + "arsenale",
126 + "arte",
127 + "artiglio",
128 + "asfalto",
129 + "asfissia",
130 + "asino",
131 + "asparagi",
132 + "aspirina",
133 + "assalire",
134 + "assegno",
135 + "assolto",
136 + "assurdo",
137 + "asta",
138 + "astratto",
139 + "atlante",
140 + "atletica",
141 + "atomo",
142 + "atropina",
143 + "attacco",
144 + "attesa",
145 + "attico",
146 + "atto",
147 + "attrarre",
148 + "auguri",
149 + "aula",
150 + "aumento",
151 + "aurora",
152 + "auspicio",
153 + "autista",
154 + "auto",
155 + "autunno",
156 + "avanzare",
157 + "avarizia",
158 + "avere",
159 + "aviatore",
160 + "avido",
161 + "avorio",
162 + "avvenire",
163 + "avviso",
164 + "avvocato",
165 + "azienda",
166 + "azione",
167 + "azzardo",
168 + "azzurro",
169 + "babbuino",
170 + "bacio",
171 + "badante",
172 + "baffi",
173 + "bagaglio",
174 + "bagliore",
175 + "bagno",
176 + "balcone",
177 + "balena",
178 + "ballare",
179 + "balordo",
180 + "balsamo",
181 + "bambola",
182 + "bancomat",
183 + "banda",
184 + "barato",
185 + "barba",
186 + "barista",
187 + "barriera",
188 + "basette",
189 + "basilico",
190 + "bassista",
191 + "bastare",
192 + "battello",
193 + "bavaglio",
194 + "beccare",
195 + "beduino",
196 + "bellezza",
197 + "bene",
198 + "benzina",
199 + "berretto",
200 + "bestia",
201 + "bevitore",
202 + "bianco",
203 + "bibbia",
204 + "biberon",
205 + "bibita",
206 + "bici",
207 + "bidone",
208 + "bilancia",
209 + "biliardo",
210 + "binario",
211 + "binocolo",
212 + "biologia",
213 + "biondina",
214 + "biopsia",
215 + "biossido",
216 + "birbante",
217 + "birra",
218 + "biscotto",
219 + "bisogno",
220 + "bistecca",
221 + "bivio",
222 + "blindare",
223 + "bloccare",
224 + "bocca",
225 + "bollire",
226 + "bombola",
227 + "bonifico",
228 + "borghese",
229 + "borsa",
230 + "bottino",
231 + "botulino",
232 + "braccio",
233 + "bradipo",
234 + "branco",
235 + "bravo",
236 + "bresaola",
237 + "bretelle",
238 + "brevetto",
239 + "briciola",
240 + "brigante",
241 + "brillare",
242 + "brindare",
243 + "brivido",
244 + "broccoli",
245 + "brontolo",
246 + "bruciare",
247 + "brufolo",
248 + "bucare",
249 + "buddista",
250 + "budino",
251 + "bufera",
252 + "buffo",
253 + "bugiardo",
254 + "buio",
255 + "buono",
256 + "burrone",
257 + "bussola",
258 + "bustina",
259 + "buttare",
260 + "cabernet",
261 + "cabina",
262 + "cacao",
263 + "cacciare",
264 + "cactus",
265 + "cadavere",
266 + "caffe",
267 + "calamari",
268 + "calcio",
269 + "caldaia",
270 + "calmare",
271 + "calunnia",
272 + "calvario",
273 + "calzone",
274 + "cambiare",
275 + "camera",
276 + "camion",
277 + "cammello",
278 + "campana",
279 + "canarino",
280 + "cancello",
281 + "candore",
282 + "cane",
283 + "canguro",
284 + "cannone",
285 + "canoa",
286 + "cantare",
287 + "canzone",
288 + "caos",
289 + "capanna",
290 + "capello",
291 + "capire",
292 + "capo",
293 + "capperi",
294 + "capra",
295 + "capsula",
296 + "caraffa",
297 + "carbone",
298 + "carciofo",
299 + "cardigan",
300 + "carenza",
301 + "caricare",
302 + "carota",
303 + "carrello",
304 + "carta",
305 + "casa",
306 + "cascare",
307 + "caserma",
308 + "cashmere",
309 + "casino",
310 + "cassetta",
311 + "castello",
312 + "catalogo",
313 + "catena",
314 + "catorcio",
315 + "cattivo",
316 + "causa",
317 + "cauzione",
318 + "cavallo",
319 + "caverna",
320 + "caviglia",
321 + "cavo",
322 + "cazzotto",
323 + "celibato",
324 + "cemento",
325 + "cenare",
326 + "centrale",
327 + "ceramica",
328 + "cercare",
329 + "ceretta",
330 + "cerniera",
331 + "certezza",
332 + "cervello",
333 + "cessione",
334 + "cestino",
335 + "cetriolo",
336 + "chiave",
337 + "chiedere",
338 + "chilo",
339 + "chimera",
340 + "chiodo",
341 + "chirurgo",
342 + "chitarra",
343 + "chiudere",
344 + "ciabatta",
345 + "ciao",
346 + "cibo",
347 + "ciccia",
348 + "cicerone",
349 + "ciclone",
350 + "cicogna",
351 + "cielo",
352 + "cifra",
353 + "cigno",
354 + "ciliegia",
355 + "cimitero",
356 + "cinema",
357 + "cinque",
358 + "cintura",
359 + "ciondolo",
360 + "ciotola",
361 + "cipolla",
362 + "cippato",
363 + "circuito",
364 + "cisterna",
365 + "citofono",
366 + "ciuccio",
367 + "civetta",
368 + "civico",
369 + "clausola",
370 + "cliente",
371 + "clima",
372 + "clinica",
373 + "cobra",
374 + "coccole",
375 + "cocktail",
376 + "cocomero",
377 + "codice",
378 + "coesione",
379 + "cogliere",
380 + "cognome",
381 + "colla",
382 + "colomba",
383 + "colpire",
384 + "coltello",
385 + "comando",
386 + "comitato",
387 + "commedia",
388 + "comodino",
389 + "compagna",
390 + "comune",
391 + "concerto",
392 + "condotto",
393 + "conforto",
394 + "congiura",
395 + "coniglio",
396 + "consegna",
397 + "conto",
398 + "convegno",
399 + "coperta",
400 + "copia",
401 + "coprire",
402 + "corazza",
403 + "corda",
404 + "corleone",
405 + "cornice",
406 + "corona",
407 + "corpo",
408 + "corrente",
409 + "corsa",
410 + "cortesia",
411 + "corvo",
412 + "coso",
413 + "costume",
414 + "cotone",
415 + "cottura",
416 + "cozza",
417 + "crampo",
418 + "cratere",
419 + "cravatta",
420 + "creare",
421 + "credere",
422 + "crema",
423 + "crescere",
424 + "crimine",
425 + "criterio",
426 + "croce",
427 + "crollare",
428 + "cronaca",
429 + "crostata",
430 + "croupier",
431 + "cubetto",
432 + "cucciolo",
433 + "cucina",
434 + "cultura",
435 + "cuoco",
436 + "cuore",
437 + "cupido",
438 + "cupola",
439 + "cura",
440 + "curva",
441 + "cuscino",
442 + "custode",
443 + "danzare",
444 + "data",
445 + "decennio",
446 + "decidere",
447 + "decollo",
448 + "dedicare",
449 + "dedurre",
450 + "definire",
451 + "delegare",
452 + "delfino",
453 + "delitto",
454 + "demone",
455 + "dentista",
456 + "denuncia",
457 + "deposito",
458 + "derivare",
459 + "deserto",
460 + "designer",
461 + "destino",
462 + "detonare",
463 + "dettagli",
464 + "diagnosi",
465 + "dialogo",
466 + "diamante",
467 + "diario",
468 + "diavolo",
469 + "dicembre",
470 + "difesa",
471 + "digerire",
472 + "digitare",
473 + "diluvio",
474 + "dinamica",
475 + "dipinto",
476 + "diploma",
477 + "diramare",
478 + "dire",
479 + "dirigere",
480 + "dirupo",
481 + "discesa",
482 + "disdetta",
483 + "disegno",
484 + "disporre",
485 + "dissenso",
486 + "distacco",
487 + "dito",
488 + "ditta",
489 + "diva",
490 + "divenire",
491 + "dividere",
492 + "divorare",
493 + "docente",
494 + "dolcetto",
495 + "dolore",
496 + "domatore",
497 + "domenica",
498 + "dominare",
499 + "donatore",
500 + "donna",
501 + "dorato",
502 + "dormire",
503 + "dorso",
504 + "dosaggio",
505 + "dottore",
506 + "dovere",
507 + "download",
508 + "dragone",
509 + "dramma",
510 + "dubbio",
511 + "dubitare",
512 + "duetto",
513 + "durata",
514 + "ebbrezza",
515 + "eccesso",
516 + "eccitare",
517 + "eclissi",
518 + "economia",
519 + "edera",
520 + "edificio",
521 + "editore",
522 + "edizione",
523 + "educare",
524 + "effetto",
525 + "egitto",
526 + "egiziano",
527 + "elastico",
528 + "elefante",
529 + "eleggere",
530 + "elemento",
531 + "elenco",
532 + "elezione",
533 + "elmetto",
534 + "elogio",
535 + "embrione",
536 + "emergere",
537 + "emettere",
538 + "eminenza",
539 + "emisfero",
540 + "emozione",
541 + "empatia",
542 + "energia",
543 + "enfasi",
544 + "enigma",
545 + "entrare",
546 + "enzima",
547 + "epidemia",
548 + "epilogo",
549 + "episodio",
550 + "epoca",
551 + "equivoco",
552 + "erba",
553 + "erede",
554 + "eroe",
555 + "erotico",
556 + "errore",
557 + "eruzione",
558 + "esaltare",
559 + "esame",
560 + "esaudire",
561 + "eseguire",
562 + "esempio",
563 + "esigere",
564 + "esistere",
565 + "esito",
566 + "esperto",
567 + "espresso",
568 + "essere",
569 + "estasi",
570 + "esterno",
571 + "estrarre",
572 + "eterno",
573 + "etica",
574 + "euforico",
575 + "europa",
576 + "evacuare",
577 + "evasione",
578 + "evento",
579 + "evidenza",
580 + "evitare",
581 + "evolvere",
582 + "fabbrica",
583 + "facciata",
584 + "fagiano",
585 + "fagotto",
586 + "falco",
587 + "fame",
588 + "famiglia",
589 + "fanale",
590 + "fango",
591 + "fantasia",
592 + "farfalla",
593 + "farmacia",
594 + "faro",
595 + "fase",
596 + "fastidio",
597 + "faticare",
598 + "fatto",
599 + "favola",
600 + "febbre",
601 + "femmina",
602 + "femore",
603 + "fenomeno",
604 + "fermata",
605 + "feromoni",
606 + "ferrari",
607 + "fessura",
608 + "festa",
609 + "fiaba",
610 + "fiamma",
611 + "fianco",
612 + "fiat",
613 + "fibbia",
614 + "fidare",
615 + "fieno",
616 + "figa",
617 + "figlio",
618 + "figura",
619 + "filetto",
620 + "filmato",
621 + "filosofo",
622 + "filtrare",
623 + "finanza",
624 + "finestra",
625 + "fingere",
626 + "finire",
627 + "finta",
628 + "finzione",
629 + "fiocco",
630 + "fioraio",
631 + "firewall",
632 + "firmare",
633 + "fisico",
634 + "fissare",
635 + "fittizio",
636 + "fiume",
637 + "flacone",
638 + "flagello",
639 + "flirtare",
640 + "flusso",
641 + "focaccia",
642 + "foglio",
643 + "fognario",
644 + "follia",
645 + "fonderia",
646 + "fontana",
647 + "forbici",
648 + "forcella",
649 + "foresta",
650 + "forgiare",
651 + "formare",
652 + "fornace",
653 + "foro",
654 + "fortuna",
655 + "forzare",
656 + "fosforo",
657 + "fotoni",
658 + "fracasso",
659 + "fragola",
660 + "frantumi",
661 + "fratello",
662 + "frazione",
663 + "freccia",
664 + "freddo",
665 + "frenare",
666 + "fresco",
667 + "friggere",
668 + "frittata",
669 + "frivolo",
670 + "frizione",
671 + "fronte",
672 + "frullato",
673 + "frumento",
674 + "frusta",
675 + "frutto",
676 + "fucile",
677 + "fuggire",
678 + "fulmine",
679 + "fumare",
680 + "funzione",
681 + "fuoco",
682 + "furbizia",
683 + "furgone",
684 + "furia",
685 + "furore",
686 + "fusibile",
687 + "fuso",
688 + "futuro",
689 + "gabbiano",
690 + "galassia",
691 + "gallina",
692 + "gamba",
693 + "gancio",
694 + "garanzia",
695 + "garofano",
696 + "gasolio",
697 + "gatto",
698 + "gazebo",
699 + "gazzetta",
700 + "gelato",
701 + "gemelli",
702 + "generare",
703 + "genitori",
704 + "gennaio",
705 + "geologia",
706 + "germania",
707 + "gestire",
708 + "gettare",
709 + "ghepardo",
710 + "ghiaccio",
711 + "giaccone",
712 + "giaguaro",
713 + "giallo",
714 + "giappone",
715 + "giardino",
716 + "gigante",
717 + "gioco",
718 + "gioiello",
719 + "giorno",
720 + "giovane",
721 + "giraffa",
722 + "giudizio",
723 + "giurare",
724 + "giusto",
725 + "globo",
726 + "gloria",
727 + "glucosio",
728 + "gnocca",
729 + "gocciola",
730 + "godere",
731 + "gomito",
732 + "gomma",
733 + "gonfiare",
734 + "gorilla",
735 + "governo",
736 + "gradire",
737 + "graffiti",
738 + "granchio",
739 + "grappolo",
740 + "grasso",
741 + "grattare",
742 + "gridare",
743 + "grissino",
744 + "grondaia",
745 + "grugnito",
746 + "gruppo",
747 + "guadagno",
748 + "guaio",
749 + "guancia",
750 + "guardare",
751 + "gufo",
752 + "guidare",
753 + "guscio",
754 + "gusto",
755 + "icona",
756 + "idea",
757 + "identico",
758 + "idolo",
759 + "idoneo",
760 + "idrante",
761 + "idrogeno",
762 + "igiene",
763 + "ignoto",
764 + "imbarco",
765 + "immagine",
766 + "immobile",
767 + "imparare",
768 + "impedire",
769 + "impianto",
770 + "importo",
771 + "impresa",
772 + "impulso",
773 + "incanto",
774 + "incendio",
775 + "incidere",
776 + "incontro",
777 + "incrocia",
778 + "incubo",
779 + "indagare",
780 + "indice",
781 + "indotto",
782 + "infanzia",
783 + "inferno",
784 + "infinito",
785 + "infranto",
786 + "ingerire",
787 + "inglese",
788 + "ingoiare",
789 + "ingresso",
790 + "iniziare",
791 + "innesco",
792 + "insalata",
793 + "inserire",
794 + "insicuro",
795 + "insonnia",
796 + "insulto",
797 + "interno",
798 + "introiti",
799 + "invasori",
800 + "inverno",
801 + "invito",
802 + "invocare",
803 + "ipnosi",
804 + "ipocrita",
805 + "ipotesi",
806 + "ironia",
807 + "irrigare",
808 + "iscritto",
809 + "isola",
810 + "ispirare",
811 + "isterico",
812 + "istinto",
813 + "istruire",
814 + "italiano",
815 + "jazz",
816 + "labbra",
817 + "labrador",
818 + "ladro",
819 + "lago",
820 + "lamento",
821 + "lampone",
822 + "lancetta",
823 + "lanterna",
824 + "lapide",
825 + "larva",
826 + "lasagne",
827 + "lasciare",
828 + "lastra",
829 + "latte",
830 + "laurea",
831 + "lavagna",
832 + "lavorare",
833 + "leccare",
834 + "legare",
835 + "leggere",
836 + "lenzuolo",
837 + "leone",
838 + "lepre",
839 + "letargo",
840 + "lettera",
841 + "levare",
842 + "levitare",
843 + "lezione",
844 + "liberare",
845 + "libidine",
846 + "libro",
847 + "licenza",
848 + "lievito",
849 + "limite",
850 + "lince",
851 + "lingua",
852 + "liquore",
853 + "lire",
854 + "listino",
855 + "litigare",
856 + "litro",
857 + "locale",
858 + "lottare",
859 + "lucciola",
860 + "lucidare",
861 + "luglio",
862 + "luna",
863 + "macchina",
864 + "madama",
865 + "madre",
866 + "maestro",
867 + "maggio",
868 + "magico",
869 + "maglione",
870 + "magnolia",
871 + "mago",
872 + "maialino",
873 + "maionese",
874 + "malattia",
875 + "male",
876 + "malloppo",
877 + "mancare",
878 + "mandorla",
879 + "mangiare",
880 + "manico",
881 + "manopola",
882 + "mansarda",
883 + "mantello",
884 + "manubrio",
885 + "manzo",
886 + "mappa",
887 + "mare",
888 + "margine",
889 + "marinaio",
890 + "marmotta",
891 + "marocco",
892 + "martello",
893 + "marzo",
894 + "maschera",
895 + "matrice",
896 + "maturare",
897 + "mazzetta",
898 + "meandri",
899 + "medaglia",
900 + "medico",
901 + "medusa",
902 + "megafono",
903 + "melone",
904 + "membrana",
905 + "menta",
906 + "mercato",
907 + "meritare",
908 + "merluzzo",
909 + "mese",
910 + "mestiere",
911 + "metafora",
912 + "meteo",
913 + "metodo",
914 + "mettere",
915 + "miele",
916 + "miglio",
917 + "miliardo",
918 + "mimetica",
919 + "minatore",
920 + "minuto",
921 + "miracolo",
922 + "mirtillo",
923 + "missile",
924 + "mistero",
925 + "misura",
926 + "mito",
927 + "mobile",
928 + "moda",
929 + "moderare",
930 + "moglie",
931 + "molecola",
932 + "molle",
933 + "momento",
934 + "moneta",
935 + "mongolia",
936 + "monologo",
937 + "montagna",
938 + "morale",
939 + "morbillo",
940 + "mordere",
941 + "mosaico",
942 + "mosca",
943 + "mostro",
944 + "motivare",
945 + "moto",
946 + "mulino",
947 + "mulo",
948 + "muovere",
949 + "muraglia",
950 + "muscolo",
951 + "museo",
952 + "musica",
953 + "mutande",
954 + "nascere",
955 + "nastro",
956 + "natale",
957 + "natura",
958 + "nave",
959 + "navigare",
960 + "negare",
961 + "negozio",
962 + "nemico",
963 + "nero",
964 + "nervo",
965 + "nessuno",
966 + "nettare",
967 + "neutroni",
968 + "neve",
969 + "nevicare",
970 + "nicotina",
971 + "nido",
972 + "nipote",
973 + "nocciola",
974 + "noleggio",
975 + "nome",
976 + "nonno",
977 + "norvegia",
978 + "notare",
979 + "notizia",
980 + "nove",
981 + "nucleo",
982 + "nuda",
983 + "nuotare",
984 + "nutrire",
985 + "obbligo",
986 + "occhio",
987 + "occupare",
988 + "oceano",
989 + "odissea",
990 + "odore",
991 + "offerta",
992 + "officina",
993 + "offrire",
994 + "oggetto",
995 + "oggi",
996 + "olfatto",
997 + "olio",
998 + "oliva",
999 + "ombelico",
1000 + "ombrello",
1001 + "omuncolo",
1002 + "ondata",
1003 + "onore",
1004 + "opera",
1005 + "opinione",
1006 + "opuscolo",
1007 + "opzione",
1008 + "orario",
1009 + "orbita",
1010 + "orchidea",
1011 + "ordine",
1012 + "orecchio",
1013 + "orgasmo",
1014 + "orgoglio",
1015 + "origine",
1016 + "orologio",
1017 + "oroscopo",
1018 + "orso",
1019 + "oscurare",
1020 + "ospedale",
1021 + "ospite",
1022 + "ossigeno",
1023 + "ostacolo",
1024 + "ostriche",
1025 + "ottenere",
1026 + "ottimo",
1027 + "ottobre",
1028 + "ovest",
1029 + "pacco",
1030 + "pace",
1031 + "pacifico",
1032 + "padella",
1033 + "pagare",
1034 + "pagina",
1035 + "pagnotta",
1036 + "palazzo",
1037 + "palestra",
1038 + "palpebre",
1039 + "pancetta",
1040 + "panfilo",
1041 + "panino",
1042 + "pannello",
1043 + "panorama",
1044 + "papa",
1045 + "paperino",
1046 + "paradiso",
1047 + "parcella",
1048 + "parente",
1049 + "parlare",
1050 + "parodia",
1051 + "parrucca",
1052 + "partire",
1053 + "passare",
1054 + "pasta",
1055 + "patata",
1056 + "patente",
1057 + "patogeno",
1058 + "patriota",
1059 + "pausa",
1060 + "pazienza",
1061 + "peccare",
1062 + "pecora",
1063 + "pedalare",
1064 + "pelare",
1065 + "pena",
1066 + "pendenza",
1067 + "penisola",
1068 + "pennello",
1069 + "pensare",
1070 + "pentirsi",
1071 + "percorso",
1072 + "perdono",
1073 + "perfetto",
1074 + "perizoma",
1075 + "perla",
1076 + "permesso",
1077 + "persona",
1078 + "pesare",
1079 + "pesce",
1080 + "peso",
1081 + "petardo",
1082 + "petrolio",
1083 + "pezzo",
1084 + "piacere",
1085 + "pianeta",
1086 + "piastra",
1087 + "piatto",
1088 + "piazza",
1089 + "piccolo",
1090 + "piede",
1091 + "piegare",
1092 + "pietra",
1093 + "pigiama",
1094 + "pigliare",
1095 + "pigrizia",
1096 + "pilastro",
1097 + "pilota",
1098 + "pinguino",
1099 + "pioggia",
1100 + "piombo",
1101 + "pionieri",
1102 + "piovra",
1103 + "pipa",
1104 + "pirata",
1105 + "pirolisi",
1106 + "piscina",
1107 + "pisolino",
1108 + "pista",
1109 + "pitone",
1110 + "piumino",
1111 + "pizza",
1112 + "plastica",
1113 + "platino",
1114 + "poesia",
1115 + "poiana",
1116 + "polaroid",
1117 + "polenta",
1118 + "polimero",
1119 + "pollo",
1120 + "polmone",
1121 + "polpetta",
1122 + "poltrona",
1123 + "pomodoro",
1124 + "pompa",
1125 + "popolo",
1126 + "porco",
1127 + "porta",
1128 + "porzione",
1129 + "possesso",
1130 + "postino",
1131 + "potassio",
1132 + "potere",
1133 + "poverino",
1134 + "pranzo",
1135 + "prato",
1136 + "prefisso",
1137 + "prelievo",
1138 + "premio",
1139 + "prendere",
1140 + "prestare",
1141 + "pretesa",
1142 + "prezzo",
1143 + "primario",
1144 + "privacy",
1145 + "problema",
1146 + "processo",
1147 + "prodotto",
1148 + "profeta",
1149 + "progetto",
1150 + "promessa",
1151 + "pronto",
1152 + "proposta",
1153 + "proroga",
1154 + "prossimo",
1155 + "proteina",
1156 + "prova",
1157 + "prudenza",
1158 + "pubblico",
1159 + "pudore",
1160 + "pugilato",
1161 + "pulire",
1162 + "pulsante",
1163 + "puntare",
1164 + "pupazzo",
1165 + "puzzle",
1166 + "quaderno",
1167 + "qualcuno",
1168 + "quarzo",
1169 + "quercia",
1170 + "quintale",
1171 + "rabbia",
1172 + "racconto",
1173 + "radice",
1174 + "raffica",
1175 + "ragazza",
1176 + "ragione",
1177 + "rammento",
1178 + "ramo",
1179 + "rana",
1180 + "randagio",
1181 + "rapace",
1182 + "rapinare",
1183 + "rapporto",
1184 + "rasatura",
1185 + "ravioli",
1186 + "reagire",
1187 + "realista",
1188 + "reattore",
1189 + "reazione",
1190 + "recitare",
1191 + "recluso",
1192 + "record",
1193 + "recupero",
1194 + "redigere",
1195 + "regalare",
1196 + "regina",
1197 + "regola",
1198 + "relatore",
1199 + "reliquia",
1200 + "remare",
1201 + "rendere",
1202 + "reparto",
1203 + "resina",
1204 + "resto",
1205 + "rete",
1206 + "retorica",
1207 + "rettile",
1208 + "revocare",
1209 + "riaprire",
1210 + "ribadire",
1211 + "ribelle",
1212 + "ricambio",
1213 + "ricetta",
1214 + "richiamo",
1215 + "ricordo",
1216 + "ridurre",
1217 + "riempire",
1218 + "riferire",
1219 + "riflesso",
1220 + "righello",
1221 + "rilancio",
1222 + "rilevare",
1223 + "rilievo",
1224 + "rimanere",
1225 + "rimborso",
1226 + "rinforzo",
1227 + "rinuncia",
1228 + "riparo",
1229 + "ripetere",
1230 + "riposare",
1231 + "ripulire",
1232 + "risalita",
1233 + "riscatto",
1234 + "riserva",
1235 + "riso",
1236 + "rispetto",
1237 + "ritaglio",
1238 + "ritmo",
1239 + "ritorno",
1240 + "ritratto",
1241 + "rituale",
1242 + "riunione",
1243 + "riuscire",
1244 + "riva",
1245 + "robotica",
1246 + "rondine",
1247 + "rosa",
1248 + "rospo",
1249 + "rosso",
1250 + "rotonda",
1251 + "rotta",
1252 + "roulotte",
1253 + "rubare",
1254 + "rubrica",
1255 + "ruffiano",
1256 + "rumore",
1257 + "ruota",
1258 + "ruscello",
1259 + "sabbia",
1260 + "sacco",
1261 + "saggio",
1262 + "sale",
1263 + "salire",
1264 + "salmone",
1265 + "salto",
1266 + "salutare",
1267 + "salvia",
1268 + "sangue",
1269 + "sanzioni",
1270 + "sapere",
1271 + "sapienza",
1272 + "sarcasmo",
1273 + "sardine",
1274 + "sartoria",
1275 + "sbalzo",
1276 + "sbarcare",
1277 + "sberla",
1278 + "sborsare",
1279 + "scadenza",
1280 + "scafo",
1281 + "scala",
1282 + "scambio",
1283 + "scappare",
1284 + "scarpa",
1285 + "scatola",
1286 + "scelta",
1287 + "scena",
1288 + "sceriffo",
1289 + "scheggia",
1290 + "schiuma",
1291 + "sciarpa",
1292 + "scienza",
1293 + "scimmia",
1294 + "sciopero",
1295 + "scivolo",
1296 + "sclerare",
1297 + "scolpire",
1298 + "sconto",
1299 + "scopa",
1300 + "scordare",
1301 + "scossa",
1302 + "scrivere",
1303 + "scrupolo",
1304 + "scuderia",
1305 + "scultore",
1306 + "scuola",
1307 + "scusare",
1308 + "sdraiare",
1309 + "secolo",
1310 + "sedativo",
1311 + "sedere",
1312 + "sedia",
1313 + "segare",
1314 + "segreto",
1315 + "seguire",
1316 + "semaforo",
1317 + "seme",
1318 + "senape",
1319 + "seno",
1320 + "sentiero",
1321 + "separare",
1322 + "sepolcro",
1323 + "sequenza",
1324 + "serata",
1325 + "serpente",
1326 + "servizio",
1327 + "sesso",
1328 + "seta",
1329 + "settore",
1330 + "sfamare",
1331 + "sfera",
1332 + "sfidare",
1333 + "sfiorare",
1334 + "sfogare",
1335 + "sgabello",
1336 + "sicuro",
1337 + "siepe",
1338 + "sigaro",
1339 + "silenzio",
1340 + "silicone",
1341 + "simbiosi",
1342 + "simpatia",
1343 + "simulare",
1344 + "sinapsi",
1345 + "sindrome",
1346 + "sinergia",
1347 + "sinonimo",
1348 + "sintonia",
1349 + "sirena",
1350 + "siringa",
1351 + "sistema",
1352 + "sito",
1353 + "smalto",
1354 + "smentire",
1355 + "smontare",
1356 + "soccorso",
1357 + "socio",
1358 + "soffitto",
1359 + "software",
1360 + "soggetto",
1361 + "sogliola",
1362 + "sognare",
1363 + "soldi",
1364 + "sole",
1365 + "sollievo",
1366 + "solo",
1367 + "sommario",
1368 + "sondare",
1369 + "sonno",
1370 + "sorpresa",
1371 + "sorriso",
1372 + "sospiro",
1373 + "sostegno",
1374 + "sovrano",
1375 + "spaccare",
1376 + "spada",
1377 + "spagnolo",
1378 + "spalla",
1379 + "sparire",
1380 + "spavento",
1381 + "spazio",
1382 + "specchio",
1383 + "spedire",
1384 + "spegnere",
1385 + "spendere",
1386 + "speranza",
1387 + "spessore",
1388 + "spezzare",
1389 + "spiaggia",
1390 + "spiccare",
1391 + "spiegare",
1392 + "spiffero",
1393 + "spingere",
1394 + "sponda",
1395 + "sporcare",
1396 + "spostare",
1397 + "spremuta",
1398 + "spugna",
1399 + "spumante",
1400 + "spuntare",
1401 + "squadra",
1402 + "squillo",
1403 + "staccare",
1404 + "stadio",
1405 + "stagione",
1406 + "stallone",
1407 + "stampa",
1408 + "stancare",
1409 + "starnuto",
1410 + "statura",
1411 + "stella",
1412 + "stendere",
1413 + "sterzo",
1414 + "stilista",
1415 + "stimolo",
1416 + "stinco",
1417 + "stiva",
1418 + "stoffa",
1419 + "storia",
1420 + "strada",
1421 + "stregone",
1422 + "striscia",
1423 + "studiare",
1424 + "stufa",
1425 + "stupendo",
1426 + "subire",
1427 + "successo",
1428 + "sudare",
1429 + "suono",
1430 + "superare",
1431 + "supporto",
1432 + "surfista",
1433 + "sussurro",
1434 + "svelto",
1435 + "svenire",
1436 + "sviluppo",
1437 + "svolta",
1438 + "svuotare",
1439 + "tabacco",
1440 + "tabella",
1441 + "tabu",
1442 + "tacchino",
1443 + "tacere",
1444 + "taglio",
1445 + "talento",
1446 + "tangente",
1447 + "tappeto",
1448 + "tartufo",
1449 + "tassello",
1450 + "tastiera",
1451 + "tavolo",
1452 + "tazza",
1453 + "teatro",
1454 + "tedesco",
1455 + "telaio",
1456 + "telefono",
1457 + "tema",
1458 + "temere",
1459 + "tempo",
1460 + "tendenza",
1461 + "tenebre",
1462 + "tensione",
1463 + "tentare",
1464 + "teologia",
1465 + "teorema",
1466 + "termica",
1467 + "terrazzo",
1468 + "teschio",
1469 + "tesi",
1470 + "tesoro",
1471 + "tessera",
1472 + "testa",
1473 + "thriller",
1474 + "tifoso",
1475 + "tigre",
1476 + "timbrare",
1477 + "timido",
1478 + "tinta",
1479 + "tirare",
1480 + "tisana",
1481 + "titano",
1482 + "titolo",
1483 + "toccare",
1484 + "togliere",
1485 + "topolino",
1486 + "torcia",
1487 + "torrente",
1488 + "tovaglia",
1489 + "traffico",
1490 + "tragitto",
1491 + "training",
1492 + "tramonto",
1493 + "transito",
1494 + "trapezio",
1495 + "trasloco",
1496 + "trattore",
1497 + "trazione",
1498 + "treccia",
1499 + "tregua",
1500 + "treno",
1501 + "triciclo",
1502 + "tridente",
1503 + "trilogia",
1504 + "tromba",
1505 + "troncare",
1506 + "trota",
1507 + "trovare",
1508 + "trucco",
1509 + "tubo",
1510 + "tulipano",
1511 + "tumulto",
1512 + "tunisia",
1513 + "tuono",
1514 + "turista",
1515 + "tuta",
1516 + "tutelare",
1517 + "tutore",
1518 + "ubriaco",
1519 + "uccello",
1520 + "udienza",
1521 + "udito",
1522 + "uffa",
1523 + "umanoide",
1524 + "umore",
1525 + "unghia",
1526 + "unguento",
1527 + "unicorno",
1528 + "unione",
1529 + "universo",
1530 + "uomo",
1531 + "uragano",
1532 + "uranio",
1533 + "urlare",
1534 + "uscire",
1535 + "utente",
1536 + "utilizzo",
1537 + "vacanza",
1538 + "vacca",
1539 + "vaglio",
1540 + "vagonata",
1541 + "valle",
1542 + "valore",
1543 + "valutare",
1544 + "valvola",
1545 + "vampiro",
1546 + "vaniglia",
1547 + "vanto",
1548 + "vapore",
1549 + "variante",
1550 + "vasca",
1551 + "vaselina",
1552 + "vassoio",
1553 + "vedere",
1554 + "vegetale",
1555 + "veglia",
1556 + "veicolo",
1557 + "vela",
1558 + "veleno",
1559 + "velivolo",
1560 + "velluto",
1561 + "vendere",
1562 + "venerare",
1563 + "venire",
1564 + "vento",
1565 + "veranda",
1566 + "verbo",
1567 + "verdura",
1568 + "vergine",
1569 + "verifica",
1570 + "vernice",
1571 + "vero",
1572 + "verruca",
1573 + "versare",
1574 + "vertebra",
1575 + "vescica",
1576 + "vespaio",
1577 + "vestito",
1578 + "vesuvio",
1579 + "veterano",
1580 + "vetro",
1581 + "vetta",
1582 + "viadotto",
1583 + "viaggio",
1584 + "vibrare",
1585 + "vicenda",
1586 + "vichingo",
1587 + "vietare",
1588 + "vigilare",
1589 + "vigneto",
1590 + "villa",
1591 + "vincere",
1592 + "violino",
1593 + "vipera",
1594 + "virgola",
1595 + "virtuoso",
1596 + "visita",
1597 + "vita",
1598 + "vitello",
1599 + "vittima",
1600 + "vivavoce",
1601 + "vivere",
1602 + "viziato",
1603 + "voglia",
1604 + "volare",
1605 + "volpe",
1606 + "volto",
1607 + "volume",
1608 + "vongole",
1609 + "voragine",
1610 + "vortice",
1611 + "votare",
1612 + "vulcano",
1613 + "vuotare",
1614 + "zabaione",
1615 + "zaffiro",
1616 + "zainetto",
1617 + "zampa",
1618 + "zanzara",
1619 + "zattera",
1620 + "zavorra",
1621 + "zenzero",
1622 + "zero",
1623 + "zingaro",
1624 + "zittire",
1625 + "zoccolo",
1626 + "zolfo",
1627 + "zombie",
1628 + "zucchero"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mnemonics/japanese.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class JapaneseMnemonics {
2 + static const words = [
3 + "あいこくしん",
4 + "あいさつ",
5 + "あいだ",
6 + "あおぞら",
7 + "あかちゃん",
8 + "あきる",
9 + "あけがた",
10 + "あける",
11 + "あこがれる",
12 + "あさい",
13 + "あさひ",
14 + "あしあと",
15 + "あじわう",
16 + "あずかる",
17 + "あずき",
18 + "あそぶ",
19 + "あたえる",
20 + "あたためる",
21 + "あたりまえ",
22 + "あたる",
23 + "あつい",
24 + "あつかう",
25 + "あっしゅく",
26 + "あつまり",
27 + "あつめる",
28 + "あてな",
29 + "あてはまる",
30 + "あひる",
31 + "あぶら",
32 + "あぶる",
33 + "あふれる",
34 + "あまい",
35 + "あまど",
36 + "あまやかす",
37 + "あまり",
38 + "あみもの",
39 + "あめりか",
40 + "あやまる",
41 + "あゆむ",
42 + "あらいぐま",
43 + "あらし",
44 + "あらすじ",
45 + "あらためる",
46 + "あらゆる",
47 + "あらわす",
48 + "ありがとう",
49 + "あわせる",
50 + "あわてる",
51 + "あんい",
52 + "あんがい",
53 + "あんこ",
54 + "あんぜん",
55 + "あんてい",
56 + "あんない",
57 + "あんまり",
58 + "いいだす",
59 + "いおん",
60 + "いがい",
61 + "いがく",
62 + "いきおい",
63 + "いきなり",
64 + "いきもの",
65 + "いきる",
66 + "いくじ",
67 + "いくぶん",
68 + "いけばな",
69 + "いけん",
70 + "いこう",
71 + "いこく",
72 + "いこつ",
73 + "いさましい",
74 + "いさん",
75 + "いしき",
76 + "いじゅう",
77 + "いじょう",
78 + "いじわる",
79 + "いずみ",
80 + "いずれ",
81 + "いせい",
82 + "いせえび",
83 + "いせかい",
84 + "いせき",
85 + "いぜん",
86 + "いそうろう",
87 + "いそがしい",
88 + "いだい",
89 + "いだく",
90 + "いたずら",
91 + "いたみ",
92 + "いたりあ",
93 + "いちおう",
94 + "いちじ",
95 + "いちど",
96 + "いちば",
97 + "いちぶ",
98 + "いちりゅう",
99 + "いつか",
100 + "いっしゅん",
101 + "いっせい",
102 + "いっそう",
103 + "いったん",
104 + "いっち",
105 + "いってい",
106 + "いっぽう",
107 + "いてざ",
108 + "いてん",
109 + "いどう",
110 + "いとこ",
111 + "いない",
112 + "いなか",
113 + "いねむり",
114 + "いのち",
115 + "いのる",
116 + "いはつ",
117 + "いばる",
118 + "いはん",
119 + "いびき",
120 + "いひん",
121 + "いふく",
122 + "いへん",
123 + "いほう",
124 + "いみん",
125 + "いもうと",
126 + "いもたれ",
127 + "いもり",
128 + "いやがる",
129 + "いやす",
130 + "いよかん",
131 + "いよく",
132 + "いらい",
133 + "いらすと",
134 + "いりぐち",
135 + "いりょう",
136 + "いれい",
137 + "いれもの",
138 + "いれる",
139 + "いろえんぴつ",
140 + "いわい",
141 + "いわう",
142 + "いわかん",
143 + "いわば",
144 + "いわゆる",
145 + "いんげんまめ",
146 + "いんさつ",
147 + "いんしょう",
148 + "いんよう",
149 + "うえき",
150 + "うえる",
151 + "うおざ",
152 + "うがい",
153 + "うかぶ",
154 + "うかべる",
155 + "うきわ",
156 + "うくらいな",
157 + "うくれれ",
158 + "うけたまわる",
159 + "うけつけ",
160 + "うけとる",
161 + "うけもつ",
162 + "うける",
163 + "うごかす",
164 + "うごく",
165 + "うこん",
166 + "うさぎ",
167 + "うしなう",
168 + "うしろがみ",
169 + "うすい",
170 + "うすぎ",
171 + "うすぐらい",
172 + "うすめる",
173 + "うせつ",
174 + "うちあわせ",
175 + "うちがわ",
176 + "うちき",
177 + "うちゅう",
178 + "うっかり",
179 + "うつくしい",
180 + "うったえる",
181 + "うつる",
182 + "うどん",
183 + "うなぎ",
184 + "うなじ",
185 + "うなずく",
186 + "うなる",
187 + "うねる",
188 + "うのう",
189 + "うぶげ",
190 + "うぶごえ",
191 + "うまれる",
192 + "うめる",
193 + "うもう",
194 + "うやまう",
195 + "うよく",
196 + "うらがえす",
197 + "うらぐち",
198 + "うらない",
199 + "うりあげ",
200 + "うりきれ",
201 + "うるさい",
202 + "うれしい",
203 + "うれゆき",
204 + "うれる",
205 + "うろこ",
206 + "うわき",
207 + "うわさ",
208 + "うんこう",
209 + "うんちん",
210 + "うんてん",
211 + "うんどう",
212 + "えいえん",
213 + "えいが",
214 + "えいきょう",
215 + "えいご",
216 + "えいせい",
217 + "えいぶん",
218 + "えいよう",
219 + "えいわ",
220 + "えおり",
221 + "えがお",
222 + "えがく",
223 + "えきたい",
224 + "えくせる",
225 + "えしゃく",
226 + "えすて",
227 + "えつらん",
228 + "えのぐ",
229 + "えほうまき",
230 + "えほん",
231 + "えまき",
232 + "えもじ",
233 + "えもの",
234 + "えらい",
235 + "えらぶ",
236 + "えりあ",
237 + "えんえん",
238 + "えんかい",
239 + "えんぎ",
240 + "えんげき",
241 + "えんしゅう",
242 + "えんぜつ",
243 + "えんそく",
244 + "えんちょう",
245 + "えんとつ",
246 + "おいかける",
247 + "おいこす",
248 + "おいしい",
249 + "おいつく",
250 + "おうえん",
251 + "おうさま",
252 + "おうじ",
253 + "おうせつ",
254 + "おうたい",
255 + "おうふく",
256 + "おうべい",
257 + "おうよう",
258 + "おえる",
259 + "おおい",
260 + "おおう",
261 + "おおどおり",
262 + "おおや",
263 + "おおよそ",
264 + "おかえり",
265 + "おかず",
266 + "おがむ",
267 + "おかわり",
268 + "おぎなう",
269 + "おきる",
270 + "おくさま",
271 + "おくじょう",
272 + "おくりがな",
273 + "おくる",
274 + "おくれる",
275 + "おこす",
276 + "おこなう",
277 + "おこる",
278 + "おさえる",
279 + "おさない",
280 + "おさめる",
281 + "おしいれ",
282 + "おしえる",
283 + "おじぎ",
284 + "おじさん",
285 + "おしゃれ",
286 + "おそらく",
287 + "おそわる",
288 + "おたがい",
289 + "おたく",
290 + "おだやか",
291 + "おちつく",
292 + "おっと",
293 + "おつり",
294 + "おでかけ",
295 + "おとしもの",
296 + "おとなしい",
297 + "おどり",
298 + "おどろかす",
299 + "おばさん",
300 + "おまいり",
301 + "おめでとう",
302 + "おもいで",
303 + "おもう",
304 + "おもたい",
305 + "おもちゃ",
306 + "おやつ",
307 + "おやゆび",
308 + "およぼす",
309 + "おらんだ",
310 + "おろす",
311 + "おんがく",
312 + "おんけい",
313 + "おんしゃ",
314 + "おんせん",
315 + "おんだん",
316 + "おんちゅう",
317 + "おんどけい",
318 + "かあつ",
319 + "かいが",
320 + "がいき",
321 + "がいけん",
322 + "がいこう",
323 + "かいさつ",
324 + "かいしゃ",
325 + "かいすいよく",
326 + "かいぜん",
327 + "かいぞうど",
328 + "かいつう",
329 + "かいてん",
330 + "かいとう",
331 + "かいふく",
332 + "がいへき",
333 + "かいほう",
334 + "かいよう",
335 + "がいらい",
336 + "かいわ",
337 + "かえる",
338 + "かおり",
339 + "かかえる",
340 + "かがく",
341 + "かがし",
342 + "かがみ",
343 + "かくご",
344 + "かくとく",
345 + "かざる",
346 + "がぞう",
347 + "かたい",
348 + "かたち",
349 + "がちょう",
350 + "がっきゅう",
351 + "がっこう",
352 + "がっさん",
353 + "がっしょう",
354 + "かなざわし",
355 + "かのう",
356 + "がはく",
357 + "かぶか",
358 + "かほう",
359 + "かほご",
360 + "かまう",
361 + "かまぼこ",
362 + "かめれおん",
363 + "かゆい",
364 + "かようび",
365 + "からい",
366 + "かるい",
367 + "かろう",
368 + "かわく",
369 + "かわら",
370 + "がんか",
371 + "かんけい",
372 + "かんこう",
373 + "かんしゃ",
374 + "かんそう",
375 + "かんたん",
376 + "かんち",
377 + "がんばる",
378 + "きあい",
379 + "きあつ",
380 + "きいろ",
381 + "ぎいん",
382 + "きうい",
383 + "きうん",
384 + "きえる",
385 + "きおう",
386 + "きおく",
387 + "きおち",
388 + "きおん",
389 + "きかい",
390 + "きかく",
391 + "きかんしゃ",
392 + "ききて",
393 + "きくばり",
394 + "きくらげ",
395 + "きけんせい",
396 + "きこう",
397 + "きこえる",
398 + "きこく",
399 + "きさい",
400 + "きさく",
401 + "きさま",
402 + "きさらぎ",
403 + "ぎじかがく",
404 + "ぎしき",
405 + "ぎじたいけん",
406 + "ぎじにってい",
407 + "ぎじゅつしゃ",
408 + "きすう",
409 + "きせい",
410 + "きせき",
411 + "きせつ",
412 + "きそう",
413 + "きぞく",
414 + "きぞん",
415 + "きたえる",
416 + "きちょう",
417 + "きつえん",
418 + "ぎっちり",
419 + "きつつき",
420 + "きつね",
421 + "きてい",
422 + "きどう",
423 + "きどく",
424 + "きない",
425 + "きなが",
426 + "きなこ",
427 + "きぬごし",
428 + "きねん",
429 + "きのう",
430 + "きのした",
431 + "きはく",
432 + "きびしい",
433 + "きひん",
434 + "きふく",
435 + "きぶん",
436 + "きぼう",
437 + "きほん",
438 + "きまる",
439 + "きみつ",
440 + "きむずかしい",
441 + "きめる",
442 + "きもだめし",
443 + "きもち",
444 + "きもの",
445 + "きゃく",
446 + "きやく",
447 + "ぎゅうにく",
448 + "きよう",
449 + "きょうりゅう",
450 + "きらい",
451 + "きらく",
452 + "きりん",
453 + "きれい",
454 + "きれつ",
455 + "きろく",
456 + "ぎろん",
457 + "きわめる",
458 + "ぎんいろ",
459 + "きんかくじ",
460 + "きんじょ",
461 + "きんようび",
462 + "ぐあい",
463 + "くいず",
464 + "くうかん",
465 + "くうき",
466 + "くうぐん",
467 + "くうこう",
468 + "ぐうせい",
469 + "くうそう",
470 + "ぐうたら",
471 + "くうふく",
472 + "くうぼ",
473 + "くかん",
474 + "くきょう",
475 + "くげん",
476 + "ぐこう",
477 + "くさい",
478 + "くさき",
479 + "くさばな",
480 + "くさる",
481 + "くしゃみ",
482 + "くしょう",
483 + "くすのき",
484 + "くすりゆび",
485 + "くせげ",
486 + "くせん",
487 + "ぐたいてき",
488 + "くださる",
489 + "くたびれる",
490 + "くちこみ",
491 + "くちさき",
492 + "くつした",
493 + "ぐっすり",
494 + "くつろぐ",
495 + "くとうてん",
496 + "くどく",
497 + "くなん",
498 + "くねくね",
499 + "くのう",
500 + "くふう",
501 + "くみあわせ",
502 + "くみたてる",
503 + "くめる",
504 + "くやくしょ",
505 + "くらす",
506 + "くらべる",
507 + "くるま",
508 + "くれる",
509 + "くろう",
510 + "くわしい",
511 + "ぐんかん",
512 + "ぐんしょく",
513 + "ぐんたい",
514 + "ぐんて",
515 + "けあな",
516 + "けいかく",
517 + "けいけん",
518 + "けいこ",
519 + "けいさつ",
520 + "げいじゅつ",
521 + "けいたい",
522 + "げいのうじん",
523 + "けいれき",
524 + "けいろ",
525 + "けおとす",
526 + "けおりもの",
527 + "げきか",
528 + "げきげん",
529 + "げきだん",
530 + "げきちん",
531 + "げきとつ",
532 + "げきは",
533 + "げきやく",
534 + "げこう",
535 + "げこくじょう",
536 + "げざい",
537 + "けさき",
538 + "げざん",
539 + "けしき",
540 + "けしごむ",
541 + "けしょう",
542 + "げすと",
543 + "けたば",
544 + "けちゃっぷ",
545 + "けちらす",
546 + "けつあつ",
547 + "けつい",
548 + "けつえき",
549 + "けっこん",
550 + "けつじょ",
551 + "けっせき",
552 + "けってい",
553 + "けつまつ",
554 + "げつようび",
555 + "げつれい",
556 + "けつろん",
557 + "げどく",
558 + "けとばす",
559 + "けとる",
560 + "けなげ",
561 + "けなす",
562 + "けなみ",
563 + "けぬき",
564 + "げねつ",
565 + "けねん",
566 + "けはい",
567 + "げひん",
568 + "けぶかい",
569 + "げぼく",
570 + "けまり",
571 + "けみかる",
572 + "けむし",
573 + "けむり",
574 + "けもの",
575 + "けらい",
576 + "けろけろ",
577 + "けわしい",
578 + "けんい",
579 + "けんえつ",
580 + "けんお",
581 + "けんか",
582 + "げんき",
583 + "けんげん",
584 + "けんこう",
585 + "けんさく",
586 + "けんしゅう",
587 + "けんすう",
588 + "げんそう",
589 + "けんちく",
590 + "けんてい",
591 + "けんとう",
592 + "けんない",
593 + "けんにん",
594 + "げんぶつ",
595 + "けんま",
596 + "けんみん",
597 + "けんめい",
598 + "けんらん",
599 + "けんり",
600 + "こあくま",
601 + "こいぬ",
602 + "こいびと",
603 + "ごうい",
604 + "こうえん",
605 + "こうおん",
606 + "こうかん",
607 + "ごうきゅう",
608 + "ごうけい",
609 + "こうこう",
610 + "こうさい",
611 + "こうじ",
612 + "こうすい",
613 + "ごうせい",
614 + "こうそく",
615 + "こうたい",
616 + "こうちゃ",
617 + "こうつう",
618 + "こうてい",
619 + "こうどう",
620 + "こうない",
621 + "こうはい",
622 + "ごうほう",
623 + "ごうまん",
624 + "こうもく",
625 + "こうりつ",
626 + "こえる",
627 + "こおり",
628 + "ごかい",
629 + "ごがつ",
630 + "ごかん",
631 + "こくご",
632 + "こくさい",
633 + "こくとう",
634 + "こくない",
635 + "こくはく",
636 + "こぐま",
637 + "こけい",
638 + "こける",
639 + "ここのか",
640 + "こころ",
641 + "こさめ",
642 + "こしつ",
643 + "こすう",
644 + "こせい",
645 + "こせき",
646 + "こぜん",
647 + "こそだて",
648 + "こたい",
649 + "こたえる",
650 + "こたつ",
651 + "こちょう",
652 + "こっか",
653 + "こつこつ",
654 + "こつばん",
655 + "こつぶ",
656 + "こてい",
657 + "こてん",
658 + "ことがら",
659 + "ことし",
660 + "ことば",
661 + "ことり",
662 + "こなごな",
663 + "こねこね",
664 + "このまま",
665 + "このみ",
666 + "このよ",
667 + "ごはん",
668 + "こひつじ",
669 + "こふう",
670 + "こふん",
671 + "こぼれる",
672 + "ごまあぶら",
673 + "こまかい",
674 + "ごますり",
675 + "こまつな",
676 + "こまる",
677 + "こむぎこ",
678 + "こもじ",
679 + "こもち",
680 + "こもの",
681 + "こもん",
682 + "こやく",
683 + "こやま",
684 + "こゆう",
685 + "こゆび",
686 + "こよい",
687 + "こよう",
688 + "こりる",
689 + "これくしょん",
690 + "ころっけ",
691 + "こわもて",
692 + "こわれる",
693 + "こんいん",
694 + "こんかい",
695 + "こんき",
696 + "こんしゅう",
697 + "こんすい",
698 + "こんだて",
699 + "こんとん",
700 + "こんなん",
701 + "こんびに",
702 + "こんぽん",
703 + "こんまけ",
704 + "こんや",
705 + "こんれい",
706 + "こんわく",
707 + "ざいえき",
708 + "さいかい",
709 + "さいきん",
710 + "ざいげん",
711 + "ざいこ",
712 + "さいしょ",
713 + "さいせい",
714 + "ざいたく",
715 + "ざいちゅう",
716 + "さいてき",
717 + "ざいりょう",
718 + "さうな",
719 + "さかいし",
720 + "さがす",
721 + "さかな",
722 + "さかみち",
723 + "さがる",
724 + "さぎょう",
725 + "さくし",
726 + "さくひん",
727 + "さくら",
728 + "さこく",
729 + "さこつ",
730 + "さずかる",
731 + "ざせき",
732 + "さたん",
733 + "さつえい",
734 + "ざつおん",
735 + "ざっか",
736 + "ざつがく",
737 + "さっきょく",
738 + "ざっし",
739 + "さつじん",
740 + "ざっそう",
741 + "さつたば",
742 + "さつまいも",
743 + "さてい",
744 + "さといも",
745 + "さとう",
746 + "さとおや",
747 + "さとし",
748 + "さとる",
749 + "さのう",
750 + "さばく",
751 + "さびしい",
752 + "さべつ",
753 + "さほう",
754 + "さほど",
755 + "さます",
756 + "さみしい",
757 + "さみだれ",
758 + "さむけ",
759 + "さめる",
760 + "さやえんどう",
761 + "さゆう",
762 + "さよう",
763 + "さよく",
764 + "さらだ",
765 + "ざるそば",
766 + "さわやか",
767 + "さわる",
768 + "さんいん",
769 + "さんか",
770 + "さんきゃく",
771 + "さんこう",
772 + "さんさい",
773 + "ざんしょ",
774 + "さんすう",
775 + "さんせい",
776 + "さんそ",
777 + "さんち",
778 + "さんま",
779 + "さんみ",
780 + "さんらん",
781 + "しあい",
782 + "しあげ",
783 + "しあさって",
784 + "しあわせ",
785 + "しいく",
786 + "しいん",
787 + "しうち",
788 + "しえい",
789 + "しおけ",
790 + "しかい",
791 + "しかく",
792 + "じかん",
793 + "しごと",
794 + "しすう",
795 + "じだい",
796 + "したうけ",
797 + "したぎ",
798 + "したて",
799 + "したみ",
800 + "しちょう",
801 + "しちりん",
802 + "しっかり",
803 + "しつじ",
804 + "しつもん",
805 + "してい",
806 + "してき",
807 + "してつ",
808 + "じてん",
809 + "じどう",
810 + "しなぎれ",
811 + "しなもの",
812 + "しなん",
813 + "しねま",
814 + "しねん",
815 + "しのぐ",
816 + "しのぶ",
817 + "しはい",
818 + "しばかり",
819 + "しはつ",
820 + "しはらい",
821 + "しはん",
822 + "しひょう",
823 + "しふく",
824 + "じぶん",
825 + "しへい",
826 + "しほう",
827 + "しほん",
828 + "しまう",
829 + "しまる",
830 + "しみん",
831 + "しむける",
832 + "じむしょ",
833 + "しめい",
834 + "しめる",
835 + "しもん",
836 + "しゃいん",
837 + "しゃうん",
838 + "しゃおん",
839 + "じゃがいも",
840 + "しやくしょ",
841 + "しゃくほう",
842 + "しゃけん",
843 + "しゃこ",
844 + "しゃざい",
845 + "しゃしん",
846 + "しゃせん",
847 + "しゃそう",
848 + "しゃたい",
849 + "しゃちょう",
850 + "しゃっきん",
851 + "じゃま",
852 + "しゃりん",
853 + "しゃれい",
854 + "じゆう",
855 + "じゅうしょ",
856 + "しゅくはく",
857 + "じゅしん",
858 + "しゅっせき",
859 + "しゅみ",
860 + "しゅらば",
861 + "じゅんばん",
862 + "しょうかい",
863 + "しょくたく",
864 + "しょっけん",
865 + "しょどう",
866 + "しょもつ",
867 + "しらせる",
868 + "しらべる",
869 + "しんか",
870 + "しんこう",
871 + "じんじゃ",
872 + "しんせいじ",
873 + "しんちく",
874 + "しんりん",
875 + "すあげ",
876 + "すあし",
877 + "すあな",
878 + "ずあん",
879 + "すいえい",
880 + "すいか",
881 + "すいとう",
882 + "ずいぶん",
883 + "すいようび",
884 + "すうがく",
885 + "すうじつ",
886 + "すうせん",
887 + "すおどり",
888 + "すきま",
889 + "すくう",
890 + "すくない",
891 + "すける",
892 + "すごい",
893 + "すこし",
894 + "ずさん",
895 + "すずしい",
896 + "すすむ",
897 + "すすめる",
898 + "すっかり",
899 + "ずっしり",
900 + "ずっと",
901 + "すてき",
902 + "すてる",
903 + "すねる",
904 + "すのこ",
905 + "すはだ",
906 + "すばらしい",
907 + "ずひょう",
908 + "ずぶぬれ",
909 + "すぶり",
910 + "すふれ",
911 + "すべて",
912 + "すべる",
913 + "ずほう",
914 + "すぼん",
915 + "すまい",
916 + "すめし",
917 + "すもう",
918 + "すやき",
919 + "すらすら",
920 + "するめ",
921 + "すれちがう",
922 + "すろっと",
923 + "すわる",
924 + "すんぜん",
925 + "すんぽう",
926 + "せあぶら",
927 + "せいかつ",
928 + "せいげん",
929 + "せいじ",
930 + "せいよう",
931 + "せおう",
932 + "せかいかん",
933 + "せきにん",
934 + "せきむ",
935 + "せきゆ",
936 + "せきらんうん",
937 + "せけん",
938 + "せこう",
939 + "せすじ",
940 + "せたい",
941 + "せたけ",
942 + "せっかく",
943 + "せっきゃく",
944 + "ぜっく",
945 + "せっけん",
946 + "せっこつ",
947 + "せっさたくま",
948 + "せつぞく",
949 + "せつだん",
950 + "せつでん",
951 + "せっぱん",
952 + "せつび",
953 + "せつぶん",
954 + "せつめい",
955 + "せつりつ",
956 + "せなか",
957 + "せのび",
958 + "せはば",
959 + "せびろ",
960 + "せぼね",
961 + "せまい",
962 + "せまる",
963 + "せめる",
964 + "せもたれ",
965 + "せりふ",
966 + "ぜんあく",
967 + "せんい",
968 + "せんえい",
969 + "せんか",
970 + "せんきょ",
971 + "せんく",
972 + "せんげん",
973 + "ぜんご",
974 + "せんさい",
975 + "せんしゅ",
976 + "せんすい",
977 + "せんせい",
978 + "せんぞ",
979 + "せんたく",
980 + "せんちょう",
981 + "せんてい",
982 + "せんとう",
983 + "せんぬき",
984 + "せんねん",
985 + "せんぱい",
986 + "ぜんぶ",
987 + "ぜんぽう",
988 + "せんむ",
989 + "せんめんじょ",
990 + "せんもん",
991 + "せんやく",
992 + "せんゆう",
993 + "せんよう",
994 + "ぜんら",
995 + "ぜんりゃく",
996 + "せんれい",
997 + "せんろ",
998 + "そあく",
999 + "そいとげる",
1000 + "そいね",
1001 + "そうがんきょう",
1002 + "そうき",
1003 + "そうご",
1004 + "そうしん",
1005 + "そうだん",
1006 + "そうなん",
1007 + "そうび",
1008 + "そうめん",
1009 + "そうり",
1010 + "そえもの",
1011 + "そえん",
1012 + "そがい",
1013 + "そげき",
1014 + "そこう",
1015 + "そこそこ",
1016 + "そざい",
1017 + "そしな",
1018 + "そせい",
1019 + "そせん",
1020 + "そそぐ",
1021 + "そだてる",
1022 + "そつう",
1023 + "そつえん",
1024 + "そっかん",
1025 + "そつぎょう",
1026 + "そっけつ",
1027 + "そっこう",
1028 + "そっせん",
1029 + "そっと",
1030 + "そとがわ",
1031 + "そとづら",
1032 + "そなえる",
1033 + "そなた",
1034 + "そふぼ",
1035 + "そぼく",
1036 + "そぼろ",
1037 + "そまつ",
1038 + "そまる",
1039 + "そむく",
1040 + "そむりえ",
1041 + "そめる",
1042 + "そもそも",
1043 + "そよかぜ",
1044 + "そらまめ",
1045 + "そろう",
1046 + "そんかい",
1047 + "そんけい",
1048 + "そんざい",
1049 + "そんしつ",
1050 + "そんぞく",
1051 + "そんちょう",
1052 + "ぞんび",
1053 + "ぞんぶん",
1054 + "そんみん",
1055 + "たあい",
1056 + "たいいん",
1057 + "たいうん",
1058 + "たいえき",
1059 + "たいおう",
1060 + "だいがく",
1061 + "たいき",
1062 + "たいぐう",
1063 + "たいけん",
1064 + "たいこ",
1065 + "たいざい",
1066 + "だいじょうぶ",
1067 + "だいすき",
1068 + "たいせつ",
1069 + "たいそう",
1070 + "だいたい",
1071 + "たいちょう",
1072 + "たいてい",
1073 + "だいどころ",
1074 + "たいない",
1075 + "たいねつ",
1076 + "たいのう",
1077 + "たいはん",
1078 + "だいひょう",
1079 + "たいふう",
1080 + "たいへん",
1081 + "たいほ",
1082 + "たいまつばな",
1083 + "たいみんぐ",
1084 + "たいむ",
1085 + "たいめん",
1086 + "たいやき",
1087 + "たいよう",
1088 + "たいら",
1089 + "たいりょく",
1090 + "たいる",
1091 + "たいわん",
1092 + "たうえ",
1093 + "たえる",
1094 + "たおす",
1095 + "たおる",
1096 + "たおれる",
1097 + "たかい",
1098 + "たかね",
1099 + "たきび",
1100 + "たくさん",
1101 + "たこく",
1102 + "たこやき",
1103 + "たさい",
1104 + "たしざん",
1105 + "だじゃれ",
1106 + "たすける",
1107 + "たずさわる",
1108 + "たそがれ",
1109 + "たたかう",
1110 + "たたく",
1111 + "ただしい",
1112 + "たたみ",
1113 + "たちばな",
1114 + "だっかい",
1115 + "だっきゃく",
1116 + "だっこ",
1117 + "だっしゅつ",
1118 + "だったい",
1119 + "たてる",
1120 + "たとえる",
1121 + "たなばた",
1122 + "たにん",
1123 + "たぬき",
1124 + "たのしみ",
1125 + "たはつ",
1126 + "たぶん",
1127 + "たべる",
1128 + "たぼう",
1129 + "たまご",
1130 + "たまる",
1131 + "だむる",
1132 + "ためいき",
1133 + "ためす",
1134 + "ためる",
1135 + "たもつ",
1136 + "たやすい",
1137 + "たよる",
1138 + "たらす",
1139 + "たりきほんがん",
1140 + "たりょう",
1141 + "たりる",
1142 + "たると",
1143 + "たれる",
1144 + "たれんと",
1145 + "たろっと",
1146 + "たわむれる",
1147 + "だんあつ",
1148 + "たんい",
1149 + "たんおん",
1150 + "たんか",
1151 + "たんき",
1152 + "たんけん",
1153 + "たんご",
1154 + "たんさん",
1155 + "たんじょうび",
1156 + "だんせい",
1157 + "たんそく",
1158 + "たんたい",
1159 + "だんち",
1160 + "たんてい",
1161 + "たんとう",
1162 + "だんな",
1163 + "たんにん",
1164 + "だんねつ",
1165 + "たんのう",
1166 + "たんぴん",
1167 + "だんぼう",
1168 + "たんまつ",
1169 + "たんめい",
1170 + "だんれつ",
1171 + "だんろ",
1172 + "だんわ",
1173 + "ちあい",
1174 + "ちあん",
1175 + "ちいき",
1176 + "ちいさい",
1177 + "ちえん",
1178 + "ちかい",
1179 + "ちから",
1180 + "ちきゅう",
1181 + "ちきん",
1182 + "ちけいず",
1183 + "ちけん",
1184 + "ちこく",
1185 + "ちさい",
1186 + "ちしき",
1187 + "ちしりょう",
1188 + "ちせい",
1189 + "ちそう",
1190 + "ちたい",
1191 + "ちたん",
1192 + "ちちおや",
1193 + "ちつじょ",
1194 + "ちてき",
1195 + "ちてん",
1196 + "ちぬき",
1197 + "ちぬり",
1198 + "ちのう",
1199 + "ちひょう",
1200 + "ちへいせん",
1201 + "ちほう",
1202 + "ちまた",
1203 + "ちみつ",
1204 + "ちみどろ",
1205 + "ちめいど",
1206 + "ちゃんこなべ",
1207 + "ちゅうい",
1208 + "ちゆりょく",
1209 + "ちょうし",
1210 + "ちょさくけん",
1211 + "ちらし",
1212 + "ちらみ",
1213 + "ちりがみ",
1214 + "ちりょう",
1215 + "ちるど",
1216 + "ちわわ",
1217 + "ちんたい",
1218 + "ちんもく",
1219 + "ついか",
1220 + "ついたち",
1221 + "つうか",
1222 + "つうじょう",
1223 + "つうはん",
1224 + "つうわ",
1225 + "つかう",
1226 + "つかれる",
1227 + "つくね",
1228 + "つくる",
1229 + "つけね",
1230 + "つける",
1231 + "つごう",
1232 + "つたえる",
1233 + "つづく",
1234 + "つつじ",
1235 + "つつむ",
1236 + "つとめる",
1237 + "つながる",
1238 + "つなみ",
1239 + "つねづね",
1240 + "つのる",
1241 + "つぶす",
1242 + "つまらない",
1243 + "つまる",
1244 + "つみき",
1245 + "つめたい",
1246 + "つもり",
1247 + "つもる",
1248 + "つよい",
1249 + "つるぼ",
1250 + "つるみく",
1251 + "つわもの",
1252 + "つわり",
1253 + "てあし",
1254 + "てあて",
1255 + "てあみ",
1256 + "ていおん",
1257 + "ていか",
1258 + "ていき",
1259 + "ていけい",
1260 + "ていこく",
1261 + "ていさつ",
1262 + "ていし",
1263 + "ていせい",
1264 + "ていたい",
1265 + "ていど",
1266 + "ていねい",
1267 + "ていひょう",
1268 + "ていへん",
1269 + "ていぼう",
1270 + "てうち",
1271 + "ておくれ",
1272 + "てきとう",
1273 + "てくび",
1274 + "でこぼこ",
1275 + "てさぎょう",
1276 + "てさげ",
1277 + "てすり",
1278 + "てそう",
1279 + "てちがい",
1280 + "てちょう",
1281 + "てつがく",
1282 + "てつづき",
1283 + "でっぱ",
1284 + "てつぼう",
1285 + "てつや",
1286 + "でぬかえ",
1287 + "てぬき",
1288 + "てぬぐい",
1289 + "てのひら",
1290 + "てはい",
1291 + "てぶくろ",
1292 + "てふだ",
1293 + "てほどき",
1294 + "てほん",
1295 + "てまえ",
1296 + "てまきずし",
1297 + "てみじか",
1298 + "てみやげ",
1299 + "てらす",
1300 + "てれび",
1301 + "てわけ",
1302 + "てわたし",
1303 + "でんあつ",
1304 + "てんいん",
1305 + "てんかい",
1306 + "てんき",
1307 + "てんぐ",
1308 + "てんけん",
1309 + "てんごく",
1310 + "てんさい",
1311 + "てんし",
1312 + "てんすう",
1313 + "でんち",
1314 + "てんてき",
1315 + "てんとう",
1316 + "てんない",
1317 + "てんぷら",
1318 + "てんぼうだい",
1319 + "てんめつ",
1320 + "てんらんかい",
1321 + "でんりょく",
1322 + "でんわ",
1323 + "どあい",
1324 + "といれ",
1325 + "どうかん",
1326 + "とうきゅう",
1327 + "どうぐ",
1328 + "とうし",
1329 + "とうむぎ",
1330 + "とおい",
1331 + "とおか",
1332 + "とおく",
1333 + "とおす",
1334 + "とおる",
1335 + "とかい",
1336 + "とかす",
1337 + "ときおり",
1338 + "ときどき",
1339 + "とくい",
1340 + "とくしゅう",
1341 + "とくてん",
1342 + "とくに",
1343 + "とくべつ",
1344 + "とけい",
1345 + "とける",
1346 + "とこや",
1347 + "とさか",
1348 + "としょかん",
1349 + "とそう",
1350 + "とたん",
1351 + "とちゅう",
1352 + "とっきゅう",
1353 + "とっくん",
1354 + "とつぜん",
1355 + "とつにゅう",
1356 + "とどける",
1357 + "ととのえる",
1358 + "とない",
1359 + "となえる",
1360 + "となり",
1361 + "とのさま",
1362 + "とばす",
1363 + "どぶがわ",
1364 + "とほう",
1365 + "とまる",
1366 + "とめる",
1367 + "ともだち",
1368 + "ともる",
1369 + "どようび",
1370 + "とらえる",
1371 + "とんかつ",
1372 + "どんぶり",
1373 + "ないかく",
1374 + "ないこう",
1375 + "ないしょ",
1376 + "ないす",
1377 + "ないせん",
1378 + "ないそう",
1379 + "なおす",
1380 + "ながい",
1381 + "なくす",
1382 + "なげる",
1383 + "なこうど",
1384 + "なさけ",
1385 + "なたでここ",
1386 + "なっとう",
1387 + "なつやすみ",
1388 + "ななおし",
1389 + "なにごと",
1390 + "なにもの",
1391 + "なにわ",
1392 + "なのか",
1393 + "なふだ",
1394 + "なまいき",
1395 + "なまえ",
1396 + "なまみ",
1397 + "なみだ",
1398 + "なめらか",
1399 + "なめる",
1400 + "なやむ",
1401 + "ならう",
1402 + "ならび",
1403 + "ならぶ",
1404 + "なれる",
1405 + "なわとび",
1406 + "なわばり",
1407 + "にあう",
1408 + "にいがた",
1409 + "にうけ",
1410 + "におい",
1411 + "にかい",
1412 + "にがて",
1413 + "にきび",
1414 + "にくしみ",
1415 + "にくまん",
1416 + "にげる",
1417 + "にさんかたんそ",
1418 + "にしき",
1419 + "にせもの",
1420 + "にちじょう",
1421 + "にちようび",
1422 + "にっか",
1423 + "にっき",
1424 + "にっけい",
1425 + "にっこう",
1426 + "にっさん",
1427 + "にっしょく",
1428 + "にっすう",
1429 + "にっせき",
1430 + "にってい",
1431 + "になう",
1432 + "にほん",
1433 + "にまめ",
1434 + "にもつ",
1435 + "にやり",
1436 + "にゅういん",
1437 + "にりんしゃ",
1438 + "にわとり",
1439 + "にんい",
1440 + "にんか",
1441 + "にんき",
1442 + "にんげん",
1443 + "にんしき",
1444 + "にんずう",
1445 + "にんそう",
1446 + "にんたい",
1447 + "にんち",
1448 + "にんてい",
1449 + "にんにく",
1450 + "にんぷ",
1451 + "にんまり",
1452 + "にんむ",
1453 + "にんめい",
1454 + "にんよう",
1455 + "ぬいくぎ",
1456 + "ぬかす",
1457 + "ぬぐいとる",
1458 + "ぬぐう",
1459 + "ぬくもり",
1460 + "ぬすむ",
1461 + "ぬまえび",
1462 + "ぬめり",
1463 + "ぬらす",
1464 + "ぬんちゃく",
1465 + "ねあげ",
1466 + "ねいき",
1467 + "ねいる",
1468 + "ねいろ",
1469 + "ねぐせ",
1470 + "ねくたい",
1471 + "ねくら",
1472 + "ねこぜ",
1473 + "ねこむ",
1474 + "ねさげ",
1475 + "ねすごす",
1476 + "ねそべる",
1477 + "ねだん",
1478 + "ねつい",
1479 + "ねっしん",
1480 + "ねつぞう",
1481 + "ねったいぎょ",
1482 + "ねぶそく",
1483 + "ねふだ",
1484 + "ねぼう",
1485 + "ねほりはほり",
1486 + "ねまき",
1487 + "ねまわし",
1488 + "ねみみ",
1489 + "ねむい",
1490 + "ねむたい",
1491 + "ねもと",
1492 + "ねらう",
1493 + "ねわざ",
1494 + "ねんいり",
1495 + "ねんおし",
1496 + "ねんかん",
1497 + "ねんきん",
1498 + "ねんぐ",
1499 + "ねんざ",
1500 + "ねんし",
1501 + "ねんちゃく",
1502 + "ねんど",
1503 + "ねんぴ",
1504 + "ねんぶつ",
1505 + "ねんまつ",
1506 + "ねんりょう",
1507 + "ねんれい",
1508 + "のいず",
1509 + "のおづま",
1510 + "のがす",
1511 + "のきなみ",
1512 + "のこぎり",
1513 + "のこす",
1514 + "のこる",
1515 + "のせる",
1516 + "のぞく",
1517 + "のぞむ",
1518 + "のたまう",
1519 + "のちほど",
1520 + "のっく",
1521 + "のばす",
1522 + "のはら",
1523 + "のべる",
1524 + "のぼる",
1525 + "のみもの",
1526 + "のやま",
1527 + "のらいぬ",
1528 + "のらねこ",
1529 + "のりもの",
1530 + "のりゆき",
1531 + "のれん",
1532 + "のんき",
1533 + "ばあい",
1534 + "はあく",
1535 + "ばあさん",
1536 + "ばいか",
1537 + "ばいく",
1538 + "はいけん",
1539 + "はいご",
1540 + "はいしん",
1541 + "はいすい",
1542 + "はいせん",
1543 + "はいそう",
1544 + "はいち",
1545 + "ばいばい",
1546 + "はいれつ",
1547 + "はえる",
1548 + "はおる",
1549 + "はかい",
1550 + "ばかり",
1551 + "はかる",
1552 + "はくしゅ",
1553 + "はけん",
1554 + "はこぶ",
1555 + "はさみ",
1556 + "はさん",
1557 + "はしご",
1558 + "ばしょ",
1559 + "はしる",
1560 + "はせる",
1561 + "ぱそこん",
1562 + "はそん",
1563 + "はたん",
1564 + "はちみつ",
1565 + "はつおん",
1566 + "はっかく",
1567 + "はづき",
1568 + "はっきり",
1569 + "はっくつ",
1570 + "はっけん",
1571 + "はっこう",
1572 + "はっさん",
1573 + "はっしん",
1574 + "はったつ",
1575 + "はっちゅう",
1576 + "はってん",
1577 + "はっぴょう",
1578 + "はっぽう",
1579 + "はなす",
1580 + "はなび",
1581 + "はにかむ",
1582 + "はぶらし",
1583 + "はみがき",
1584 + "はむかう",
1585 + "はめつ",
1586 + "はやい",
1587 + "はやし",
1588 + "はらう",
1589 + "はろうぃん",
1590 + "はわい",
1591 + "はんい",
1592 + "はんえい",
1593 + "はんおん",
1594 + "はんかく",
1595 + "はんきょう",
1596 + "ばんぐみ",
1597 + "はんこ",
1598 + "はんしゃ",
1599 + "はんすう",
1600 + "はんだん",
1601 + "ぱんち",
1602 + "ぱんつ",
1603 + "はんてい",
1604 + "はんとし",
1605 + "はんのう",
1606 + "はんぱ",
1607 + "はんぶん",
1608 + "はんぺん",
1609 + "はんぼうき",
1610 + "はんめい",
1611 + "はんらん",
1612 + "はんろん",
1613 + "ひいき",
1614 + "ひうん",
1615 + "ひえる",
1616 + "ひかく",
1617 + "ひかり",
1618 + "ひかる",
1619 + "ひかん",
1620 + "ひくい",
1621 + "ひけつ",
1622 + "ひこうき",
1623 + "ひこく",
1624 + "ひさい",
1625 + "ひさしぶり",
1626 + "ひさん",
1627 + "びじゅつかん",
1628 + "ひしょ"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mnemonics/portuguese.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class PortugueseMnemonics {
2 + static const words = [
3 + "abaular",
4 + "abdominal",
5 + "abeto",
6 + "abissinio",
7 + "abjeto",
8 + "ablucao",
9 + "abnegar",
10 + "abotoar",
11 + "abrutalhar",
12 + "absurdo",
13 + "abutre",
14 + "acautelar",
15 + "accessorios",
16 + "acetona",
17 + "achocolatado",
18 + "acirrar",
19 + "acne",
20 + "acovardar",
21 + "acrostico",
22 + "actinomicete",
23 + "acustico",
24 + "adaptavel",
25 + "adeus",
26 + "adivinho",
27 + "adjunto",
28 + "admoestar",
29 + "adnominal",
30 + "adotivo",
31 + "adquirir",
32 + "adriatico",
33 + "adsorcao",
34 + "adutora",
35 + "advogar",
36 + "aerossol",
37 + "afazeres",
38 + "afetuoso",
39 + "afixo",
40 + "afluir",
41 + "afortunar",
42 + "afrouxar",
43 + "aftosa",
44 + "afunilar",
45 + "agentes",
46 + "agito",
47 + "aglutinar",
48 + "aiatola",
49 + "aimore",
50 + "aino",
51 + "aipo",
52 + "airoso",
53 + "ajeitar",
54 + "ajoelhar",
55 + "ajudante",
56 + "ajuste",
57 + "alazao",
58 + "albumina",
59 + "alcunha",
60 + "alegria",
61 + "alexandre",
62 + "alforriar",
63 + "alguns",
64 + "alhures",
65 + "alivio",
66 + "almoxarife",
67 + "alotropico",
68 + "alpiste",
69 + "alquimista",
70 + "alsaciano",
71 + "altura",
72 + "aluviao",
73 + "alvura",
74 + "amazonico",
75 + "ambulatorio",
76 + "ametodico",
77 + "amizades",
78 + "amniotico",
79 + "amovivel",
80 + "amurada",
81 + "anatomico",
82 + "ancorar",
83 + "anexo",
84 + "anfora",
85 + "aniversario",
86 + "anjo",
87 + "anotar",
88 + "ansioso",
89 + "anturio",
90 + "anuviar",
91 + "anverso",
92 + "anzol",
93 + "aonde",
94 + "apaziguar",
95 + "apito",
96 + "aplicavel",
97 + "apoteotico",
98 + "aprimorar",
99 + "aprumo",
100 + "apto",
101 + "apuros",
102 + "aquoso",
103 + "arauto",
104 + "arbusto",
105 + "arduo",
106 + "aresta",
107 + "arfar",
108 + "arguto",
109 + "aritmetico",
110 + "arlequim",
111 + "armisticio",
112 + "aromatizar",
113 + "arpoar",
114 + "arquivo",
115 + "arrumar",
116 + "arsenio",
117 + "arturiano",
118 + "aruaque",
119 + "arvores",
120 + "asbesto",
121 + "ascorbico",
122 + "aspirina",
123 + "asqueroso",
124 + "assustar",
125 + "astuto",
126 + "atazanar",
127 + "ativo",
128 + "atletismo",
129 + "atmosferico",
130 + "atormentar",
131 + "atroz",
132 + "aturdir",
133 + "audivel",
134 + "auferir",
135 + "augusto",
136 + "aula",
137 + "aumento",
138 + "aurora",
139 + "autuar",
140 + "avatar",
141 + "avexar",
142 + "avizinhar",
143 + "avolumar",
144 + "avulso",
145 + "axiomatico",
146 + "azerbaijano",
147 + "azimute",
148 + "azoto",
149 + "azulejo",
150 + "bacteriologista",
151 + "badulaque",
152 + "baforada",
153 + "baixote",
154 + "bajular",
155 + "balzaquiana",
156 + "bambuzal",
157 + "banzo",
158 + "baoba",
159 + "baqueta",
160 + "barulho",
161 + "bastonete",
162 + "batuta",
163 + "bauxita",
164 + "bavaro",
165 + "bazuca",
166 + "bcrepuscular",
167 + "beato",
168 + "beduino",
169 + "begonia",
170 + "behaviorista",
171 + "beisebol",
172 + "belzebu",
173 + "bemol",
174 + "benzido",
175 + "beocio",
176 + "bequer",
177 + "berro",
178 + "besuntar",
179 + "betume",
180 + "bexiga",
181 + "bezerro",
182 + "biatlon",
183 + "biboca",
184 + "bicuspide",
185 + "bidirecional",
186 + "bienio",
187 + "bifurcar",
188 + "bigorna",
189 + "bijuteria",
190 + "bimotor",
191 + "binormal",
192 + "bioxido",
193 + "bipolarizacao",
194 + "biquini",
195 + "birutice",
196 + "bisturi",
197 + "bituca",
198 + "biunivoco",
199 + "bivalve",
200 + "bizarro",
201 + "blasfemo",
202 + "blenorreia",
203 + "blindar",
204 + "bloqueio",
205 + "blusao",
206 + "boazuda",
207 + "bofete",
208 + "bojudo",
209 + "bolso",
210 + "bombordo",
211 + "bonzo",
212 + "botina",
213 + "boquiaberto",
214 + "bostoniano",
215 + "botulismo",
216 + "bourbon",
217 + "bovino",
218 + "boximane",
219 + "bravura",
220 + "brevidade",
221 + "britar",
222 + "broxar",
223 + "bruno",
224 + "bruxuleio",
225 + "bubonico",
226 + "bucolico",
227 + "buda",
228 + "budista",
229 + "bueiro",
230 + "buffer",
231 + "bugre",
232 + "bujao",
233 + "bumerangue",
234 + "burundines",
235 + "busto",
236 + "butique",
237 + "buzios",
238 + "caatinga",
239 + "cabuqui",
240 + "cacunda",
241 + "cafuzo",
242 + "cajueiro",
243 + "camurca",
244 + "canudo",
245 + "caquizeiro",
246 + "carvoeiro",
247 + "casulo",
248 + "catuaba",
249 + "cauterizar",
250 + "cebolinha",
251 + "cedula",
252 + "ceifeiro",
253 + "celulose",
254 + "cerzir",
255 + "cesto",
256 + "cetro",
257 + "ceus",
258 + "cevar",
259 + "chavena",
260 + "cheroqui",
261 + "chita",
262 + "chovido",
263 + "chuvoso",
264 + "ciatico",
265 + "cibernetico",
266 + "cicuta",
267 + "cidreira",
268 + "cientistas",
269 + "cifrar",
270 + "cigarro",
271 + "cilio",
272 + "cimo",
273 + "cinzento",
274 + "cioso",
275 + "cipriota",
276 + "cirurgico",
277 + "cisto",
278 + "citrico",
279 + "ciumento",
280 + "civismo",
281 + "clavicula",
282 + "clero",
283 + "clitoris",
284 + "cluster",
285 + "coaxial",
286 + "cobrir",
287 + "cocota",
288 + "codorniz",
289 + "coexistir",
290 + "cogumelo",
291 + "coito",
292 + "colusao",
293 + "compaixao",
294 + "comutativo",
295 + "contentamento",
296 + "convulsivo",
297 + "coordenativa",
298 + "coquetel",
299 + "correto",
300 + "corvo",
301 + "costureiro",
302 + "cotovia",
303 + "covil",
304 + "cozinheiro",
305 + "cretino",
306 + "cristo",
307 + "crivo",
308 + "crotalo",
309 + "cruzes",
310 + "cubo",
311 + "cucuia",
312 + "cueiro",
313 + "cuidar",
314 + "cujo",
315 + "cultural",
316 + "cunilingua",
317 + "cupula",
318 + "curvo",
319 + "custoso",
320 + "cutucar",
321 + "czarismo",
322 + "dablio",
323 + "dacota",
324 + "dados",
325 + "daguerreotipo",
326 + "daiquiri",
327 + "daltonismo",
328 + "damista",
329 + "dantesco",
330 + "daquilo",
331 + "darwinista",
332 + "dasein",
333 + "dativo",
334 + "deao",
335 + "debutantes",
336 + "decurso",
337 + "deduzir",
338 + "defunto",
339 + "degustar",
340 + "dejeto",
341 + "deltoide",
342 + "demover",
343 + "denunciar",
344 + "deputado",
345 + "deque",
346 + "dervixe",
347 + "desvirtuar",
348 + "deturpar",
349 + "deuteronomio",
350 + "devoto",
351 + "dextrose",
352 + "dezoito",
353 + "diatribe",
354 + "dicotomico",
355 + "didatico",
356 + "dietista",
357 + "difuso",
358 + "digressao",
359 + "diluvio",
360 + "diminuto",
361 + "dinheiro",
362 + "dinossauro",
363 + "dioxido",
364 + "diplomatico",
365 + "dique",
366 + "dirimivel",
367 + "disturbio",
368 + "diurno",
369 + "divulgar",
370 + "dizivel",
371 + "doar",
372 + "dobro",
373 + "docura",
374 + "dodoi",
375 + "doer",
376 + "dogue",
377 + "doloso",
378 + "domo",
379 + "donzela",
380 + "doping",
381 + "dorsal",
382 + "dossie",
383 + "dote",
384 + "doutro",
385 + "doze",
386 + "dravidico",
387 + "dreno",
388 + "driver",
389 + "dropes",
390 + "druso",
391 + "dubnio",
392 + "ducto",
393 + "dueto",
394 + "dulija",
395 + "dundum",
396 + "duodeno",
397 + "duquesa",
398 + "durou",
399 + "duvidoso",
400 + "duzia",
401 + "ebano",
402 + "ebrio",
403 + "eburneo",
404 + "echarpe",
405 + "eclusa",
406 + "ecossistema",
407 + "ectoplasma",
408 + "ecumenismo",
409 + "eczema",
410 + "eden",
411 + "editorial",
412 + "edredom",
413 + "edulcorar",
414 + "efetuar",
415 + "efigie",
416 + "efluvio",
417 + "egiptologo",
418 + "egresso",
419 + "egua",
420 + "einsteiniano",
421 + "eira",
422 + "eivar",
423 + "eixos",
424 + "ejetar",
425 + "elastomero",
426 + "eldorado",
427 + "elixir",
428 + "elmo",
429 + "eloquente",
430 + "elucidativo",
431 + "emaranhar",
432 + "embutir",
433 + "emerito",
434 + "emfa",
435 + "emitir",
436 + "emotivo",
437 + "empuxo",
438 + "emulsao",
439 + "enamorar",
440 + "encurvar",
441 + "enduro",
442 + "enevoar",
443 + "enfurnar",
444 + "enguico",
445 + "enho",
446 + "enigmista",
447 + "enlutar",
448 + "enormidade",
449 + "enpreendimento",
450 + "enquanto",
451 + "enriquecer",
452 + "enrugar",
453 + "entusiastico",
454 + "enunciar",
455 + "envolvimento",
456 + "enxuto",
457 + "enzimatico",
458 + "eolico",
459 + "epiteto",
460 + "epoxi",
461 + "epura",
462 + "equivoco",
463 + "erario",
464 + "erbio",
465 + "ereto",
466 + "erguido",
467 + "erisipela",
468 + "ermo",
469 + "erotizar",
470 + "erros",
471 + "erupcao",
472 + "ervilha",
473 + "esburacar",
474 + "escutar",
475 + "esfuziante",
476 + "esguio",
477 + "esloveno",
478 + "esmurrar",
479 + "esoterismo",
480 + "esperanca",
481 + "espirito",
482 + "espurio",
483 + "essencialmente",
484 + "esturricar",
485 + "esvoacar",
486 + "etario",
487 + "eterno",
488 + "etiquetar",
489 + "etnologo",
490 + "etos",
491 + "etrusco",
492 + "euclidiano",
493 + "euforico",
494 + "eugenico",
495 + "eunuco",
496 + "europio",
497 + "eustaquio",
498 + "eutanasia",
499 + "evasivo",
500 + "eventualidade",
501 + "evitavel",
502 + "evoluir",
503 + "exaustor",
504 + "excursionista",
505 + "exercito",
506 + "exfoliado",
507 + "exito",
508 + "exotico",
509 + "expurgo",
510 + "exsudar",
511 + "extrusora",
512 + "exumar",
513 + "fabuloso",
514 + "facultativo",
515 + "fado",
516 + "fagulha",
517 + "faixas",
518 + "fajuto",
519 + "faltoso",
520 + "famoso",
521 + "fanzine",
522 + "fapesp",
523 + "faquir",
524 + "fartura",
525 + "fastio",
526 + "faturista",
527 + "fausto",
528 + "favorito",
529 + "faxineira",
530 + "fazer",
531 + "fealdade",
532 + "febril",
533 + "fecundo",
534 + "fedorento",
535 + "feerico",
536 + "feixe",
537 + "felicidade",
538 + "felpudo",
539 + "feltro",
540 + "femur",
541 + "fenotipo",
542 + "fervura",
543 + "festivo",
544 + "feto",
545 + "feudo",
546 + "fevereiro",
547 + "fezinha",
548 + "fiasco",
549 + "fibra",
550 + "ficticio",
551 + "fiduciario",
552 + "fiesp",
553 + "fifa",
554 + "figurino",
555 + "fijiano",
556 + "filtro",
557 + "finura",
558 + "fiorde",
559 + "fiquei",
560 + "firula",
561 + "fissurar",
562 + "fitoteca",
563 + "fivela",
564 + "fixo",
565 + "flavio",
566 + "flexor",
567 + "flibusteiro",
568 + "flotilha",
569 + "fluxograma",
570 + "fobos",
571 + "foco",
572 + "fofura",
573 + "foguista",
574 + "foie",
575 + "foliculo",
576 + "fominha",
577 + "fonte",
578 + "forum",
579 + "fosso",
580 + "fotossintese",
581 + "foxtrote",
582 + "fraudulento",
583 + "frevo",
584 + "frivolo",
585 + "frouxo",
586 + "frutose",
587 + "fuba",
588 + "fucsia",
589 + "fugitivo",
590 + "fuinha",
591 + "fujao",
592 + "fulustreco",
593 + "fumo",
594 + "funileiro",
595 + "furunculo",
596 + "fustigar",
597 + "futurologo",
598 + "fuxico",
599 + "fuzue",
600 + "gabriel",
601 + "gado",
602 + "gaelico",
603 + "gafieira",
604 + "gaguejo",
605 + "gaivota",
606 + "gajo",
607 + "galvanoplastico",
608 + "gamo",
609 + "ganso",
610 + "garrucha",
611 + "gastronomo",
612 + "gatuno",
613 + "gaussiano",
614 + "gaviao",
615 + "gaxeta",
616 + "gazeteiro",
617 + "gear",
618 + "geiser",
619 + "geminiano",
620 + "generoso",
621 + "genuino",
622 + "geossinclinal",
623 + "gerundio",
624 + "gestual",
625 + "getulista",
626 + "gibi",
627 + "gigolo",
628 + "gilete",
629 + "ginseng",
630 + "giroscopio",
631 + "glaucio",
632 + "glacial",
633 + "gleba",
634 + "glifo",
635 + "glote",
636 + "glutonia",
637 + "gnostico",
638 + "goela",
639 + "gogo",
640 + "goitaca",
641 + "golpista",
642 + "gomo",
643 + "gonzo",
644 + "gorro",
645 + "gostou",
646 + "goticula",
647 + "gourmet",
648 + "governo",
649 + "gozo",
650 + "graxo",
651 + "grevista",
652 + "grito",
653 + "grotesco",
654 + "gruta",
655 + "guaxinim",
656 + "gude",
657 + "gueto",
658 + "guizo",
659 + "guloso",
660 + "gume",
661 + "guru",
662 + "gustativo",
663 + "grelhado",
664 + "gutural",
665 + "habitue",
666 + "haitiano",
667 + "halterofilista",
668 + "hamburguer",
669 + "hanseniase",
670 + "happening",
671 + "harpista",
672 + "hastear",
673 + "haveres",
674 + "hebreu",
675 + "hectometro",
676 + "hedonista",
677 + "hegira",
678 + "helena",
679 + "helminto",
680 + "hemorroidas",
681 + "henrique",
682 + "heptassilabo",
683 + "hertziano",
684 + "hesitar",
685 + "heterossexual",
686 + "heuristico",
687 + "hexagono",
688 + "hiato",
689 + "hibrido",
690 + "hidrostatico",
691 + "hieroglifo",
692 + "hifenizar",
693 + "higienizar",
694 + "hilario",
695 + "himen",
696 + "hino",
697 + "hippie",
698 + "hirsuto",
699 + "historiografia",
700 + "hitlerista",
701 + "hodometro",
702 + "hoje",
703 + "holograma",
704 + "homus",
705 + "honroso",
706 + "hoquei",
707 + "horto",
708 + "hostilizar",
709 + "hotentote",
710 + "huguenote",
711 + "humilde",
712 + "huno",
713 + "hurra",
714 + "hutu",
715 + "iaia",
716 + "ialorixa",
717 + "iambico",
718 + "iansa",
719 + "iaque",
720 + "iara",
721 + "iatista",
722 + "iberico",
723 + "ibis",
724 + "icar",
725 + "iceberg",
726 + "icosagono",
727 + "idade",
728 + "ideologo",
729 + "idiotice",
730 + "idoso",
731 + "iemenita",
732 + "iene",
733 + "igarape",
734 + "iglu",
735 + "ignorar",
736 + "igreja",
737 + "iguaria",
738 + "iidiche",
739 + "ilativo",
740 + "iletrado",
741 + "ilharga",
742 + "ilimitado",
743 + "ilogismo",
744 + "ilustrissimo",
745 + "imaturo",
746 + "imbuzeiro",
747 + "imerso",
748 + "imitavel",
749 + "imovel",
750 + "imputar",
751 + "imutavel",
752 + "inaveriguavel",
753 + "incutir",
754 + "induzir",
755 + "inextricavel",
756 + "infusao",
757 + "ingua",
758 + "inhame",
759 + "iniquo",
760 + "injusto",
761 + "inning",
762 + "inoxidavel",
763 + "inquisitorial",
764 + "insustentavel",
765 + "intumescimento",
766 + "inutilizavel",
767 + "invulneravel",
768 + "inzoneiro",
769 + "iodo",
770 + "iogurte",
771 + "ioio",
772 + "ionosfera",
773 + "ioruba",
774 + "iota",
775 + "ipsilon",
776 + "irascivel",
777 + "iris",
778 + "irlandes",
779 + "irmaos",
780 + "iroques",
781 + "irrupcao",
782 + "isca",
783 + "isento",
784 + "islandes",
785 + "isotopo",
786 + "isqueiro",
787 + "israelita",
788 + "isso",
789 + "isto",
790 + "iterbio",
791 + "itinerario",
792 + "itrio",
793 + "iuane",
794 + "iugoslavo",
795 + "jabuticabeira",
796 + "jacutinga",
797 + "jade",
798 + "jagunco",
799 + "jainista",
800 + "jaleco",
801 + "jambo",
802 + "jantarada",
803 + "japones",
804 + "jaqueta",
805 + "jarro",
806 + "jasmim",
807 + "jato",
808 + "jaula",
809 + "javel",
810 + "jazz",
811 + "jegue",
812 + "jeitoso",
813 + "jejum",
814 + "jenipapo",
815 + "jeova",
816 + "jequitiba",
817 + "jersei",
818 + "jesus",
819 + "jetom",
820 + "jiboia",
821 + "jihad",
822 + "jilo",
823 + "jingle",
824 + "jipe",
825 + "jocoso",
826 + "joelho",
827 + "joguete",
828 + "joio",
829 + "jojoba",
830 + "jorro",
831 + "jota",
832 + "joule",
833 + "joviano",
834 + "jubiloso",
835 + "judoca",
836 + "jugular",
837 + "juizo",
838 + "jujuba",
839 + "juliano",
840 + "jumento",
841 + "junto",
842 + "jururu",
843 + "justo",
844 + "juta",
845 + "juventude",
846 + "labutar",
847 + "laguna",
848 + "laico",
849 + "lajota",
850 + "lanterninha",
851 + "lapso",
852 + "laquear",
853 + "lastro",
854 + "lauto",
855 + "lavrar",
856 + "laxativo",
857 + "lazer",
858 + "leasing",
859 + "lebre",
860 + "lecionar",
861 + "ledo",
862 + "leguminoso",
863 + "leitura",
864 + "lele",
865 + "lemure",
866 + "lento",
867 + "leonardo",
868 + "leopardo",
869 + "lepton",
870 + "leque",
871 + "leste",
872 + "letreiro",
873 + "leucocito",
874 + "levitico",
875 + "lexicologo",
876 + "lhama",
877 + "lhufas",
878 + "liame",
879 + "licoroso",
880 + "lidocaina",
881 + "liliputiano",
882 + "limusine",
883 + "linotipo",
884 + "lipoproteina",
885 + "liquidos",
886 + "lirismo",
887 + "lisura",
888 + "liturgico",
889 + "livros",
890 + "lixo",
891 + "lobulo",
892 + "locutor",
893 + "lodo",
894 + "logro",
895 + "lojista",
896 + "lombriga",
897 + "lontra",
898 + "loop",
899 + "loquaz",
900 + "lorota",
901 + "losango",
902 + "lotus",
903 + "louvor",
904 + "luar",
905 + "lubrificavel",
906 + "lucros",
907 + "lugubre",
908 + "luis",
909 + "luminoso",
910 + "luneta",
911 + "lustroso",
912 + "luto",
913 + "luvas",
914 + "luxuriante",
915 + "luzeiro",
916 + "maduro",
917 + "maestro",
918 + "mafioso",
919 + "magro",
920 + "maiuscula",
921 + "majoritario",
922 + "malvisto",
923 + "mamute",
924 + "manutencao",
925 + "mapoteca",
926 + "maquinista",
927 + "marzipa",
928 + "masturbar",
929 + "matuto",
930 + "mausoleu",
931 + "mavioso",
932 + "maxixe",
933 + "mazurca",
934 + "meandro",
935 + "mecha",
936 + "medusa",
937 + "mefistofelico",
938 + "megera",
939 + "meirinho",
940 + "melro",
941 + "memorizar",
942 + "menu",
943 + "mequetrefe",
944 + "mertiolate",
945 + "mestria",
946 + "metroviario",
947 + "mexilhao",
948 + "mezanino",
949 + "miau",
950 + "microssegundo",
951 + "midia",
952 + "migratorio",
953 + "mimosa",
954 + "minuto",
955 + "miosotis",
956 + "mirtilo",
957 + "misturar",
958 + "mitzvah",
959 + "miudos",
960 + "mixuruca",
961 + "mnemonico",
962 + "moagem",
963 + "mobilizar",
964 + "modulo",
965 + "moer",
966 + "mofo",
967 + "mogno",
968 + "moita",
969 + "molusco",
970 + "monumento",
971 + "moqueca",
972 + "morubixaba",
973 + "mostruario",
974 + "motriz",
975 + "mouse",
976 + "movivel",
977 + "mozarela",
978 + "muarra",
979 + "muculmano",
980 + "mudo",
981 + "mugir",
982 + "muitos",
983 + "mumunha",
984 + "munir",
985 + "muon",
986 + "muquira",
987 + "murros",
988 + "musselina",
989 + "nacoes",
990 + "nado",
991 + "naftalina",
992 + "nago",
993 + "naipe",
994 + "naja",
995 + "nalgum",
996 + "namoro",
997 + "nanquim",
998 + "napolitano",
999 + "naquilo",
1000 + "nascimento",
1001 + "nautilo",
1002 + "navios",
1003 + "nazista",
1004 + "nebuloso",
1005 + "nectarina",
1006 + "nefrologo",
1007 + "negus",
1008 + "nelore",
1009 + "nenufar",
1010 + "nepotismo",
1011 + "nervura",
1012 + "neste",
1013 + "netuno",
1014 + "neutron",
1015 + "nevoeiro",
1016 + "newtoniano",
1017 + "nexo",
1018 + "nhenhenhem",
1019 + "nhoque",
1020 + "nigeriano",
1021 + "niilista",
1022 + "ninho",
1023 + "niobio",
1024 + "niponico",
1025 + "niquelar",
1026 + "nirvana",
1027 + "nisto",
1028 + "nitroglicerina",
1029 + "nivoso",
1030 + "nobreza",
1031 + "nocivo",
1032 + "noel",
1033 + "nogueira",
1034 + "noivo",
1035 + "nojo",
1036 + "nominativo",
1037 + "nonuplo",
1038 + "noruegues",
1039 + "nostalgico",
1040 + "noturno",
1041 + "nouveau",
1042 + "nuanca",
1043 + "nublar",
1044 + "nucleotideo",
1045 + "nudista",
1046 + "nulo",
1047 + "numismatico",
1048 + "nunquinha",
1049 + "nupcias",
1050 + "nutritivo",
1051 + "nuvens",
1052 + "oasis",
1053 + "obcecar",
1054 + "obeso",
1055 + "obituario",
1056 + "objetos",
1057 + "oblongo",
1058 + "obnoxio",
1059 + "obrigatorio",
1060 + "obstruir",
1061 + "obtuso",
1062 + "obus",
1063 + "obvio",
1064 + "ocaso",
1065 + "occipital",
1066 + "oceanografo",
1067 + "ocioso",
1068 + "oclusivo",
1069 + "ocorrer",
1070 + "ocre",
1071 + "octogono",
1072 + "odalisca",
1073 + "odisseia",
1074 + "odorifico",
1075 + "oersted",
1076 + "oeste",
1077 + "ofertar",
1078 + "ofidio",
1079 + "oftalmologo",
1080 + "ogiva",
1081 + "ogum",
1082 + "oigale",
1083 + "oitavo",
1084 + "oitocentos",
1085 + "ojeriza",
1086 + "olaria",
1087 + "oleoso",
1088 + "olfato",
1089 + "olhos",
1090 + "oliveira",
1091 + "olmo",
1092 + "olor",
1093 + "olvidavel",
1094 + "ombudsman",
1095 + "omeleteira",
1096 + "omitir",
1097 + "omoplata",
1098 + "onanismo",
1099 + "ondular",
1100 + "oneroso",
1101 + "onomatopeico",
1102 + "ontologico",
1103 + "onus",
1104 + "onze",
1105 + "opalescente",
1106 + "opcional",
1107 + "operistico",
1108 + "opio",
1109 + "oposto",
1110 + "oprobrio",
1111 + "optometrista",
1112 + "opusculo",
1113 + "oratorio",
1114 + "orbital",
1115 + "orcar",
1116 + "orfao",
1117 + "orixa",
1118 + "orla",
1119 + "ornitologo",
1120 + "orquidea",
1121 + "ortorrombico",
1122 + "orvalho",
1123 + "osculo",
1124 + "osmotico",
1125 + "ossudo",
1126 + "ostrogodo",
1127 + "otario",
1128 + "otite",
1129 + "ouro",
1130 + "ousar",
1131 + "outubro",
1132 + "ouvir",
1133 + "ovario",
1134 + "overnight",
1135 + "oviparo",
1136 + "ovni",
1137 + "ovoviviparo",
1138 + "ovulo",
1139 + "oxala",
1140 + "oxente",
1141 + "oxiuro",
1142 + "oxossi",
1143 + "ozonizar",
1144 + "paciente",
1145 + "pactuar",
1146 + "padronizar",
1147 + "paete",
1148 + "pagodeiro",
1149 + "paixao",
1150 + "pajem",
1151 + "paludismo",
1152 + "pampas",
1153 + "panturrilha",
1154 + "papudo",
1155 + "paquistanes",
1156 + "pastoso",
1157 + "patua",
1158 + "paulo",
1159 + "pauzinhos",
1160 + "pavoroso",
1161 + "paxa",
1162 + "pazes",
1163 + "peao",
1164 + "pecuniario",
1165 + "pedunculo",
1166 + "pegaso",
1167 + "peixinho",
1168 + "pejorativo",
1169 + "pelvis",
1170 + "penuria",
1171 + "pequno",
1172 + "petunia",
1173 + "pezada",
1174 + "piauiense",
1175 + "pictorico",
1176 + "pierro",
1177 + "pigmeu",
1178 + "pijama",
1179 + "pilulas",
1180 + "pimpolho",
1181 + "pintura",
1182 + "piorar",
1183 + "pipocar",
1184 + "piqueteiro",
1185 + "pirulito",
1186 + "pistoleiro",
1187 + "pituitaria",
1188 + "pivotar",
1189 + "pixote",
1190 + "pizzaria",
1191 + "plistoceno",
1192 + "plotar",
1193 + "pluviometrico",
1194 + "pneumonico",
1195 + "poco",
1196 + "podridao",
1197 + "poetisa",
1198 + "pogrom",
1199 + "pois",
1200 + "polvorosa",
1201 + "pomposo",
1202 + "ponderado",
1203 + "pontudo",
1204 + "populoso",
1205 + "poquer",
1206 + "porvir",
1207 + "posudo",
1208 + "potro",
1209 + "pouso",
1210 + "povoar",
1211 + "prazo",
1212 + "prezar",
1213 + "privilegios",
1214 + "proximo",
1215 + "prussiano",
1216 + "pseudopode",
1217 + "psoriase",
1218 + "pterossauros",
1219 + "ptialina",
1220 + "ptolemaico",
1221 + "pudor",
1222 + "pueril",
1223 + "pufe",
1224 + "pugilista",
1225 + "puir",
1226 + "pujante",
1227 + "pulverizar",
1228 + "pumba",
1229 + "punk",
1230 + "purulento",
1231 + "pustula",
1232 + "putsch",
1233 + "puxe",
1234 + "quatrocentos",
1235 + "quetzal",
1236 + "quixotesco",
1237 + "quotizavel",
1238 + "rabujice",
1239 + "racista",
1240 + "radonio",
1241 + "rafia",
1242 + "ragu",
1243 + "rajado",
1244 + "ralo",
1245 + "rampeiro",
1246 + "ranzinza",
1247 + "raptor",
1248 + "raquitismo",
1249 + "raro",
1250 + "rasurar",
1251 + "ratoeira",
1252 + "ravioli",
1253 + "razoavel",
1254 + "reavivar",
1255 + "rebuscar",
1256 + "recusavel",
1257 + "reduzivel",
1258 + "reexposicao",
1259 + "refutavel",
1260 + "regurgitar",
1261 + "reivindicavel",
1262 + "rejuvenescimento",
1263 + "relva",
1264 + "remuneravel",
1265 + "renunciar",
1266 + "reorientar",
1267 + "repuxo",
1268 + "requisito",
1269 + "resumo",
1270 + "returno",
1271 + "reutilizar",
1272 + "revolvido",
1273 + "rezonear",
1274 + "riacho",
1275 + "ribossomo",
1276 + "ricota",
1277 + "ridiculo",
1278 + "rifle",
1279 + "rigoroso",
1280 + "rijo",
1281 + "rimel",
1282 + "rins",
1283 + "rios",
1284 + "riqueza",
1285 + "respeito",
1286 + "rissole",
1287 + "ritualistico",
1288 + "rivalizar",
1289 + "rixa",
1290 + "robusto",
1291 + "rococo",
1292 + "rodoviario",
1293 + "roer",
1294 + "rogo",
1295 + "rojao",
1296 + "rolo",
1297 + "rompimento",
1298 + "ronronar",
1299 + "roqueiro",
1300 + "rorqual",
1301 + "rosto",
1302 + "rotundo",
1303 + "rouxinol",
1304 + "roxo",
1305 + "royal",
1306 + "ruas",
1307 + "rucula",
1308 + "rudimentos",
1309 + "ruela",
1310 + "rufo",
1311 + "rugoso",
1312 + "ruivo",
1313 + "rule",
1314 + "rumoroso",
1315 + "runico",
1316 + "ruptura",
1317 + "rural",
1318 + "rustico",
1319 + "rutilar",
1320 + "saariano",
1321 + "sabujo",
1322 + "sacudir",
1323 + "sadomasoquista",
1324 + "safra",
1325 + "sagui",
1326 + "sais",
1327 + "samurai",
1328 + "santuario",
1329 + "sapo",
1330 + "saquear",
1331 + "sartriano",
1332 + "saturno",
1333 + "saude",
1334 + "sauva",
1335 + "saveiro",
1336 + "saxofonista",
1337 + "sazonal",
1338 + "scherzo",
1339 + "script",
1340 + "seara",
1341 + "seborreia",
1342 + "secura",
1343 + "seduzir",
1344 + "sefardim",
1345 + "seguro",
1346 + "seja",
1347 + "selvas",
1348 + "sempre",
1349 + "senzala",
1350 + "sepultura",
1351 + "sequoia",
1352 + "sestercio",
1353 + "setuplo",
1354 + "seus",
1355 + "seviciar",
1356 + "sezonismo",
1357 + "shalom",
1358 + "siames",
1359 + "sibilante",
1360 + "sicrano",
1361 + "sidra",
1362 + "sifilitico",
1363 + "signos",
1364 + "silvo",
1365 + "simultaneo",
1366 + "sinusite",
1367 + "sionista",
1368 + "sirio",
1369 + "sisudo",
1370 + "situar",
1371 + "sivan",
1372 + "slide",
1373 + "slogan",
1374 + "soar",
1375 + "sobrio",
1376 + "socratico",
1377 + "sodomizar",
1378 + "soerguer",
1379 + "software",
1380 + "sogro",
1381 + "soja",
1382 + "solver",
1383 + "somente",
1384 + "sonso",
1385 + "sopro",
1386 + "soquete",
1387 + "sorveteiro",
1388 + "sossego",
1389 + "soturno",
1390 + "sousafone",
1391 + "sovinice",
1392 + "sozinho",
1393 + "suavizar",
1394 + "subverter",
1395 + "sucursal",
1396 + "sudoriparo",
1397 + "sufragio",
1398 + "sugestoes",
1399 + "suite",
1400 + "sujo",
1401 + "sultao",
1402 + "sumula",
1403 + "suntuoso",
1404 + "suor",
1405 + "supurar",
1406 + "suruba",
1407 + "susto",
1408 + "suturar",
1409 + "suvenir",
1410 + "tabuleta",
1411 + "taco",
1412 + "tadjique",
1413 + "tafeta",
1414 + "tagarelice",
1415 + "taitiano",
1416 + "talvez",
1417 + "tampouco",
1418 + "tanzaniano",
1419 + "taoista",
1420 + "tapume",
1421 + "taquion",
1422 + "tarugo",
1423 + "tascar",
1424 + "tatuar",
1425 + "tautologico",
1426 + "tavola",
1427 + "taxionomista",
1428 + "tchecoslovaco",
1429 + "teatrologo",
1430 + "tectonismo",
1431 + "tedioso",
1432 + "teflon",
1433 + "tegumento",
1434 + "teixo",
1435 + "telurio",
1436 + "temporas",
1437 + "tenue",
1438 + "teosofico",
1439 + "tepido",
1440 + "tequila",
1441 + "terrorista",
1442 + "testosterona",
1443 + "tetrico",
1444 + "teutonico",
1445 + "teve",
1446 + "texugo",
1447 + "tiara",
1448 + "tibia",
1449 + "tiete",
1450 + "tifoide",
1451 + "tigresa",
1452 + "tijolo",
1453 + "tilintar",
1454 + "timpano",
1455 + "tintureiro",
1456 + "tiquete",
1457 + "tiroteio",
1458 + "tisico",
1459 + "titulos",
1460 + "tive",
1461 + "toar",
1462 + "toboga",
1463 + "tofu",
1464 + "togoles",
1465 + "toicinho",
1466 + "tolueno",
1467 + "tomografo",
1468 + "tontura",
1469 + "toponimo",
1470 + "toquio",
1471 + "torvelinho",
1472 + "tostar",
1473 + "toto",
1474 + "touro",
1475 + "toxina",
1476 + "trazer",
1477 + "trezentos",
1478 + "trivialidade",
1479 + "trovoar",
1480 + "truta",
1481 + "tuaregue",
1482 + "tubular",
1483 + "tucano",
1484 + "tudo",
1485 + "tufo",
1486 + "tuiste",
1487 + "tulipa",
1488 + "tumultuoso",
1489 + "tunisino",
1490 + "tupiniquim",
1491 + "turvo",
1492 + "tutu",
1493 + "ucraniano",
1494 + "udenista",
1495 + "ufanista",
1496 + "ufologo",
1497 + "ugaritico",
1498 + "uiste",
1499 + "uivo",
1500 + "ulceroso",
1501 + "ulema",
1502 + "ultravioleta",
1503 + "umbilical",
1504 + "umero",
1505 + "umido",
1506 + "umlaut",
1507 + "unanimidade",
1508 + "unesco",
1509 + "ungulado",
1510 + "unheiro",
1511 + "univoco",
1512 + "untuoso",
1513 + "urano",
1514 + "urbano",
1515 + "urdir",
1516 + "uretra",
1517 + "urgente",
1518 + "urinol",
1519 + "urna",
1520 + "urologo",
1521 + "urro",
1522 + "ursulina",
1523 + "urtiga",
1524 + "urupe",
1525 + "usavel",
1526 + "usbeque",
1527 + "usei",
1528 + "usineiro",
1529 + "usurpar",
1530 + "utero",
1531 + "utilizar",
1532 + "utopico",
1533 + "uvular",
1534 + "uxoricidio",
1535 + "vacuo",
1536 + "vadio",
1537 + "vaguear",
1538 + "vaivem",
1539 + "valvula",
1540 + "vampiro",
1541 + "vantajoso",
1542 + "vaporoso",
1543 + "vaquinha",
1544 + "varziano",
1545 + "vasto",
1546 + "vaticinio",
1547 + "vaudeville",
1548 + "vazio",
1549 + "veado",
1550 + "vedico",
1551 + "veemente",
1552 + "vegetativo",
1553 + "veio",
1554 + "veja",
1555 + "veludo",
1556 + "venusiano",
1557 + "verdade",
1558 + "verve",
1559 + "vestuario",
1560 + "vetusto",
1561 + "vexatorio",
1562 + "vezes",
1563 + "viavel",
1564 + "vibratorio",
1565 + "victor",
1566 + "vicunha",
1567 + "vidros",
1568 + "vietnamita",
1569 + "vigoroso",
1570 + "vilipendiar",
1571 + "vime",
1572 + "vintem",
1573 + "violoncelo",
1574 + "viquingue",
1575 + "virus",
1576 + "visualizar",
1577 + "vituperio",
1578 + "viuvo",
1579 + "vivo",
1580 + "vizir",
1581 + "voar",
1582 + "vociferar",
1583 + "vodu",
1584 + "vogar",
1585 + "voile",
1586 + "volver",
1587 + "vomito",
1588 + "vontade",
1589 + "vortice",
1590 + "vosso",
1591 + "voto",
1592 + "vovozinha",
1593 + "voyeuse",
1594 + "vozes",
1595 + "vulva",
1596 + "vupt",
1597 + "western",
1598 + "xadrez",
1599 + "xale",
1600 + "xampu",
1601 + "xango",
1602 + "xarope",
1603 + "xaual",
1604 + "xavante",
1605 + "xaxim",
1606 + "xenonio",
1607 + "xepa",
1608 + "xerox",
1609 + "xicara",
1610 + "xifopago",
1611 + "xiita",
1612 + "xilogravura",
1613 + "xinxim",
1614 + "xistoso",
1615 + "xixi",
1616 + "xodo",
1617 + "xogum",
1618 + "xucro",
1619 + "zabumba",
1620 + "zagueiro",
1621 + "zambiano",
1622 + "zanzar",
1623 + "zarpar",
1624 + "zebu",
1625 + "zefiro",
1626 + "zeloso",
1627 + "zenite",
1628 + "zumbi"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mnemonics/russian.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class RussianMnemonics {
2 + static const words = [
3 + "абажур",
4 + "абзац",
5 + "абонент",
6 + "абрикос",
7 + "абсурд",
8 + "авангард",
9 + "август",
10 + "авиация",
11 + "авоська",
12 + "автор",
13 + "агат",
14 + "агент",
15 + "агитатор",
16 + "агнец",
17 + "агония",
18 + "агрегат",
19 + "адвокат",
20 + "адмирал",
21 + "адрес",
22 + "ажиотаж",
23 + "азарт",
24 + "азбука",
25 + "азот",
26 + "аист",
27 + "айсберг",
28 + "академия",
29 + "аквариум",
30 + "аккорд",
31 + "акробат",
32 + "аксиома",
33 + "актер",
34 + "акула",
35 + "акция",
36 + "алгоритм",
37 + "алебарда",
38 + "аллея",
39 + "алмаз",
40 + "алтарь",
41 + "алфавит",
42 + "алхимик",
43 + "алый",
44 + "альбом",
45 + "алюминий",
46 + "амбар",
47 + "аметист",
48 + "амнезия",
49 + "ампула",
50 + "амфора",
51 + "анализ",
52 + "ангел",
53 + "анекдот",
54 + "анимация",
55 + "анкета",
56 + "аномалия",
57 + "ансамбль",
58 + "антенна",
59 + "апатия",
60 + "апельсин",
61 + "апофеоз",
62 + "аппарат",
63 + "апрель",
64 + "аптека",
65 + "арабский",
66 + "арбуз",
67 + "аргумент",
68 + "арест",
69 + "ария",
70 + "арка",
71 + "армия",
72 + "аромат",
73 + "арсенал",
74 + "артист",
75 + "архив",
76 + "аршин",
77 + "асбест",
78 + "аскетизм",
79 + "аспект",
80 + "ассорти",
81 + "астроном",
82 + "асфальт",
83 + "атака",
84 + "ателье",
85 + "атлас",
86 + "атом",
87 + "атрибут",
88 + "аудитор",
89 + "аукцион",
90 + "аура",
91 + "афера",
92 + "афиша",
93 + "ахинея",
94 + "ацетон",
95 + "аэропорт",
96 + "бабушка",
97 + "багаж",
98 + "бадья",
99 + "база",
100 + "баклажан",
101 + "балкон",
102 + "бампер",
103 + "банк",
104 + "барон",
105 + "бассейн",
106 + "батарея",
107 + "бахрома",
108 + "башня",
109 + "баян",
110 + "бегство",
111 + "бедро",
112 + "бездна",
113 + "бекон",
114 + "белый",
115 + "бензин",
116 + "берег",
117 + "беседа",
118 + "бетонный",
119 + "биатлон",
120 + "библия",
121 + "бивень",
122 + "бигуди",
123 + "бидон",
124 + "бизнес",
125 + "бикини",
126 + "билет",
127 + "бинокль",
128 + "биология",
129 + "биржа",
130 + "бисер",
131 + "битва",
132 + "бицепс",
133 + "благо",
134 + "бледный",
135 + "близкий",
136 + "блок",
137 + "блуждать",
138 + "блюдо",
139 + "бляха",
140 + "бобер",
141 + "богатый",
142 + "бодрый",
143 + "боевой",
144 + "бокал",
145 + "большой",
146 + "борьба",
147 + "босой",
148 + "ботинок",
149 + "боцман",
150 + "бочка",
151 + "боярин",
152 + "брать",
153 + "бревно",
154 + "бригада",
155 + "бросать",
156 + "брызги",
157 + "брюки",
158 + "бублик",
159 + "бугор",
160 + "будущее",
161 + "буква",
162 + "бульвар",
163 + "бумага",
164 + "бунт",
165 + "бурный",
166 + "бусы",
167 + "бутылка",
168 + "буфет",
169 + "бухта",
170 + "бушлат",
171 + "бывалый",
172 + "быль",
173 + "быстрый",
174 + "быть",
175 + "бюджет",
176 + "бюро",
177 + "бюст",
178 + "вагон",
179 + "важный",
180 + "ваза",
181 + "вакцина",
182 + "валюта",
183 + "вампир",
184 + "ванная",
185 + "вариант",
186 + "вассал",
187 + "вата",
188 + "вафля",
189 + "вахта",
190 + "вдова",
191 + "вдыхать",
192 + "ведущий",
193 + "веер",
194 + "вежливый",
195 + "везти",
196 + "веко",
197 + "великий",
198 + "вена",
199 + "верить",
200 + "веселый",
201 + "ветер",
202 + "вечер",
203 + "вешать",
204 + "вещь",
205 + "веяние",
206 + "взаимный",
207 + "взбучка",
208 + "взвод",
209 + "взгляд",
210 + "вздыхать",
211 + "взлетать",
212 + "взмах",
213 + "взнос",
214 + "взор",
215 + "взрыв",
216 + "взывать",
217 + "взятка",
218 + "вибрация",
219 + "визит",
220 + "вилка",
221 + "вино",
222 + "вирус",
223 + "висеть",
224 + "витрина",
225 + "вихрь",
226 + "вишневый",
227 + "включать",
228 + "вкус",
229 + "власть",
230 + "влечь",
231 + "влияние",
232 + "влюблять",
233 + "внешний",
234 + "внимание",
235 + "внук",
236 + "внятный",
237 + "вода",
238 + "воевать",
239 + "вождь",
240 + "воздух",
241 + "войти",
242 + "вокзал",
243 + "волос",
244 + "вопрос",
245 + "ворота",
246 + "восток",
247 + "впадать",
248 + "впускать",
249 + "врач",
250 + "время",
251 + "вручать",
252 + "всадник",
253 + "всеобщий",
254 + "вспышка",
255 + "встреча",
256 + "вторник",
257 + "вулкан",
258 + "вурдалак",
259 + "входить",
260 + "въезд",
261 + "выбор",
262 + "вывод",
263 + "выгодный",
264 + "выделять",
265 + "выезжать",
266 + "выживать",
267 + "вызывать",
268 + "выигрыш",
269 + "вылезать",
270 + "выносить",
271 + "выпивать",
272 + "высокий",
273 + "выходить",
274 + "вычет",
275 + "вышка",
276 + "выяснять",
277 + "вязать",
278 + "вялый",
279 + "гавань",
280 + "гадать",
281 + "газета",
282 + "гаишник",
283 + "галстук",
284 + "гамма",
285 + "гарантия",
286 + "гастроли",
287 + "гвардия",
288 + "гвоздь",
289 + "гектар",
290 + "гель",
291 + "генерал",
292 + "геолог",
293 + "герой",
294 + "гешефт",
295 + "гибель",
296 + "гигант",
297 + "гильза",
298 + "гимн",
299 + "гипотеза",
300 + "гитара",
301 + "глаз",
302 + "глина",
303 + "глоток",
304 + "глубокий",
305 + "глыба",
306 + "глядеть",
307 + "гнать",
308 + "гнев",
309 + "гнить",
310 + "гном",
311 + "гнуть",
312 + "говорить",
313 + "годовой",
314 + "голова",
315 + "гонка",
316 + "город",
317 + "гость",
318 + "готовый",
319 + "граница",
320 + "грех",
321 + "гриб",
322 + "громкий",
323 + "группа",
324 + "грызть",
325 + "грязный",
326 + "губа",
327 + "гудеть",
328 + "гулять",
329 + "гуманный",
330 + "густой",
331 + "гуща",
332 + "давать",
333 + "далекий",
334 + "дама",
335 + "данные",
336 + "дарить",
337 + "дать",
338 + "дача",
339 + "дверь",
340 + "движение",
341 + "двор",
342 + "дебют",
343 + "девушка",
344 + "дедушка",
345 + "дежурный",
346 + "дезертир",
347 + "действие",
348 + "декабрь",
349 + "дело",
350 + "демократ",
351 + "день",
352 + "депутат",
353 + "держать",
354 + "десяток",
355 + "детский",
356 + "дефицит",
357 + "дешевый",
358 + "деятель",
359 + "джаз",
360 + "джинсы",
361 + "джунгли",
362 + "диалог",
363 + "диван",
364 + "диета",
365 + "дизайн",
366 + "дикий",
367 + "динамика",
368 + "диплом",
369 + "директор",
370 + "диск",
371 + "дитя",
372 + "дичь",
373 + "длинный",
374 + "дневник",
375 + "добрый",
376 + "доверие",
377 + "договор",
378 + "дождь",
379 + "доза",
380 + "документ",
381 + "должен",
382 + "домашний",
383 + "допрос",
384 + "дорога",
385 + "доход",
386 + "доцент",
387 + "дочь",
388 + "дощатый",
389 + "драка",
390 + "древний",
391 + "дрожать",
392 + "друг",
393 + "дрянь",
394 + "дубовый",
395 + "дуга",
396 + "дудка",
397 + "дукат",
398 + "дуло",
399 + "думать",
400 + "дупло",
401 + "дурак",
402 + "дуть",
403 + "духи",
404 + "душа",
405 + "дуэт",
406 + "дымить",
407 + "дыня",
408 + "дыра",
409 + "дыханье",
410 + "дышать",
411 + "дьявол",
412 + "дюжина",
413 + "дюйм",
414 + "дюна",
415 + "дядя",
416 + "дятел",
417 + "егерь",
418 + "единый",
419 + "едкий",
420 + "ежевика",
421 + "ежик",
422 + "езда",
423 + "елка",
424 + "емкость",
425 + "ерунда",
426 + "ехать",
427 + "жадный",
428 + "жажда",
429 + "жалеть",
430 + "жанр",
431 + "жара",
432 + "жать",
433 + "жгучий",
434 + "ждать",
435 + "жевать",
436 + "желание",
437 + "жемчуг",
438 + "женщина",
439 + "жертва",
440 + "жесткий",
441 + "жечь",
442 + "живой",
443 + "жидкость",
444 + "жизнь",
445 + "жилье",
446 + "жирный",
447 + "житель",
448 + "журнал",
449 + "жюри",
450 + "забывать",
451 + "завод",
452 + "загадка",
453 + "задача",
454 + "зажечь",
455 + "зайти",
456 + "закон",
457 + "замечать",
458 + "занимать",
459 + "западный",
460 + "зарплата",
461 + "засыпать",
462 + "затрата",
463 + "захват",
464 + "зацепка",
465 + "зачет",
466 + "защита",
467 + "заявка",
468 + "звать",
469 + "звезда",
470 + "звонить",
471 + "звук",
472 + "здание",
473 + "здешний",
474 + "здоровье",
475 + "зебра",
476 + "зевать",
477 + "зеленый",
478 + "земля",
479 + "зенит",
480 + "зеркало",
481 + "зефир",
482 + "зигзаг",
483 + "зима",
484 + "зиять",
485 + "злак",
486 + "злой",
487 + "змея",
488 + "знать",
489 + "зной",
490 + "зодчий",
491 + "золотой",
492 + "зомби",
493 + "зона",
494 + "зоопарк",
495 + "зоркий",
496 + "зрачок",
497 + "зрение",
498 + "зритель",
499 + "зубной",
500 + "зыбкий",
501 + "зять",
502 + "игла",
503 + "иголка",
504 + "играть",
505 + "идея",
506 + "идиот",
507 + "идол",
508 + "идти",
509 + "иерархия",
510 + "избрать",
511 + "известие",
512 + "изгонять",
513 + "издание",
514 + "излагать",
515 + "изменять",
516 + "износ",
517 + "изоляция",
518 + "изрядный",
519 + "изучать",
520 + "изымать",
521 + "изящный",
522 + "икона",
523 + "икра",
524 + "иллюзия",
525 + "имбирь",
526 + "иметь",
527 + "имидж",
528 + "иммунный",
529 + "империя",
530 + "инвестор",
531 + "индивид",
532 + "инерция",
533 + "инженер",
534 + "иномарка",
535 + "институт",
536 + "интерес",
537 + "инфекция",
538 + "инцидент",
539 + "ипподром",
540 + "ирис",
541 + "ирония",
542 + "искать",
543 + "история",
544 + "исходить",
545 + "исчезать",
546 + "итог",
547 + "июль",
548 + "июнь",
549 + "кабинет",
550 + "кавалер",
551 + "кадр",
552 + "казарма",
553 + "кайф",
554 + "кактус",
555 + "калитка",
556 + "камень",
557 + "канал",
558 + "капитан",
559 + "картина",
560 + "касса",
561 + "катер",
562 + "кафе",
563 + "качество",
564 + "каша",
565 + "каюта",
566 + "квартира",
567 + "квинтет",
568 + "квота",
569 + "кедр",
570 + "кекс",
571 + "кенгуру",
572 + "кепка",
573 + "керосин",
574 + "кетчуп",
575 + "кефир",
576 + "кибитка",
577 + "кивнуть",
578 + "кидать",
579 + "километр",
580 + "кино",
581 + "киоск",
582 + "кипеть",
583 + "кирпич",
584 + "кисть",
585 + "китаец",
586 + "класс",
587 + "клетка",
588 + "клиент",
589 + "клоун",
590 + "клуб",
591 + "клык",
592 + "ключ",
593 + "клятва",
594 + "книга",
595 + "кнопка",
596 + "кнут",
597 + "князь",
598 + "кобура",
599 + "ковер",
600 + "коготь",
601 + "кодекс",
602 + "кожа",
603 + "козел",
604 + "койка",
605 + "коктейль",
606 + "колено",
607 + "компания",
608 + "конец",
609 + "копейка",
610 + "короткий",
611 + "костюм",
612 + "котел",
613 + "кофе",
614 + "кошка",
615 + "красный",
616 + "кресло",
617 + "кричать",
618 + "кровь",
619 + "крупный",
620 + "крыша",
621 + "крючок",
622 + "кубок",
623 + "кувшин",
624 + "кудрявый",
625 + "кузов",
626 + "кукла",
627 + "культура",
628 + "кумир",
629 + "купить",
630 + "курс",
631 + "кусок",
632 + "кухня",
633 + "куча",
634 + "кушать",
635 + "кювет",
636 + "лабиринт",
637 + "лавка",
638 + "лагерь",
639 + "ладонь",
640 + "лазерный",
641 + "лайнер",
642 + "лакей",
643 + "лампа",
644 + "ландшафт",
645 + "лапа",
646 + "ларек",
647 + "ласковый",
648 + "лауреат",
649 + "лачуга",
650 + "лаять",
651 + "лгать",
652 + "лебедь",
653 + "левый",
654 + "легкий",
655 + "ледяной",
656 + "лежать",
657 + "лекция",
658 + "лента",
659 + "лепесток",
660 + "лесной",
661 + "лето",
662 + "лечь",
663 + "леший",
664 + "лживый",
665 + "либерал",
666 + "ливень",
667 + "лига",
668 + "лидер",
669 + "ликовать",
670 + "лиловый",
671 + "лимон",
672 + "линия",
673 + "липа",
674 + "лирика",
675 + "лист",
676 + "литр",
677 + "лифт",
678 + "лихой",
679 + "лицо",
680 + "личный",
681 + "лишний",
682 + "лобовой",
683 + "ловить",
684 + "логика",
685 + "лодка",
686 + "ложка",
687 + "лозунг",
688 + "локоть",
689 + "ломать",
690 + "лоно",
691 + "лопата",
692 + "лорд",
693 + "лось",
694 + "лоток",
695 + "лохматый",
696 + "лошадь",
697 + "лужа",
698 + "лукавый",
699 + "луна",
700 + "лупить",
701 + "лучший",
702 + "лыжный",
703 + "лысый",
704 + "львиный",
705 + "льгота",
706 + "льдина",
707 + "любить",
708 + "людской",
709 + "люстра",
710 + "лютый",
711 + "лягушка",
712 + "магазин",
713 + "мадам",
714 + "мазать",
715 + "майор",
716 + "максимум",
717 + "мальчик",
718 + "манера",
719 + "март",
720 + "масса",
721 + "мать",
722 + "мафия",
723 + "махать",
724 + "мачта",
725 + "машина",
726 + "маэстро",
727 + "маяк",
728 + "мгла",
729 + "мебель",
730 + "медведь",
731 + "мелкий",
732 + "мемуары",
733 + "менять",
734 + "мера",
735 + "место",
736 + "метод",
737 + "механизм",
738 + "мечтать",
739 + "мешать",
740 + "миграция",
741 + "мизинец",
742 + "микрофон",
743 + "миллион",
744 + "минута",
745 + "мировой",
746 + "миссия",
747 + "митинг",
748 + "мишень",
749 + "младший",
750 + "мнение",
751 + "мнимый",
752 + "могила",
753 + "модель",
754 + "мозг",
755 + "мойка",
756 + "мокрый",
757 + "молодой",
758 + "момент",
759 + "монах",
760 + "море",
761 + "мост",
762 + "мотор",
763 + "мохнатый",
764 + "мочь",
765 + "мошенник",
766 + "мощный",
767 + "мрачный",
768 + "мстить",
769 + "мудрый",
770 + "мужчина",
771 + "музыка",
772 + "мука",
773 + "мумия",
774 + "мундир",
775 + "муравей",
776 + "мусор",
777 + "мутный",
778 + "муфта",
779 + "муха",
780 + "мучить",
781 + "мушкетер",
782 + "мыло",
783 + "мысль",
784 + "мыть",
785 + "мычать",
786 + "мышь",
787 + "мэтр",
788 + "мюзикл",
789 + "мягкий",
790 + "мякиш",
791 + "мясо",
792 + "мятый",
793 + "мячик",
794 + "набор",
795 + "навык",
796 + "нагрузка",
797 + "надежда",
798 + "наемный",
799 + "нажать",
800 + "называть",
801 + "наивный",
802 + "накрыть",
803 + "налог",
804 + "намерен",
805 + "наносить",
806 + "написать",
807 + "народ",
808 + "натура",
809 + "наука",
810 + "нация",
811 + "начать",
812 + "небо",
813 + "невеста",
814 + "негодяй",
815 + "неделя",
816 + "нежный",
817 + "незнание",
818 + "нелепый",
819 + "немалый",
820 + "неправда",
821 + "нервный",
822 + "нести",
823 + "нефть",
824 + "нехватка",
825 + "нечистый",
826 + "неясный",
827 + "нива",
828 + "нижний",
829 + "низкий",
830 + "никель",
831 + "нирвана",
832 + "нить",
833 + "ничья",
834 + "ниша",
835 + "нищий",
836 + "новый",
837 + "нога",
838 + "ножницы",
839 + "ноздря",
840 + "ноль",
841 + "номер",
842 + "норма",
843 + "нота",
844 + "ночь",
845 + "ноша",
846 + "ноябрь",
847 + "нрав",
848 + "нужный",
849 + "нутро",
850 + "нынешний",
851 + "нырнуть",
852 + "ныть",
853 + "нюанс",
854 + "нюхать",
855 + "няня",
856 + "оазис",
857 + "обаяние",
858 + "обвинять",
859 + "обгонять",
860 + "обещать",
861 + "обжигать",
862 + "обзор",
863 + "обида",
864 + "область",
865 + "обмен",
866 + "обнимать",
867 + "оборона",
868 + "образ",
869 + "обучение",
870 + "обходить",
871 + "обширный",
872 + "общий",
873 + "объект",
874 + "обычный",
875 + "обязать",
876 + "овальный",
877 + "овес",
878 + "овощи",
879 + "овраг",
880 + "овца",
881 + "овчарка",
882 + "огненный",
883 + "огонь",
884 + "огромный",
885 + "огурец",
886 + "одежда",
887 + "одинокий",
888 + "одобрить",
889 + "ожидать",
890 + "ожог",
891 + "озарение",
892 + "озеро",
893 + "означать",
894 + "оказать",
895 + "океан",
896 + "оклад",
897 + "окно",
898 + "округ",
899 + "октябрь",
900 + "окурок",
901 + "олень",
902 + "опасный",
903 + "операция",
904 + "описать",
905 + "оплата",
906 + "опора",
907 + "оппонент",
908 + "опрос",
909 + "оптимизм",
910 + "опускать",
911 + "опыт",
912 + "орать",
913 + "орбита",
914 + "орган",
915 + "орден",
916 + "орел",
917 + "оригинал",
918 + "оркестр",
919 + "орнамент",
920 + "оружие",
921 + "осадок",
922 + "освещать",
923 + "осень",
924 + "осина",
925 + "осколок",
926 + "осмотр",
927 + "основной",
928 + "особый",
929 + "осуждать",
930 + "отбор",
931 + "отвечать",
932 + "отдать",
933 + "отец",
934 + "отзыв",
935 + "открытие",
936 + "отмечать",
937 + "относить",
938 + "отпуск",
939 + "отрасль",
940 + "отставка",
941 + "оттенок",
942 + "отходить",
943 + "отчет",
944 + "отъезд",
945 + "офицер",
946 + "охапка",
947 + "охота",
948 + "охрана",
949 + "оценка",
950 + "очаг",
951 + "очередь",
952 + "очищать",
953 + "очки",
954 + "ошейник",
955 + "ошибка",
956 + "ощущение",
957 + "павильон",
958 + "падать",
959 + "паек",
960 + "пакет",
961 + "палец",
962 + "память",
963 + "панель",
964 + "папка",
965 + "партия",
966 + "паспорт",
967 + "патрон",
968 + "пауза",
969 + "пафос",
970 + "пахнуть",
971 + "пациент",
972 + "пачка",
973 + "пашня",
974 + "певец",
975 + "педагог",
976 + "пейзаж",
977 + "пельмень",
978 + "пенсия",
979 + "пепел",
980 + "период",
981 + "песня",
982 + "петля",
983 + "пехота",
984 + "печать",
985 + "пешеход",
986 + "пещера",
987 + "пианист",
988 + "пиво",
989 + "пиджак",
990 + "пиковый",
991 + "пилот",
992 + "пионер",
993 + "пирог",
994 + "писать",
995 + "пить",
996 + "пицца",
997 + "пишущий",
998 + "пища",
999 + "план",
1000 + "плечо",
1001 + "плита",
1002 + "плохой",
1003 + "плыть",
1004 + "плюс",
1005 + "пляж",
1006 + "победа",
1007 + "повод",
1008 + "погода",
1009 + "подумать",
1010 + "поехать",
1011 + "пожимать",
1012 + "позиция",
1013 + "поиск",
1014 + "покой",
1015 + "получать",
1016 + "помнить",
1017 + "пони",
1018 + "поощрять",
1019 + "попадать",
1020 + "порядок",
1021 + "пост",
1022 + "поток",
1023 + "похожий",
1024 + "поцелуй",
1025 + "почва",
1026 + "пощечина",
1027 + "поэт",
1028 + "пояснить",
1029 + "право",
1030 + "предмет",
1031 + "проблема",
1032 + "пруд",
1033 + "прыгать",
1034 + "прямой",
1035 + "психолог",
1036 + "птица",
1037 + "публика",
1038 + "пугать",
1039 + "пудра",
1040 + "пузырь",
1041 + "пуля",
1042 + "пункт",
1043 + "пурга",
1044 + "пустой",
1045 + "путь",
1046 + "пухлый",
1047 + "пучок",
1048 + "пушистый",
1049 + "пчела",
1050 + "пшеница",
1051 + "пыль",
1052 + "пытка",
1053 + "пыхтеть",
1054 + "пышный",
1055 + "пьеса",
1056 + "пьяный",
1057 + "пятно",
1058 + "работа",
1059 + "равный",
1060 + "радость",
1061 + "развитие",
1062 + "район",
1063 + "ракета",
1064 + "рамка",
1065 + "ранний",
1066 + "рапорт",
1067 + "рассказ",
1068 + "раунд",
1069 + "рация",
1070 + "рвать",
1071 + "реальный",
1072 + "ребенок",
1073 + "реветь",
1074 + "регион",
1075 + "редакция",
1076 + "реестр",
1077 + "режим",
1078 + "резкий",
1079 + "рейтинг",
1080 + "река",
1081 + "религия",
1082 + "ремонт",
1083 + "рента",
1084 + "реплика",
1085 + "ресурс",
1086 + "реформа",
1087 + "рецепт",
1088 + "речь",
1089 + "решение",
1090 + "ржавый",
1091 + "рисунок",
1092 + "ритм",
1093 + "рифма",
1094 + "робкий",
1095 + "ровный",
1096 + "рогатый",
1097 + "родитель",
1098 + "рождение",
1099 + "розовый",
1100 + "роковой",
1101 + "роль",
1102 + "роман",
1103 + "ронять",
1104 + "рост",
1105 + "рота",
1106 + "роща",
1107 + "рояль",
1108 + "рубль",
1109 + "ругать",
1110 + "руда",
1111 + "ружье",
1112 + "руины",
1113 + "рука",
1114 + "руль",
1115 + "румяный",
1116 + "русский",
1117 + "ручка",
1118 + "рыба",
1119 + "рывок",
1120 + "рыдать",
1121 + "рыжий",
1122 + "рынок",
1123 + "рысь",
1124 + "рыть",
1125 + "рыхлый",
1126 + "рыцарь",
1127 + "рычаг",
1128 + "рюкзак",
1129 + "рюмка",
1130 + "рябой",
1131 + "рядовой",
1132 + "сабля",
1133 + "садовый",
1134 + "сажать",
1135 + "салон",
1136 + "самолет",
1137 + "сани",
1138 + "сапог",
1139 + "сарай",
1140 + "сатира",
1141 + "сауна",
1142 + "сахар",
1143 + "сбегать",
1144 + "сбивать",
1145 + "сбор",
1146 + "сбыт",
1147 + "свадьба",
1148 + "свет",
1149 + "свидание",
1150 + "свобода",
1151 + "связь",
1152 + "сгорать",
1153 + "сдвигать",
1154 + "сеанс",
1155 + "северный",
1156 + "сегмент",
1157 + "седой",
1158 + "сезон",
1159 + "сейф",
1160 + "секунда",
1161 + "сельский",
1162 + "семья",
1163 + "сентябрь",
1164 + "сердце",
1165 + "сеть",
1166 + "сечение",
1167 + "сеять",
1168 + "сигнал",
1169 + "сидеть",
1170 + "сизый",
1171 + "сила",
1172 + "символ",
1173 + "синий",
1174 + "сирота",
1175 + "система",
1176 + "ситуация",
1177 + "сиять",
1178 + "сказать",
1179 + "скважина",
1180 + "скелет",
1181 + "скидка",
1182 + "склад",
1183 + "скорый",
1184 + "скрывать",
1185 + "скучный",
1186 + "слава",
1187 + "слеза",
1188 + "слияние",
1189 + "слово",
1190 + "случай",
1191 + "слышать",
1192 + "слюна",
1193 + "смех",
1194 + "смирение",
1195 + "смотреть",
1196 + "смутный",
1197 + "смысл",
1198 + "смятение",
1199 + "снаряд",
1200 + "снег",
1201 + "снижение",
1202 + "сносить",
1203 + "снять",
1204 + "событие",
1205 + "совет",
1206 + "согласие",
1207 + "сожалеть",
1208 + "сойти",
1209 + "сокол",
1210 + "солнце",
1211 + "сомнение",
1212 + "сонный",
1213 + "сообщать",
1214 + "соперник",
1215 + "сорт",
1216 + "состав",
1217 + "сотня",
1218 + "соус",
1219 + "социолог",
1220 + "сочинять",
1221 + "союз",
1222 + "спать",
1223 + "спешить",
1224 + "спина",
1225 + "сплошной",
1226 + "способ",
1227 + "спутник",
1228 + "средство",
1229 + "срок",
1230 + "срывать",
1231 + "стать",
1232 + "ствол",
1233 + "стена",
1234 + "стихи",
1235 + "сторона",
1236 + "страна",
1237 + "студент",
1238 + "стыд",
1239 + "субъект",
1240 + "сувенир",
1241 + "сугроб",
1242 + "судьба",
1243 + "суета",
1244 + "суждение",
1245 + "сукно",
1246 + "сулить",
1247 + "сумма",
1248 + "сунуть",
1249 + "супруг",
1250 + "суровый",
1251 + "сустав",
1252 + "суть",
1253 + "сухой",
1254 + "суша",
1255 + "существо",
1256 + "сфера",
1257 + "схема",
1258 + "сцена",
1259 + "счастье",
1260 + "счет",
1261 + "считать",
1262 + "сшивать",
1263 + "съезд",
1264 + "сынок",
1265 + "сыпать",
1266 + "сырье",
1267 + "сытый",
1268 + "сыщик",
1269 + "сюжет",
1270 + "сюрприз",
1271 + "таблица",
1272 + "таежный",
1273 + "таинство",
1274 + "тайна",
1275 + "такси",
1276 + "талант",
1277 + "таможня",
1278 + "танец",
1279 + "тарелка",
1280 + "таскать",
1281 + "тахта",
1282 + "тачка",
1283 + "таять",
1284 + "тварь",
1285 + "твердый",
1286 + "творить",
1287 + "театр",
1288 + "тезис",
1289 + "текст",
1290 + "тело",
1291 + "тема",
1292 + "тень",
1293 + "теория",
1294 + "теплый",
1295 + "терять",
1296 + "тесный",
1297 + "тетя",
1298 + "техника",
1299 + "течение",
1300 + "тигр",
1301 + "типичный",
1302 + "тираж",
1303 + "титул",
1304 + "тихий",
1305 + "тишина",
1306 + "ткань",
1307 + "товарищ",
1308 + "толпа",
1309 + "тонкий",
1310 + "топливо",
1311 + "торговля",
1312 + "тоска",
1313 + "точка",
1314 + "тощий",
1315 + "традиция",
1316 + "тревога",
1317 + "трибуна",
1318 + "трогать",
1319 + "труд",
1320 + "трюк",
1321 + "тряпка",
1322 + "туалет",
1323 + "тугой",
1324 + "туловище",
1325 + "туман",
1326 + "тундра",
1327 + "тупой",
1328 + "турнир",
1329 + "тусклый",
1330 + "туфля",
1331 + "туча",
1332 + "туша",
1333 + "тыкать",
1334 + "тысяча",
1335 + "тьма",
1336 + "тюльпан",
1337 + "тюрьма",
1338 + "тяга",
1339 + "тяжелый",
1340 + "тянуть",
1341 + "убеждать",
1342 + "убирать",
1343 + "убогий",
1344 + "убыток",
1345 + "уважение",
1346 + "уверять",
1347 + "увлекать",
1348 + "угнать",
1349 + "угол",
1350 + "угроза",
1351 + "удар",
1352 + "удивлять",
1353 + "удобный",
1354 + "уезд",
1355 + "ужас",
1356 + "ужин",
1357 + "узел",
1358 + "узкий",
1359 + "узнавать",
1360 + "узор",
1361 + "уйма",
1362 + "уклон",
1363 + "укол",
1364 + "уксус",
1365 + "улетать",
1366 + "улица",
1367 + "улучшать",
1368 + "улыбка",
1369 + "уметь",
1370 + "умиление",
1371 + "умный",
1372 + "умолять",
1373 + "умысел",
1374 + "унижать",
1375 + "уносить",
1376 + "уныние",
1377 + "упасть",
1378 + "уплата",
1379 + "упор",
1380 + "упрекать",
1381 + "упускать",
1382 + "уран",
1383 + "урна",
1384 + "уровень",
1385 + "усадьба",
1386 + "усердие",
1387 + "усилие",
1388 + "ускорять",
1389 + "условие",
1390 + "усмешка",
1391 + "уснуть",
1392 + "успеть",
1393 + "усыпать",
1394 + "утешать",
1395 + "утка",
1396 + "уточнять",
1397 + "утро",
1398 + "утюг",
1399 + "уходить",
1400 + "уцелеть",
1401 + "участие",
1402 + "ученый",
1403 + "учитель",
1404 + "ушко",
1405 + "ущерб",
1406 + "уютный",
1407 + "уяснять",
1408 + "фабрика",
1409 + "фаворит",
1410 + "фаза",
1411 + "файл",
1412 + "факт",
1413 + "фамилия",
1414 + "фантазия",
1415 + "фара",
1416 + "фасад",
1417 + "февраль",
1418 + "фельдшер",
1419 + "феномен",
1420 + "ферма",
1421 + "фигура",
1422 + "физика",
1423 + "фильм",
1424 + "финал",
1425 + "фирма",
1426 + "фишка",
1427 + "флаг",
1428 + "флейта",
1429 + "флот",
1430 + "фокус",
1431 + "фольклор",
1432 + "фонд",
1433 + "форма",
1434 + "фото",
1435 + "фраза",
1436 + "фреска",
1437 + "фронт",
1438 + "фрукт",
1439 + "функция",
1440 + "фуражка",
1441 + "футбол",
1442 + "фыркать",
1443 + "халат",
1444 + "хамство",
1445 + "хаос",
1446 + "характер",
1447 + "хата",
1448 + "хватать",
1449 + "хвост",
1450 + "хижина",
1451 + "хилый",
1452 + "химия",
1453 + "хирург",
1454 + "хитрый",
1455 + "хищник",
1456 + "хлам",
1457 + "хлеб",
1458 + "хлопать",
1459 + "хмурый",
1460 + "ходить",
1461 + "хозяин",
1462 + "хоккей",
1463 + "холодный",
1464 + "хороший",
1465 + "хотеть",
1466 + "хохотать",
1467 + "храм",
1468 + "хрен",
1469 + "хриплый",
1470 + "хроника",
1471 + "хрупкий",
1472 + "художник",
1473 + "хулиган",
1474 + "хутор",
1475 + "царь",
1476 + "цвет",
1477 + "цель",
1478 + "цемент",
1479 + "центр",
1480 + "цепь",
1481 + "церковь",
1482 + "цикл",
1483 + "цилиндр",
1484 + "циничный",
1485 + "цирк",
1486 + "цистерна",
1487 + "цитата",
1488 + "цифра",
1489 + "цыпленок",
1490 + "чадо",
1491 + "чайник",
1492 + "часть",
1493 + "чашка",
1494 + "человек",
1495 + "чемодан",
1496 + "чепуха",
1497 + "черный",
1498 + "честь",
1499 + "четкий",
1500 + "чехол",
1501 + "чиновник",
1502 + "число",
1503 + "читать",
1504 + "членство",
1505 + "чреватый",
1506 + "чтение",
1507 + "чувство",
1508 + "чугунный",
1509 + "чудо",
1510 + "чужой",
1511 + "чукча",
1512 + "чулок",
1513 + "чума",
1514 + "чуткий",
1515 + "чучело",
1516 + "чушь",
1517 + "шаблон",
1518 + "шагать",
1519 + "шайка",
1520 + "шакал",
1521 + "шалаш",
1522 + "шампунь",
1523 + "шанс",
1524 + "шапка",
1525 + "шарик",
1526 + "шасси",
1527 + "шатер",
1528 + "шахта",
1529 + "шашлык",
1530 + "швейный",
1531 + "швырять",
1532 + "шевелить",
1533 + "шедевр",
1534 + "шейка",
1535 + "шелковый",
1536 + "шептать",
1537 + "шерсть",
1538 + "шестерка",
1539 + "шикарный",
1540 + "шинель",
1541 + "шипеть",
1542 + "широкий",
1543 + "шить",
1544 + "шишка",
1545 + "шкаф",
1546 + "школа",
1547 + "шкура",
1548 + "шланг",
1549 + "шлем",
1550 + "шлюпка",
1551 + "шляпа",
1552 + "шнур",
1553 + "шоколад",
1554 + "шорох",
1555 + "шоссе",
1556 + "шофер",
1557 + "шпага",
1558 + "шпион",
1559 + "шприц",
1560 + "шрам",
1561 + "шрифт",
1562 + "штаб",
1563 + "штора",
1564 + "штраф",
1565 + "штука",
1566 + "штык",
1567 + "шуба",
1568 + "шуметь",
1569 + "шуршать",
1570 + "шутка",
1571 + "щадить",
1572 + "щедрый",
1573 + "щека",
1574 + "щель",
1575 + "щенок",
1576 + "щепка",
1577 + "щетка",
1578 + "щука",
1579 + "эволюция",
1580 + "эгоизм",
1581 + "экзамен",
1582 + "экипаж",
1583 + "экономия",
1584 + "экран",
1585 + "эксперт",
1586 + "элемент",
1587 + "элита",
1588 + "эмблема",
1589 + "эмигрант",
1590 + "эмоция",
1591 + "энергия",
1592 + "эпизод",
1593 + "эпоха",
1594 + "эскиз",
1595 + "эссе",
1596 + "эстрада",
1597 + "этап",
1598 + "этика",
1599 + "этюд",
1600 + "эфир",
1601 + "эффект",
1602 + "эшелон",
1603 + "юбилей",
1604 + "юбка",
1605 + "южный",
1606 + "юмор",
1607 + "юноша",
1608 + "юрист",
1609 + "яблоко",
1610 + "явление",
1611 + "ягода",
1612 + "ядерный",
1613 + "ядовитый",
1614 + "ядро",
1615 + "язва",
1616 + "язык",
1617 + "яйцо",
1618 + "якорь",
1619 + "январь",
1620 + "японец",
1621 + "яркий",
1622 + "ярмарка",
1623 + "ярость",
1624 + "ярус",
1625 + "ясный",
1626 + "яхта",
1627 + "ячейка",
1628 + "ящик"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mnemonics/spanish.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class SpanishMnemonics {
2 + static const words = [
3 + "ábaco",
4 + "abdomen",
5 + "abeja",
6 + "abierto",
7 + "abogado",
8 + "abono",
9 + "aborto",
10 + "abrazo",
11 + "abrir",
12 + "abuelo",
13 + "abuso",
14 + "acabar",
15 + "academia",
16 + "acceso",
17 + "acción",
18 + "aceite",
19 + "acelga",
20 + "acento",
21 + "aceptar",
22 + "ácido",
23 + "aclarar",
24 + "acné",
25 + "acoger",
26 + "acoso",
27 + "activo",
28 + "acto",
29 + "actriz",
30 + "actuar",
31 + "acudir",
32 + "acuerdo",
33 + "acusar",
34 + "adicto",
35 + "admitir",
36 + "adoptar",
37 + "adorno",
38 + "aduana",
39 + "adulto",
40 + "aéreo",
41 + "afectar",
42 + "afición",
43 + "afinar",
44 + "afirmar",
45 + "ágil",
46 + "agitar",
47 + "agonía",
48 + "agosto",
49 + "agotar",
50 + "agregar",
51 + "agrio",
52 + "agua",
53 + "agudo",
54 + "águila",
55 + "aguja",
56 + "ahogo",
57 + "ahorro",
58 + "aire",
59 + "aislar",
60 + "ajedrez",
61 + "ajeno",
62 + "ajuste",
63 + "alacrán",
64 + "alambre",
65 + "alarma",
66 + "alba",
67 + "álbum",
68 + "alcalde",
69 + "aldea",
70 + "alegre",
71 + "alejar",
72 + "alerta",
73 + "aleta",
74 + "alfiler",
75 + "alga",
76 + "algodón",
77 + "aliado",
78 + "aliento",
79 + "alivio",
80 + "alma",
81 + "almeja",
82 + "almíbar",
83 + "altar",
84 + "alteza",
85 + "altivo",
86 + "alto",
87 + "altura",
88 + "alumno",
89 + "alzar",
90 + "amable",
91 + "amante",
92 + "amapola",
93 + "amargo",
94 + "amasar",
95 + "ámbar",
96 + "ámbito",
97 + "ameno",
98 + "amigo",
99 + "amistad",
100 + "amor",
101 + "amparo",
102 + "amplio",
103 + "ancho",
104 + "anciano",
105 + "ancla",
106 + "andar",
107 + "andén",
108 + "anemia",
109 + "ángulo",
110 + "anillo",
111 + "ánimo",
112 + "anís",
113 + "anotar",
114 + "antena",
115 + "antiguo",
116 + "antojo",
117 + "anual",
118 + "anular",
119 + "anuncio",
120 + "añadir",
121 + "añejo",
122 + "año",
123 + "apagar",
124 + "aparato",
125 + "apetito",
126 + "apio",
127 + "aplicar",
128 + "apodo",
129 + "aporte",
130 + "apoyo",
131 + "aprender",
132 + "aprobar",
133 + "apuesta",
134 + "apuro",
135 + "arado",
136 + "araña",
137 + "arar",
138 + "árbitro",
139 + "árbol",
140 + "arbusto",
141 + "archivo",
142 + "arco",
143 + "arder",
144 + "ardilla",
145 + "arduo",
146 + "área",
147 + "árido",
148 + "aries",
149 + "armonía",
150 + "arnés",
151 + "aroma",
152 + "arpa",
153 + "arpón",
154 + "arreglo",
155 + "arroz",
156 + "arruga",
157 + "arte",
158 + "artista",
159 + "asa",
160 + "asado",
161 + "asalto",
162 + "ascenso",
163 + "asegurar",
164 + "aseo",
165 + "asesor",
166 + "asiento",
167 + "asilo",
168 + "asistir",
169 + "asno",
170 + "asombro",
171 + "áspero",
172 + "astilla",
173 + "astro",
174 + "astuto",
175 + "asumir",
176 + "asunto",
177 + "atajo",
178 + "ataque",
179 + "atar",
180 + "atento",
181 + "ateo",
182 + "ático",
183 + "atleta",
184 + "átomo",
185 + "atraer",
186 + "atroz",
187 + "atún",
188 + "audaz",
189 + "audio",
190 + "auge",
191 + "aula",
192 + "aumento",
193 + "ausente",
194 + "autor",
195 + "aval",
196 + "avance",
197 + "avaro",
198 + "ave",
199 + "avellana",
200 + "avena",
201 + "avestruz",
202 + "avión",
203 + "aviso",
204 + "ayer",
205 + "ayuda",
206 + "ayuno",
207 + "azafrán",
208 + "azar",
209 + "azote",
210 + "azúcar",
211 + "azufre",
212 + "azul",
213 + "baba",
214 + "babor",
215 + "bache",
216 + "bahía",
217 + "baile",
218 + "bajar",
219 + "balanza",
220 + "balcón",
221 + "balde",
222 + "bambú",
223 + "banco",
224 + "banda",
225 + "baño",
226 + "barba",
227 + "barco",
228 + "barniz",
229 + "barro",
230 + "báscula",
231 + "bastón",
232 + "basura",
233 + "batalla",
234 + "batería",
235 + "batir",
236 + "batuta",
237 + "baúl",
238 + "bazar",
239 + "bebé",
240 + "bebida",
241 + "bello",
242 + "besar",
243 + "beso",
244 + "bestia",
245 + "bicho",
246 + "bien",
247 + "bingo",
248 + "blanco",
249 + "bloque",
250 + "blusa",
251 + "boa",
252 + "bobina",
253 + "bobo",
254 + "boca",
255 + "bocina",
256 + "boda",
257 + "bodega",
258 + "boina",
259 + "bola",
260 + "bolero",
261 + "bolsa",
262 + "bomba",
263 + "bondad",
264 + "bonito",
265 + "bono",
266 + "bonsái",
267 + "borde",
268 + "borrar",
269 + "bosque",
270 + "bote",
271 + "botín",
272 + "bóveda",
273 + "bozal",
274 + "bravo",
275 + "brazo",
276 + "brecha",
277 + "breve",
278 + "brillo",
279 + "brinco",
280 + "brisa",
281 + "broca",
282 + "broma",
283 + "bronce",
284 + "brote",
285 + "bruja",
286 + "brusco",
287 + "bruto",
288 + "buceo",
289 + "bucle",
290 + "bueno",
291 + "buey",
292 + "bufanda",
293 + "bufón",
294 + "búho",
295 + "buitre",
296 + "bulto",
297 + "burbuja",
298 + "burla",
299 + "burro",
300 + "buscar",
301 + "butaca",
302 + "buzón",
303 + "caballo",
304 + "cabeza",
305 + "cabina",
306 + "cabra",
307 + "cacao",
308 + "cadáver",
309 + "cadena",
310 + "caer",
311 + "café",
312 + "caída",
313 + "caimán",
314 + "caja",
315 + "cajón",
316 + "cal",
317 + "calamar",
318 + "calcio",
319 + "caldo",
320 + "calidad",
321 + "calle",
322 + "calma",
323 + "calor",
324 + "calvo",
325 + "cama",
326 + "cambio",
327 + "camello",
328 + "camino",
329 + "campo",
330 + "cáncer",
331 + "candil",
332 + "canela",
333 + "canguro",
334 + "canica",
335 + "canto",
336 + "caña",
337 + "cañón",
338 + "caoba",
339 + "caos",
340 + "capaz",
341 + "capitán",
342 + "capote",
343 + "captar",
344 + "capucha",
345 + "cara",
346 + "carbón",
347 + "cárcel",
348 + "careta",
349 + "carga",
350 + "cariño",
351 + "carne",
352 + "carpeta",
353 + "carro",
354 + "carta",
355 + "casa",
356 + "casco",
357 + "casero",
358 + "caspa",
359 + "castor",
360 + "catorce",
361 + "catre",
362 + "caudal",
363 + "causa",
364 + "cazo",
365 + "cebolla",
366 + "ceder",
367 + "cedro",
368 + "celda",
369 + "célebre",
370 + "celoso",
371 + "célula",
372 + "cemento",
373 + "ceniza",
374 + "centro",
375 + "cerca",
376 + "cerdo",
377 + "cereza",
378 + "cero",
379 + "cerrar",
380 + "certeza",
381 + "césped",
382 + "cetro",
383 + "chacal",
384 + "chaleco",
385 + "champú",
386 + "chancla",
387 + "chapa",
388 + "charla",
389 + "chico",
390 + "chiste",
391 + "chivo",
392 + "choque",
393 + "choza",
394 + "chuleta",
395 + "chupar",
396 + "ciclón",
397 + "ciego",
398 + "cielo",
399 + "cien",
400 + "cierto",
401 + "cifra",
402 + "cigarro",
403 + "cima",
404 + "cinco",
405 + "cine",
406 + "cinta",
407 + "ciprés",
408 + "circo",
409 + "ciruela",
410 + "cisne",
411 + "cita",
412 + "ciudad",
413 + "clamor",
414 + "clan",
415 + "claro",
416 + "clase",
417 + "clave",
418 + "cliente",
419 + "clima",
420 + "clínica",
421 + "cobre",
422 + "cocción",
423 + "cochino",
424 + "cocina",
425 + "coco",
426 + "código",
427 + "codo",
428 + "cofre",
429 + "coger",
430 + "cohete",
431 + "cojín",
432 + "cojo",
433 + "cola",
434 + "colcha",
435 + "colegio",
436 + "colgar",
437 + "colina",
438 + "collar",
439 + "colmo",
440 + "columna",
441 + "combate",
442 + "comer",
443 + "comida",
444 + "cómodo",
445 + "compra",
446 + "conde",
447 + "conejo",
448 + "conga",
449 + "conocer",
450 + "consejo",
451 + "contar",
452 + "copa",
453 + "copia",
454 + "corazón",
455 + "corbata",
456 + "corcho",
457 + "cordón",
458 + "corona",
459 + "correr",
460 + "coser",
461 + "cosmos",
462 + "costa",
463 + "cráneo",
464 + "cráter",
465 + "crear",
466 + "crecer",
467 + "creído",
468 + "crema",
469 + "cría",
470 + "crimen",
471 + "cripta",
472 + "crisis",
473 + "cromo",
474 + "crónica",
475 + "croqueta",
476 + "crudo",
477 + "cruz",
478 + "cuadro",
479 + "cuarto",
480 + "cuatro",
481 + "cubo",
482 + "cubrir",
483 + "cuchara",
484 + "cuello",
485 + "cuento",
486 + "cuerda",
487 + "cuesta",
488 + "cueva",
489 + "cuidar",
490 + "culebra",
491 + "culpa",
492 + "culto",
493 + "cumbre",
494 + "cumplir",
495 + "cuna",
496 + "cuneta",
497 + "cuota",
498 + "cupón",
499 + "cúpula",
500 + "curar",
501 + "curioso",
502 + "curso",
503 + "curva",
504 + "cutis",
505 + "dama",
506 + "danza",
507 + "dar",
508 + "dardo",
509 + "dátil",
510 + "deber",
511 + "débil",
512 + "década",
513 + "decir",
514 + "dedo",
515 + "defensa",
516 + "definir",
517 + "dejar",
518 + "delfín",
519 + "delgado",
520 + "delito",
521 + "demora",
522 + "denso",
523 + "dental",
524 + "deporte",
525 + "derecho",
526 + "derrota",
527 + "desayuno",
528 + "deseo",
529 + "desfile",
530 + "desnudo",
531 + "destino",
532 + "desvío",
533 + "detalle",
534 + "detener",
535 + "deuda",
536 + "día",
537 + "diablo",
538 + "diadema",
539 + "diamante",
540 + "diana",
541 + "diario",
542 + "dibujo",
543 + "dictar",
544 + "diente",
545 + "dieta",
546 + "diez",
547 + "difícil",
548 + "digno",
549 + "dilema",
550 + "diluir",
551 + "dinero",
552 + "directo",
553 + "dirigir",
554 + "disco",
555 + "diseño",
556 + "disfraz",
557 + "diva",
558 + "divino",
559 + "doble",
560 + "doce",
561 + "dolor",
562 + "domingo",
563 + "don",
564 + "donar",
565 + "dorado",
566 + "dormir",
567 + "dorso",
568 + "dos",
569 + "dosis",
570 + "dragón",
571 + "droga",
572 + "ducha",
573 + "duda",
574 + "duelo",
575 + "dueño",
576 + "dulce",
577 + "dúo",
578 + "duque",
579 + "durar",
580 + "dureza",
581 + "duro",
582 + "ébano",
583 + "ebrio",
584 + "echar",
585 + "eco",
586 + "ecuador",
587 + "edad",
588 + "edición",
589 + "edificio",
590 + "editor",
591 + "educar",
592 + "efecto",
593 + "eficaz",
594 + "eje",
595 + "ejemplo",
596 + "elefante",
597 + "elegir",
598 + "elemento",
599 + "elevar",
600 + "elipse",
601 + "élite",
602 + "elixir",
603 + "elogio",
604 + "eludir",
605 + "embudo",
606 + "emitir",
607 + "emoción",
608 + "empate",
609 + "empeño",
610 + "empleo",
611 + "empresa",
612 + "enano",
613 + "encargo",
614 + "enchufe",
615 + "encía",
616 + "enemigo",
617 + "enero",
618 + "enfado",
619 + "enfermo",
620 + "engaño",
621 + "enigma",
622 + "enlace",
623 + "enorme",
624 + "enredo",
625 + "ensayo",
626 + "enseñar",
627 + "entero",
628 + "entrar",
629 + "envase",
630 + "envío",
631 + "época",
632 + "equipo",
633 + "erizo",
634 + "escala",
635 + "escena",
636 + "escolar",
637 + "escribir",
638 + "escudo",
639 + "esencia",
640 + "esfera",
641 + "esfuerzo",
642 + "espada",
643 + "espejo",
644 + "espía",
645 + "esposa",
646 + "espuma",
647 + "esquí",
648 + "estar",
649 + "este",
650 + "estilo",
651 + "estufa",
652 + "etapa",
653 + "eterno",
654 + "ética",
655 + "etnia",
656 + "evadir",
657 + "evaluar",
658 + "evento",
659 + "evitar",
660 + "exacto",
661 + "examen",
662 + "exceso",
663 + "excusa",
664 + "exento",
665 + "exigir",
666 + "exilio",
667 + "existir",
668 + "éxito",
669 + "experto",
670 + "explicar",
671 + "exponer",
672 + "extremo",
673 + "fábrica",
674 + "fábula",
675 + "fachada",
676 + "fácil",
677 + "factor",
678 + "faena",
679 + "faja",
680 + "falda",
681 + "fallo",
682 + "falso",
683 + "faltar",
684 + "fama",
685 + "familia",
686 + "famoso",
687 + "faraón",
688 + "farmacia",
689 + "farol",
690 + "farsa",
691 + "fase",
692 + "fatiga",
693 + "fauna",
694 + "favor",
695 + "fax",
696 + "febrero",
697 + "fecha",
698 + "feliz",
699 + "feo",
700 + "feria",
701 + "feroz",
702 + "fértil",
703 + "fervor",
704 + "festín",
705 + "fiable",
706 + "fianza",
707 + "fiar",
708 + "fibra",
709 + "ficción",
710 + "ficha",
711 + "fideo",
712 + "fiebre",
713 + "fiel",
714 + "fiera",
715 + "fiesta",
716 + "figura",
717 + "fijar",
718 + "fijo",
719 + "fila",
720 + "filete",
721 + "filial",
722 + "filtro",
723 + "fin",
724 + "finca",
725 + "fingir",
726 + "finito",
727 + "firma",
728 + "flaco",
729 + "flauta",
730 + "flecha",
731 + "flor",
732 + "flota",
733 + "fluir",
734 + "flujo",
735 + "flúor",
736 + "fobia",
737 + "foca",
738 + "fogata",
739 + "fogón",
740 + "folio",
741 + "folleto",
742 + "fondo",
743 + "forma",
744 + "forro",
745 + "fortuna",
746 + "forzar",
747 + "fosa",
748 + "foto",
749 + "fracaso",
750 + "frágil",
751 + "franja",
752 + "frase",
753 + "fraude",
754 + "freír",
755 + "freno",
756 + "fresa",
757 + "frío",
758 + "frito",
759 + "fruta",
760 + "fuego",
761 + "fuente",
762 + "fuerza",
763 + "fuga",
764 + "fumar",
765 + "función",
766 + "funda",
767 + "furgón",
768 + "furia",
769 + "fusil",
770 + "fútbol",
771 + "futuro",
772 + "gacela",
773 + "gafas",
774 + "gaita",
775 + "gajo",
776 + "gala",
777 + "galería",
778 + "gallo",
779 + "gamba",
780 + "ganar",
781 + "gancho",
782 + "ganga",
783 + "ganso",
784 + "garaje",
785 + "garza",
786 + "gasolina",
787 + "gastar",
788 + "gato",
789 + "gavilán",
790 + "gemelo",
791 + "gemir",
792 + "gen",
793 + "género",
794 + "genio",
795 + "gente",
796 + "geranio",
797 + "gerente",
798 + "germen",
799 + "gesto",
800 + "gigante",
801 + "gimnasio",
802 + "girar",
803 + "giro",
804 + "glaciar",
805 + "globo",
806 + "gloria",
807 + "gol",
808 + "golfo",
809 + "goloso",
810 + "golpe",
811 + "goma",
812 + "gordo",
813 + "gorila",
814 + "gorra",
815 + "gota",
816 + "goteo",
817 + "gozar",
818 + "grada",
819 + "gráfico",
820 + "grano",
821 + "grasa",
822 + "gratis",
823 + "grave",
824 + "grieta",
825 + "grillo",
826 + "gripe",
827 + "gris",
828 + "grito",
829 + "grosor",
830 + "grúa",
831 + "grueso",
832 + "grumo",
833 + "grupo",
834 + "guante",
835 + "guapo",
836 + "guardia",
837 + "guerra",
838 + "guía",
839 + "guiño",
840 + "guion",
841 + "guiso",
842 + "guitarra",
843 + "gusano",
844 + "gustar",
845 + "haber",
846 + "hábil",
847 + "hablar",
848 + "hacer",
849 + "hacha",
850 + "hada",
851 + "hallar",
852 + "hamaca",
853 + "harina",
854 + "haz",
855 + "hazaña",
856 + "hebilla",
857 + "hebra",
858 + "hecho",
859 + "helado",
860 + "helio",
861 + "hembra",
862 + "herir",
863 + "hermano",
864 + "héroe",
865 + "hervir",
866 + "hielo",
867 + "hierro",
868 + "hígado",
869 + "higiene",
870 + "hijo",
871 + "himno",
872 + "historia",
873 + "hocico",
874 + "hogar",
875 + "hoguera",
876 + "hoja",
877 + "hombre",
878 + "hongo",
879 + "honor",
880 + "honra",
881 + "hora",
882 + "hormiga",
883 + "horno",
884 + "hostil",
885 + "hoyo",
886 + "hueco",
887 + "huelga",
888 + "huerta",
889 + "hueso",
890 + "huevo",
891 + "huida",
892 + "huir",
893 + "humano",
894 + "húmedo",
895 + "humilde",
896 + "humo",
897 + "hundir",
898 + "huracán",
899 + "hurto",
900 + "icono",
901 + "ideal",
902 + "idioma",
903 + "ídolo",
904 + "iglesia",
905 + "iglú",
906 + "igual",
907 + "ilegal",
908 + "ilusión",
909 + "imagen",
910 + "imán",
911 + "imitar",
912 + "impar",
913 + "imperio",
914 + "imponer",
915 + "impulso",
916 + "incapaz",
917 + "índice",
918 + "inerte",
919 + "infiel",
920 + "informe",
921 + "ingenio",
922 + "inicio",
923 + "inmenso",
924 + "inmune",
925 + "innato",
926 + "insecto",
927 + "instante",
928 + "interés",
929 + "íntimo",
930 + "intuir",
931 + "inútil",
932 + "invierno",
933 + "ira",
934 + "iris",
935 + "ironía",
936 + "isla",
937 + "islote",
938 + "jabalí",
939 + "jabón",
940 + "jamón",
941 + "jarabe",
942 + "jardín",
943 + "jarra",
944 + "jaula",
945 + "jazmín",
946 + "jefe",
947 + "jeringa",
948 + "jinete",
949 + "jornada",
950 + "joroba",
951 + "joven",
952 + "joya",
953 + "juerga",
954 + "jueves",
955 + "juez",
956 + "jugador",
957 + "jugo",
958 + "juguete",
959 + "juicio",
960 + "junco",
961 + "jungla",
962 + "junio",
963 + "juntar",
964 + "júpiter",
965 + "jurar",
966 + "justo",
967 + "juvenil",
968 + "juzgar",
969 + "kilo",
970 + "koala",
971 + "labio",
972 + "lacio",
973 + "lacra",
974 + "lado",
975 + "ladrón",
976 + "lagarto",
977 + "lágrima",
978 + "laguna",
979 + "laico",
980 + "lamer",
981 + "lámina",
982 + "lámpara",
983 + "lana",
984 + "lancha",
985 + "langosta",
986 + "lanza",
987 + "lápiz",
988 + "largo",
989 + "larva",
990 + "lástima",
991 + "lata",
992 + "látex",
993 + "latir",
994 + "laurel",
995 + "lavar",
996 + "lazo",
997 + "leal",
998 + "lección",
999 + "leche",
1000 + "lector",
1001 + "leer",
1002 + "legión",
1003 + "legumbre",
1004 + "lejano",
1005 + "lengua",
1006 + "lento",
1007 + "leña",
1008 + "león",
1009 + "leopardo",
1010 + "lesión",
1011 + "letal",
1012 + "letra",
1013 + "leve",
1014 + "leyenda",
1015 + "libertad",
1016 + "libro",
1017 + "licor",
1018 + "líder",
1019 + "lidiar",
1020 + "lienzo",
1021 + "liga",
1022 + "ligero",
1023 + "lima",
1024 + "límite",
1025 + "limón",
1026 + "limpio",
1027 + "lince",
1028 + "lindo",
1029 + "línea",
1030 + "lingote",
1031 + "lino",
1032 + "linterna",
1033 + "líquido",
1034 + "liso",
1035 + "lista",
1036 + "litera",
1037 + "litio",
1038 + "litro",
1039 + "llaga",
1040 + "llama",
1041 + "llanto",
1042 + "llave",
1043 + "llegar",
1044 + "llenar",
1045 + "llevar",
1046 + "llorar",
1047 + "llover",
1048 + "lluvia",
1049 + "lobo",
1050 + "loción",
1051 + "loco",
1052 + "locura",
1053 + "lógica",
1054 + "logro",
1055 + "lombriz",
1056 + "lomo",
1057 + "lonja",
1058 + "lote",
1059 + "lucha",
1060 + "lucir",
1061 + "lugar",
1062 + "lujo",
1063 + "luna",
1064 + "lunes",
1065 + "lupa",
1066 + "lustro",
1067 + "luto",
1068 + "luz",
1069 + "maceta",
1070 + "macho",
1071 + "madera",
1072 + "madre",
1073 + "maduro",
1074 + "maestro",
1075 + "mafia",
1076 + "magia",
1077 + "mago",
1078 + "maíz",
1079 + "maldad",
1080 + "maleta",
1081 + "malla",
1082 + "malo",
1083 + "mamá",
1084 + "mambo",
1085 + "mamut",
1086 + "manco",
1087 + "mando",
1088 + "manejar",
1089 + "manga",
1090 + "maniquí",
1091 + "manjar",
1092 + "mano",
1093 + "manso",
1094 + "manta",
1095 + "mañana",
1096 + "mapa",
1097 + "máquina",
1098 + "mar",
1099 + "marco",
1100 + "marea",
1101 + "marfil",
1102 + "margen",
1103 + "marido",
1104 + "mármol",
1105 + "marrón",
1106 + "martes",
1107 + "marzo",
1108 + "masa",
1109 + "máscara",
1110 + "masivo",
1111 + "matar",
1112 + "materia",
1113 + "matiz",
1114 + "matriz",
1115 + "máximo",
1116 + "mayor",
1117 + "mazorca",
1118 + "mecha",
1119 + "medalla",
1120 + "medio",
1121 + "médula",
1122 + "mejilla",
1123 + "mejor",
1124 + "melena",
1125 + "melón",
1126 + "memoria",
1127 + "menor",
1128 + "mensaje",
1129 + "mente",
1130 + "menú",
1131 + "mercado",
1132 + "merengue",
1133 + "mérito",
1134 + "mes",
1135 + "mesón",
1136 + "meta",
1137 + "meter",
1138 + "método",
1139 + "metro",
1140 + "mezcla",
1141 + "miedo",
1142 + "miel",
1143 + "miembro",
1144 + "miga",
1145 + "mil",
1146 + "milagro",
1147 + "militar",
1148 + "millón",
1149 + "mimo",
1150 + "mina",
1151 + "minero",
1152 + "mínimo",
1153 + "minuto",
1154 + "miope",
1155 + "mirar",
1156 + "misa",
1157 + "miseria",
1158 + "misil",
1159 + "mismo",
1160 + "mitad",
1161 + "mito",
1162 + "mochila",
1163 + "moción",
1164 + "moda",
1165 + "modelo",
1166 + "moho",
1167 + "mojar",
1168 + "molde",
1169 + "moler",
1170 + "molino",
1171 + "momento",
1172 + "momia",
1173 + "monarca",
1174 + "moneda",
1175 + "monja",
1176 + "monto",
1177 + "moño",
1178 + "morada",
1179 + "morder",
1180 + "moreno",
1181 + "morir",
1182 + "morro",
1183 + "morsa",
1184 + "mortal",
1185 + "mosca",
1186 + "mostrar",
1187 + "motivo",
1188 + "mover",
1189 + "móvil",
1190 + "mozo",
1191 + "mucho",
1192 + "mudar",
1193 + "mueble",
1194 + "muela",
1195 + "muerte",
1196 + "muestra",
1197 + "mugre",
1198 + "mujer",
1199 + "mula",
1200 + "muleta",
1201 + "multa",
1202 + "mundo",
1203 + "muñeca",
1204 + "mural",
1205 + "muro",
1206 + "músculo",
1207 + "museo",
1208 + "musgo",
1209 + "música",
1210 + "muslo",
1211 + "nácar",
1212 + "nación",
1213 + "nadar",
1214 + "naipe",
1215 + "naranja",
1216 + "nariz",
1217 + "narrar",
1218 + "nasal",
1219 + "natal",
1220 + "nativo",
1221 + "natural",
1222 + "náusea",
1223 + "naval",
1224 + "nave",
1225 + "navidad",
1226 + "necio",
1227 + "néctar",
1228 + "negar",
1229 + "negocio",
1230 + "negro",
1231 + "neón",
1232 + "nervio",
1233 + "neto",
1234 + "neutro",
1235 + "nevar",
1236 + "nevera",
1237 + "nicho",
1238 + "nido",
1239 + "niebla",
1240 + "nieto",
1241 + "niñez",
1242 + "niño",
1243 + "nítido",
1244 + "nivel",
1245 + "nobleza",
1246 + "noche",
1247 + "nómina",
1248 + "noria",
1249 + "norma",
1250 + "norte",
1251 + "nota",
1252 + "noticia",
1253 + "novato",
1254 + "novela",
1255 + "novio",
1256 + "nube",
1257 + "nuca",
1258 + "núcleo",
1259 + "nudillo",
1260 + "nudo",
1261 + "nuera",
1262 + "nueve",
1263 + "nuez",
1264 + "nulo",
1265 + "número",
1266 + "nutria",
1267 + "oasis",
1268 + "obeso",
1269 + "obispo",
1270 + "objeto",
1271 + "obra",
1272 + "obrero",
1273 + "observar",
1274 + "obtener",
1275 + "obvio",
1276 + "oca",
1277 + "ocaso",
1278 + "océano",
1279 + "ochenta",
1280 + "ocho",
1281 + "ocio",
1282 + "ocre",
1283 + "octavo",
1284 + "octubre",
1285 + "oculto",
1286 + "ocupar",
1287 + "ocurrir",
1288 + "odiar",
1289 + "odio",
1290 + "odisea",
1291 + "oeste",
1292 + "ofensa",
1293 + "oferta",
1294 + "oficio",
1295 + "ofrecer",
1296 + "ogro",
1297 + "oído",
1298 + "oír",
1299 + "ojo",
1300 + "ola",
1301 + "oleada",
1302 + "olfato",
1303 + "olivo",
1304 + "olla",
1305 + "olmo",
1306 + "olor",
1307 + "olvido",
1308 + "ombligo",
1309 + "onda",
1310 + "onza",
1311 + "opaco",
1312 + "opción",
1313 + "ópera",
1314 + "opinar",
1315 + "oponer",
1316 + "optar",
1317 + "óptica",
1318 + "opuesto",
1319 + "oración",
1320 + "orador",
1321 + "oral",
1322 + "órbita",
1323 + "orca",
1324 + "orden",
1325 + "oreja",
1326 + "órgano",
1327 + "orgía",
1328 + "orgullo",
1329 + "oriente",
1330 + "origen",
1331 + "orilla",
1332 + "oro",
1333 + "orquesta",
1334 + "oruga",
1335 + "osadía",
1336 + "oscuro",
1337 + "osezno",
1338 + "oso",
1339 + "ostra",
1340 + "otoño",
1341 + "otro",
1342 + "oveja",
1343 + "óvulo",
1344 + "óxido",
1345 + "oxígeno",
1346 + "oyente",
1347 + "ozono",
1348 + "pacto",
1349 + "padre",
1350 + "paella",
1351 + "página",
1352 + "pago",
1353 + "país",
1354 + "pájaro",
1355 + "palabra",
1356 + "palco",
1357 + "paleta",
1358 + "pálido",
1359 + "palma",
1360 + "paloma",
1361 + "palpar",
1362 + "pan",
1363 + "panal",
1364 + "pánico",
1365 + "pantera",
1366 + "pañuelo",
1367 + "papá",
1368 + "papel",
1369 + "papilla",
1370 + "paquete",
1371 + "parar",
1372 + "parcela",
1373 + "pared",
1374 + "parir",
1375 + "paro",
1376 + "párpado",
1377 + "parque",
1378 + "párrafo",
1379 + "parte",
1380 + "pasar",
1381 + "paseo",
1382 + "pasión",
1383 + "paso",
1384 + "pasta",
1385 + "pata",
1386 + "patio",
1387 + "patria",
1388 + "pausa",
1389 + "pauta",
1390 + "pavo",
1391 + "payaso",
1392 + "peatón",
1393 + "pecado",
1394 + "pecera",
1395 + "pecho",
1396 + "pedal",
1397 + "pedir",
1398 + "pegar",
1399 + "peine",
1400 + "pelar",
1401 + "peldaño",
1402 + "pelea",
1403 + "peligro",
1404 + "pellejo",
1405 + "pelo",
1406 + "peluca",
1407 + "pena",
1408 + "pensar",
1409 + "peñón",
1410 + "peón",
1411 + "peor",
1412 + "pepino",
1413 + "pequeño",
1414 + "pera",
1415 + "percha",
1416 + "perder",
1417 + "pereza",
1418 + "perfil",
1419 + "perico",
1420 + "perla",
1421 + "permiso",
1422 + "perro",
1423 + "persona",
1424 + "pesa",
1425 + "pesca",
1426 + "pésimo",
1427 + "pestaña",
1428 + "pétalo",
1429 + "petróleo",
1430 + "pez",
1431 + "pezuña",
1432 + "picar",
1433 + "pichón",
1434 + "pie",
1435 + "piedra",
1436 + "pierna",
1437 + "pieza",
1438 + "pijama",
1439 + "pilar",
1440 + "piloto",
1441 + "pimienta",
1442 + "pino",
1443 + "pintor",
1444 + "pinza",
1445 + "piña",
1446 + "piojo",
1447 + "pipa",
1448 + "pirata",
1449 + "pisar",
1450 + "piscina",
1451 + "piso",
1452 + "pista",
1453 + "pitón",
1454 + "pizca",
1455 + "placa",
1456 + "plan",
1457 + "plata",
1458 + "playa",
1459 + "plaza",
1460 + "pleito",
1461 + "pleno",
1462 + "plomo",
1463 + "pluma",
1464 + "plural",
1465 + "pobre",
1466 + "poco",
1467 + "poder",
1468 + "podio",
1469 + "poema",
1470 + "poesía",
1471 + "poeta",
1472 + "polen",
1473 + "policía",
1474 + "pollo",
1475 + "polvo",
1476 + "pomada",
1477 + "pomelo",
1478 + "pomo",
1479 + "pompa",
1480 + "poner",
1481 + "porción",
1482 + "portal",
1483 + "posada",
1484 + "poseer",
1485 + "posible",
1486 + "poste",
1487 + "potencia",
1488 + "potro",
1489 + "pozo",
1490 + "prado",
1491 + "precoz",
1492 + "pregunta",
1493 + "premio",
1494 + "prensa",
1495 + "preso",
1496 + "previo",
1497 + "primo",
1498 + "príncipe",
1499 + "prisión",
1500 + "privar",
1501 + "proa",
1502 + "probar",
1503 + "proceso",
1504 + "producto",
1505 + "proeza",
1506 + "profesor",
1507 + "programa",
1508 + "prole",
1509 + "promesa",
1510 + "pronto",
1511 + "propio",
1512 + "próximo",
1513 + "prueba",
1514 + "público",
1515 + "puchero",
1516 + "pudor",
1517 + "pueblo",
1518 + "puerta",
1519 + "puesto",
1520 + "pulga",
1521 + "pulir",
1522 + "pulmón",
1523 + "pulpo",
1524 + "pulso",
1525 + "puma",
1526 + "punto",
1527 + "puñal",
1528 + "puño",
1529 + "pupa",
1530 + "pupila",
1531 + "puré",
1532 + "quedar",
1533 + "queja",
1534 + "quemar",
1535 + "querer",
1536 + "queso",
1537 + "quieto",
1538 + "química",
1539 + "quince",
1540 + "quitar",
1541 + "rábano",
1542 + "rabia",
1543 + "rabo",
1544 + "ración",
1545 + "radical",
1546 + "raíz",
1547 + "rama",
1548 + "rampa",
1549 + "rancho",
1550 + "rango",
1551 + "rapaz",
1552 + "rápido",
1553 + "rapto",
1554 + "rasgo",
1555 + "raspa",
1556 + "rato",
1557 + "rayo",
1558 + "raza",
1559 + "razón",
1560 + "reacción",
1561 + "realidad",
1562 + "rebaño",
1563 + "rebote",
1564 + "recaer",
1565 + "receta",
1566 + "rechazo",
1567 + "recoger",
1568 + "recreo",
1569 + "recto",
1570 + "recurso",
1571 + "red",
1572 + "redondo",
1573 + "reducir",
1574 + "reflejo",
1575 + "reforma",
1576 + "refrán",
1577 + "refugio",
1578 + "regalo",
1579 + "regir",
1580 + "regla",
1581 + "regreso",
1582 + "rehén",
1583 + "reino",
1584 + "reír",
1585 + "reja",
1586 + "relato",
1587 + "relevo",
1588 + "relieve",
1589 + "relleno",
1590 + "reloj",
1591 + "remar",
1592 + "remedio",
1593 + "remo",
1594 + "rencor",
1595 + "rendir",
1596 + "renta",
1597 + "reparto",
1598 + "repetir",
1599 + "reposo",
1600 + "reptil",
1601 + "res",
1602 + "rescate",
1603 + "resina",
1604 + "respeto",
1605 + "resto",
1606 + "resumen",
1607 + "retiro",
1608 + "retorno",
1609 + "retrato",
1610 + "reunir",
1611 + "revés",
1612 + "revista",
1613 + "rey",
1614 + "rezar",
1615 + "rico",
1616 + "riego",
1617 + "rienda",
1618 + "riesgo",
1619 + "rifa",
1620 + "rígido",
1621 + "rigor",
1622 + "rincón",
1623 + "riñón",
1624 + "río",
1625 + "riqueza",
1626 + "risa",
1627 + "ritmo",
1628 + "rito"
1629 + ];
1630 +}
\ No newline at end of file
cw_wownero/lib/mywownero.dart new
+1689
@@ -0,0 +1,1689 @@
1 +const prefixLength = 3;
2 +
3 +String swapEndianBytes(String original) {
4 + if (original.length != 8) {
5 + return '';
6 + }
7 +
8 + return original[6] +
9 + original[7] +
10 + original[4] +
11 + original[5] +
12 + original[2] +
13 + original[3] +
14 + original[0] +
15 + original[1];
16 +}
17 +
18 +List<String> tructWords(List<String> wordSet) {
19 + final start = 0;
20 + final end = prefixLength;
21 +
22 + return wordSet.map((word) => word.substring(start, end)).toList();
23 +}
24 +
25 +String mnemonicDecode(String seed) {
26 + final n = englistWordSet.length;
27 + var out = '';
28 + var wlist = seed.split(' ');
29 + wlist.removeLast();
30 +
31 + for (var i = 0; i < wlist.length; i += 3) {
32 + final w1 =
33 + tructWords(englistWordSet).indexOf(wlist[i].substring(0, prefixLength));
34 + final w2 = tructWords(englistWordSet)
35 + .indexOf(wlist[i + 1].substring(0, prefixLength));
36 + final w3 = tructWords(englistWordSet)
37 + .indexOf(wlist[i + 2].substring(0, prefixLength));
38 +
39 + if (w1 == -1 || w2 == -1 || w3 == -1) {
40 + print("invalid word in mnemonic");
41 + return '';
42 + }
43 +
44 + final x = w1 + n * (((n - w1) + w2) % n) + n * n * (((n - w2) + w3) % n);
45 +
46 + if (x % n != w1) {
47 + print("Something went wrong when decoding your private key, please try again");
48 + return '';
49 + }
50 +
51 + final _res = '0000000' + x.toRadixString(16);
52 + final start = _res.length - 8;
53 + final end = _res.length;
54 + final res = _res.substring(start, end);
55 +
56 + out += swapEndianBytes(res);
57 + }
58 +
59 + return out;
60 +}
61 +
62 +final englistWordSet = [
63 + "abbey",
64 + "abducts",
65 + "ability",
66 + "ablaze",
67 + "abnormal",
68 + "abort",
69 + "abrasive",
70 + "absorb",
71 + "abyss",
72 + "academy",
73 + "aces",
74 + "aching",
75 + "acidic",
76 + "acoustic",
77 + "acquire",
78 + "across",
79 + "actress",
80 + "acumen",
81 + "adapt",
82 + "addicted",
83 + "adept",
84 + "adhesive",
85 + "adjust",
86 + "adopt",
87 + "adrenalin",
88 + "adult",
89 + "adventure",
90 + "aerial",
91 + "afar",
92 + "affair",
93 + "afield",
94 + "afloat",
95 + "afoot",
96 + "afraid",
97 + "after",
98 + "against",
99 + "agenda",
100 + "aggravate",
101 + "agile",
102 + "aglow",
103 + "agnostic",
104 + "agony",
105 + "agreed",
106 + "ahead",
107 + "aided",
108 + "ailments",
109 + "aimless",
110 + "airport",
111 + "aisle",
112 + "ajar",
113 + "akin",
114 + "alarms",
115 + "album",
116 + "alchemy",
117 + "alerts",
118 + "algebra",
119 + "alkaline",
120 + "alley",
121 + "almost",
122 + "aloof",
123 + "alpine",
124 + "already",
125 + "also",
126 + "altitude",
127 + "alumni",
128 + "always",
129 + "amaze",
130 + "ambush",
131 + "amended",
132 + "amidst",
133 + "ammo",
134 + "amnesty",
135 + "among",
136 + "amply",
137 + "amused",
138 + "anchor",
139 + "android",
140 + "anecdote",
141 + "angled",
142 + "ankle",
143 + "annoyed",
144 + "answers",
145 + "antics",
146 + "anvil",
147 + "anxiety",
148 + "anybody",
149 + "apart",
150 + "apex",
151 + "aphid",
152 + "aplomb",
153 + "apology",
154 + "apply",
155 + "apricot",
156 + "aptitude",
157 + "aquarium",
158 + "arbitrary",
159 + "archer",
160 + "ardent",
161 + "arena",
162 + "argue",
163 + "arises",
164 + "army",
165 + "around",
166 + "arrow",
167 + "arsenic",
168 + "artistic",
169 + "ascend",
170 + "ashtray",
171 + "aside",
172 + "asked",
173 + "asleep",
174 + "aspire",
175 + "assorted",
176 + "asylum",
177 + "athlete",
178 + "atlas",
179 + "atom",
180 + "atrium",
181 + "attire",
182 + "auburn",
183 + "auctions",
184 + "audio",
185 + "august",
186 + "aunt",
187 + "austere",
188 + "autumn",
189 + "avatar",
190 + "avidly",
191 + "avoid",
192 + "awakened",
193 + "awesome",
194 + "awful",
195 + "awkward",
196 + "awning",
197 + "awoken",
198 + "axes",
199 + "axis",
200 + "axle",
201 + "aztec",
202 + "azure",
203 + "baby",
204 + "bacon",
205 + "badge",
206 + "baffles",
207 + "bagpipe",
208 + "bailed",
209 + "bakery",
210 + "balding",
211 + "bamboo",
212 + "banjo",
213 + "baptism",
214 + "basin",
215 + "batch",
216 + "bawled",
217 + "bays",
218 + "because",
219 + "beer",
220 + "befit",
221 + "begun",
222 + "behind",
223 + "being",
224 + "below",
225 + "bemused",
226 + "benches",
227 + "berries",
228 + "bested",
229 + "betting",
230 + "bevel",
231 + "beware",
232 + "beyond",
233 + "bias",
234 + "bicycle",
235 + "bids",
236 + "bifocals",
237 + "biggest",
238 + "bikini",
239 + "bimonthly",
240 + "binocular",
241 + "biology",
242 + "biplane",
243 + "birth",
244 + "biscuit",
245 + "bite",
246 + "biweekly",
247 + "blender",
248 + "blip",
249 + "bluntly",
250 + "boat",
251 + "bobsled",
252 + "bodies",
253 + "bogeys",
254 + "boil",
255 + "boldly",
256 + "bomb",
257 + "border",
258 + "boss",
259 + "both",
260 + "bounced",
261 + "bovine",
262 + "bowling",
263 + "boxes",
264 + "boyfriend",
265 + "broken",
266 + "brunt",
267 + "bubble",
268 + "buckets",
269 + "budget",
270 + "buffet",
271 + "bugs",
272 + "building",
273 + "bulb",
274 + "bumper",
275 + "bunch",
276 + "business",
277 + "butter",
278 + "buying",
279 + "buzzer",
280 + "bygones",
281 + "byline",
282 + "bypass",
283 + "cabin",
284 + "cactus",
285 + "cadets",
286 + "cafe",
287 + "cage",
288 + "cajun",
289 + "cake",
290 + "calamity",
291 + "camp",
292 + "candy",
293 + "casket",
294 + "catch",
295 + "cause",
296 + "cavernous",
297 + "cease",
298 + "cedar",
299 + "ceiling",
300 + "cell",
301 + "cement",
302 + "cent",
303 + "certain",
304 + "chlorine",
305 + "chrome",
306 + "cider",
307 + "cigar",
308 + "cinema",
309 + "circle",
310 + "cistern",
311 + "citadel",
312 + "civilian",
313 + "claim",
314 + "click",
315 + "clue",
316 + "coal",
317 + "cobra",
318 + "cocoa",
319 + "code",
320 + "coexist",
321 + "coffee",
322 + "cogs",
323 + "cohesive",
324 + "coils",
325 + "colony",
326 + "comb",
327 + "cool",
328 + "copy",
329 + "corrode",
330 + "costume",
331 + "cottage",
332 + "cousin",
333 + "cowl",
334 + "criminal",
335 + "cube",
336 + "cucumber",
337 + "cuddled",
338 + "cuffs",
339 + "cuisine",
340 + "cunning",
341 + "cupcake",
342 + "custom",
343 + "cycling",
344 + "cylinder",
345 + "cynical",
346 + "dabbing",
347 + "dads",
348 + "daft",
349 + "dagger",
350 + "daily",
351 + "damp",
352 + "dangerous",
353 + "dapper",
354 + "darted",
355 + "dash",
356 + "dating",
357 + "dauntless",
358 + "dawn",
359 + "daytime",
360 + "dazed",
361 + "debut",
362 + "decay",
363 + "dedicated",
364 + "deepest",
365 + "deftly",
366 + "degrees",
367 + "dehydrate",
368 + "deity",
369 + "dejected",
370 + "delayed",
371 + "demonstrate",
372 + "dented",
373 + "deodorant",
374 + "depth",
375 + "desk",
376 + "devoid",
377 + "dewdrop",
378 + "dexterity",
379 + "dialect",
380 + "dice",
381 + "diet",
382 + "different",
383 + "digit",
384 + "dilute",
385 + "dime",
386 + "dinner",
387 + "diode",
388 + "diplomat",
389 + "directed",
390 + "distance",
391 + "ditch",
392 + "divers",
393 + "dizzy",
394 + "doctor",
395 + "dodge",
396 + "does",
397 + "dogs",
398 + "doing",
399 + "dolphin",
400 + "domestic",
401 + "donuts",
402 + "doorway",
403 + "dormant",
404 + "dosage",
405 + "dotted",
406 + "double",
407 + "dove",
408 + "down",
409 + "dozen",
410 + "dreams",
411 + "drinks",
412 + "drowning",
413 + "drunk",
414 + "drying",
415 + "dual",
416 + "dubbed",
417 + "duckling",
418 + "dude",
419 + "duets",
420 + "duke",
421 + "dullness",
422 + "dummy",
423 + "dunes",
424 + "duplex",
425 + "duration",
426 + "dusted",
427 + "duties",
428 + "dwarf",
429 + "dwelt",
430 + "dwindling",
431 + "dying",
432 + "dynamite",
433 + "dyslexic",
434 + "each",
435 + "eagle",
436 + "earth",
437 + "easy",
438 + "eating",
439 + "eavesdrop",
440 + "eccentric",
441 + "echo",
442 + "eclipse",
443 + "economics",
444 + "ecstatic",
445 + "eden",
446 + "edgy",
447 + "edited",
448 + "educated",
449 + "eels",
450 + "efficient",
451 + "eggs",
452 + "egotistic",
453 + "eight",
454 + "either",
455 + "eject",
456 + "elapse",
457 + "elbow",
458 + "eldest",
459 + "eleven",
460 + "elite",
461 + "elope",
462 + "else",
463 + "eluded",
464 + "emails",
465 + "ember",
466 + "emerge",
467 + "emit",
468 + "emotion",
469 + "empty",
470 + "emulate",
471 + "energy",
472 + "enforce",
473 + "enhanced",
474 + "enigma",
475 + "enjoy",
476 + "enlist",
477 + "enmity",
478 + "enough",
479 + "enraged",
480 + "ensign",
481 + "entrance",
482 + "envy",
483 + "epoxy",
484 + "equip",
485 + "erase",
486 + "erected",
487 + "erosion",
488 + "error",
489 + "eskimos",
490 + "espionage",
491 + "essential",
492 + "estate",
493 + "etched",
494 + "eternal",
495 + "ethics",
496 + "etiquette",
497 + "evaluate",
498 + "evenings",
499 + "evicted",
500 + "evolved",
501 + "examine",
502 + "excess",
503 + "exhale",
504 + "exit",
505 + "exotic",
506 + "exquisite",
507 + "extra",
508 + "exult",
509 + "fabrics",
510 + "factual",
511 + "fading",
512 + "fainted",
513 + "faked",
514 + "fall",
515 + "family",
516 + "fancy",
517 + "farming",
518 + "fatal",
519 + "faulty",
520 + "fawns",
521 + "faxed",
522 + "fazed",
523 + "feast",
524 + "february",
525 + "federal",
526 + "feel",
527 + "feline",
528 + "females",
529 + "fences",
530 + "ferry",
531 + "festival",
532 + "fetches",
533 + "fever",
534 + "fewest",
535 + "fiat",
536 + "fibula",
537 + "fictional",
538 + "fidget",
539 + "fierce",
540 + "fifteen",
541 + "fight",
542 + "films",
543 + "firm",
544 + "fishing",
545 + "fitting",
546 + "five",
547 + "fixate",
548 + "fizzle",
549 + "fleet",
550 + "flippant",
551 + "flying",
552 + "foamy",
553 + "focus",
554 + "foes",
555 + "foggy",
556 + "foiled",
557 + "folding",
558 + "fonts",
559 + "foolish",
560 + "fossil",
561 + "fountain",
562 + "fowls",
563 + "foxes",
564 + "foyer",
565 + "framed",
566 + "friendly",
567 + "frown",
568 + "fruit",
569 + "frying",
570 + "fudge",
571 + "fuel",
572 + "fugitive",
573 + "fully",
574 + "fuming",
575 + "fungal",
576 + "furnished",
577 + "fuselage",
578 + "future",
579 + "fuzzy",
580 + "gables",
581 + "gadget",
582 + "gags",
583 + "gained",
584 + "galaxy",
585 + "gambit",
586 + "gang",
587 + "gasp",
588 + "gather",
589 + "gauze",
590 + "gave",
591 + "gawk",
592 + "gaze",
593 + "gearbox",
594 + "gecko",
595 + "geek",
596 + "gels",
597 + "gemstone",
598 + "general",
599 + "geometry",
600 + "germs",
601 + "gesture",
602 + "getting",
603 + "geyser",
604 + "ghetto",
605 + "ghost",
606 + "giant",
607 + "giddy",
608 + "gifts",
609 + "gigantic",
610 + "gills",
611 + "gimmick",
612 + "ginger",
613 + "girth",
614 + "giving",
615 + "glass",
616 + "gleeful",
617 + "glide",
618 + "gnaw",
619 + "gnome",
620 + "goat",
621 + "goblet",
622 + "godfather",
623 + "goes",
624 + "goggles",
625 + "going",
626 + "goldfish",
627 + "gone",
628 + "goodbye",
629 + "gopher",
630 + "gorilla",
631 + "gossip",
632 + "gotten",
633 + "gourmet",
634 + "governing",
635 + "gown",
636 + "greater",
637 + "grunt",
638 + "guarded",
639 + "guest",
640 + "guide",
641 + "gulp",
642 + "gumball",
643 + "guru",
644 + "gusts",
645 + "gutter",
646 + "guys",
647 + "gymnast",
648 + "gypsy",
649 + "gyrate",
650 + "habitat",
651 + "hacksaw",
652 + "haggled",
653 + "hairy",
654 + "hamburger",
655 + "happens",
656 + "hashing",
657 + "hatchet",
658 + "haunted",
659 + "having",
660 + "hawk",
661 + "haystack",
662 + "hazard",
663 + "hectare",
664 + "hedgehog",
665 + "heels",
666 + "hefty",
667 + "height",
668 + "hemlock",
669 + "hence",
670 + "heron",
671 + "hesitate",
672 + "hexagon",
673 + "hickory",
674 + "hiding",
675 + "highway",
676 + "hijack",
677 + "hiker",
678 + "hills",
679 + "himself",
680 + "hinder",
681 + "hippo",
682 + "hire",
683 + "history",
684 + "hitched",
685 + "hive",
686 + "hoax",
687 + "hobby",
688 + "hockey",
689 + "hoisting",
690 + "hold",
691 + "honked",
692 + "hookup",
693 + "hope",
694 + "hornet",
695 + "hospital",
696 + "hotel",
697 + "hounded",
698 + "hover",
699 + "howls",
700 + "hubcaps",
701 + "huddle",
702 + "huge",
703 + "hull",
704 + "humid",
705 + "hunter",
706 + "hurried",
707 + "husband",
708 + "huts",
709 + "hybrid",
710 + "hydrogen",
711 + "hyper",
712 + "iceberg",
713 + "icing",
714 + "icon",
715 + "identity",
716 + "idiom",
717 + "idled",
718 + "idols",
719 + "igloo",
720 + "ignore",
721 + "iguana",
722 + "illness",
723 + "imagine",
724 + "imbalance",
725 + "imitate",
726 + "impel",
727 + "inactive",
728 + "inbound",
729 + "incur",
730 + "industrial",
731 + "inexact",
732 + "inflamed",
733 + "ingested",
734 + "initiate",
735 + "injury",
736 + "inkling",
737 + "inline",
738 + "inmate",
739 + "innocent",
740 + "inorganic",
741 + "input",
742 + "inquest",
743 + "inroads",
744 + "insult",
745 + "intended",
746 + "inundate",
747 + "invoke",
748 + "inwardly",
749 + "ionic",
750 + "irate",
751 + "iris",
752 + "irony",
753 + "irritate",
754 + "island",
755 + "isolated",
756 + "issued",
757 + "italics",
758 + "itches",
759 + "items",
760 + "itinerary",
761 + "itself",
762 + "ivory",
763 + "jabbed",
764 + "jackets",
765 + "jaded",
766 + "jagged",
767 + "jailed",
768 + "jamming",
769 + "january",
770 + "jargon",
771 + "jaunt",
772 + "javelin",
773 + "jaws",
774 + "jazz",
775 + "jeans",
776 + "jeers",
777 + "jellyfish",
778 + "jeopardy",
779 + "jerseys",
780 + "jester",
781 + "jetting",
782 + "jewels",
783 + "jigsaw",
784 + "jingle",
785 + "jittery",
786 + "jive",
787 + "jobs",
788 + "jockey",
789 + "jogger",
790 + "joining",
791 + "joking",
792 + "jolted",
793 + "jostle",
794 + "journal",
795 + "joyous",
796 + "jubilee",
797 + "judge",
798 + "juggled",
799 + "juicy",
800 + "jukebox",
801 + "july",
802 + "jump",
803 + "junk",
804 + "jury",
805 + "justice",
806 + "juvenile",
807 + "kangaroo",
808 + "karate",
809 + "keep",
810 + "kennel",
811 + "kept",
812 + "kernels",
813 + "kettle",
814 + "keyboard",
815 + "kickoff",
816 + "kidneys",
817 + "king",
818 + "kiosk",
819 + "kisses",
820 + "kitchens",
821 + "kiwi",
822 + "knapsack",
823 + "knee",
824 + "knife",
825 + "knowledge",
826 + "knuckle",
827 + "koala",
828 + "laboratory",
829 + "ladder",
830 + "lagoon",
831 + "lair",
832 + "lakes",
833 + "lamb",
834 + "language",
835 + "laptop",
836 + "large",
837 + "last",
838 + "later",
839 + "launching",
840 + "lava",
841 + "lawsuit",
842 + "layout",
843 + "lazy",
844 + "lectures",
845 + "ledge",
846 + "leech",
847 + "left",
848 + "legion",
849 + "leisure",
850 + "lemon",
851 + "lending",
852 + "leopard",
853 + "lesson",
854 + "lettuce",
855 + "lexicon",
856 + "liar",
857 + "library",
858 + "licks",
859 + "lids",
860 + "lied",
861 + "lifestyle",
862 + "light",
863 + "likewise",
864 + "lilac",
865 + "limits",
866 + "linen",
867 + "lion",
868 + "lipstick",
869 + "liquid",
870 + "listen",
871 + "lively",
872 + "loaded",
873 + "lobster",
874 + "locker",
875 + "lodge",
876 + "lofty",
877 + "logic",
878 + "loincloth",
879 + "long",
880 + "looking",
881 + "lopped",
882 + "lordship",
883 + "losing",
884 + "lottery",
885 + "loudly",
886 + "love",
887 + "lower",
888 + "loyal",
889 + "lucky",
890 + "luggage",
891 + "lukewarm",
892 + "lullaby",
893 + "lumber",
894 + "lunar",
895 + "lurk",
896 + "lush",
897 + "luxury",
898 + "lymph",
899 + "lynx",
900 + "lyrics",
901 + "macro",
902 + "madness",
903 + "magically",
904 + "mailed",
905 + "major",
906 + "makeup",
907 + "malady",
908 + "mammal",
909 + "maps",
910 + "masterful",
911 + "match",
912 + "maul",
913 + "maverick",
914 + "maximum",
915 + "mayor",
916 + "maze",
917 + "meant",
918 + "mechanic",
919 + "medicate",
920 + "meeting",
921 + "megabyte",
922 + "melting",
923 + "memoir",
924 + "menu",
925 + "merger",
926 + "mesh",
927 + "metro",
928 + "mews",
929 + "mice",
930 + "midst",
931 + "mighty",
932 + "mime",
933 + "mirror",
934 + "misery",
935 + "mittens",
936 + "mixture",
937 + "moat",
938 + "mobile",
939 + "mocked",
940 + "mohawk",
941 + "moisture",
942 + "molten",
943 + "moment",
944 + "money",
945 + "moon",
946 + "mops",
947 + "morsel",
948 + "mostly",
949 + "motherly",
950 + "mouth",
951 + "movement",
952 + "mowing",
953 + "much",
954 + "muddy",
955 + "muffin",
956 + "mugged",
957 + "mullet",
958 + "mumble",
959 + "mundane",
960 + "muppet",
961 + "mural",
962 + "musical",
963 + "muzzle",
964 + "myriad",
965 + "mystery",
966 + "myth",
967 + "nabbing",
968 + "nagged",
969 + "nail",
970 + "names",
971 + "nanny",
972 + "napkin",
973 + "narrate",
974 + "nasty",
975 + "natural",
976 + "nautical",
977 + "navy",
978 + "nearby",
979 + "necklace",
980 + "needed",
981 + "negative",
982 + "neither",
983 + "neon",
984 + "nephew",
985 + "nerves",
986 + "nestle",
987 + "network",
988 + "neutral",
989 + "never",
990 + "newt",
991 + "nexus",
992 + "nibs",
993 + "niche",
994 + "niece",
995 + "nifty",
996 + "nightly",
997 + "nimbly",
998 + "nineteen",
999 + "nirvana",
1000 + "nitrogen",
1001 + "nobody",
1002 + "nocturnal",
1003 + "nodes",
1004 + "noises",
1005 + "nomad",
1006 + "noodles",
1007 + "northern",
1008 + "nostril",
1009 + "noted",
1010 + "nouns",
1011 + "novelty",
1012 + "nowhere",
1013 + "nozzle",
1014 + "nuance",
1015 + "nucleus",
1016 + "nudged",
1017 + "nugget",
1018 + "nuisance",
1019 + "null",
1020 + "number",
1021 + "nuns",
1022 + "nurse",
1023 + "nutshell",
1024 + "nylon",
1025 + "oaks",
1026 + "oars",
1027 + "oasis",
1028 + "oatmeal",
1029 + "obedient",
1030 + "object",
1031 + "obliged",
1032 + "obnoxious",
1033 + "observant",
1034 + "obtains",
1035 + "obvious",
1036 + "occur",
1037 + "ocean",
1038 + "october",
1039 + "odds",
1040 + "odometer",
1041 + "offend",
1042 + "often",
1043 + "oilfield",
1044 + "ointment",
1045 + "okay",
1046 + "older",
1047 + "olive",
1048 + "olympics",
1049 + "omega",
1050 + "omission",
1051 + "omnibus",
1052 + "onboard",
1053 + "oncoming",
1054 + "oneself",
1055 + "ongoing",
1056 + "onion",
1057 + "online",
1058 + "onslaught",
1059 + "onto",
1060 + "onward",
1061 + "oozed",
1062 + "opacity",
1063 + "opened",
1064 + "opposite",
1065 + "optical",
1066 + "opus",
1067 + "orange",
1068 + "orbit",
1069 + "orchid",
1070 + "orders",
1071 + "organs",
1072 + "origin",
1073 + "ornament",
1074 + "orphans",
1075 + "oscar",
1076 + "ostrich",
1077 + "otherwise",
1078 + "otter",
1079 + "ouch",
1080 + "ought",
1081 + "ounce",
1082 + "ourselves",
1083 + "oust",
1084 + "outbreak",
1085 + "oval",
1086 + "oven",
1087 + "owed",
1088 + "owls",
1089 + "owner",
1090 + "oxidant",
1091 + "oxygen",
1092 + "oyster",
1093 + "ozone",
1094 + "pact",
1095 + "paddles",
1096 + "pager",
1097 + "pairing",
1098 + "palace",
1099 + "pamphlet",
1100 + "pancakes",
1101 + "paper",
1102 + "paradise",
1103 + "pastry",
1104 + "patio",
1105 + "pause",
1106 + "pavements",
1107 + "pawnshop",
1108 + "payment",
1109 + "peaches",
1110 + "pebbles",
1111 + "peculiar",
1112 + "pedantic",
1113 + "peeled",
1114 + "pegs",
1115 + "pelican",
1116 + "pencil",
1117 + "people",
1118 + "pepper",
1119 + "perfect",
1120 + "pests",
1121 + "petals",
1122 + "phase",
1123 + "pheasants",
1124 + "phone",
1125 + "phrases",
1126 + "physics",
1127 + "piano",
1128 + "picked",
1129 + "pierce",
1130 + "pigment",
1131 + "piloted",
1132 + "pimple",
1133 + "pinched",
1134 + "pioneer",
1135 + "pipeline",
1136 + "pirate",
1137 + "pistons",
1138 + "pitched",
1139 + "pivot",
1140 + "pixels",
1141 + "pizza",
1142 + "playful",
1143 + "pledge",
1144 + "pliers",
1145 + "plotting",
1146 + "plus",
1147 + "plywood",
1148 + "poaching",
1149 + "pockets",
1150 + "podcast",
1151 + "poetry",
1152 + "point",
1153 + "poker",
1154 + "polar",
1155 + "ponies",
1156 + "pool",
1157 + "popular",
1158 + "portents",
1159 + "possible",
1160 + "potato",
1161 + "pouch",
1162 + "poverty",
1163 + "powder",
1164 + "pram",
1165 + "present",
1166 + "pride",
1167 + "problems",
1168 + "pruned",
1169 + "prying",
1170 + "psychic",
1171 + "public",
1172 + "puck",
1173 + "puddle",
1174 + "puffin",
1175 + "pulp",
1176 + "pumpkins",
1177 + "punch",
1178 + "puppy",
1179 + "purged",
1180 + "push",
1181 + "putty",
1182 + "puzzled",
1183 + "pylons",
1184 + "pyramid",
1185 + "python",
1186 + "queen",
1187 + "quick",
1188 + "quote",
1189 + "rabbits",
1190 + "racetrack",
1191 + "radar",
1192 + "rafts",
1193 + "rage",
1194 + "railway",
1195 + "raking",
1196 + "rally",
1197 + "ramped",
1198 + "randomly",
1199 + "rapid",
1200 + "rarest",
1201 + "rash",
1202 + "rated",
1203 + "ravine",
1204 + "rays",
1205 + "razor",
1206 + "react",
1207 + "rebel",
1208 + "recipe",
1209 + "reduce",
1210 + "reef",
1211 + "refer",
1212 + "regular",
1213 + "reheat",
1214 + "reinvest",
1215 + "rejoices",
1216 + "rekindle",
1217 + "relic",
1218 + "remedy",
1219 + "renting",
1220 + "reorder",
1221 + "repent",
1222 + "request",
1223 + "reruns",
1224 + "rest",
1225 + "return",
1226 + "reunion",
1227 + "revamp",
1228 + "rewind",
1229 + "rhino",
1230 + "rhythm",
1231 + "ribbon",
1232 + "richly",
1233 + "ridges",
1234 + "rift",
1235 + "rigid",
1236 + "rims",
1237 + "ringing",
1238 + "riots",
1239 + "ripped",
1240 + "rising",
1241 + "ritual",
1242 + "river",
1243 + "roared",
1244 + "robot",
1245 + "rockets",
1246 + "rodent",
1247 + "rogue",
1248 + "roles",
1249 + "romance",
1250 + "roomy",
1251 + "roped",
1252 + "roster",
1253 + "rotate",
1254 + "rounded",
1255 + "rover",
1256 + "rowboat",
1257 + "royal",
1258 + "ruby",
1259 + "rudely",
1260 + "ruffled",
1261 + "rugged",
1262 + "ruined",
1263 + "ruling",
1264 + "rumble",
1265 + "runway",
1266 + "rural",
1267 + "rustled",
1268 + "ruthless",
1269 + "sabotage",
1270 + "sack",
1271 + "sadness",
1272 + "safety",
1273 + "saga",
1274 + "sailor",
1275 + "sake",
1276 + "salads",
1277 + "sample",
1278 + "sanity",
1279 + "sapling",
1280 + "sarcasm",
1281 + "sash",
1282 + "satin",
1283 + "saucepan",
1284 + "saved",
1285 + "sawmill",
1286 + "saxophone",
1287 + "sayings",
1288 + "scamper",
1289 + "scenic",
1290 + "school",
1291 + "science",
1292 + "scoop",
1293 + "scrub",
1294 + "scuba",
1295 + "seasons",
1296 + "second",
1297 + "sedan",
1298 + "seeded",
1299 + "segments",
1300 + "seismic",
1301 + "selfish",
1302 + "semifinal",
1303 + "sensible",
1304 + "september",
1305 + "sequence",
1306 + "serving",
1307 + "session",
1308 + "setup",
1309 + "seventh",
1310 + "sewage",
1311 + "shackles",
1312 + "shelter",
1313 + "shipped",
1314 + "shocking",
1315 + "shrugged",
1316 + "shuffled",
1317 + "shyness",
1318 + "siblings",
1319 + "sickness",
1320 + "sidekick",
1321 + "sieve",
1322 + "sifting",
1323 + "sighting",
1324 + "silk",
1325 + "simplest",
1326 + "sincerely",
1327 + "sipped",
1328 + "siren",
1329 + "situated",
1330 + "sixteen",
1331 + "sizes",
1332 + "skater",
1333 + "skew",
1334 + "skirting",
1335 + "skulls",
1336 + "skydive",
1337 + "slackens",
1338 + "sleepless",
1339 + "slid",
1340 + "slower",
1341 + "slug",
1342 + "smash",
1343 + "smelting",
1344 + "smidgen",
1345 + "smog",
1346 + "smuggled",
1347 + "snake",
1348 + "sneeze",
1349 + "sniff",
1350 + "snout",
1351 + "snug",
1352 + "soapy",
1353 + "sober",
1354 + "soccer",
1355 + "soda",
1356 + "software",
1357 + "soggy",
1358 + "soil",
1359 + "solved",
1360 + "somewhere",
1361 + "sonic",
1362 + "soothe",
1363 + "soprano",
1364 + "sorry",
1365 + "southern",
1366 + "sovereign",
1367 + "sowed",
1368 + "soya",
1369 + "space",
1370 + "speedy",
1371 + "sphere",
1372 + "spiders",
1373 + "splendid",
1374 + "spout",
1375 + "sprig",
1376 + "spud",
1377 + "spying",
1378 + "square",
1379 + "stacking",
1380 + "stellar",
1381 + "stick",
1382 + "stockpile",
1383 + "strained",
1384 + "stunning",
1385 + "stylishly",
1386 + "subtly",
1387 + "succeed",
1388 + "suddenly",
1389 + "suede",
1390 + "suffice",
1391 + "sugar",
1392 + "suitcase",
1393 + "sulking",
1394 + "summon",
1395 + "sunken",
1396 + "superior",
1397 + "surfer",
1398 + "sushi",
1399 + "suture",
1400 + "swagger",
1401 + "swept",
1402 + "swiftly",
1403 + "sword",
1404 + "swung",
1405 + "syllabus",
1406 + "symptoms",
1407 + "syndrome",
1408 + "syringe",
1409 + "system",
1410 + "taboo",
1411 + "tacit",
1412 + "tadpoles",
1413 + "tagged",
1414 + "tail",
1415 + "taken",
1416 + "talent",
1417 + "tamper",
1418 + "tanks",
1419 + "tapestry",
1420 + "tarnished",
1421 + "tasked",
1422 + "tattoo",
1423 + "taunts",
1424 + "tavern",
1425 + "tawny",
1426 + "taxi",
1427 + "teardrop",
1428 + "technical",
1429 + "tedious",
1430 + "teeming",
1431 + "tell",
1432 + "template",
1433 + "tender",
1434 + "tepid",
1435 + "tequila",
1436 + "terminal",
1437 + "testing",
1438 + "tether",
1439 + "textbook",
1440 + "thaw",
1441 + "theatrics",
1442 + "thirsty",
1443 + "thorn",
1444 + "threaten",
1445 + "thumbs",
1446 + "thwart",
1447 + "ticket",
1448 + "tidy",
1449 + "tiers",
1450 + "tiger",
1451 + "tilt",
1452 + "timber",
1453 + "tinted",
1454 + "tipsy",
1455 + "tirade",
1456 + "tissue",
1457 + "titans",
1458 + "toaster",
1459 + "tobacco",
1460 + "today",
1461 + "toenail",
1462 + "toffee",
1463 + "together",
1464 + "toilet",
1465 + "token",
1466 + "tolerant",
1467 + "tomorrow",
1468 + "tonic",
1469 + "toolbox",
1470 + "topic",
1471 + "torch",
1472 + "tossed",
1473 + "total",
1474 + "touchy",
1475 + "towel",
1476 + "toxic",
1477 + "toyed",
1478 + "trash",
1479 + "trendy",
1480 + "tribal",
1481 + "trolling",
1482 + "truth",
1483 + "trying",
1484 + "tsunami",
1485 + "tubes",
1486 + "tucks",
1487 + "tudor",
1488 + "tuesday",
1489 + "tufts",
1490 + "tugs",
1491 + "tuition",
1492 + "tulips",
1493 + "tumbling",
1494 + "tunnel",
1495 + "turnip",
1496 + "tusks",
1497 + "tutor",
1498 + "tuxedo",
1499 + "twang",
1500 + "tweezers",
1501 + "twice",
1502 + "twofold",
1503 + "tycoon",
1504 + "typist",
1505 + "tyrant",
1506 + "ugly",
1507 + "ulcers",
1508 + "ultimate",
1509 + "umbrella",
1510 + "umpire",
1511 + "unafraid",
1512 + "unbending",
1513 + "uncle",
1514 + "under",
1515 + "uneven",
1516 + "unfit",
1517 + "ungainly",
1518 + "unhappy",
1519 + "union",
1520 + "unjustly",
1521 + "unknown",
1522 + "unlikely",
1523 + "unmask",
1524 + "unnoticed",
1525 + "unopened",
1526 + "unplugs",
1527 + "unquoted",
1528 + "unrest",
1529 + "unsafe",
1530 + "until",
1531 + "unusual",
1532 + "unveil",
1533 + "unwind",
1534 + "unzip",
1535 + "upbeat",
1536 + "upcoming",
1537 + "update",
1538 + "upgrade",
1539 + "uphill",
1540 + "upkeep",
1541 + "upload",
1542 + "upon",
1543 + "upper",
1544 + "upright",
1545 + "upstairs",
1546 + "uptight",
1547 + "upwards",
1548 + "urban",
1549 + "urchins",
1550 + "urgent",
1551 + "usage",
1552 + "useful",
1553 + "usher",
1554 + "using",
1555 + "usual",
1556 + "utensils",
1557 + "utility",
1558 + "utmost",
1559 + "utopia",
1560 + "uttered",
1561 + "vacation",
1562 + "vague",
1563 + "vain",
1564 + "value",
1565 + "vampire",
1566 + "vane",
1567 + "vapidly",
1568 + "vary",
1569 + "vastness",
1570 + "vats",
1571 + "vaults",
1572 + "vector",
1573 + "veered",
1574 + "vegan",
1575 + "vehicle",
1576 + "vein",
1577 + "velvet",
1578 + "venomous",
1579 + "verification",
1580 + "vessel",
1581 + "veteran",
1582 + "vexed",
1583 + "vials",
1584 + "vibrate",
1585 + "victim",
1586 + "video",
1587 + "viewpoint",
1588 + "vigilant",
1589 + "viking",
1590 + "village",
1591 + "vinegar",
1592 + "violin",
1593 + "vipers",
1594 + "virtual",
1595 + "visited",
1596 + "vitals",
1597 + "vivid",
1598 + "vixen",
1599 + "vocal",
1600 + "vogue",
1601 + "voice",
1602 + "volcano",
1603 + "vortex",
1604 + "voted",
1605 + "voucher",
1606 + "vowels",
1607 + "voyage",
1608 + "vulture",
1609 + "wade",
1610 + "waffle",
1611 + "wagtail",
1612 + "waist",
1613 + "waking",
1614 + "wallets",
1615 + "wanted",
1616 + "warped",
1617 + "washing",
1618 + "water",
1619 + "waveform",
1620 + "waxing",
1621 + "wayside",
1622 + "weavers",
1623 + "website",
1624 + "wedge",
1625 + "weekday",
1626 + "weird",
1627 + "welders",
1628 + "went",
1629 + "wept",
1630 + "were",
1631 + "western",
1632 + "wetsuit",
1633 + "whale",
1634 + "when",
1635 + "whipped",
1636 + "whole",
1637 + "wickets",
1638 + "width",
1639 + "wield",
1640 + "wife",
1641 + "wiggle",
1642 + "wildly",
1643 + "winter",
1644 + "wipeout",
1645 + "wiring",
1646 + "wise",
1647 + "withdrawn",
1648 + "wives",
1649 + "wizard",
1650 + "wobbly",
1651 + "woes",
1652 + "woken",
1653 + "wolf",
1654 + "womanly",
1655 + "wonders",
1656 + "woozy",
1657 + "worry",
1658 + "wounded",
1659 + "woven",
1660 + "wrap",
1661 + "wrist",
1662 + "wrong",
1663 + "yacht",
1664 + "yahoo",
1665 + "yanks",
1666 + "yard",
1667 + "yawning",
1668 + "yearbook",
1669 + "yellow",
1670 + "yesterday",
1671 + "yeti",
1672 + "yields",
1673 + "yodel",
1674 + "yoga",
1675 + "younger",
1676 + "yoyo",
1677 + "zapped",
1678 + "zeal",
1679 + "zebra",
1680 + "zero",
1681 + "zesty",
1682 + "zigzags",
1683 + "zinger",
1684 + "zippers",
1685 + "zodiac",
1686 + "zombie",
1687 + "zones",
1688 + "zoom"
1689 +];
cw_wownero/lib/pending_wownero_transaction.dart new
+53
@@ -0,0 +1,53 @@
1 +import 'package:cw_wownero/api/structs/pending_transaction.dart';
2 +import 'package:cw_wownero/api/transaction_history.dart'
3 + as wownero_transaction_history;
4 +import 'package:cw_core/crypto_currency.dart';
5 +import 'package:cw_core/amount_converter.dart';
6 +
7 +import 'package:cw_core/pending_transaction.dart';
8 +
9 +class DoubleSpendException implements Exception {
10 + DoubleSpendException();
11 +
12 + @override
13 + String toString() =>
14 + 'This transaction cannot be committed. This can be due to many reasons including the wallet not being synced, there is not enough WOW in your available balance, or previous transactions are not yet fully processed.';
15 +}
16 +
17 +class PendingWowneroTransaction with PendingTransaction {
18 + PendingWowneroTransaction(this.pendingTransactionDescription);
19 +
20 + final PendingTransactionDescription pendingTransactionDescription;
21 +
22 + @override
23 + String get id => pendingTransactionDescription.hash;
24 +
25 + @override
26 + String get hex => pendingTransactionDescription.hex;
27 +
28 + String get txKey => pendingTransactionDescription.txKey;
29 +
30 + @override
31 + String get amountFormatted =>
32 + AmountConverter.amountIntToString(CryptoCurrency.wow, pendingTransactionDescription.amount);
33 +
34 + @override
35 + String get feeFormatted =>
36 + AmountConverter.amountIntToString(CryptoCurrency.wow, pendingTransactionDescription.fee);
37 +
38 + @override
39 + Future<void> commit() async {
40 + try {
41 + wownero_transaction_history.commitTransactionFromPointerAddress(
42 + address: pendingTransactionDescription.pointerAddress);
43 + } catch (e) {
44 + final message = e.toString();
45 +
46 + if (message.contains('Reason: double spend')) {
47 + throw DoubleSpendException();
48 + }
49 +
50 + rethrow;
51 + }
52 + }
53 +}
cw_wownero/lib/wownero_account_list.dart new
+81
@@ -0,0 +1,81 @@
1 +import 'package:cw_core/wownero_amount_format.dart';
2 +import 'package:mobx/mobx.dart';
3 +import 'package:cw_core/account.dart';
4 +import 'package:cw_wownero/api/account_list.dart' as account_list;
5 +import 'package:monero/wownero.dart' as wownero;
6 +
7 +part 'wownero_account_list.g.dart';
8 +
9 +class WowneroAccountList = WowneroAccountListBase with _$WowneroAccountList;
10 +
11 +abstract class WowneroAccountListBase with Store {
12 + WowneroAccountListBase()
13 + : accounts = ObservableList<Account>(),
14 + _isRefreshing = false,
15 + _isUpdating = false {
16 + refresh();
17 + }
18 +
19 + @observable
20 + ObservableList<Account> accounts;
21 + bool _isRefreshing;
22 + bool _isUpdating;
23 +
24 + void update() async {
25 + if (_isUpdating) {
26 + return;
27 + }
28 +
29 + try {
30 + _isUpdating = true;
31 + refresh();
32 + final accounts = getAll();
33 +
34 + if (accounts.isNotEmpty) {
35 + this.accounts.clear();
36 + this.accounts.addAll(accounts);
37 + }
38 +
39 + _isUpdating = false;
40 + } catch (e) {
41 + _isUpdating = false;
42 + rethrow;
43 + }
44 + }
45 +
46 + List<Account> getAll() => account_list.getAllAccount().map((accountRow) {
47 + final balance = wownero.SubaddressAccountRow_getUnlockedBalance(accountRow);
48 +
49 + return Account(
50 + id: wownero.SubaddressAccountRow_getRowId(accountRow),
51 + label: wownero.SubaddressAccountRow_getLabel(accountRow),
52 + balance: wowneroAmountToString(amount: wownero.Wallet_amountFromString(balance)),
53 + );
54 + }).toList();
55 +
56 + Future<void> addAccount({required String label}) async {
57 + await account_list.addAccount(label: label);
58 + update();
59 + }
60 +
61 + Future<void> setLabelAccount({required int accountIndex, required String label}) async {
62 + await account_list.setLabelForAccount(accountIndex: accountIndex, label: label);
63 + update();
64 + }
65 +
66 + void refresh() {
67 + if (_isRefreshing) {
68 + return;
69 + }
70 +
71 + try {
72 + _isRefreshing = true;
73 + account_list.refreshAccounts();
74 + _isRefreshing = false;
75 + } catch (e) {
76 + _isRefreshing = false;
77 + print(e);
78 + rethrow;
79 + }
80 + }
81 +}
cw_wownero/lib/wownero_subaddress_list.dart new
+162
@@ -0,0 +1,162 @@
1 +import 'package:cw_core/subaddress.dart';
2 +import 'package:cw_wownero/api/coins_info.dart';
3 +import 'package:cw_wownero/api/subaddress_list.dart' as subaddress_list;
4 +import 'package:flutter/services.dart';
5 +import 'package:mobx/mobx.dart';
6 +
7 +part 'wownero_subaddress_list.g.dart';
8 +
9 +class WowneroSubaddressList = WowneroSubaddressListBase with _$WowneroSubaddressList;
10 +
11 +abstract class WowneroSubaddressListBase with Store {
12 + WowneroSubaddressListBase()
13 + : _isRefreshing = false,
14 + _isUpdating = false,
15 + subaddresses = ObservableList<Subaddress>();
16 +
17 + final List<String> _usedAddresses = [];
18 +
19 + @observable
20 + ObservableList<Subaddress> subaddresses;
21 +
22 + bool _isRefreshing;
23 + bool _isUpdating;
24 +
25 + void update({required int accountIndex}) {
26 + refreshCoins(accountIndex);
27 +
28 + if (_isUpdating) {
29 + return;
30 + }
31 +
32 + try {
33 + _isUpdating = true;
34 + refresh(accountIndex: accountIndex);
35 + subaddresses.clear();
36 + subaddresses.addAll(getAll());
37 + _isUpdating = false;
38 + } catch (e) {
39 + _isUpdating = false;
40 + rethrow;
41 + }
42 + }
43 +
44 + List<Subaddress> getAll() {
45 + var subaddresses = subaddress_list.getAllSubaddresses();
46 +
47 + if (subaddresses.length > 2) {
48 + final primary = subaddresses.first;
49 + final rest = subaddresses.sublist(1).reversed;
50 + subaddresses = [primary] + rest.toList();
51 + }
52 +
53 + return subaddresses.map((s) {
54 + final address = s.address;
55 + final label = s.label;
56 + final id = s.addressIndex;
57 + final hasDefaultAddressName =
58 + label.toLowerCase() == 'Primary account'.toLowerCase() ||
59 + label.toLowerCase() == 'Untitled account'.toLowerCase();
60 + final isPrimaryAddress = id == 0 && hasDefaultAddressName;
61 + return Subaddress(
62 + id: id,
63 + address: address,
64 + label: isPrimaryAddress
65 + ? 'Primary address'
66 + : hasDefaultAddressName
67 + ? ''
68 + : label);
69 + }).toList();
70 + }
71 +
72 + Future<void> addSubaddress({required int accountIndex, required String label}) async {
73 + await subaddress_list.addSubaddress(accountIndex: accountIndex, label: label);
74 + update(accountIndex: accountIndex);
75 + }
76 +
77 + Future<void> setLabelSubaddress(
78 + {required int accountIndex, required int addressIndex, required String label}) async {
79 + await subaddress_list.setLabelForSubaddress(
80 + accountIndex: accountIndex, addressIndex: addressIndex, label: label);
81 + update(accountIndex: accountIndex);
82 + }
83 +
84 + void refresh({required int accountIndex}) {
85 + if (_isRefreshing) {
86 + return;
87 + }
88 +
89 + try {
90 + _isRefreshing = true;
91 + subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
92 + _isRefreshing = false;
93 + } on PlatformException catch (e) {
94 + _isRefreshing = false;
95 + print(e);
96 + rethrow;
97 + }
98 + }
99 +
100 + Future<void> updateWithAutoGenerate({
101 + required int accountIndex,
102 + required String defaultLabel,
103 + required List<String> usedAddresses,
104 + }) async {
105 + _usedAddresses.addAll(usedAddresses);
106 + if (_isUpdating) {
107 + return;
108 + }
109 +
110 + try {
111 + _isUpdating = true;
112 + refresh(accountIndex: accountIndex);
113 + subaddresses.clear();
114 + final newSubAddresses =
115 + await _getAllUnusedAddresses(accountIndex: accountIndex, label: defaultLabel);
116 + subaddresses.addAll(newSubAddresses);
117 + } catch (e) {
118 + rethrow;
119 + } finally {
120 + _isUpdating = false;
121 + }
122 + }
123 +
124 + Future<List<Subaddress>> _getAllUnusedAddresses(
125 + {required int accountIndex, required String label}) async {
126 + final allAddresses = subaddress_list.getAllSubaddresses();
127 + final lastAddress = allAddresses.last.address;
128 + if (allAddresses.isEmpty || _usedAddresses.contains(lastAddress)) {
129 + final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label);
130 + if (!isAddressUnused) {
131 + return await _getAllUnusedAddresses(accountIndex: accountIndex, label: label);
132 + }
133 + }
134 +
135 + return allAddresses
136 + .map((s) {
137 + final id = s.addressIndex;
138 + final address = s.address;
139 + final label = s.label;
140 + return Subaddress(
141 + id: id,
142 + address: address,
143 + label: id == 0 &&
144 + label.toLowerCase() == 'Primary account'.toLowerCase()
145 + ? 'Primary address'
146 + : label);
147 + })
148 + .toList();
149 + }
150 +
151 + Future<bool> _newSubaddress({required int accountIndex, required String label}) async {
152 + await subaddress_list.addSubaddress(accountIndex: accountIndex, label: label);
153 +
154 + return subaddress_list
155 + .getAllSubaddresses()
156 + .where((s) {
157 + final address = s.address;
158 + return !_usedAddresses.contains(address);
159 + })
160 + .isNotEmpty;
161 + }
162 +}
cw_wownero/lib/wownero_transaction_creation_credentials.dart new
+9
@@ -0,0 +1,9 @@
1 +import 'package:cw_core/monero_transaction_priority.dart';
2 +import 'package:cw_core/output_info.dart';
3 +
4 +class WowneroTransactionCreationCredentials {
5 + WowneroTransactionCreationCredentials({required this.outputs, required this.priority});
6 +
7 + final List<OutputInfo> outputs;
8 + final MoneroTransactionPriority priority;
9 +}
cw_wownero/lib/wownero_transaction_history.dart new
+28
@@ -0,0 +1,28 @@
1 +import 'dart:core';
2 +import 'package:mobx/mobx.dart';
3 +import 'package:cw_core/transaction_history.dart';
4 +import 'package:cw_wownero/wownero_transaction_info.dart';
5 +
6 +part 'wownero_transaction_history.g.dart';
7 +
8 +class WowneroTransactionHistory = WowneroTransactionHistoryBase
9 + with _$WowneroTransactionHistory;
10 +
11 +abstract class WowneroTransactionHistoryBase
12 + extends TransactionHistoryBase<WowneroTransactionInfo> with Store {
13 + WowneroTransactionHistoryBase() {
14 + transactions = ObservableMap<String, WowneroTransactionInfo>();
15 + }
16 +
17 + @override
18 + Future<void> save() async {}
19 +
20 + @override
21 + void addOne(WowneroTransactionInfo transaction) =>
22 + transactions[transaction.id] = transaction;
23 +
24 + @override
25 + void addMany(Map<String, WowneroTransactionInfo> transactions) =>
26 + this.transactions.addAll(transactions);
27 +
28 +}
cw_wownero/lib/wownero_transaction_info.dart new
+80
@@ -0,0 +1,80 @@
1 +import 'package:cw_core/transaction_info.dart';
2 +import 'package:cw_core/wownero_amount_format.dart';
3 +import 'package:cw_wownero/api/structs/transaction_info_row.dart';
4 +import 'package:cw_core/parseBoolFromString.dart';
5 +import 'package:cw_core/transaction_direction.dart';
6 +import 'package:cw_core/format_amount.dart';
7 +import 'package:cw_wownero/api/transaction_history.dart';
8 +
9 +class WowneroTransactionInfo extends TransactionInfo {
10 + WowneroTransactionInfo(this.id, this.height, this.direction, this.date,
11 + this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee,
12 + this.confirmations);
13 +
14 + WowneroTransactionInfo.fromMap(Map<String, Object?> map)
15 + : id = (map['hash'] ?? '') as String,
16 + height = (map['height'] ?? 0) as int,
17 + direction = map['direction'] != null
18 + ? parseTransactionDirectionFromNumber(map['direction'] as String)
19 + : TransactionDirection.incoming,
20 + date = DateTime.fromMillisecondsSinceEpoch(
21 + (int.tryParse(map['timestamp'] as String? ?? '') ?? 0) * 1000),
22 + isPending = parseBoolFromString(map['isPending'] as String),
23 + amount = map['amount'] as int,
24 + accountIndex = int.parse(map['accountIndex'] as String),
25 + addressIndex = map['addressIndex'] as int,
26 + confirmations = map['confirmations'] as int,
27 + key = getTxKey((map['hash'] ?? '') as String),
28 + fee = map['fee'] as int? ?? 0 {
29 + additionalInfo = <String, dynamic>{
30 + 'key': key,
31 + 'accountIndex': accountIndex,
32 + 'addressIndex': addressIndex
33 + };
34 + }
35 +
36 + WowneroTransactionInfo.fromRow(TransactionInfoRow row)
37 + : id = row.getHash(),
38 + height = row.blockHeight,
39 + direction = parseTransactionDirectionFromInt(row.direction),
40 + date = DateTime.fromMillisecondsSinceEpoch(row.getDatetime() * 1000),
41 + isPending = row.isPending != 0,
42 + amount = row.getAmount(),
43 + accountIndex = row.subaddrAccount,
44 + addressIndex = row.subaddrIndex,
45 + confirmations = row.confirmations,
46 + key = getTxKey(row.getHash()),
47 + fee = row.fee {
48 + additionalInfo = <String, dynamic>{
49 + 'key': key,
50 + 'accountIndex': accountIndex,
51 + 'addressIndex': addressIndex
52 + };
53 + }
54 +
55 + final String id;
56 + final int height;
57 + final TransactionDirection direction;
58 + final DateTime date;
59 + final int accountIndex;
60 + final bool isPending;
61 + final int amount;
62 + final int fee;
63 + final int addressIndex;
64 + final int confirmations;
65 + String? recipientAddress;
66 + String? key;
67 + String? _fiatAmount;
68 +
69 + @override
70 + String amountFormatted() => '${formatAmount(wowneroAmountToString(amount: amount))} WOW';
71 +
72 + @override
73 + String fiatAmount() => _fiatAmount ?? '';
74 +
75 + @override
76 + void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
77 +
78 + @override
79 + String feeFormatted() => '${formatAmount(wowneroAmountToString(amount: fee))} WOW';
80 +}
cw_wownero/lib/wownero_unspent.dart new
+20
@@ -0,0 +1,20 @@
1 +import 'package:cw_core/unspent_transaction_output.dart';
2 +import 'package:cw_wownero/api/structs/coins_info_row.dart';
3 +
4 +class WowneroUnspent extends Unspent {
5 + WowneroUnspent(
6 + String address, String hash, String keyImage, int value, bool isFrozen, this.isUnlocked)
7 + : super(address, hash, value, 0, keyImage) {
8 + this.isFrozen = isFrozen;
9 + }
10 +
11 + factory WowneroUnspent.fromCoinsInfoRow(CoinsInfoRow coinsInfoRow) => WowneroUnspent(
12 + coinsInfoRow.getAddress(),
13 + coinsInfoRow.getHash(),
14 + coinsInfoRow.getKeyImage(),
15 + coinsInfoRow.amount,
16 + coinsInfoRow.frozen == 1,
17 + coinsInfoRow.unlocked == 1);
18 +
19 + final bool isUnlocked;
20 +}
cw_wownero/lib/wownero_wallet.dart new
+747
@@ -0,0 +1,747 @@
1 +import 'dart:async';
2 +import 'dart:ffi';
3 +import 'dart:io';
4 +import 'dart:isolate';
5 +
6 +import 'package:cw_core/account.dart';
7 +import 'package:cw_core/crypto_currency.dart';
8 +import 'package:cw_core/monero_transaction_priority.dart';
9 +import 'package:cw_core/monero_wallet_keys.dart';
10 +import 'package:cw_core/monero_wallet_utils.dart';
11 +import 'package:cw_core/node.dart';
12 +import 'package:cw_core/pathForWallet.dart';
13 +import 'package:cw_core/pending_transaction.dart';
14 +import 'package:cw_core/sync_status.dart';
15 +import 'package:cw_core/transaction_direction.dart';
16 +import 'package:cw_core/transaction_priority.dart';
17 +import 'package:cw_core/unspent_coins_info.dart';
18 +import 'package:cw_core/wallet_base.dart';
19 +import 'package:cw_core/wallet_info.dart';
20 +import 'package:cw_core/wownero_amount_format.dart';
21 +import 'package:cw_core/wownero_balance.dart';
22 +import 'package:cw_wownero/api/coins_info.dart';
23 +import 'package:cw_wownero/api/structs/pending_transaction.dart';
24 +import 'package:cw_wownero/api/transaction_history.dart' as transaction_history;
25 +import 'package:cw_wownero/api/wallet.dart' as wownero_wallet;
26 +import 'package:cw_wownero/api/wallet_manager.dart';
27 +import 'package:cw_wownero/api/wownero_output.dart';
28 +import 'package:cw_wownero/exceptions/wownero_transaction_creation_exception.dart';
29 +import 'package:cw_wownero/exceptions/wownero_transaction_no_inputs_exception.dart';
30 +import 'package:cw_wownero/pending_wownero_transaction.dart';
31 +import 'package:cw_wownero/wownero_transaction_creation_credentials.dart';
32 +import 'package:cw_wownero/wownero_transaction_history.dart';
33 +import 'package:cw_wownero/wownero_transaction_info.dart';
34 +import 'package:cw_wownero/wownero_unspent.dart';
35 +import 'package:cw_wownero/wownero_wallet_addresses.dart';
36 +import 'package:flutter/foundation.dart';
37 +import 'package:hive/hive.dart';
38 +import 'package:mobx/mobx.dart';
39 +import 'package:monero/wownero.dart' as wownero;
40 +
41 +part 'wownero_wallet.g.dart';
42 +
43 +const wowneroBlockSize = 1000;
44 +// not sure if this should just be 0 but setting it higher feels safer / should catch more cases:
45 +const MIN_RESTORE_HEIGHT = 1000;
46 +
47 +class WowneroWallet = WowneroWalletBase with _$WowneroWallet;
48 +
49 +abstract class WowneroWalletBase
50 + extends WalletBase<WowneroBalance, WowneroTransactionHistory, WowneroTransactionInfo>
51 + with Store {
52 + WowneroWalletBase(
53 + {required WalletInfo walletInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo})
54 + : balance = ObservableMap<CryptoCurrency, WowneroBalance>.of({
55 + CryptoCurrency.wow: WowneroBalance(
56 + fullBalance: wownero_wallet.getFullBalance(accountIndex: 0),
57 + unlockedBalance: wownero_wallet.getFullBalance(accountIndex: 0))
58 + }),
59 + _isTransactionUpdating = false,
60 + _hasSyncAfterStartup = false,
61 + isEnabledAutoGenerateSubaddress = false,
62 + syncStatus = NotConnectedSyncStatus(),
63 + unspentCoins = [],
64 + this.unspentCoinsInfo = unspentCoinsInfo,
65 + super(walletInfo) {
66 + transactionHistory = WowneroTransactionHistory();
67 + walletAddresses = WowneroWalletAddresses(walletInfo, transactionHistory);
68 +
69 + _onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) {
70 + if (account == null) return;
71 +
72 + balance = ObservableMap<CryptoCurrency, WowneroBalance>.of(<CryptoCurrency, WowneroBalance>{
73 + currency: WowneroBalance(
74 + fullBalance: wownero_wallet.getFullBalance(accountIndex: account.id),
75 + unlockedBalance: wownero_wallet.getUnlockedBalance(accountIndex: account.id))
76 + });
77 + _updateSubAddress(isEnabledAutoGenerateSubaddress, account: account);
78 + _askForUpdateTransactionHistory();
79 + });
80 +
81 + reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) {
82 + _updateSubAddress(enabled, account: walletAddresses.account);
83 + });
84 + }
85 +
86 + static const int _autoSaveInterval = 30;
87 +
88 + Box<UnspentCoinsInfo> unspentCoinsInfo;
89 +
90 + void Function(FlutterErrorDetails)? onError;
91 +
92 + @override
93 + late WowneroWalletAddresses walletAddresses;
94 +
95 + @override
96 + @observable
97 + bool isEnabledAutoGenerateSubaddress;
98 +
99 + @override
100 + @observable
101 + SyncStatus syncStatus;
102 +
103 + @override
104 + @observable
105 + ObservableMap<CryptoCurrency, WowneroBalance> balance;
106 +
107 + @override
108 + String get seed => wownero_wallet.getSeed();
109 +
110 + String seedLegacy(String? language) {
111 + return wownero_wallet.getSeedLegacy(language);
112 + }
113 +
114 + @override
115 + MoneroWalletKeys get keys => MoneroWalletKeys(
116 + privateSpendKey: wownero_wallet.getSecretSpendKey(),
117 + privateViewKey: wownero_wallet.getSecretViewKey(),
118 + publicSpendKey: wownero_wallet.getPublicSpendKey(),
119 + publicViewKey: wownero_wallet.getPublicViewKey());
120 +
121 + wownero_wallet.SyncListener? _listener;
122 + ReactionDisposer? _onAccountChangeReaction;
123 + bool _isTransactionUpdating;
124 + bool _hasSyncAfterStartup;
125 + Timer? _autoSaveTimer;
126 + List<WowneroUnspent> unspentCoins;
127 +
128 + Future<void> init() async {
129 + await walletAddresses.init();
130 + balance = ObservableMap<CryptoCurrency, WowneroBalance>.of(<CryptoCurrency, WowneroBalance>{
131 + currency: WowneroBalance(
132 + fullBalance: wownero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id),
133 + unlockedBalance:
134 + wownero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id))
135 + });
136 + _setListeners();
137 + await updateTransactions();
138 +
139 + if (walletInfo.isRecovery) {
140 + wownero_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
141 +
142 + if (wownero_wallet.getCurrentHeight() <= 1) {
143 + wownero_wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight);
144 + }
145 + }
146 +
147 + _autoSaveTimer =
148 + Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save());
149 + }
150 +
151 + @override
152 + Future<void>? updateBalance() => null;
153 +
154 + @override
155 + void close() async {
156 + _listener?.stop();
157 + _onAccountChangeReaction?.reaction.dispose();
158 + _autoSaveTimer?.cancel();
159 + }
160 +
161 + @override
162 + Future<void> connectToNode({required Node node}) async {
163 + try {
164 + syncStatus = ConnectingSyncStatus();
165 + await wownero_wallet.setupNode(
166 + address: node.uri.toString(),
167 + login: node.login,
168 + password: node.password,
169 + useSSL: node.isSSL,
170 + isLightWallet: false,
171 + // FIXME: hardcoded value
172 + socksProxyAddress: node.socksProxyAddress);
173 +
174 + wownero_wallet.setTrustedDaemon(node.trusted);
175 + syncStatus = ConnectedSyncStatus();
176 + } catch (e) {
177 + syncStatus = FailedSyncStatus();
178 + print(e);
179 + }
180 + }
181 +
182 + @override
183 + Future<void> startSync() async {
184 + try {
185 + _setInitialHeight();
186 + } catch (_) {
187 + // our restore height wasn't correct, so lets see if using the backup works:
188 + try {
189 + await resetCache(name);
190 + _setInitialHeight();
191 + } catch (e) {
192 + // we still couldn't get a valid height from the backup?!:
193 + // try to use the date instead:
194 + try {
195 + _setHeightFromDate();
196 + } catch (_) {
197 + // we still couldn't get a valid sync height :/
198 + }
199 + }
200 + }
201 +
202 + try {
203 + syncStatus = AttemptingSyncStatus();
204 + wownero_wallet.startRefresh();
205 + _setListeners();
206 + _listener?.start();
207 + } catch (e) {
208 + syncStatus = FailedSyncStatus();
209 + print(e);
210 + rethrow;
211 + }
212 + }
213 +
214 + @override
215 + Future<PendingTransaction> createTransaction(Object credentials) async {
216 + final _credentials = credentials as WowneroTransactionCreationCredentials;
217 + final inputs = <String>[];
218 + final outputs = _credentials.outputs;
219 + final hasMultiDestination = outputs.length > 1;
220 + final unlockedBalance =
221 + wownero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
222 + var allInputsAmount = 0;
223 +
224 + PendingTransactionDescription pendingTransactionDescription;
225 +
226 + if (!(syncStatus is SyncedSyncStatus)) {
227 + throw WowneroTransactionCreationException('The wallet is not synced.');
228 + }
229 +
230 + if (unspentCoins.isEmpty) {
231 + await updateUnspent();
232 + }
233 +
234 + for (final utx in unspentCoins) {
235 + if (utx.isSending) {
236 + allInputsAmount += utx.value;
237 + inputs.add(utx.keyImage!);
238 + }
239 + }
240 + final spendAllCoins = inputs.length == unspentCoins.length;
241 +
242 + if (hasMultiDestination) {
243 + if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
244 + throw WowneroTransactionCreationException(
245 + 'You do not have enough WOW to send this amount.');
246 + }
247 +
248 + final int totalAmount =
249 + outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
250 +
251 + final estimatedFee = calculateEstimatedFee(_credentials.priority, totalAmount);
252 + if (unlockedBalance < totalAmount) {
253 + throw WowneroTransactionCreationException(
254 + 'You do not have enough WOW to send this amount.');
255 + }
256 +
257 + if (!spendAllCoins && (allInputsAmount < totalAmount + estimatedFee)) {
258 + throw WowneroTransactionNoInputsException(inputs.length);
259 + }
260 +
261 + final wowneroOutputs = outputs.map((output) {
262 + final outputAddress = output.isParsedAddress ? output.extractedAddress : output.address;
263 +
264 + return WowneroOutput(
265 + address: outputAddress!, amount: output.cryptoAmount!.replaceAll(',', '.'));
266 + }).toList();
267 +
268 + pendingTransactionDescription = await transaction_history.createTransactionMultDest(
269 + outputs: wowneroOutputs,
270 + priorityRaw: _credentials.priority.serialize(),
271 + accountIndex: walletAddresses.account!.id,
272 + preferredInputs: inputs);
273 + } else {
274 + final output = outputs.first;
275 + final address = output.isParsedAddress ? output.extractedAddress : output.address;
276 + final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
277 + final formattedAmount = output.sendAll ? null : output.formattedCryptoAmount;
278 +
279 + if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
280 + (formattedAmount == null && unlockedBalance <= 0)) {
281 + final formattedBalance = wowneroAmountToString(amount: unlockedBalance);
282 +
283 + throw WowneroTransactionCreationException(
284 + 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
285 + }
286 +
287 + final estimatedFee = calculateEstimatedFee(_credentials.priority, formattedAmount);
288 + if (!spendAllCoins &&
289 + ((formattedAmount != null && allInputsAmount < (formattedAmount + estimatedFee)) ||
290 + formattedAmount == null)) {
291 + throw WowneroTransactionNoInputsException(inputs.length);
292 + }
293 +
294 + pendingTransactionDescription = await transaction_history.createTransaction(
295 + address: address!,
296 + amount: amount,
297 + priorityRaw: _credentials.priority.serialize(),
298 + accountIndex: walletAddresses.account!.id,
299 + preferredInputs: inputs);
300 + }
301 +
302 + return PendingWowneroTransaction(pendingTransactionDescription);
303 + }
304 +
305 + @override
306 + int calculateEstimatedFee(TransactionPriority priority, int? amount) {
307 + // FIXME: hardcoded value;
308 +
309 + if (priority is MoneroTransactionPriority) {
310 + switch (priority) {
311 + case MoneroTransactionPriority.slow:
312 + return 24590000;
313 + case MoneroTransactionPriority.automatic:
314 + return 123050000;
315 + case MoneroTransactionPriority.medium:
316 + return 245029999;
317 + case MoneroTransactionPriority.fast:
318 + return 614530000;
319 + case MoneroTransactionPriority.fastest:
320 + return 26021600000;
321 + }
322 + }
323 +
324 + return 0;
325 + }
326 +
327 + @override
328 + Future<void> save() async {
329 + await walletAddresses.updateUsedSubaddress();
330 +
331 + if (isEnabledAutoGenerateSubaddress) {
332 + walletAddresses.updateUnusedSubaddress(
333 + accountIndex: walletAddresses.account?.id ?? 0,
334 + defaultLabel: walletAddresses.account?.label ?? '');
335 + }
336 +
337 + await walletAddresses.updateAddressesInBox();
338 + await wownero_wallet.store();
339 + try {
340 + await backupWalletFiles(name);
341 + } catch (e) {
342 + print("¯\\_(ツ)_/¯");
343 + print(e);
344 + }
345 + }
346 +
347 + @override
348 + Future<void> renameWalletFiles(String newWalletName) async {
349 + final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
350 + if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) {
351 + // NOTE: this is realistically only required on windows.
352 + print("closing wallet");
353 + final wmaddr = wmPtr.address;
354 + final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address;
355 + await Isolate.run(() {
356 + wownero.WalletManager_closeWallet(
357 + Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
358 + });
359 + openedWalletsByPath.remove("$currentWalletDirPath/$name");
360 + print("wallet closed");
361 + }
362 + try {
363 + // -- rename the waller folder --
364 + final currentWalletDir = Directory(await pathForWalletDir(name: name, type: type));
365 + final newWalletDirPath = await pathForWalletDir(name: newWalletName, type: type);
366 + await currentWalletDir.rename(newWalletDirPath);
367 +
368 + // -- use new waller folder to rename files with old names still --
369 + final renamedWalletPath = newWalletDirPath + '/$name';
370 +
371 + final currentCacheFile = File(renamedWalletPath);
372 + final currentKeysFile = File('$renamedWalletPath.keys');
373 + final currentAddressListFile = File('$renamedWalletPath.address.txt');
374 +
375 + final newWalletPath = await pathForWallet(name: newWalletName, type: type);
376 +
377 + if (currentCacheFile.existsSync()) {
378 + await currentCacheFile.rename(newWalletPath);
379 + }
380 + if (currentKeysFile.existsSync()) {
381 + await currentKeysFile.rename('$newWalletPath.keys');
382 + }
383 + if (currentAddressListFile.existsSync()) {
384 + await currentAddressListFile.rename('$newWalletPath.address.txt');
385 + }
386 +
387 + await backupWalletFiles(newWalletName);
388 + } catch (e) {
389 + final currentWalletPath = await pathForWallet(name: name, type: type);
390 +
391 + final currentCacheFile = File(currentWalletPath);
392 + final currentKeysFile = File('$currentWalletPath.keys');
393 + final currentAddressListFile = File('$currentWalletPath.address.txt');
394 +
395 + final newWalletPath = await pathForWallet(name: newWalletName, type: type);
396 +
397 + // Copies current wallet files into new wallet name's dir and files
398 + if (currentCacheFile.existsSync()) {
399 + await currentCacheFile.copy(newWalletPath);
400 + }
401 + if (currentKeysFile.existsSync()) {
402 + await currentKeysFile.copy('$newWalletPath.keys');
403 + }
404 + if (currentAddressListFile.existsSync()) {
405 + await currentAddressListFile.copy('$newWalletPath.address.txt');
406 + }
407 +
408 + // Delete old name's dir and files
409 + await Directory(currentWalletDirPath).delete(recursive: true);
410 + }
411 + }
412 +
413 + @override
414 + Future<void> changePassword(String password) async => wownero_wallet.setPasswordSync(password);
415 +
416 + Future<int> getNodeHeight() async => wownero_wallet.getNodeHeight();
417 +
418 + Future<bool> isConnected() async => wownero_wallet.isConnected();
419 +
420 + Future<void> setAsRecovered() async {
421 + walletInfo.isRecovery = false;
422 + await walletInfo.save();
423 + }
424 +
425 + @override
426 + Future<void> rescan({required int height}) async {
427 + walletInfo.restoreHeight = height;
428 + walletInfo.isRecovery = true;
429 + wownero_wallet.setRefreshFromBlockHeight(height: height);
430 + wownero_wallet.rescanBlockchainAsync();
431 + await startSync();
432 + _askForUpdateBalance();
433 + walletAddresses.accountList.update();
434 + await _askForUpdateTransactionHistory();
435 + await save();
436 + await walletInfo.save();
437 + }
438 +
439 + Future<void> updateUnspent() async {
440 + try {
441 + refreshCoins(walletAddresses.account!.id);
442 +
443 + unspentCoins.clear();
444 +
445 + final coinCount = countOfCoins();
446 + for (var i = 0; i < coinCount; i++) {
447 + final coin = getCoin(i);
448 + final coinSpent = wownero.CoinsInfo_spent(coin);
449 + if (coinSpent == false) {
450 + final unspent = WowneroUnspent(
451 + wownero.CoinsInfo_address(coin),
452 + wownero.CoinsInfo_hash(coin),
453 + wownero.CoinsInfo_keyImage(coin),
454 + wownero.CoinsInfo_amount(coin),
455 + wownero.CoinsInfo_frozen(coin),
456 + wownero.CoinsInfo_unlocked(coin),
457 + );
458 + if (unspent.hash.isNotEmpty) {
459 + unspent.isChange = transaction_history.getTransaction(unspent.hash) == 1;
460 + }
461 + unspentCoins.add(unspent);
462 + }
463 + }
464 +
465 + if (unspentCoinsInfo.isEmpty) {
466 + unspentCoins.forEach((coin) => _addCoinInfo(coin));
467 + return;
468 + }
469 +
470 + if (unspentCoins.isNotEmpty) {
471 + unspentCoins.forEach((coin) {
472 + final coinInfoList = unspentCoinsInfo.values.where((element) =>
473 + element.walletId.contains(id) &&
474 + element.accountIndex == walletAddresses.account!.id &&
475 + element.keyImage!.contains(coin.keyImage!));
476 +
477 + if (coinInfoList.isNotEmpty) {
478 + final coinInfo = coinInfoList.first;
479 +
480 + coin.isFrozen = coinInfo.isFrozen;
481 + coin.isSending = coinInfo.isSending;
482 + coin.note = coinInfo.note;
483 + } else {
484 + _addCoinInfo(coin);
485 + }
486 + });
487 + }
488 +
489 + await _refreshUnspentCoinsInfo();
490 + _askForUpdateBalance();
491 + } catch (e, s) {
492 + print(e.toString());
493 + onError?.call(FlutterErrorDetails(
494 + exception: e,
495 + stack: s,
496 + library: this.runtimeType.toString(),
497 + ));
498 + }
499 + }
500 +
501 + Future<void> _addCoinInfo(WowneroUnspent coin) async {
502 + final newInfo = UnspentCoinsInfo(
503 + walletId: id,
504 + hash: coin.hash,
505 + isFrozen: coin.isFrozen,
506 + isSending: coin.isSending,
507 + noteRaw: coin.note,
508 + address: coin.address,
509 + value: coin.value,
510 + vout: 0,
511 + keyImage: coin.keyImage,
512 + isChange: coin.isChange,
513 + accountIndex: walletAddresses.account!.id);
514 +
515 + await unspentCoinsInfo.add(newInfo);
516 + }
517 +
518 + Future<void> _refreshUnspentCoinsInfo() async {
519 + try {
520 + final List<dynamic> keys = <dynamic>[];
521 + final currentWalletUnspentCoins = unspentCoinsInfo.values.where((element) =>
522 + element.walletId.contains(id) && element.accountIndex == walletAddresses.account!.id);
523 +
524 + if (currentWalletUnspentCoins.isNotEmpty) {
525 + currentWalletUnspentCoins.forEach((element) {
526 + final existUnspentCoins =
527 + unspentCoins.where((coin) => element.keyImage!.contains(coin.keyImage!));
528 +
529 + if (existUnspentCoins.isEmpty) {
530 + keys.add(element.key);
531 + }
532 + });
533 + }
534 +
535 + if (keys.isNotEmpty) {
536 + await unspentCoinsInfo.deleteAll(keys);
537 + }
538 + } catch (e) {
539 + print(e.toString());
540 + }
541 + }
542 +
543 + String getTransactionAddress(int accountIndex, int addressIndex) =>
544 + wownero_wallet.getAddress(accountIndex: accountIndex, addressIndex: addressIndex);
545 +
546 + @override
547 + Future<Map<String, WowneroTransactionInfo>> fetchTransactions() async {
548 + transaction_history.refreshTransactions();
549 + return _getAllTransactionsOfAccount(walletAddresses.account?.id)
550 + .fold<Map<String, WowneroTransactionInfo>>(<String, WowneroTransactionInfo>{},
551 + (Map<String, WowneroTransactionInfo> acc, WowneroTransactionInfo tx) {
552 + acc[tx.id] = tx;
553 + return acc;
554 + });
555 + }
556 +
557 + Future<void> updateTransactions() async {
558 + try {
559 + if (_isTransactionUpdating) {
560 + return;
561 + }
562 +
563 + _isTransactionUpdating = true;
564 + transactionHistory.clear();
565 + final transactions = await fetchTransactions();
566 + transactionHistory.addMany(transactions);
567 + await transactionHistory.save();
568 + _isTransactionUpdating = false;
569 + } catch (e) {
570 + print(e);
571 + _isTransactionUpdating = false;
572 + }
573 + }
574 +
575 + String getSubaddressLabel(int accountIndex, int addressIndex) =>
576 + wownero_wallet.getSubaddressLabel(accountIndex, addressIndex);
577 +
578 + List<WowneroTransactionInfo> _getAllTransactionsOfAccount(int? accountIndex) =>
579 + transaction_history
580 + .getAllTransactions()
581 + .map(
582 + (row) => WowneroTransactionInfo(
583 + row.hash,
584 + row.blockheight,
585 + row.isSpend ? TransactionDirection.outgoing : TransactionDirection.incoming,
586 + row.timeStamp,
587 + row.isPending,
588 + row.amount,
589 + row.accountIndex,
590 + 0,
591 + row.fee,
592 + row.confirmations,
593 + )..additionalInfo = <String, dynamic>{
594 + 'key': row.key,
595 + 'accountIndex': row.accountIndex,
596 + 'addressIndex': row.addressIndex
597 + },
598 + )
599 + .where((element) => element.accountIndex == (accountIndex ?? 0))
600 + .toList();
601 +
602 + void _setListeners() {
603 + _listener?.stop();
604 + _listener = wownero_wallet.setListeners(_onNewBlock, _onNewTransaction);
605 + }
606 +
607 + // check if the height is correct:
608 + void _setInitialHeight() {
609 + if (walletInfo.isRecovery) {
610 + return;
611 + }
612 +
613 + final height = wownero_wallet.getCurrentHeight();
614 +
615 + if (height > MIN_RESTORE_HEIGHT) {
616 + // the restore height is probably correct, so we do nothing:
617 + return;
618 + }
619 +
620 + throw Exception("height isn't > $MIN_RESTORE_HEIGHT!");
621 + }
622 +
623 + void _setHeightFromDate() {
624 + if (walletInfo.isRecovery) {
625 + return;
626 + }
627 +
628 + int height = 0;
629 + try {
630 + height = _getHeightByDate(walletInfo.date);
631 + } catch (_) {}
632 +
633 + wownero_wallet.setRecoveringFromSeed(isRecovery: true);
634 + wownero_wallet.setRefreshFromBlockHeight(height: height);
635 + }
636 +
637 + int _getHeightDistance(DateTime date) {
638 + final distance = DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
639 + final daysTmp = (distance / 86400).round();
640 + final days = daysTmp < 1 ? 1 : daysTmp;
641 +
642 + return days * 1000;
643 + }
644 +
645 + int _getHeightByDate(DateTime date) {
646 + final nodeHeight = wownero_wallet.getNodeHeightSync();
647 + final heightDistance = _getHeightDistance(date);
648 +
649 + if (nodeHeight <= 0) {
650 + // the node returned 0 (an error state)
651 + throw Exception("nodeHeight is <= 0!");
652 + }
653 +
654 + return nodeHeight - heightDistance;
655 + }
656 +
657 + void _askForUpdateBalance() {
658 + final unlockedBalance = _getUnlockedBalance();
659 + final fullBalance = _getFullBalance();
660 + final frozenBalance = _getFrozenBalance();
661 +
662 + if (balance[currency]!.fullBalance != fullBalance ||
663 + balance[currency]!.unlockedBalance != unlockedBalance ||
664 + balance[currency]!.frozenBalance != frozenBalance) {
665 + balance[currency] = WowneroBalance(
666 + fullBalance: fullBalance, unlockedBalance: unlockedBalance, frozenBalance: frozenBalance);
667 + }
668 + }
669 +
670 + Future<void> _askForUpdateTransactionHistory() async => await updateTransactions();
671 +
672 + int _getFullBalance() => wownero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id);
673 +
674 + int _getUnlockedBalance() =>
675 + wownero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
676 +
677 + int _getFrozenBalance() {
678 + var frozenBalance = 0;
679 +
680 + for (var coin in unspentCoinsInfo.values.where((element) =>
681 + element.walletId == id && element.accountIndex == walletAddresses.account!.id)) {
682 + if (coin.isFrozen) frozenBalance += coin.value;
683 + }
684 +
685 + return frozenBalance;
686 + }
687 +
688 + void _onNewBlock(int height, int blocksLeft, double ptc) async {
689 + try {
690 + if (walletInfo.isRecovery) {
691 + await _askForUpdateTransactionHistory();
692 + _askForUpdateBalance();
693 + walletAddresses.accountList.update();
694 + }
695 +
696 + if (blocksLeft < 100) {
697 + await _askForUpdateTransactionHistory();
698 + _askForUpdateBalance();
699 + walletAddresses.accountList.update();
700 + syncStatus = SyncedSyncStatus();
701 +
702 + if (!_hasSyncAfterStartup) {
703 + _hasSyncAfterStartup = true;
704 + await save();
705 + }
706 +
707 + if (walletInfo.isRecovery) {
708 + await setAsRecovered();
709 + }
710 + } else {
711 + syncStatus = SyncingSyncStatus(blocksLeft, ptc);
712 + }
713 + } catch (e) {
714 + print(e.toString());
715 + }
716 + }
717 +
718 + void _onNewTransaction() async {
719 + try {
720 + await _askForUpdateTransactionHistory();
721 + _askForUpdateBalance();
722 + await Future<void>.delayed(Duration(seconds: 1));
723 + } catch (e) {
724 + print(e.toString());
725 + }
726 + }
727 +
728 + void _updateSubAddress(bool enableAutoGenerate, {Account? account}) {
729 + if (enableAutoGenerate) {
730 + walletAddresses.updateUnusedSubaddress(
731 + accountIndex: account?.id ?? 0,
732 + defaultLabel: account?.label ?? '',
733 + );
734 + } else {
735 + walletAddresses.updateSubaddressList(accountIndex: account?.id ?? 0);
736 + }
737 + }
738 +
739 + @override
740 + void setExceptionHandler(void Function(FlutterErrorDetails) e) => onError = e;
741 +
742 + @override
743 + Future<String> signMessage(String message, {String? address}) async {
744 + final useAddress = address ?? "";
745 + return wownero_wallet.signMessage(message, address: useAddress);
746 + }
747 +}
cw_wownero/lib/wownero_wallet_addresses.dart new
+119
@@ -0,0 +1,119 @@
1 +import 'package:cw_core/account.dart';
2 +import 'package:cw_core/address_info.dart';
3 +import 'package:cw_core/subaddress.dart';
4 +import 'package:cw_core/wallet_addresses.dart';
5 +import 'package:cw_core/wallet_info.dart';
6 +import 'package:cw_wownero/api/wallet.dart';
7 +import 'package:cw_wownero/wownero_account_list.dart';
8 +import 'package:cw_wownero/wownero_subaddress_list.dart';
9 +import 'package:cw_wownero/wownero_transaction_history.dart';
10 +import 'package:mobx/mobx.dart';
11 +
12 +part 'wownero_wallet_addresses.g.dart';
13 +
14 +class WowneroWalletAddresses = WowneroWalletAddressesBase with _$WowneroWalletAddresses;
15 +
16 +abstract class WowneroWalletAddressesBase extends WalletAddresses with Store {
17 + WowneroWalletAddressesBase(
18 + WalletInfo walletInfo, WowneroTransactionHistory wowneroTransactionHistory)
19 + : accountList = WowneroAccountList(),
20 + _wowneroTransactionHistory = wowneroTransactionHistory,
21 + subaddressList = WowneroSubaddressList(),
22 + address = '',
23 + super(walletInfo);
24 +
25 + final WowneroTransactionHistory _wowneroTransactionHistory;
26 + @override
27 + @observable
28 + String address;
29 +
30 + @observable
31 + Account? account;
32 +
33 + @observable
34 + Subaddress? subaddress;
35 +
36 + WowneroSubaddressList subaddressList;
37 +
38 + WowneroAccountList accountList;
39 +
40 + @override
41 + Future<void> init() async {
42 + accountList.update();
43 + account = accountList.accounts.first;
44 + updateSubaddressList(accountIndex: account?.id ?? 0);
45 + await updateAddressesInBox();
46 + }
47 +
48 + @override
49 + Future<void> updateAddressesInBox() async {
50 + try {
51 + final _subaddressList = WowneroSubaddressList();
52 +
53 + addressesMap.clear();
54 + addressInfos.clear();
55 +
56 + accountList.accounts.forEach((account) {
57 + _subaddressList.update(accountIndex: account.id);
58 + _subaddressList.subaddresses.forEach((subaddress) {
59 + addressesMap[subaddress.address] = subaddress.label;
60 + addressInfos[account.id] ??= [];
61 + addressInfos[account.id]?.add(AddressInfo(
62 + address: subaddress.address, label: subaddress.label, accountIndex: account.id));
63 + });
64 + });
65 +
66 + await saveAddressesInBox();
67 + } catch (e) {
68 + print(e.toString());
69 + }
70 + }
71 +
72 + bool validate() {
73 + accountList.update();
74 + final accountListLength = accountList.accounts.length;
75 +
76 + if (accountListLength <= 0) {
77 + return false;
78 + }
79 +
80 + subaddressList.update(accountIndex: accountList.accounts.first.id);
81 + final subaddressListLength = subaddressList.subaddresses.length;
82 +
83 + if (subaddressListLength <= 0) {
84 + return false;
85 + }
86 +
87 + return true;
88 + }
89 +
90 + void updateSubaddressList({required int accountIndex}) {
91 + subaddressList.update(accountIndex: accountIndex);
92 + subaddress = subaddressList.subaddresses.first;
93 + address = subaddress!.address;
94 + }
95 +
96 + Future<void> updateUsedSubaddress() async {
97 + final transactions = _wowneroTransactionHistory.transactions.values.toList();
98 +
99 + transactions.forEach((element) {
100 + final accountIndex = element.accountIndex;
101 + final addressIndex = element.addressIndex;
102 + usedAddresses.add(getAddress(accountIndex: accountIndex, addressIndex: addressIndex));
103 + });
104 + }
105 +
106 + Future<void> updateUnusedSubaddress(
107 + {required int accountIndex, required String defaultLabel}) async {
108 + await subaddressList.updateWithAutoGenerate(
109 + accountIndex: accountIndex,
110 + defaultLabel: defaultLabel,
111 + usedAddresses: usedAddresses.toList());
112 + subaddress = subaddressList.subaddresses.last;
113 + address = subaddress!.address;
114 + }
115 +
116 + @override
117 + bool containsAddress(String address) =>
118 + addressInfos[account?.id ?? 0]?.any((it) => it.address == address) ?? false;
119 +}
cw_wownero/lib/wownero_wallet_service.dart new
+354
@@ -0,0 +1,354 @@
1 +import 'dart:ffi';
2 +import 'dart:io';
3 +import 'package:cw_core/monero_wallet_utils.dart';
4 +import 'package:cw_core/pathForWallet.dart';
5 +import 'package:cw_core/unspent_coins_info.dart';
6 +import 'package:cw_core/wallet_base.dart';
7 +import 'package:cw_core/wallet_credentials.dart';
8 +import 'package:cw_core/wallet_info.dart';
9 +import 'package:cw_core/wallet_service.dart';
10 +import 'package:cw_core/wallet_type.dart';
11 +import 'package:cw_core/get_height_by_date.dart';
12 +import 'package:cw_wownero/api/exceptions/wallet_opening_exception.dart';
13 +import 'package:cw_wownero/api/wallet_manager.dart' as wownero_wallet_manager;
14 +import 'package:cw_wownero/api/wallet_manager.dart';
15 +import 'package:cw_wownero/wownero_wallet.dart';
16 +import 'package:flutter/widgets.dart';
17 +import 'package:hive/hive.dart';
18 +import 'package:polyseed/polyseed.dart';
19 +import 'package:monero/wownero.dart' as wownero;
20 +
21 +class WowneroNewWalletCredentials extends WalletCredentials {
22 + WowneroNewWalletCredentials(
23 + {required String name, required this.language, required this.isPolyseed, String? password})
24 + : super(name: name, password: password);
25 +
26 + final String language;
27 + final bool isPolyseed;
28 +}
29 +
30 +class WowneroRestoreWalletFromSeedCredentials extends WalletCredentials {
31 + WowneroRestoreWalletFromSeedCredentials(
32 + {required String name, required this.mnemonic, int height = 0, String? password})
33 + : super(name: name, password: password, height: height);
34 +
35 + final String mnemonic;
36 +}
37 +
38 +class WowneroWalletLoadingException implements Exception {
39 + @override
40 + String toString() => 'Failure to load the wallet.';
41 +}
42 +
43 +class WowneroRestoreWalletFromKeysCredentials extends WalletCredentials {
44 + WowneroRestoreWalletFromKeysCredentials(
45 + {required String name,
46 + required String password,
47 + required this.language,
48 + required this.address,
49 + required this.viewKey,
50 + required this.spendKey,
51 + int height = 0})
52 + : super(name: name, password: password, height: height);
53 +
54 + final String language;
55 + final String address;
56 + final String viewKey;
57 + final String spendKey;
58 +}
59 +
60 +class WowneroWalletService extends WalletService<
61 + WowneroNewWalletCredentials,
62 + WowneroRestoreWalletFromSeedCredentials,
63 + WowneroRestoreWalletFromKeysCredentials,
64 + WowneroNewWalletCredentials> {
65 + WowneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
66 +
67 + final Box<WalletInfo> walletInfoSource;
68 + final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
69 +
70 + static bool walletFilesExist(String path) =>
71 + !File(path).existsSync() && !File('$path.keys').existsSync();
72 +
73 + @override
74 + WalletType getType() => WalletType.wownero;
75 +
76 + @override
77 + Future<WowneroWallet> create(WowneroNewWalletCredentials credentials, {bool? isTestnet}) async {
78 + try {
79 + final path = await pathForWallet(name: credentials.name, type: getType());
80 +
81 + if (credentials.isPolyseed) {
82 + final polyseed = Polyseed.create();
83 + final lang = PolyseedLang.getByEnglishName(credentials.language);
84 +
85 + final heightOverride =
86 + getWowneroHeightByDate(date: DateTime.now().subtract(Duration(days: 2)));
87 +
88 + return _restoreFromPolyseed(
89 + path, credentials.password!, polyseed, credentials.walletInfo!, lang,
90 + overrideHeight: heightOverride);
91 + }
92 +
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);
97 + await wallet.init();
98 +
99 + return wallet;
100 + } catch (e) {
101 + // TODO: Implement Exception for wallet list service.
102 + print('WowneroWalletsManager Error: ${e.toString()}');
103 + rethrow;
104 + }
105 + }
106 +
107 + @override
108 + Future<bool> isWalletExit(String name) async {
109 + try {
110 + final path = await pathForWallet(name: name, type: getType());
111 + return wownero_wallet_manager.isWalletExist(path: path);
112 + } catch (e) {
113 + // TODO: Implement Exception for wallet list service.
114 + print('WowneroWalletsManager Error: $e');
115 + rethrow;
116 + }
117 + }
118 +
119 + @override
120 + Future<WowneroWallet> openWallet(String name, String password) async {
121 + WowneroWallet? wallet;
122 + try {
123 + final path = await pathForWallet(name: name, type: getType());
124 +
125 + if (walletFilesExist(path)) {
126 + await repairOldAndroidWallet(name);
127 + }
128 +
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);
133 + final isValid = wallet.walletAddresses.validate();
134 +
135 + if (!isValid) {
136 + await restoreOrResetWalletFiles(name);
137 + wallet.close();
138 + return openWallet(name, password);
139 + }
140 +
141 + await wallet.init();
142 +
143 + return wallet;
144 + } catch (e, s) {
145 + // TODO: Implement Exception for wallet list service.
146 +
147 + final bool isBadAlloc = e.toString().contains('bad_alloc') ||
148 + (e is WalletOpeningException &&
149 + (e.message == 'std::bad_alloc' || e.message.contains('bad_alloc')));
150 +
151 + final bool doesNotCorrespond = e.toString().contains('does not correspond') ||
152 + (e is WalletOpeningException && e.message.contains('does not correspond'));
153 +
154 + final bool isMissingCacheFilesIOS = e.toString().contains('basic_string') ||
155 + (e is WalletOpeningException && e.message.contains('basic_string'));
156 +
157 + final bool isMissingCacheFilesAndroid = e.toString().contains('input_stream') ||
158 + e.toString().contains('input stream error') ||
159 + (e is WalletOpeningException &&
160 + (e.message.contains('input_stream') || e.message.contains('input stream error')));
161 +
162 + final bool invalidSignature = e.toString().contains('invalid signature') ||
163 + (e is WalletOpeningException && e.message.contains('invalid signature'));
164 +
165 + if (!isBadAlloc &&
166 + !doesNotCorrespond &&
167 + !isMissingCacheFilesIOS &&
168 + !isMissingCacheFilesAndroid &&
169 + !invalidSignature &&
170 + wallet != null &&
171 + wallet.onError != null) {
172 + wallet.onError!(FlutterErrorDetails(exception: e, stack: s));
173 + }
174 +
175 + await restoreOrResetWalletFiles(name);
176 + return openWallet(name, password);
177 + }
178 + }
179 +
180 + @override
181 + Future<void> remove(String wallet) async {
182 + final path = await pathForWalletDir(name: wallet, type: getType());
183 + if (openedWalletsByPath["$path/$wallet"] != null) {
184 + // NOTE: this is realistically only required on windows.
185 + print("closing wallet");
186 + final wmaddr = wmPtr.address;
187 + final waddr = openedWalletsByPath["$path/$wallet"]!.address;
188 + // await Isolate.run(() {
189 + wownero.WalletManager_closeWallet(
190 + Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), false);
191 + // });
192 + openedWalletsByPath.remove("$path/$wallet");
193 + print("wallet closed");
194 + }
195 +
196 + final file = Directory(path);
197 + final isExist = file.existsSync();
198 +
199 + if (isExist) {
200 + await file.delete(recursive: true);
201 + }
202 +
203 + final walletInfo = walletInfoSource.values
204 + .firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
205 + await walletInfoSource.delete(walletInfo.key);
206 + }
207 +
208 + @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 + WowneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
214 +
215 + await currentWallet.renameWalletFiles(newName);
216 +
217 + final newWalletInfo = currentWalletInfo;
218 + newWalletInfo.id = WalletBase.idFor(newName, getType());
219 + newWalletInfo.name = newName;
220 +
221 + await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
222 + }
223 +
224 + @override
225 + Future<WowneroWallet> restoreFromKeys(WowneroRestoreWalletFromKeysCredentials credentials,
226 + {bool? isTestnet}) async {
227 + try {
228 + final path = await pathForWallet(name: credentials.name, type: getType());
229 + await wownero_wallet_manager.restoreFromKeys(
230 + path: path,
231 + password: credentials.password!,
232 + language: credentials.language,
233 + restoreHeight: credentials.height!,
234 + address: credentials.address,
235 + viewKey: credentials.viewKey,
236 + spendKey: credentials.spendKey);
237 + final wallet = WowneroWallet(
238 + walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
239 + await wallet.init();
240 +
241 + return wallet;
242 + } catch (e) {
243 + // TODO: Implement Exception for wallet list service.
244 + print('WowneroWalletsManager Error: $e');
245 + rethrow;
246 + }
247 + }
248 +
249 + @override
250 + Future<WowneroWallet> restoreFromHardwareWallet(WowneroNewWalletCredentials credentials) {
251 + throw UnimplementedError(
252 + "Restoring a Wownero wallet from a hardware wallet is not yet supported!");
253 + }
254 +
255 + @override
256 + Future<WowneroWallet> restoreFromSeed(WowneroRestoreWalletFromSeedCredentials credentials,
257 + {bool? isTestnet}) async {
258 + // Restore from Polyseed
259 + if (Polyseed.isValidSeed(credentials.mnemonic)) {
260 + return restoreFromPolyseed(credentials);
261 + }
262 +
263 + try {
264 + final path = await pathForWallet(name: credentials.name, type: getType());
265 + await wownero_wallet_manager.restoreFromSeed(
266 + path: path,
267 + password: credentials.password!,
268 + seed: credentials.mnemonic,
269 + restoreHeight: credentials.height!);
270 + final wallet = WowneroWallet(
271 + walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource);
272 + await wallet.init();
273 +
274 + return wallet;
275 + } catch (e) {
276 + // TODO: Implement Exception for wallet list service.
277 + print('WowneroWalletsManager Error: $e');
278 + rethrow;
279 + }
280 + }
281 +
282 + Future<WowneroWallet> restoreFromPolyseed(
283 + WowneroRestoreWalletFromSeedCredentials credentials) async {
284 + try {
285 + final path = await pathForWallet(name: credentials.name, type: getType());
286 + final polyseedCoin = PolyseedCoin.POLYSEED_WOWNERO;
287 + final lang = PolyseedLang.getByPhrase(credentials.mnemonic);
288 + final polyseed = Polyseed.decode(credentials.mnemonic, lang, polyseedCoin);
289 +
290 + return _restoreFromPolyseed(
291 + path, credentials.password!, polyseed, credentials.walletInfo!, lang);
292 + } catch (e) {
293 + // TODO: Implement Exception for wallet list service.
294 + print('WowneroWalletsManager Error: $e');
295 + rethrow;
296 + }
297 + }
298 +
299 + Future<WowneroWallet> _restoreFromPolyseed(
300 + String path, String password, Polyseed polyseed, WalletInfo walletInfo, PolyseedLang lang,
301 + {PolyseedCoin coin = PolyseedCoin.POLYSEED_WOWNERO, int? overrideHeight}) async {
302 + final height = overrideHeight ??
303 + getWowneroHeightByDate(date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
304 + final spendKey = polyseed.generateKey(coin, 32).toHexString();
305 + final seed = polyseed.encode(lang, coin);
306 +
307 + walletInfo.isRecovery = true;
308 + walletInfo.restoreHeight = height;
309 +
310 + await wownero_wallet_manager.restoreFromSpendKey(
311 + path: path,
312 + password: password,
313 + seed: seed,
314 + language: lang.nameEnglish,
315 + restoreHeight: height,
316 + spendKey: spendKey);
317 +
318 + final wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
319 + await wallet.init();
320 +
321 + return wallet;
322 + }
323 +
324 + Future<void> repairOldAndroidWallet(String name) async {
325 + try {
326 + if (!Platform.isAndroid) {
327 + return;
328 + }
329 +
330 + final oldAndroidWalletDirPath = await outdatedAndroidPathForWalletDir(name: name);
331 + final dir = Directory(oldAndroidWalletDirPath);
332 +
333 + if (!dir.existsSync()) {
334 + return;
335 + }
336 +
337 + final newWalletDirPath = await pathForWalletDir(name: name, type: getType());
338 +
339 + dir.listSync().forEach((f) {
340 + final file = File(f.path);
341 + final name = f.path.split('/').last;
342 + final newPath = newWalletDirPath + '/$name';
343 + final newFile = File(newPath);
344 +
345 + if (!newFile.existsSync()) {
346 + newFile.createSync();
347 + }
348 + newFile.writeAsBytesSync(file.readAsBytesSync());
349 + });
350 + } catch (e) {
351 + print(e.toString());
352 + }
353 + }
354 +}
cw_wownero/pubspec.lock renamed
+332 -42
@@ -1,6 +1,22 @@
1 # Generated by pub
2 # See https://dart.dev/tools/pub/glossary#lockfile
3 packages:
4 + _fe_analyzer_shared:
5 + dependency: transitive
6 + description:
7 + name: _fe_analyzer_shared
8 + sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
9 + url: "https://pub.dev"
10 + source: hosted
11 + version: "47.0.0"
12 + analyzer:
13 + dependency: transitive
14 + description:
15 + name: analyzer
16 + sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
17 + url: "https://pub.dev"
18 + source: hosted
19 + version: "4.7.0"
20 args:
21 dependency: transitive
22 description:
@@ -33,6 +49,70 @@ packages:
49 url: "https://pub.dev"
50 source: hosted
51 version: "2.1.1"
52 + build:
53 + dependency: transitive
54 + description:
55 + name: build
56 + sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777"
57 + url: "https://pub.dev"
58 + source: hosted
59 + version: "2.3.1"
60 + build_config:
61 + dependency: transitive
62 + description:
63 + name: build_config
64 + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
65 + url: "https://pub.dev"
66 + source: hosted
67 + version: "1.1.1"
68 + build_daemon:
69 + dependency: transitive
70 + description:
71 + name: build_daemon
72 + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65"
73 + url: "https://pub.dev"
74 + source: hosted
75 + version: "4.0.0"
76 + build_resolvers:
77 + dependency: "direct dev"
78 + description:
79 + name: build_resolvers
80 + sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
81 + url: "https://pub.dev"
82 + source: hosted
83 + version: "2.0.10"
84 + build_runner:
85 + dependency: "direct dev"
86 + description:
87 + name: build_runner
88 + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22"
89 + url: "https://pub.dev"
90 + source: hosted
91 + version: "2.4.9"
92 + build_runner_core:
93 + dependency: transitive
94 + description:
95 + name: build_runner_core
96 + sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
97 + url: "https://pub.dev"
98 + source: hosted
99 + version: "7.2.7"
100 + built_collection:
101 + dependency: transitive
102 + description:
103 + name: built_collection
104 + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
105 + url: "https://pub.dev"
106 + source: hosted
107 + version: "5.1.1"
108 + built_value:
109 + dependency: transitive
110 + description:
111 + name: built_value
112 + sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725"
113 + url: "https://pub.dev"
114 + source: hosted
115 + version: "8.4.3"
116 characters:
117 dependency: transitive
118 description:
@@ -41,6 +121,14 @@ packages:
121 url: "https://pub.dev"
122 source: hosted
123 version: "1.3.0"
124 + checked_yaml:
125 + dependency: transitive
126 + description:
127 + name: checked_yaml
128 + sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311"
129 + url: "https://pub.dev"
130 + source: hosted
131 + version: "2.0.2"
132 clock:
133 dependency: transitive
134 description:
@@ -49,6 +137,14 @@ packages:
137 url: "https://pub.dev"
138 source: hosted
139 version: "1.1.1"
140 + code_builder:
141 + dependency: transitive
142 + description:
143 + name: code_builder
144 + sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
145 + url: "https://pub.dev"
146 + source: hosted
147 + version: "4.4.0"
148 collection:
149 dependency: transitive
150 description:
@@ -73,30 +169,23 @@ packages:
169 url: "https://pub.dev"
170 source: hosted
171 version: "3.0.2"
76 - cupertino_icons:
77 - dependency: "direct main"
78 - description:
79 - name: cupertino_icons
80 - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
81 - url: "https://pub.dev"
82 - source: hosted
83 - version: "1.0.5"
172 cw_core:
85 - dependency: transitive
86 - description:
87 - path: "../../cw_core"
88 - relative: true
89 - source: path
90 - version: "0.0.1"
91 - cw_monero:
173 dependency: "direct main"
174 description:
94 - path: ".."
175 + path: "../cw_core"
176 relative: true
177 source: path
178 version: "0.0.1"
98 - encrypt:
179 + dart_style:
180 dependency: transitive
181 + description:
182 + name: dart_style
183 + sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
184 + url: "https://pub.dev"
185 + source: hosted
186 + version: "2.2.4"
187 + encrypt:
188 + dependency: "direct main"
189 description:
190 name: encrypt
191 sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
@@ -112,13 +201,13 @@ packages:
201 source: hosted
202 version: "1.3.1"
203 ffi:
115 - dependency: transitive
204 + dependency: "direct main"
205 description:
206 name: ffi
118 - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
207 + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
208 url: "https://pub.dev"
209 source: hosted
121 - version: "2.0.1"
210 + version: "2.1.0"
211 file:
212 dependency: transitive
213 description:
@@ -127,21 +216,21 @@ packages:
216 url: "https://pub.dev"
217 source: hosted
218 version: "6.1.4"
219 + fixnum:
220 + dependency: transitive
221 + description:
222 + name: fixnum
223 + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
224 + url: "https://pub.dev"
225 + source: hosted
226 + version: "1.1.0"
227 flutter:
228 dependency: "direct main"
229 description: flutter
230 source: sdk
231 version: "0.0.0"
135 - flutter_lints:
136 - dependency: "direct dev"
137 - description:
138 - name: flutter_lints
139 - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
140 - url: "https://pub.dev"
141 - source: hosted
142 - version: "2.0.1"
232 flutter_mobx:
144 - dependency: transitive
233 + dependency: "direct main"
234 description:
235 name: flutter_mobx
236 sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e"
@@ -153,6 +242,30 @@ packages:
242 description: flutter
243 source: sdk
244 version: "0.0.0"
245 + frontend_server_client:
246 + dependency: transitive
247 + description:
248 + name: frontend_server_client
249 + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
250 + url: "https://pub.dev"
251 + source: hosted
252 + version: "3.2.0"
253 + glob:
254 + dependency: transitive
255 + description:
256 + name: glob
257 + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
258 + url: "https://pub.dev"
259 + source: hosted
260 + version: "2.1.1"
261 + graphs:
262 + dependency: transitive
263 + description:
264 + name: graphs
265 + sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2
266 + url: "https://pub.dev"
267 + source: hosted
268 + version: "2.2.0"
269 hashlib:
270 dependency: transitive
271 description:
@@ -169,14 +282,38 @@ packages:
282 url: "https://pub.dev"
283 source: hosted
284 version: "2.2.0"
172 - http:
285 + hive:
286 dependency: transitive
287 + description:
288 + name: hive
289 + sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
290 + url: "https://pub.dev"
291 + source: hosted
292 + version: "2.2.3"
293 + hive_generator:
294 + dependency: "direct dev"
295 + description:
296 + name: hive_generator
297 + sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
298 + url: "https://pub.dev"
299 + source: hosted
300 + version: "1.1.3"
301 + http:
302 + dependency: "direct main"
303 description:
304 name: http
305 sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
306 url: "https://pub.dev"
307 source: hosted
308 version: "1.1.0"
309 + http_multi_server:
310 + dependency: transitive
311 + description:
312 + name: http_multi_server
313 + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
314 + url: "https://pub.dev"
315 + source: hosted
316 + version: "3.2.1"
317 http_parser:
318 dependency: transitive
319 description:
@@ -186,13 +323,21 @@ packages:
323 source: hosted
324 version: "4.0.2"
325 intl:
189 - dependency: transitive
326 + dependency: "direct main"
327 description:
328 name: intl
329 sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
330 url: "https://pub.dev"
331 source: hosted
332 version: "0.18.1"
333 + io:
334 + dependency: transitive
335 + description:
336 + name: io
337 + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
338 + url: "https://pub.dev"
339 + source: hosted
340 + version: "1.0.4"
341 js:
342 dependency: transitive
343 description:
@@ -201,6 +346,14 @@ packages:
346 url: "https://pub.dev"
347 source: hosted
348 version: "0.6.7"
349 + json_annotation:
350 + dependency: transitive
351 + description:
352 + name: json_annotation
353 + sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
354 + url: "https://pub.dev"
355 + source: hosted
356 + version: "4.8.0"
357 leak_tracker:
358 dependency: transitive
359 description:
@@ -225,14 +378,14 @@ packages:
378 url: "https://pub.dev"
379 source: hosted
380 version: "2.0.1"
228 - lints:
381 + logging:
382 dependency: transitive
383 description:
231 - name: lints
232 - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
384 + name: logging
385 + sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
386 url: "https://pub.dev"
387 source: hosted
235 - version: "2.0.1"
388 + version: "1.1.1"
389 matcher:
390 dependency: transitive
391 description:
@@ -257,14 +410,55 @@ packages:
410 url: "https://pub.dev"
411 source: hosted
412 version: "1.11.0"
260 - mobx:
413 + mime:
414 dependency: transitive
415 + description:
416 + name: mime
417 + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
418 + url: "https://pub.dev"
419 + source: hosted
420 + version: "1.0.4"
421 + mobx:
422 + dependency: "direct main"
423 description:
424 name: mobx
425 sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a
426 url: "https://pub.dev"
427 source: hosted
428 version: "2.1.3+1"
429 + mobx_codegen:
430 + dependency: "direct dev"
431 + description:
432 + name: mobx_codegen
433 + sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181"
434 + url: "https://pub.dev"
435 + source: hosted
436 + version: "2.1.1"
437 + monero:
438 + dependency: "direct main"
439 + description:
440 + path: "."
441 + ref: d46753eca865e9e56c2f0ef6fe485c42e11982c5
442 + resolved-ref: d46753eca865e9e56c2f0ef6fe485c42e11982c5
443 + url: "https://github.com/mrcyjanek/monero.dart"
444 + source: git
445 + version: "0.0.0"
446 + mutex:
447 + dependency: "direct main"
448 + description:
449 + name: mutex
450 + sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2"
451 + url: "https://pub.dev"
452 + source: hosted
453 + version: "3.1.0"
454 + package_config:
455 + dependency: transitive
456 + description:
457 + name: package_config
458 + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
459 + url: "https://pub.dev"
460 + source: hosted
461 + version: "2.1.0"
462 path:
463 dependency: transitive
464 description:
@@ -274,7 +468,7 @@ packages:
468 source: hosted
469 version: "1.9.0"
470 path_provider:
277 - dependency: transitive
471 + dependency: "direct main"
472 description:
473 name: path_provider
474 sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
@@ -346,13 +540,21 @@ packages:
540 source: hosted
541 version: "3.7.3"
542 polyseed:
349 - dependency: transitive
543 + dependency: "direct main"
544 description:
545 name: polyseed
352 - sha256: "9b48ec535b10863f78f6354ec983b4cc0c88ca69ff48fee469d0fd1954b01d4f"
546 + sha256: a340962242d7917b0f3e6bd02c4acc3f90eae8ff766f1244f793ae7a6414dd68
547 + url: "https://pub.dev"
548 + source: hosted
549 + version: "0.0.4"
550 + pool:
551 + dependency: transitive
552 + description:
553 + name: pool
554 + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
555 url: "https://pub.dev"
556 source: hosted
355 - version: "0.0.2"
557 + version: "1.5.1"
558 process:
559 dependency: transitive
560 description:
@@ -361,6 +563,38 @@ packages:
563 url: "https://pub.dev"
564 source: hosted
565 version: "4.2.4"
566 + pub_semver:
567 + dependency: transitive
568 + description:
569 + name: pub_semver
570 + sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
571 + url: "https://pub.dev"
572 + source: hosted
573 + version: "2.1.3"
574 + pubspec_parse:
575 + dependency: transitive
576 + description:
577 + name: pubspec_parse
578 + sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a"
579 + url: "https://pub.dev"
580 + source: hosted
581 + version: "1.2.1"
582 + shelf:
583 + dependency: transitive
584 + description:
585 + name: shelf
586 + sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
587 + url: "https://pub.dev"
588 + source: hosted
589 + version: "1.4.0"
590 + shelf_web_socket:
591 + dependency: transitive
592 + description:
593 + name: shelf_web_socket
594 + sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
595 + url: "https://pub.dev"
596 + source: hosted
597 + version: "1.0.3"
598 sky_engine:
599 dependency: transitive
600 description: flutter
@@ -374,6 +608,22 @@ packages:
608 url: "https://pub.dev"
609 source: hosted
610 version: "1.0.4"
611 + source_gen:
612 + dependency: transitive
613 + description:
614 + name: source_gen
615 + sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
616 + url: "https://pub.dev"
617 + source: hosted
618 + version: "1.2.6"
619 + source_helper:
620 + dependency: transitive
621 + description:
622 + name: source_helper
623 + sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
624 + url: "https://pub.dev"
625 + source: hosted
626 + version: "1.3.3"
627 source_span:
628 dependency: transitive
629 description:
@@ -398,6 +648,14 @@ packages:
648 url: "https://pub.dev"
649 source: hosted
650 version: "2.1.2"
651 + stream_transform:
652 + dependency: transitive
653 + description:
654 + name: stream_transform
655 + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
656 + url: "https://pub.dev"
657 + source: hosted
658 + version: "2.1.0"
659 string_scanner:
660 dependency: transitive
661 description:
@@ -422,6 +680,14 @@ packages:
680 url: "https://pub.dev"
681 source: hosted
682 version: "0.6.1"
683 + timing:
684 + dependency: transitive
685 + description:
686 + name: timing
687 + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
688 + url: "https://pub.dev"
689 + source: hosted
690 + version: "1.0.1"
691 typed_data:
692 dependency: transitive
693 description:
@@ -446,14 +712,30 @@ packages:
712 url: "https://pub.dev"
713 source: hosted
714 version: "13.0.0"
715 + watcher:
716 + dependency: "direct overridden"
717 + description:
718 + name: watcher
719 + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
720 + url: "https://pub.dev"
721 + source: hosted
722 + version: "1.1.0"
723 + web_socket_channel:
724 + dependency: transitive
725 + description:
726 + name: web_socket_channel
727 + sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
728 + url: "https://pub.dev"
729 + source: hosted
730 + version: "2.3.0"
731 win32:
732 dependency: transitive
733 description:
734 name: win32
453 - sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4
735 + sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
736 url: "https://pub.dev"
737 source: hosted
456 - version: "3.1.4"
738 + version: "3.1.3"
739 xdg_directories:
740 dependency: transitive
741 description:
@@ -462,6 +744,14 @@ packages:
744 url: "https://pub.dev"
745 source: hosted
746 version: "0.2.0+3"
747 + yaml:
748 + dependency: transitive
749 + description:
750 + name: yaml
751 + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
752 + url: "https://pub.dev"
753 + source: hosted
754 + version: "3.1.1"
755 sdks:
756 dart: ">=3.2.0-0 <4.0.0"
757 flutter: ">=3.7.0"
cw_wownero/pubspec.yaml new
+82
@@ -0,0 +1,82 @@
1 +name: cw_wownero
2 +description: A new flutter plugin project.
3 +version: 0.0.1
4 +publish_to: none
5 +author: Cake Wallet
6 +homepage: https://cakewallet.com
7 +
8 +environment:
9 + sdk: ">=2.19.0 <3.0.0"
10 + flutter: ">=1.20.0"
11 +
12 +dependencies:
13 + flutter:
14 + sdk: flutter
15 + ffi: ^2.0.1
16 + http: ^1.1.0
17 + path_provider: ^2.0.11
18 + mobx: ^2.0.7+4
19 + flutter_mobx: ^2.0.6+1
20 + intl: ^0.18.0
21 + encrypt: ^5.0.1
22 + polyseed: ^0.0.4
23 + cw_core:
24 + path: ../cw_core
25 + monero:
26 + git:
27 + url: https://github.com/mrcyjanek/monero.dart
28 + ref: d46753eca865e9e56c2f0ef6fe485c42e11982c5
29 + mutex: ^3.1.0
30 +
31 +dev_dependencies:
32 + flutter_test:
33 + sdk: flutter
34 + build_runner: ^2.4.7
35 + build_resolvers: ^2.0.9
36 + mobx_codegen: ^2.0.7
37 + hive_generator: ^1.1.3
38 +
39 +dependency_overrides:
40 + watcher: ^1.1.0
41 +
42 +# For information on the generic Dart part of this file, see the
43 +# following page: https://dart.dev/tools/pub/pubspec
44 +
45 +# The following section is specific to Flutter.
46 +flutter:
47 + # This section identifies this Flutter project as a plugin project.
48 + # The androidPackage and pluginClass identifiers should not ordinarily
49 + # be modified. They are used by the tooling to maintain consistency when
50 + # adding or updating assets for this project.
51 +
52 +
53 + # To add assets to your plugin package, add an assets section, like this:
54 + # assets:
55 + # - images/a_dot_burr.jpeg
56 + # - images/a_dot_ham.jpeg
57 + #
58 + # For details regarding assets in packages, see
59 + # https://flutter.dev/assets-and-images/#from-packages
60 + #
61 + # An image asset can refer to one or more resolution-specific "variants", see
62 + # https://flutter.dev/assets-and-images/#resolution-aware.
63 +
64 + # To add custom fonts to your plugin package, add a fonts section here,
65 + # in this "flutter" section. Each entry in this list should have a
66 + # "family" key with the font family name, and a "fonts" key with a
67 + # list giving the asset and other descriptors for the font. For
68 + # example:
69 + # fonts:
70 + # - family: Schyler
71 + # fonts:
72 + # - asset: fonts/Schyler-Regular.ttf
73 + # - asset: fonts/Schyler-Italic.ttf
74 + # style: italic
75 + # - family: Trajan Pro
76 + # fonts:
77 + # - asset: fonts/TrajanPro.ttf
78 + # - asset: fonts/TrajanPro_Bold.ttf
79 + # weight: 700
80 + #
81 + # For details regarding fonts in packages, see
82 + # https://flutter.dev/custom-fonts/#from-packages
env.json new
+6
@@ -0,0 +1,6 @@
1 +{
2 + "CW_WIN_APP_NAME":"Cake Wallet",
3 + "CW_WIN_APP_PACKAGE_NAME": "com.cakewallet.cake_wallet",
4 + "CW_WIN_APP_VERSION": "1.0.0",
5 + "CW_WIN_APP_BUILD_NUMBER": "1"
6 +}
how_to_add_new_wallet_type.md
+3 -3
@@ -7,7 +7,7 @@
7 **Core Folder/Files Setup**
8 - Idenitify your core component/package (major project component), which would power the integration e.g web3dart, solana, onchain etc
9 - Add a new entry to `WalletType` class in `cw_core/wallet_type.dart`.
10 -- Fill out the necessary information int he various functions in the files, concerning the wallet name, the native currency type, symbol etc.
10 +- Fill out the necessary information in the various functions in the files, concerning the wallet name, the native currency type, symbol etc.
11 - Go to `cw_core/lib/currency_for_wallet_type.dart`, in the `currencyForWalletType` function, add a case for `walletx`, returning the native cryptocurrency for `walletx`.
12 - If the cryptocurrency for walletx is not available among the default cryptocurrencies, add a new cryptocurrency entry in `cw_core/lib/cryptocurrency.dart`.
13 - Add the newly created cryptocurrency name to the list named `all` in this file.
@@ -70,7 +70,7 @@ A `Proxy` class is used to communicate with the specific wallet package we have.
70 outputContent += '\tWalletType.walletx,\n’;
71 }
72
73 -- Head over to `scripts/android/pubspec.sh` script, and modify the `CONFIG_ARGS` under `$CAKEWALLET`. Add `"—walletx”` to the end of the passed in params.
73 +- Head over to `scripts/android/pubspec_gen.sh` script, and modify the `CONFIG_ARGS` under `$CAKEWALLET`. Add `"—walletx”` to the end of the passed in params.
74 - Repeat this in `scripts/ios/app_config.sh` and `scripts/macos/app_config.sh`
75 - Open a terminal and cd into `scripts/android/`. Run the following commands to run setup configuration scripts(proxy class, add walletx to list of wallet types and add cw_walletx to pubspec).
76
@@ -214,7 +214,7 @@ Now you can run the codebase and successfully create a wallet for type walletX s
214 **Restore Wallet**
215 - Go to `lib/core/seed_validator.dart`
216 - In the `getWordList` method, add a case to handle `WalletType.walletx` which would return the word list to be used to validate the passed in seeds.
217 -- Next, go to `lib/restore_view_model.dart`
217 +- Next, go to `lib/wallet_restore_view_model.dart`
218 - Modify the `hasRestoreFromPrivateKey` to reflect if walletx supports restore from Key
219 - Add a switch case to handle the various restore modes that walletX supports
220 - Modify the `getCredential` method to handle the restore flows for `WalletType.walletx`
howto-build-android.md
+3 -7
@@ -8,7 +8,7 @@ The following are the system requirements to build CakeWallet for your Android d
8 Ubuntu >= 20.04
9 Android SDK 29 or higher (better to have the latest one 33)
10 Android NDK 17c
11 -Flutter 3.10.x or earlier
11 +Flutter 3.19.x or earlier
12 ```
13
14 ## Building CakeWallet on Android
@@ -55,7 +55,7 @@ You may download and install the latest version of Android Studio [here](https:/
55
56 ### 3. Installing Flutter
57
58 -Need to install flutter with version `3.7.x`. For this please check section [Install Flutter manually](https://docs.flutter.dev/get-started/install/linux#install-flutter-manually).
58 +Need to install flutter with version `3.19.x`. For this please check section [Install Flutter manually](https://docs.flutter.dev/get-started/install/linux#install-flutter-manually).
59
60 ### 4. Verify Installations
61
@@ -66,7 +66,7 @@ Verify that the Android toolchain, Flutter, and Android Studio have been correct
66 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.
67 ```
68 Doctor summary (to see all details, run flutter doctor -v):
69 -[✓] Flutter (Channel stable, 3.10.x, on Linux, locale en_US.UTF-8)
69 +[✓] Flutter (Channel stable, 3.19.x, on Linux, locale en_US.UTF-8)
70 [✓] Android toolchain - develop for Android devices (Android SDK version 29 or higher)
71 [✓] Android Studio (version 4.0 or higher)
72 ```
@@ -116,10 +116,6 @@ Build the Monero libraries and their dependencies:
116
117 `$ ./build_all.sh`
118
119 -Now the dependencies need to be copied into the CakeWallet project with this command:
120 -
121 -`$ ./copy_monero_deps.sh`
122 -
119 It is now time to change back to the base directory of the CakeWallet source code:
120
121 `$ cd ../../`
howto-build-ios.md new
+101
@@ -0,0 +1,101 @@
1 +# Building CakeWallet for iOS
2 +
3 +## Requirements and Setup
4 +
5 +The following are the system requirements to build CakeWallet for your iOS device.
6 +
7 +```
8 +macOS >= 14.0
9 +Xcode 15.3
10 +Flutter 3.19.x
11 +```
12 +
13 +## Building CakeWallet on iOS
14 +
15 +These steps will help you configure and execute a build of CakeWallet from its source code.
16 +
17 +### 1. Installing Package Dependencies
18 +
19 +CakeWallet cannot be built without the following packages installed on your build system.
20 +
21 +For installing dependency tools you can use brew [Install brew](https://brew.sh).
22 +
23 +You may easily install them on your build system with the following command:
24 +
25 +`$ brew install cmake xz cocoapods`
26 +
27 +### 2. Installing Xcode
28 +
29 +You may download and install the latest version of [Xcode](https://developer.apple.com/xcode/) from macOS App Store.
30 +
31 +### 3. Installing Flutter
32 +
33 +Need to install flutter with version `3.19.x`. For this please check section [Install Flutter](https://docs.flutter.dev/get-started/install/macos/mobile-ios?tab=download).
34 +
35 +### 4. Verify Installations
36 +
37 +Verify that the Flutter and Xcode have been correctly installed on your system with the following command:
38 +
39 +`$ flutter doctor`
40 +
41 +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.
42 +```
43 +Doctor summary (to see all details, run flutter doctor -v):
44 +[✓] Flutter (Channel stable, 3.19.x, on macOS 14.x.x)
45 +[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
46 +```
47 +
48 +### 5. Acquiring the CakeWallet source code
49 +
50 +Download the source code.
51 +
52 +`$ git clone https://github.com/cake-tech/cake_wallet.git --branch main`
53 +
54 +Proceed into the source code before proceeding with the next steps:
55 +
56 +`$ cd cake_wallet/scripts/ios/`
57 +
58 +### 6. Execute Build & Setup Commands for CakeWallet
59 +
60 +We need to generate project settings like app name, app icon, package name, etc. For this need to setup environment variables and configure project files.
61 +
62 +Please pick what app you want to build: cakewallet or monero.com.
63 +
64 +`$ source ./app_env.sh <cakewallet OR monero.com>`
65 +(it should be like `$ source ./app_env.sh cakewallet` or `$ source ./app_env.sh monero.com`)
66 +
67 +Then run configuration script for setup app name, app icon and etc:
68 +
69 +`$ ./app_config.sh`
70 +
71 +Build the Monero libraries and their dependencies:
72 +
73 +`$ ./build_monero_all.sh`
74 +
75 +It is now time to change back to the base directory of the CakeWallet source code:
76 +
77 +`$ cd ../../`
78 +
79 +Install Flutter package dependencies with this command:
80 +
81 +`$ flutter pub get`
82 +
83 +Your CakeWallet binary will be built with cryptographic salts, which are used for secure encryption of your data. You may generate these secret salts with the following command:
84 +
85 +`$ flutter packages pub run tool/generate_new_secrets.dart`
86 +
87 +Then we need to generate localization files and mobx models.
88 +
89 +`$ ./configure_cake_wallet.sh ios`
90 +
91 +### 7. Build!
92 +
93 +`$ flutter build ios --release`
94 +
95 +Then you can open `ios/Runner.xcworkspace` with Xcode and you can to archive the application.
96 +
97 +Or if you want to run to connected device:
98 +
99 +`$ flutter run --release`
100 +
101 +Copyright (c) 2024 Cake Technologies LLC.
howto-build-macos.md new
+112
@@ -0,0 +1,112 @@
1 +# Building CakeWallet for macOS
2 +
3 +## Requirements and Setup
4 +
5 +The following are the system requirements to build CakeWallet for your macOS device.
6 +
7 +```
8 +macOS >= 14.0
9 +Xcode 15.3
10 +Flutter 3.19.x
11 +```
12 +
13 +## Building CakeWallet on macOS
14 +
15 +These steps will help you configure and execute a build of CakeWallet from its source code.
16 +
17 +### 1. Installing Package Dependencies
18 +
19 +CakeWallet cannot be built without the following packages installed on your build system.
20 +
21 +For installing dependency tools you can use brew [Install brew](https://brew.sh).
22 +
23 +You may easily install them on your build system with the following command:
24 +
25 +`$ brew install cmake xz automake autoconf libtool boost@1.76 zmq cocoapods`
26 +
27 +`$ brew link boost@1.76`
28 +
29 +### 2. Installing Xcode
30 +
31 +You may download and install the latest version of [Xcode](https://developer.apple.com/xcode/) from macOS App Store.
32 +
33 +### 3. Installing Flutter
34 +
35 +Need to install flutter with version `3.19.x`. For this please check section [Install Flutter](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
36 +
37 +### 4. Verify Installations
38 +
39 +Verify that Flutter and Xcode have been correctly installed on your system with the following command:
40 +
41 +`$ flutter doctor`
42 +
43 +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.
44 +```
45 +Doctor summary (to see all details, run flutter doctor -v):
46 +[✓] Flutter (Channel stable, 3.19.x, on macOS 14.x.x)
47 +[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
48 +```
49 +
50 +### 5. Acquiring the CakeWallet source code
51 +
52 +Download the source code.
53 +
54 +`$ git clone https://github.com/cake-tech/cake_wallet.git --branch main`
55 +
56 +Proceed into the source code before proceeding with the next steps:
57 +
58 +`$ cd cake_wallet/scripts/macos/`
59 +
60 +### 6. Execute Build & Setup Commands for CakeWallet
61 +
62 +We need to generate project settings like app name, app icon, package name, etc. For this need to setup environment variables and configure project files.
63 +
64 +Please pick what app you want to build: cakewallet or monero.com.
65 +
66 +`$ source ./app_env.sh <cakewallet OR monero.com>`
67 +(it should be like `$ source ./app_env.sh cakewallet` or `$ source ./app_env.sh monero.com`)
68 +
69 +Then run configuration script for setup app name, app icon and etc:
70 +
71 +`$ ./app_config.sh`
72 +
73 +Build the Monero libraries and their dependencies:
74 +
75 +`$ ./build_monero_all.sh`
76 +
77 +If you be needed to build universal monero lib, then it will require additional steps. Steps for build universal monero lib on mac with Apple Silicon (arm64):
78 +
79 +- Need to install Rosetta: `$ softwareupdate --install-rosetta`
80 +- Need to install [Brew](https://brew.sh/) with rosetta: `$ arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` (or take another way to install brew, but be use that you have installed it into /usr/local as it's using for x86_64 macs)
81 +- Install dependencies for build monero wallet lib for x86_64 with brew: `$ arch -x86_64 /usr/local/bin/brew install automake autoconf libtool openssl boost@1.76 zmq` and link installed boost@1.76 for x86_64 `$ arch -x86_64 /usr/local/bin/brew link boost@1.76`
82 +- Run building script with additional argument: `$ ./build_monero_all.sh universal`
83 +
84 +If you will be needed to build monero wallet lib only for x86_64 on arm64 mac, then you need use steps above, but run build script with rosetta without arguments: `$ arch -x86_64 ./build_monero_all.sh`.
85 +
86 +It is now time to change back to the base directory of the CakeWallet source code:
87 +
88 +`$ cd ../../`
89 +
90 +Install Flutter package dependencies with this command:
91 +
92 +`$ flutter pub get`
93 +
94 +Your CakeWallet binary will be built with cryptographic salts, which are used for secure encryption of your data. You may generate these secret salts with the following command:
95 +
96 +`$ flutter packages pub run tool/generate_new_secrets.dart`
97 +
98 +Then we need to generate localization files and mobx models.
99 +
100 +`$ ./configure_cake_wallet.sh macos`
101 +
102 +### 7. Build!
103 +
104 +`$ flutter build macos --release`
105 +
106 +Then you can open `macos/Runner.xcworkspace` with Xcode and you can to archive the application.
107 +
108 +Or if you want to run to connected device:
109 +
110 +`$ flutter run --release`
111 +
112 +Copyright (c) 2024 Cake Technologies LLC.
ios/MoneroWallet.framework/Info.plist
Binary files /dev/null and b/ios/MoneroWallet.framework/Info.plist differ
ios/Podfile.lock
+31 -58
@@ -7,7 +7,7 @@ PODS:
7 - connectivity_plus (0.0.1):
8 - Flutter
9 - ReachabilitySwift
10 - - CryptoSwift (1.8.1)
10 + - CryptoSwift (1.8.2)
11 - cw_haven (0.0.1):
12 - cw_haven/Boost (= 0.0.1)
13 - cw_haven/Haven (= 0.0.1)
@@ -27,29 +27,6 @@ PODS:
27 - cw_haven/Sodium (0.0.1):
28 - cw_shared_external
29 - Flutter
30 - - cw_monero (0.0.2):
31 - - cw_monero/Boost (= 0.0.2)
32 - - cw_monero/Monero (= 0.0.2)
33 - - cw_monero/OpenSSL (= 0.0.2)
34 - - cw_monero/Sodium (= 0.0.2)
35 - - cw_monero/Unbound (= 0.0.2)
36 - - cw_shared_external
37 - - Flutter
38 - - cw_monero/Boost (0.0.2):
39 - - cw_shared_external
40 - - Flutter
41 - - cw_monero/Monero (0.0.2):
42 - - cw_shared_external
43 - - Flutter
44 - - cw_monero/OpenSSL (0.0.2):
45 - - cw_shared_external
46 - - Flutter
47 - - cw_monero/Sodium (0.0.2):
48 - - cw_shared_external
49 - - Flutter
50 - - cw_monero/Unbound (0.0.2):
51 - - cw_shared_external
52 - - Flutter
30 - cw_shared_external (0.0.1):
31 - cw_shared_external/Boost (= 0.0.1)
32 - cw_shared_external/OpenSSL (= 0.0.1)
@@ -67,35 +44,35 @@ PODS:
44 - Flutter
45 - devicelocale (0.0.1):
46 - Flutter
70 - - DKImagePickerController/Core (4.3.4):
47 + - DKImagePickerController/Core (4.3.9):
48 - DKImagePickerController/ImageDataManager
49 - DKImagePickerController/Resource
73 - - DKImagePickerController/ImageDataManager (4.3.4)
74 - - DKImagePickerController/PhotoGallery (4.3.4):
50 + - DKImagePickerController/ImageDataManager (4.3.9)
51 + - DKImagePickerController/PhotoGallery (4.3.9):
52 - DKImagePickerController/Core
53 - DKPhotoGallery
77 - - DKImagePickerController/Resource (4.3.4)
78 - - DKPhotoGallery (0.0.17):
79 - - DKPhotoGallery/Core (= 0.0.17)
80 - - DKPhotoGallery/Model (= 0.0.17)
81 - - DKPhotoGallery/Preview (= 0.0.17)
82 - - DKPhotoGallery/Resource (= 0.0.17)
54 + - DKImagePickerController/Resource (4.3.9)
55 + - DKPhotoGallery (0.0.19):
56 + - DKPhotoGallery/Core (= 0.0.19)
57 + - DKPhotoGallery/Model (= 0.0.19)
58 + - DKPhotoGallery/Preview (= 0.0.19)
59 + - DKPhotoGallery/Resource (= 0.0.19)
60 - SDWebImage
61 - SwiftyGif
85 - - DKPhotoGallery/Core (0.0.17):
62 + - DKPhotoGallery/Core (0.0.19):
63 - DKPhotoGallery/Model
64 - DKPhotoGallery/Preview
65 - SDWebImage
66 - SwiftyGif
90 - - DKPhotoGallery/Model (0.0.17):
67 + - DKPhotoGallery/Model (0.0.19):
68 - SDWebImage
69 - SwiftyGif
93 - - DKPhotoGallery/Preview (0.0.17):
70 + - DKPhotoGallery/Preview (0.0.19):
71 - DKPhotoGallery/Model
72 - DKPhotoGallery/Resource
73 - SDWebImage
74 - SwiftyGif
98 - - DKPhotoGallery/Resource (0.0.17):
75 + - DKPhotoGallery/Resource (0.0.19):
76 - SDWebImage
77 - SwiftyGif
78 - file_picker (0.0.1):
@@ -131,15 +108,15 @@ PODS:
108 - FlutterMacOS
109 - permission_handler_apple (9.1.1):
110 - Flutter
134 - - Protobuf (3.25.3)
135 - - ReachabilitySwift (5.0.0)
111 + - Protobuf (3.27.2)
112 + - ReachabilitySwift (5.2.3)
113 - reactive_ble_mobile (0.0.1):
114 - Flutter
115 - Protobuf (~> 3.5)
116 - SwiftProtobuf (~> 1.0)
140 - - SDWebImage (5.18.11):
141 - - SDWebImage/Core (= 5.18.11)
142 - - SDWebImage/Core (5.18.11)
117 + - SDWebImage (5.19.4):
118 + - SDWebImage/Core (= 5.19.4)
119 + - SDWebImage/Core (5.19.4)
120 - sensitive_clipboard (0.0.1):
121 - Flutter
122 - share_plus (0.0.1):
@@ -149,9 +126,9 @@ PODS:
126 - FlutterMacOS
127 - sp_scanner (0.0.1):
128 - Flutter
152 - - SwiftProtobuf (1.25.2)
153 - - SwiftyGif (5.4.4)
154 - - Toast (4.1.0)
129 + - SwiftProtobuf (1.26.0)
130 + - SwiftyGif (5.4.5)
131 + - Toast (4.1.1)
132 - uni_links (0.0.1):
133 - Flutter
134 - UnstoppableDomainsResolution (4.0.0):
@@ -169,7 +146,6 @@ DEPENDENCIES:
146 - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
147 - CryptoSwift
148 - cw_haven (from `.symlinks/plugins/cw_haven/ios`)
172 - - cw_monero (from `.symlinks/plugins/cw_monero/ios`)
149 - cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`)
150 - device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`)
151 - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
@@ -220,8 +196,6 @@ EXTERNAL SOURCES:
196 :path: ".symlinks/plugins/connectivity_plus/ios"
197 cw_haven:
198 :path: ".symlinks/plugins/cw_haven/ios"
223 - cw_monero:
224 - :path: ".symlinks/plugins/cw_monero/ios"
199 cw_shared_external:
200 :path: ".symlinks/plugins/cw_shared_external/ios"
201 device_display_brightness:
@@ -277,15 +251,14 @@ SPEC CHECKSUMS:
251 barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
252 BigInt: f668a80089607f521586bbe29513d708491ef2f7
253 connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
280 - CryptoSwift: b9c701d6f5011df23794dbf7f2e480a77835d83d
254 + CryptoSwift: c63a805d8bb5e5538e88af4e44bb537776af11ea
255 cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a
282 - cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d
256 cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
257 device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
258 device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
259 devicelocale: b22617f40038496deffba44747101255cee005b0
287 - DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
288 - DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
260 + DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
261 + DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
262 file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de
263 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
264 flutter_inappwebview_ios: 97215cf7d4677db55df76782dbd2930c5e1c1ea0
@@ -300,17 +273,17 @@ SPEC CHECKSUMS:
273 package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
274 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
275 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
303 - Protobuf: 8e9074797a13c484a79959fdb819ef4ae6da7dbe
304 - ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
276 + Protobuf: fb2c13674723f76ff6eede14f78847a776455fa2
277 + ReachabilitySwift: 7f151ff156cea1481a8411701195ac6a984f4979
278 reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c
306 - SDWebImage: a3ba0b8faac7228c3c8eadd1a55c9c9fe5e16457
279 + SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
280 sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
281 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
282 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
283 sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
311 - SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1
312 - SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
313 - Toast: ec33c32b8688982cecc6348adeae667c1b9938da
284 + SwiftProtobuf: 5e8349171e7c2f88f5b9e683cb3cb79d1dc780b3
285 + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
286 + Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
287 uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
288 UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
289 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
ios/Runner.xcodeproj/project.pbxproj
+95 -3
@@ -8,32 +8,70 @@
8
9 /* Begin PBXBuildFile section */
10 0C44A71A2518EF8000B570ED /* decrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C44A7192518EF8000B570ED /* decrypt.swift */; };
11 + 0C50DFB92BF3CB56002B0EB3 /* MoneroWallet.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0C50DFB82BF3CB56002B0EB3 /* MoneroWallet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12 0C9D68C9264854B60011B691 /* secRandom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C9D68C8264854B60011B691 /* secRandom.swift */; };
13 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
14 + 2193F104374FA2746CE8945B /* ResourceHelper.swift in Resources */ = {isa = PBXBuildFile; fileRef = 78D25C60B94E9D9E48D52E5E /* ResourceHelper.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
15 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
16 + 495FEFF9B395392FED3425DE /* TaskProtocol.swift in Resources */ = {isa = PBXBuildFile; fileRef = 0F42D8065219E0653321EE2B /* TaskProtocol.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
17 4DFD1BB54A3A50573E19A583 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C663361C56EBB242598F609 /* Pods_Runner.framework */; };
18 + 525A2200C6C2A43EDC5C8FC5 /* BreezSDKConnector.swift in Resources */ = {isa = PBXBuildFile; fileRef = 1FB06A93B13D606F06B3924D /* BreezSDKConnector.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
19 + 6909E1D79C9986ADF2DE41E9 /* LnurlPayInvoice.swift in Resources */ = {isa = PBXBuildFile; fileRef = DCEA540E3586164FB47AD13E /* LnurlPayInvoice.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
20 + 724FDA327BF191BC29DCAA2E /* Constants.swift in Resources */ = {isa = PBXBuildFile; fileRef = 0CCA7ADAD6FF9185EBBB2BCA /* Constants.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
21 + 73138617307FA4F838D21D62 /* ServiceLogger.swift in Resources */ = {isa = PBXBuildFile; fileRef = F42258C3697CFE3C8C8D1933 /* ServiceLogger.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
22 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
23 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
24 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
25 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
26 9F46EE5E2BC11178009318F5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 9F46EE5D2BC11178009318F5 /* PrivacyInfo.xcprivacy */; };
27 + A1B4A70C9CFA13AB71662216 /* LnurlPay.swift in Resources */ = {isa = PBXBuildFile; fileRef = 7D3364C03978A8A74B6D586E /* LnurlPay.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
28 + A3D5E17CC53DF13FA740DEFA /* RedeemSwap.swift in Resources */ = {isa = PBXBuildFile; fileRef = 9D2F2C9F2555316C95EE7EA3 /* RedeemSwap.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
29 + B6C6E59403ACDE44724C12F4 /* ServiceConfig.swift in Resources */ = {isa = PBXBuildFile; fileRef = B3D5E78267F5F18D882FDC3B /* ServiceConfig.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
30 + CE291CFE2C15DB9A00B9F709 /* WowneroWallet.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE291CFD2C15DB9A00B9F709 /* WowneroWallet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
31 + CFEFC24F82F78FE747DF1D22 /* LnurlPayInfo.swift in Resources */ = {isa = PBXBuildFile; fileRef = 58C22CBD8C22B9D6023D59F8 /* LnurlPayInfo.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
32 + D0D7A0D4E13F31C4E02E235B /* ReceivePayment.swift in Resources */ = {isa = PBXBuildFile; fileRef = 91C524F800843E0A3F17E004 /* ReceivePayment.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
33 + D3AD73A327249AFE8F016A51 /* BreezSDK.swift in Resources */ = {isa = PBXBuildFile; fileRef = ABD6FCBB0F4244B090459128 /* BreezSDK.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
34 + F5EE19868D6F10D814BF73AD /* SDKNotificationService.swift in Resources */ = {isa = PBXBuildFile; fileRef = 41102141140E57B1DC27FBA1 /* SDKNotificationService.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; };
35 /* End PBXBuildFile section */
36
37 +/* Begin PBXCopyFilesBuildPhase section */
38 + CE5E8A222BEE19C700608EA1 /* CopyFiles */ = {
39 + isa = PBXCopyFilesBuildPhase;
40 + buildActionMask = 2147483647;
41 + dstPath = "";
42 + dstSubfolderSpec = 10;
43 + files = (
44 + CE291CFE2C15DB9A00B9F709 /* WowneroWallet.framework in CopyFiles */,
45 + 0C50DFB92BF3CB56002B0EB3 /* MoneroWallet.framework in CopyFiles */,
46 + );
47 + runOnlyForDeploymentPostprocessing = 0;
48 + };
49 +/* End PBXCopyFilesBuildPhase section */
50 +
51 /* Begin PBXFileReference section */
52 0C400E0F25B21ABB0025E469 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
53 0C44A7192518EF8000B570ED /* decrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = decrypt.swift; sourceTree = "<group>"; };
54 + 0C50DFB82BF3CB56002B0EB3 /* MoneroWallet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MoneroWallet.framework; sourceTree = "<group>"; };
55 0C9986A3251A932F00D566FD /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
56 0C9D68C8264854B60011B691 /* secRandom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = secRandom.swift; sourceTree = "<group>"; };
57 + 0CCA7ADAD6FF9185EBBB2BCA /* Constants.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Constants.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/Constants.swift"; sourceTree = "<group>"; };
58 + 0F42D8065219E0653321EE2B /* TaskProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TaskProtocol.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/TaskProtocol.swift"; sourceTree = "<group>"; };
59 11F9FC13F9EE2A705B213FA9 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
60 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
61 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
62 1F083F2041D1F553F2AF8B62 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
63 + 1FB06A93B13D606F06B3924D /* BreezSDKConnector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BreezSDKConnector.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/BreezSDKConnector.swift"; sourceTree = "<group>"; };
64 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
65 3C663361C56EBB242598F609 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
66 + 41102141140E57B1DC27FBA1 /* SDKNotificationService.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SDKNotificationService.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/SDKNotificationService.swift"; sourceTree = "<group>"; };
67 + 58C22CBD8C22B9D6023D59F8 /* LnurlPayInfo.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LnurlPayInfo.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/Task/LnurlPayInfo.swift"; sourceTree = "<group>"; };
68 5AFFEBFC279AD49C00F906A4 /* wakeLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = wakeLock.swift; sourceTree = "<group>"; };
69 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
70 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
71 + 78D25C60B94E9D9E48D52E5E /* ResourceHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ResourceHelper.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/ResourceHelper.swift"; sourceTree = "<group>"; };
72 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
73 + 7D3364C03978A8A74B6D586E /* LnurlPay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LnurlPay.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/Task/LnurlPay.swift"; sourceTree = "<group>"; };
74 + 91C524F800843E0A3F17E004 /* ReceivePayment.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReceivePayment.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/Task/ReceivePayment.swift"; sourceTree = "<group>"; };
75 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
76 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
77 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -41,8 +79,14 @@
79 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
80 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
81 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
82 + 9D2F2C9F2555316C95EE7EA3 /* RedeemSwap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RedeemSwap.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/Task/RedeemSwap.swift"; sourceTree = "<group>"; };
83 9F46EE5D2BC11178009318F5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
84 + ABD6FCBB0F4244B090459128 /* BreezSDK.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BreezSDK.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/BreezSDK.swift"; sourceTree = "<group>"; };
85 AD0937B0140D5A4C24E73BEA /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
86 + B3D5E78267F5F18D882FDC3B /* ServiceConfig.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServiceConfig.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/ServiceConfig.swift"; sourceTree = "<group>"; };
87 + CE291CFD2C15DB9A00B9F709 /* WowneroWallet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WowneroWallet.framework; sourceTree = "<group>"; };
88 + DCEA540E3586164FB47AD13E /* LnurlPayInvoice.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LnurlPayInvoice.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/Task/LnurlPayInvoice.swift"; sourceTree = "<group>"; };
89 + F42258C3697CFE3C8C8D1933 /* ServiceLogger.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServiceLogger.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/ServiceLogger.swift"; sourceTree = "<group>"; };
90 /* End PBXFileReference section */
91
92 /* Begin PBXFrameworksBuildPhase section */
@@ -66,6 +110,14 @@
110 name = Frameworks;
111 sourceTree = "<group>";
112 };
113 + 0B80439B9064C9708DDB0ADA /* breez_sdk-OnDemandResources */ = {
114 + isa = PBXGroup;
115 + children = (
116 + ADEC151FA90C8F1EBCDA8CA3 /* BreezSDK */,
117 + );
118 + name = "breez_sdk-OnDemandResources";
119 + sourceTree = "<group>";
120 + };
121 0C44A7182518EF4A00B570ED /* CakeWallet */ = {
122 isa = PBXGroup;
123 children = (
@@ -82,6 +134,7 @@
134 11F9FC13F9EE2A705B213FA9 /* Pods-Runner.debug.xcconfig */,
135 1F083F2041D1F553F2AF8B62 /* Pods-Runner.release.xcconfig */,
136 AD0937B0140D5A4C24E73BEA /* Pods-Runner.profile.xcconfig */,
137 + 0B80439B9064C9708DDB0ADA /* breez_sdk-OnDemandResources */,
138 );
139 path = Pods;
140 sourceTree = "<group>";
@@ -100,6 +153,8 @@
153 97C146E51CF9000F007C117D = {
154 isa = PBXGroup;
155 children = (
156 + CE291CFD2C15DB9A00B9F709 /* WowneroWallet.framework */,
157 + 0C50DFB82BF3CB56002B0EB3 /* MoneroWallet.framework */,
158 0C44A7182518EF4A00B570ED /* CakeWallet */,
159 9740EEB11CF90186004384FC /* Flutter */,
160 97C146F01CF9000F007C117D /* Runner */,
@@ -134,6 +189,26 @@
189 path = Runner;
190 sourceTree = "<group>";
191 };
192 + ADEC151FA90C8F1EBCDA8CA3 /* BreezSDK */ = {
193 + isa = PBXGroup;
194 + children = (
195 + ABD6FCBB0F4244B090459128 /* BreezSDK.swift */,
196 + 1FB06A93B13D606F06B3924D /* BreezSDKConnector.swift */,
197 + 0CCA7ADAD6FF9185EBBB2BCA /* Constants.swift */,
198 + 78D25C60B94E9D9E48D52E5E /* ResourceHelper.swift */,
199 + 41102141140E57B1DC27FBA1 /* SDKNotificationService.swift */,
200 + B3D5E78267F5F18D882FDC3B /* ServiceConfig.swift */,
201 + F42258C3697CFE3C8C8D1933 /* ServiceLogger.swift */,
202 + 0F42D8065219E0653321EE2B /* TaskProtocol.swift */,
203 + 7D3364C03978A8A74B6D586E /* LnurlPay.swift */,
204 + 58C22CBD8C22B9D6023D59F8 /* LnurlPayInfo.swift */,
205 + DCEA540E3586164FB47AD13E /* LnurlPayInvoice.swift */,
206 + 91C524F800843E0A3F17E004 /* ReceivePayment.swift */,
207 + 9D2F2C9F2555316C95EE7EA3 /* RedeemSwap.swift */,
208 + );
209 + name = BreezSDK;
210 + sourceTree = "<group>";
211 + };
212 /* End PBXGroup section */
213
214 /* Begin PBXNativeTarget section */
@@ -142,6 +217,7 @@
217 buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
218 buildPhases = (
219 B91154210ADCED81FBF06A85 /* [CP] Check Pods Manifest.lock */,
220 + CE5E8A222BEE19C700608EA1 /* CopyFiles */,
221 9740EEB61CF901F6004384FC /* Run Script */,
222 97C146EA1CF9000F007C117D /* Sources */,
223 97C146EB1CF9000F007C117D /* Frameworks */,
@@ -164,6 +240,9 @@
240 97C146E61CF9000F007C117D /* Project object */ = {
241 isa = PBXProject;
242 attributes = {
243 + KnownAssetTags = (
244 + BreezSDK,
245 + );
246 LastUpgradeCheck = 1510;
247 ORGANIZATIONNAME = "";
248 TargetAttributes = {
@@ -201,6 +280,19 @@
280 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
281 9F46EE5E2BC11178009318F5 /* PrivacyInfo.xcprivacy in Resources */,
282 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
283 + D3AD73A327249AFE8F016A51 /* BreezSDK.swift in Resources */,
284 + 525A2200C6C2A43EDC5C8FC5 /* BreezSDKConnector.swift in Resources */,
285 + 724FDA327BF191BC29DCAA2E /* Constants.swift in Resources */,
286 + 2193F104374FA2746CE8945B /* ResourceHelper.swift in Resources */,
287 + F5EE19868D6F10D814BF73AD /* SDKNotificationService.swift in Resources */,
288 + B6C6E59403ACDE44724C12F4 /* ServiceConfig.swift in Resources */,
289 + 73138617307FA4F838D21D62 /* ServiceLogger.swift in Resources */,
290 + 495FEFF9B395392FED3425DE /* TaskProtocol.swift in Resources */,
291 + A1B4A70C9CFA13AB71662216 /* LnurlPay.swift in Resources */,
292 + CFEFC24F82F78FE747DF1D22 /* LnurlPayInfo.swift in Resources */,
293 + 6909E1D79C9986ADF2DE41E9 /* LnurlPayInvoice.swift in Resources */,
294 + D0D7A0D4E13F31C4E02E235B /* ReceivePayment.swift in Resources */,
295 + A3D5E17CC53DF13FA740DEFA /* RedeemSwap.swift in Resources */,
296 );
297 runOnlyForDeploymentPostprocessing = 0;
298 };
@@ -391,7 +483,7 @@
483 "$(PROJECT_DIR)/Flutter",
484 );
485 MARKETING_VERSION = 1.0.1;
394 - PRODUCT_BUNDLE_IDENTIFIER = "";
486 + PRODUCT_BUNDLE_IDENTIFIER = "com.fotolockr.cakewallet";
487 PRODUCT_NAME = "$(TARGET_NAME)";
488 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
489 SWIFT_VERSION = 5.0;
@@ -537,7 +629,7 @@
629 "$(PROJECT_DIR)/Flutter",
630 );
631 MARKETING_VERSION = 1.0.1;
540 - PRODUCT_BUNDLE_IDENTIFIER = "";
632 + PRODUCT_BUNDLE_IDENTIFIER = "com.fotolockr.cakewallet";
633 PRODUCT_NAME = "$(TARGET_NAME)";
634 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
635 SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -575,7 +667,7 @@
667 "$(PROJECT_DIR)/Flutter",
668 );
669 MARKETING_VERSION = 1.0.1;
578 - PRODUCT_BUNDLE_IDENTIFIER = "";
670 + PRODUCT_BUNDLE_IDENTIFIER = "com.fotolockr.cakewallet";
671 PRODUCT_NAME = "$(TARGET_NAME)";
672 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
673 SWIFT_VERSION = 5.0;
ios/Runner/InfoBase.plist
+21 -1
@@ -200,7 +200,7 @@
200 <string>solana-wallet</string>
201 </array>
202 </dict>
203 - <dict>
203 + <dict>
204 <key>CFBundleTypeRole</key>
205 <string>Viewer</string>
206 <key>CFBundleURLName</key>
@@ -220,6 +220,26 @@
220 <string>tron-wallet</string>
221 </array>
222 </dict>
223 + <dict>
224 + <key>CFBundleTypeRole</key>
225 + <string>Viewer</string>
226 + <key>CFBundleURLName</key>
227 + <string>wownero</string>
228 + <key>CFBundleURLSchemes</key>
229 + <array>
230 + <string>wownero</string>
231 + </array>
232 + </dict>
233 + <dict>
234 + <key>CFBundleTypeRole</key>
235 + <string>Viewer</string>
236 + <key>CFBundleURLName</key>
237 + <string>wownero-wallet</string>
238 + <key>CFBundleURLSchemes</key>
239 + <array>
240 + <string>wownero-wallet</string>
241 + </array>
242 + </dict>
243 </array>
244 <key>CFBundleVersion</key>
245 <string>$(CURRENT_PROJECT_VERSION)</string>
ios/WowneroWallet.framework/Info.plist
Binary files /dev/null and b/ios/WowneroWallet.framework/Info.plist differ
ios/monero_libwallet2_api_c.dylib new
+1
@@ -0,0 +1 @@
1 +../scripts/monero_c/release/monero/host-apple-ios_libwallet2_api_c.dylib
\ No newline at end of file
ios/wownero_libwallet2_api_c.dylib new
+1
@@ -0,0 +1 @@
1 +../scripts/monero_c/release/wownero/host-apple-ios_libwallet2_api_c.dylib
\ No newline at end of file
lib/core/address_validator.dart
+3
@@ -91,6 +91,7 @@ class AddressValidator extends TextValidator {
91 case CryptoCurrency.dai:
92 case CryptoCurrency.dash:
93 case CryptoCurrency.eos:
94 + case CryptoCurrency.wow:
95 return '[0-9a-zA-Z]';
96 case CryptoCurrency.bch:
97 return '^(?!bitcoincash:)[0-9a-zA-Z]*\$|^(?!bitcoincash:)q|p[0-9a-zA-Z]{41}\$|^(?!bitcoincash:)q|p[0-9a-zA-Z]{42}\$|^bitcoincash:q|p[0-9a-zA-Z]{41}\$|^bitcoincash:q|p[0-9a-zA-Z]{42}\$';
@@ -139,6 +140,7 @@ class AddressValidator extends TextValidator {
140
141 switch (type) {
142 case CryptoCurrency.xmr:
143 + case CryptoCurrency.wow:
144 return null;
145 case CryptoCurrency.ada:
146 return null;
@@ -266,6 +268,7 @@ class AddressValidator extends TextValidator {
268 static String? getAddressFromStringPattern(CryptoCurrency type) {
269 switch (type) {
270 case CryptoCurrency.xmr:
271 + case CryptoCurrency.wow:
272 return '([^0-9a-zA-Z]|^)4[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
273 '|([^0-9a-zA-Z]|^)8[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
274 '|([^0-9a-zA-Z]|^)[0-9a-zA-Z]{106}([^0-9a-zA-Z]|\$)';
lib/core/backup_service.dart
+8 -7
@@ -4,6 +4,7 @@ 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:cake_wallet/utils/device_info.dart';
7 +import 'package:cw_core/root_dir.dart';
8 import 'package:cw_core/wallet_type.dart';
9 import 'package:flutter/foundation.dart';
10 import 'package:hive/hive.dart';
@@ -76,7 +77,7 @@ class BackupService {
77
78 Future<Uint8List> _exportBackupV2(String password) async {
79 final zipEncoder = ZipFileEncoder();
79 - final appDir = await getApplicationDocumentsDirectory();
80 + final appDir = await getAppDir();
81 final now = DateTime.now();
82 final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
83 final archivePath = '${tmpDir.path}/backup_${now.toString()}.zip';
@@ -116,7 +117,7 @@ class BackupService {
117 }
118
119 Future<void> _importBackupV1(Uint8List data, String password, {required String nonce}) async {
119 - final appDir = await getApplicationDocumentsDirectory();
120 + final appDir = await getAppDir();
121 final decryptedData = await _decryptV1(data, password, nonce);
122 final zip = ZipDecoder().decodeBytes(decryptedData);
123
@@ -139,7 +140,7 @@ class BackupService {
140 }
141
142 Future<void> _importBackupV2(Uint8List data, String password) async {
142 - final appDir = await getApplicationDocumentsDirectory();
143 + final appDir = await getAppDir();
144 final decryptedData = await _decryptV2(data, password);
145 final zip = ZipDecoder().decodeBytes(decryptedData);
146
@@ -172,7 +173,7 @@ class BackupService {
173 }
174
175 Future<Box<WalletInfo>> _reloadHiveWalletInfoBox() async {
175 - final appDir = await getApplicationDocumentsDirectory();
176 + final appDir = await getAppDir();
177 await CakeHive.close();
178 CakeHive.init(appDir.path);
179
@@ -184,7 +185,7 @@ class BackupService {
185 }
186
187 Future<void> _importPreferencesDump() async {
187 - final appDir = await getApplicationDocumentsDirectory();
188 + final appDir = await getAppDir();
189 final preferencesFile = File('${appDir.path}/~_preferences_dump');
190
191 if (!preferencesFile.existsSync()) {
@@ -361,7 +362,7 @@ class BackupService {
362
363 Future<void> _importKeychainDumpV1(String password,
364 {required String nonce, String keychainSalt = secrets.backupKeychainSalt}) async {
364 - final appDir = await getApplicationDocumentsDirectory();
365 + final appDir = await getAppDir();
366 final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
367 final decryptedKeychainDumpFileData =
368 await _decryptV1(keychainDumpFile.readAsBytesSync(), '$keychainSalt$password', nonce);
@@ -387,7 +388,7 @@ class BackupService {
388
389 Future<void> _importKeychainDumpV2(String password,
390 {String keychainSalt = secrets.backupKeychainSalt}) async {
390 - final appDir = await getApplicationDocumentsDirectory();
391 + final appDir = await getAppDir();
392 final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
393 final decryptedKeychainDumpFileData =
394 await _decryptV2(keychainDumpFile.readAsBytesSync(), '$keychainSalt$password');
lib/core/seed_validator.dart
+4 -1
@@ -8,6 +8,7 @@ import 'package:cake_wallet/nano/nano.dart';
8 import 'package:cake_wallet/polygon/polygon.dart';
9 import 'package:cake_wallet/solana/solana.dart';
10 import 'package:cake_wallet/tron/tron.dart';
11 +import 'package:cake_wallet/wownero/wownero.dart';
12 import 'package:cake_wallet/utils/language_list.dart';
13 import 'package:cw_core/wallet_type.dart';
14
@@ -43,7 +44,9 @@ class SeedValidator extends Validator<MnemonicItem> {
44 return solana!.getSolanaWordList(language);
45 case WalletType.tron:
46 return tron!.getTronWordList(language);
46 - default:
47 + case WalletType.wownero:
48 + return wownero!.getWowneroWordList(language);
49 + case WalletType.none:
50 return [];
51 }
52 }
lib/core/wallet_creation_service.dart
+1
@@ -81,6 +81,7 @@ class WalletCreationService {
81 case WalletType.tron:
82 return true;
83 case WalletType.monero:
84 + case WalletType.wownero:
85 case WalletType.none:
86 case WalletType.bitcoin:
87 case WalletType.litecoin:
lib/di.dart
+5 -1
@@ -215,6 +215,7 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
215 import 'package:cake_wallet/view_model/wallet_new_vm.dart';
216 import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
217 import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
218 +import 'package:cake_wallet/wownero/wownero.dart';
219 import 'package:cw_core/crypto_currency.dart';
220 import 'package:cw_core/receive_page_option.dart';
221 import 'package:cw_core/wallet_info.dart';
@@ -900,6 +901,7 @@ Future<void> setup({
901 return bitcoinCash!
902 .createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource);
903 case WalletType.nano:
904 + case WalletType.banano:
905 return nano!.createNanoWalletService(_walletInfoSource);
906 case WalletType.polygon:
907 return polygon!.createPolygonWalletService(_walletInfoSource);
@@ -907,7 +909,9 @@ Future<void> setup({
909 return solana!.createSolanaWalletService(_walletInfoSource);
910 case WalletType.tron:
911 return tron!.createTronWalletService(_walletInfoSource);
910 - default:
912 + case WalletType.wownero:
913 + return wownero!.createWowneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
914 + case WalletType.none:
915 throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
916 }
917 });
lib/entities/background_tasks.dart
+8 -8
@@ -31,8 +31,6 @@ void callbackDispatcher() {
31
32 final walletLoadingService = getIt.get<WalletLoadingService>();
33
34 - final node = getIt.get<SettingsStore>().getCurrentNode(WalletType.monero);
35 -
34 final typeRaw = getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType);
35
36 WalletBase? wallet;
@@ -42,23 +40,25 @@ void callbackDispatcher() {
40 final List<WalletListItem> moneroWallets = getIt
41 .get<WalletListViewModel>()
42 .wallets
45 - .where((element) => element.type == WalletType.monero)
43 + .where((element) => [WalletType.monero, WalletType.wownero].contains(element.type))
44 .toList();
45
46 for (int i = 0; i < moneroWallets.length; i++) {
49 - wallet = await walletLoadingService.load(WalletType.monero, moneroWallets[i].name);
50 -
47 + wallet =
48 + await walletLoadingService.load(moneroWallets[i].type, moneroWallets[i].name);
49 + final node = getIt.get<SettingsStore>().getCurrentNode(moneroWallets[i].type);
50 await wallet.connectToNode(node: node);
51 await wallet.startSync();
52 }
53 } else {
54 /// if the user chose to sync only active wallet
55 /// if the current wallet is monero; sync it only
57 - if (typeRaw == WalletType.monero.index) {
56 + if (typeRaw == WalletType.monero.index || typeRaw == WalletType.wownero.index) {
57 final name =
58 getIt.get<SharedPreferences>().getString(PreferencesKey.currentWalletName);
59
61 - wallet = await walletLoadingService.load(WalletType.monero, name!);
60 + wallet = await walletLoadingService.load(WalletType.values[typeRaw!], name!);
61 + final node = getIt.get<SettingsStore>().getCurrentNode(WalletType.values[typeRaw]);
62
63 await wallet.connectToNode(node: node);
64 await wallet.startSync();
@@ -66,7 +66,7 @@ void callbackDispatcher() {
66 }
67
68 if (wallet?.syncStatus.progress() == null) {
69 - return Future.error("No Monero wallet found");
69 + return Future.error("No Monero/Wownero wallet found");
70 }
71
72 for (int i = 0;; i++) {
lib/entities/default_settings_migration.dart
+57 -3
@@ -5,8 +5,8 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart';
5 import 'package:cake_wallet/entities/fiat_api_mode.dart';
6 import 'package:cw_core/pathForWallet.dart';
7 import 'package:cake_wallet/entities/secret_store_key.dart';
8 +import 'package:cw_core/root_dir.dart';
9 import 'package:hive/hive.dart';
9 -import 'package:path_provider/path_provider.dart';
10 import 'package:shared_preferences/shared_preferences.dart';
11 import 'package:cake_wallet/entities/preferences_key.dart';
12 import 'package:cw_core/wallet_type.dart';
@@ -39,6 +39,7 @@ const nanoDefaultPowNodeUri = 'rpc.nano.to';
39 const solanaDefaultNodeUri = 'rpc.ankr.com';
40 const tronDefaultNodeUri = 'trx.nownodes.io';
41 const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
42 +const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
43
44 Future<void> defaultSettingsMigration(
45 {required int version,
@@ -231,7 +232,8 @@ Future<void> defaultSettingsMigration(
232 await _switchElectRsNode(nodes, sharedPreferences);
233 break;
234 case 36:
234 - await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
235 + await addWowneroNodeList(nodes: nodes);
236 + await changeWowneroCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
237 break;
238 case 37:
239 await replaceTronDefaultNode(sharedPreferences: sharedPreferences, nodes: nodes);
@@ -305,7 +307,7 @@ Future<void> _updateMoneroPriority(SharedPreferences sharedPreferences) async {
307
308 Future<void> _validateWalletInfoBoxData(Box<WalletInfo> walletInfoSource) async {
309 try {
308 - final root = await getApplicationDocumentsDirectory();
310 + final root = await getAppDir();
311
312 for (var type in WalletType.values) {
313 if (type == WalletType.none) {
@@ -498,6 +500,32 @@ Node? getTronDefaultNode({required Box<Node> nodes}) {
500 nodes.values.firstWhereOrNull((node) => node.type == WalletType.tron);
501 }
502
503 +Node getWowneroDefaultNode({required Box<Node> nodes}) {
504 + final timeZone = DateTime.now().timeZoneOffset.inHours;
505 + var nodeUri = '';
506 +
507 + if (timeZone >= 1) {
508 + // Eurasia
509 + nodeUri = 'node2.monerodevs.org.lol:34568';
510 + } else if (timeZone <= -4) {
511 + // America
512 + nodeUri = 'node3.monerodevs.org:34568';
513 + }
514 +
515 + if (nodeUri == '') {
516 + return nodes.values.where((element) => element.type == WalletType.wownero).first;
517 + }
518 +
519 + try {
520 + return nodes.values.firstWhere(
521 + (Node node) => node.uriRaw == nodeUri,
522 + orElse: () => nodes.values.where((element) => element.type == WalletType.wownero).first,
523 + );
524 + } catch (_) {
525 + return nodes.values.where((element) => element.type == WalletType.wownero).first;
526 + }
527 +}
528 +
529 Future<void> insecureStorageMigration({
530 required SharedPreferences sharedPreferences,
531 required SecureStorage secureStorage,
@@ -898,6 +926,7 @@ Future<void> checkCurrentNodes(
926 sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
927 final currentSolanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
928 final currentTronNodeId = sharedPreferences.getInt(PreferencesKey.currentTronNodeIdKey);
929 + final currentWowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
930 final currentMoneroNode =
931 nodeSource.values.firstWhereOrNull((node) => node.key == currentMoneroNodeId);
932 final currentBitcoinElectrumServer =
@@ -920,6 +949,8 @@ Future<void> checkCurrentNodes(
949 nodeSource.values.firstWhereOrNull((node) => node.key == currentSolanaNodeId);
950 final currentTronNodeServer =
951 nodeSource.values.firstWhereOrNull((node) => node.key == currentTronNodeId);
952 + final currentWowneroNodeServer =
953 + nodeSource.values.firstWhereOrNull((node) => node.key == currentWowneroNodeId);
954 if (currentMoneroNode == null) {
955 final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
956 await nodeSource.add(newCakeWalletNode);
@@ -997,6 +1028,12 @@ Future<void> checkCurrentNodes(
1028 await nodeSource.add(node);
1029 await sharedPreferences.setInt(PreferencesKey.currentTronNodeIdKey, node.key as int);
1030 }
1031 +
1032 + if (currentWowneroNodeServer == null) {
1033 + final node = Node(uri: wowneroDefaultNodeUri, type: WalletType.wownero);
1034 + await nodeSource.add(node);
1035 + await sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, node.key as int);
1036 + }
1037 }
1038
1039 Future<void> resetBitcoinElectrumServer(
@@ -1063,6 +1100,23 @@ Future<void> changeEthereumCurrentNodeToDefault(
1100 await sharedPreferences.setInt(PreferencesKey.currentEthereumNodeIdKey, nodeId);
1101 }
1102
1103 +Future<void> addWowneroNodeList({required Box<Node> nodes}) async {
1104 + final nodeList = await loadDefaultWowneroNodes();
1105 + for (var node in nodeList) {
1106 + if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
1107 + await nodes.add(node);
1108 + }
1109 + }
1110 +}
1111 +
1112 +Future<void> changeWowneroCurrentNodeToDefault(
1113 + {required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
1114 + final node = getWowneroDefaultNode(nodes: nodes);
1115 + final nodeId = node?.key as int? ?? 0;
1116 +
1117 + await sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, nodeId);
1118 +}
1119 +
1120 Future<void> addNanoNodeList({required Box<Node> nodes}) async {
1121 final nodeList = await loadDefaultNanoNodes();
1122 for (var node in nodeList) {
lib/entities/language_service.dart
+12 -3
@@ -63,6 +63,8 @@ class LanguageService {
63
64 static final list = <String, String>{};
65
66 + static const defaultLocale = 'en';
67 +
68 static void loadLocaleList() {
69 supportedLocales.forEach((key, value) {
70 if (locales.contains(key)) {
@@ -72,9 +74,16 @@ class LanguageService {
74 }
75
76 static Future<String> localeDetection() async {
75 - var locale = await Devicelocale.currentLocale ?? '';
76 - locale = Intl.shortLocale(locale);
77 + try {
78 + var locale = await Devicelocale.currentLocale ?? '';
79 + locale = Intl.shortLocale(locale);
80
78 - return list.keys.contains(locale) ? locale : 'en';
81 + if (list.keys.contains(locale)) {
82 + return locale;
83 + }
84 + return LanguageService.defaultLocale;
85 + } catch(_) {
86 + return LanguageService.defaultLocale;
87 + }
88 }
89 }
lib/entities/node_list.dart
+17
@@ -183,6 +183,23 @@ Future<List<Node>> loadDefaultTronNodes() async {
183 return nodes;
184 }
185
186 +Future<List<Node>> loadDefaultWowneroNodes() async {
187 + final nodesRaw = await rootBundle.loadString('assets/wownero_node_list.yml');
188 + final loadedNodes = loadYaml(nodesRaw) as YamlList;
189 + final nodes = <Node>[];
190 +
191 + for (final raw in loadedNodes) {
192 + if (raw is Map) {
193 + final node = Node.fromMap(Map<String, Object>.from(raw));
194 +
195 + node.type = WalletType.wownero;
196 + nodes.add(node);
197 + }
198 + }
199 +
200 + return nodes;
201 +}
202 +
203 Future<void> resetToDefault(Box<Node> nodeSource) async {
204 final moneroNodes = await loadDefaultNodes();
205 final bitcoinElectrumServerList = await loadBitcoinElectrumServerList();
lib/entities/preferences_key.dart
+2
@@ -15,6 +15,7 @@ class PreferencesKey {
15 static const currentBitcoinCashNodeIdKey = 'current_node_id_bch';
16 static const currentSolanaNodeIdKey = 'current_node_id_sol';
17 static const currentTronNodeIdKey = 'current_node_id_trx';
18 + static const currentWowneroNodeIdKey = 'current_node_id_wow';
19 static const currentTransactionPriorityKeyLegacy = 'current_fee_priority';
20 static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
21 static const shouldSaveRecipientAddressKey = 'save_recipient_address';
@@ -43,6 +44,7 @@ class PreferencesKey {
44 static const ethereumTransactionPriority = 'current_fee_priority_ethereum';
45 static const polygonTransactionPriority = 'current_fee_priority_polygon';
46 static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash';
47 + static const wowneroTransactionPriority = 'current_fee_priority_wownero';
48 static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
49 static const silentPaymentsCardDisplay = 'silentPaymentsCardDisplay';
50 static const silentPaymentsAlwaysScan = 'silentPaymentsAlwaysScan';
lib/entities/priority_for_wallet_type.dart
+3
@@ -4,6 +4,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
4 import 'package:cake_wallet/haven/haven.dart';
5 import 'package:cake_wallet/monero/monero.dart';
6 import 'package:cake_wallet/polygon/polygon.dart';
7 +import 'package:cake_wallet/wownero/wownero.dart';
8 import 'package:cw_core/transaction_priority.dart';
9 import 'package:cw_core/wallet_type.dart';
10
@@ -11,6 +12,8 @@ List<TransactionPriority> priorityForWalletType(WalletType type) {
12 switch (type) {
13 case WalletType.monero:
14 return monero!.getTransactionPriorities();
15 + case WalletType.wownero:
16 + return wownero!.getTransactionPriorities();
17 case WalletType.bitcoin:
18 return bitcoin!.getTransactionPriorities();
19 case WalletType.litecoin:
lib/entities/provider_types.dart
+2
@@ -51,6 +51,7 @@ class ProvidersHelper {
51 switch (walletType) {
52 case WalletType.nano:
53 case WalletType.banano:
54 + case WalletType.wownero:
55 return [ProviderType.askEachTime, ProviderType.onramper];
56 case WalletType.monero:
57 return [ProviderType.askEachTime, ProviderType.onramper, ProviderType.dfx];
@@ -114,6 +115,7 @@ class ProvidersHelper {
115 case WalletType.banano:
116 case WalletType.none:
117 case WalletType.haven:
118 + case WalletType.wownero:
119 return [];
120 }
121 }
lib/entities/seed_type.dart
+5
@@ -10,6 +10,7 @@ class SeedType extends EnumerableItem<int> with Serializable<int> {
10
11 static const legacy = SeedType(raw: 0, title: 'Legacy (25 words)');
12 static const polyseed = SeedType(raw: 1, title: 'Polyseed (16 words)');
13 + static const wowneroSeed = SeedType(raw: 2, title: 'Wownero (14 words)');
14
15 static SeedType deserialize({required int raw}) {
16 switch (raw) {
@@ -17,6 +18,8 @@ class SeedType extends EnumerableItem<int> with Serializable<int> {
18 return legacy;
19 case 1:
20 return polyseed;
21 + case 2:
22 + return wowneroSeed;
23 default:
24 throw Exception('Unexpected token: $raw for SeedType deserialize');
25 }
@@ -29,6 +32,8 @@ class SeedType extends EnumerableItem<int> with Serializable<int> {
32 return S.current.seedtype_legacy;
33 case SeedType.polyseed:
34 return S.current.seedtype_polyseed;
35 + case SeedType.wowneroSeed:
36 + return S.current.seedtype_wownero;
37 default:
38 return '';
39 }
lib/main.dart
+28 -27
@@ -1,45 +1,45 @@
1 import 'dart:async';
2 import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
3 +import 'package:cake_wallet/buy/order.dart';
4 import 'package:cake_wallet/core/auth_service.dart';
5 +import 'package:cake_wallet/di.dart';
6 +import 'package:cake_wallet/entities/contact.dart';
7 +import 'package:cake_wallet/entities/default_settings_migration.dart';
8 +import 'package:cake_wallet/entities/get_encryption_key.dart';
9 import 'package:cake_wallet/core/secure_storage.dart';
10 import 'package:cake_wallet/entities/language_service.dart';
6 -import 'package:cake_wallet/buy/order.dart';
11 +import 'package:cake_wallet/entities/template.dart';
12 +import 'package:cake_wallet/entities/transaction_description.dart';
13 +import 'package:cake_wallet/exchange/exchange_template.dart';
14 +import 'package:cake_wallet/exchange/trade.dart';
15 +import 'package:cake_wallet/generated/i18n.dart';
16 import 'package:cake_wallet/locales/locale.dart';
17 +import 'package:cake_wallet/monero/monero.dart';
18 +import 'package:cake_wallet/reactions/bootstrap.dart';
19 +import 'package:cake_wallet/router.dart' as Router;
20 +import 'package:cake_wallet/routes.dart';
21 +import 'package:cake_wallet/src/screens/root/root.dart';
22 +import 'package:cake_wallet/store/app_store.dart';
23 +import 'package:cake_wallet/store/authentication_store.dart';
24 +import 'package:cake_wallet/themes/theme_base.dart';
25 import 'package:cake_wallet/utils/device_info.dart';
26 import 'package:cake_wallet/utils/exception_handler.dart';
27 import 'package:cake_wallet/view_model/link_view_model.dart';
11 -import 'package:cw_core/address_info.dart';
28 import 'package:cake_wallet/utils/responsive_layout_util.dart';
29 +import 'package:cw_core/address_info.dart';
30 +import 'package:cw_core/cake_hive.dart';
31 import 'package:cw_core/hive_type_ids.dart';
32 +import 'package:cw_core/node.dart';
33 +import 'package:cw_core/unspent_coins_info.dart';
34 +import 'package:cw_core/wallet_info.dart';
35 +import 'package:cw_core/wallet_type.dart';
36 import 'package:flutter/foundation.dart';
37 import 'package:flutter/material.dart';
38 import 'package:flutter/services.dart';
39 +import 'package:flutter_mobx/flutter_mobx.dart';
40 import 'package:hive/hive.dart';
18 -import 'package:cake_wallet/di.dart';
19 -import 'package:path_provider/path_provider.dart';
41 +import 'package:cw_core/root_dir.dart';
42 import 'package:shared_preferences/shared_preferences.dart';
21 -import 'package:flutter_mobx/flutter_mobx.dart';
22 -import 'package:cake_wallet/themes/theme_base.dart';
23 -import 'package:cake_wallet/router.dart' as Router;
24 -import 'package:cake_wallet/routes.dart';
25 -import 'package:cake_wallet/generated/i18n.dart';
26 -import 'package:cake_wallet/reactions/bootstrap.dart';
27 -import 'package:cake_wallet/store/app_store.dart';
28 -import 'package:cake_wallet/store/authentication_store.dart';
29 -import 'package:cake_wallet/entities/transaction_description.dart';
30 -import 'package:cake_wallet/entities/get_encryption_key.dart';
31 -import 'package:cake_wallet/entities/contact.dart';
32 -import 'package:cw_core/node.dart';
33 -import 'package:cw_core/wallet_info.dart';
34 -import 'package:cake_wallet/entities/default_settings_migration.dart';
35 -import 'package:cw_core/wallet_type.dart';
36 -import 'package:cake_wallet/entities/template.dart';
37 -import 'package:cake_wallet/exchange/trade.dart';
38 -import 'package:cake_wallet/exchange/exchange_template.dart';
39 -import 'package:cake_wallet/src/screens/root/root.dart';
40 -import 'package:cw_core/unspent_coins_info.dart';
41 -import 'package:cake_wallet/monero/monero.dart';
42 -import 'package:cw_core/cake_hive.dart';
43 import 'package:cw_core/window_size.dart';
44
45 final navigatorKey = GlobalKey<NavigatorState>();
@@ -103,7 +103,8 @@ Future<void> main() async {
103 }
104
105 Future<void> initializeAppConfigs() async {
106 - final appDir = await getApplicationDocumentsDirectory();
106 + setRootDirFromEnv();
107 + final appDir = await getAppDir();
108 CakeHive.init(appDir.path);
109
110 if (!CakeHive.isAdapterRegistered(Contact.typeId)) {
lib/monero/cw_monero.dart
+5
@@ -341,4 +341,9 @@ class CWMonero extends Monero {
341 final moneroWallet = wallet as MoneroWallet;
342 await moneroWallet.updateUnspent();
343 }
344 +
345 + @override
346 + Future<int> getCurrentHeight() async {
347 + return monero_wallet_api.getCurrentHeight();
348 + }
349 }
lib/reactions/on_current_wallet_change.dart
+1
@@ -71,6 +71,7 @@ void startCurrentWalletChangeReaction(
71 .setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type));
72
73 if (wallet.type == WalletType.monero ||
74 + wallet.type == WalletType.wownero ||
75 wallet.type == WalletType.bitcoin ||
76 wallet.type == WalletType.litecoin ||
77 wallet.type == WalletType.bitcoinCash) {
lib/src/screens/dashboard/dashboard_page.dart
+22 -1
@@ -7,6 +7,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sideba
7 import 'package:cake_wallet/src/screens/dashboard/pages/cake_features_page.dart';
8 import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
9 import 'package:cake_wallet/src/widgets/gradient_background.dart';
10 +import 'package:cake_wallet/src/widgets/haven_wallet_removal_popup.dart';
11 import 'package:cake_wallet/src/widgets/services_updates_widget.dart';
12 import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
13 import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
@@ -351,10 +352,12 @@ class _DashboardPageView extends BasePage {
352
353 _showVulnerableSeedsPopup(context);
354
355 + _showHavenPopup(context);
356 +
357 var needToPresentYat = false;
358 var isInactive = false;
359
357 - _onInactiveSub = rootKey.currentState!.isInactive.listen(
360 + _onInactiveSub = rootKey.currentState?.isInactive.listen(
361 (inactive) {
362 isInactive = inactive;
363
@@ -428,4 +431,22 @@ class _DashboardPageView extends BasePage {
431 );
432 }
433 }
434 +
435 + void _showHavenPopup(BuildContext context) async {
436 + final List<String> havenWalletList = await dashboardViewModel.checkForHavenWallets();
437 +
438 + if (havenWalletList.isNotEmpty) {
439 + Future<void>.delayed(
440 + Duration(seconds: 1),
441 + () {
442 + showPopUp<void>(
443 + context: context,
444 + builder: (BuildContext context) {
445 + return HavenWalletRemovalPopup(havenWalletList);
446 + },
447 + );
448 + },
449 + );
450 + }
451 + }
452 }
lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart
+1
@@ -40,6 +40,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
40 final bananoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
41 final solanaIcon = Image.asset('assets/images/sol_icon.png', height: 24, width: 24);
42 final tronIcon = Image.asset('assets/images/trx_icon.png', height: 24, width: 24);
43 + final wowneroIcon = Image.asset('assets/images/wownero_icon.png', height: 24, width: 24);
44 final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
45
46 Image _newWalletImage(BuildContext context) => Image.asset(
lib/src/screens/dashboard/widgets/menu_widget.dart
+5 -1
@@ -36,7 +36,8 @@ class MenuWidgetState extends State<MenuWidget> {
36 this.bitcoinCashIcon = Image.asset('assets/images/bch_icon.png'),
37 this.polygonIcon = Image.asset('assets/images/matic_icon.png'),
38 this.solanaIcon = Image.asset('assets/images/sol_icon.png'),
39 - this.tronIcon = Image.asset('assets/images/trx_icon.png');
39 + this.tronIcon = Image.asset('assets/images/trx_icon.png'),
40 + this.wowneroIcon = Image.asset('assets/images/wownero_icon.png');
41
42 final largeScreen = 731;
43
@@ -60,6 +61,7 @@ class MenuWidgetState extends State<MenuWidget> {
61 Image polygonIcon;
62 Image solanaIcon;
63 Image tronIcon;
64 + Image wowneroIcon;
65
66 @override
67 void initState() {
@@ -236,6 +238,8 @@ class MenuWidgetState extends State<MenuWidget> {
238 return solanaIcon;
239 case WalletType.tron:
240 return tronIcon;
241 + case WalletType.wownero:
242 + return wowneroIcon;
243 default:
244 throw Exception('No icon for ${type.toString()}');
245 }
lib/src/screens/new_wallet/new_wallet_page.dart
+1 -1
@@ -82,7 +82,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
82 void initState() {
83 _stateReaction ??= reaction((_) => _walletNewVM.state, (ExecutionState state) async {
84 if (state is ExecutedSuccessfullyState) {
85 - Navigator.of(navigatorKey.currentContext!)
85 + Navigator.of(navigatorKey.currentContext ?? context)
86 .pushNamed(Routes.preSeedPage, arguments: _walletNewVM.seedPhraseWordsLength);
87 }
88
lib/src/screens/rescan/rescan_page.dart
+1
@@ -33,6 +33,7 @@ class RescanPage extends BasePage {
33 doSingleScan: _rescanViewModel.doSingleScan,
34 toggleSingleScan: () =>
35 _rescanViewModel.doSingleScan = !_rescanViewModel.doSingleScan,
36 + walletType: _rescanViewModel.wallet.type,
37 )),
38 Observer(
39 builder: (_) => LoadingPrimaryButton(
lib/src/screens/restore/wallet_restore_from_keys_form.dart
+1
@@ -171,6 +171,7 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
171 hasDatePicker: widget.walletRestoreViewModel.type != WalletType.haven,
172 onHeightChange: (_) => null,
173 onHeightOrDateEntered: widget.onHeightOrDateEntered,
174 + walletType: widget.walletRestoreViewModel.type,
175 ),
176 ],
177 );
lib/src/screens/restore/wallet_restore_from_seed_form.dart
+40 -12
@@ -83,12 +83,17 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
83 }
84
85 void onSeedChange(String seed) {
86 - if (widget.type == WalletType.monero && Polyseed.isValidSeed(seed)) {
86 + if ((widget.type == WalletType.monero || widget.type == WalletType.wownero) &&
87 + Polyseed.isValidSeed(seed)) {
88 final lang = PolyseedLang.getByPhrase(seed);
89
90 _changeSeedType(SeedType.polyseed);
91 _changeLanguage(lang.nameEnglish);
92 }
93 + if (widget.type == WalletType.wownero && seed.split(" ").length == 14) {
94 + _changeSeedType(SeedType.wowneroSeed);
95 + _changeLanguage("English");
96 + }
97 widget.onSeedChange?.call(seed);
98 }
99
@@ -142,14 +147,18 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
147 language: language,
148 type: widget.type,
149 onSeedChange: onSeedChange),
145 - if (widget.type == WalletType.monero)
150 + if (widget.type == WalletType.monero || widget.type == WalletType.wownero)
151 GestureDetector(
152 onTap: () async {
153 await showPopUp<void>(
154 context: context,
155 builder: (_) => Picker(
151 - items: SeedType.all,
152 - selectedAtIndex: isPolyseed ? 1 : 0,
156 + items: _getItems(),
157 + selectedAtIndex: isPolyseed
158 + ? 1
159 + : seedTypeController.value.text.contains("14")
160 + ? 2
161 + : 0,
162 mainAxisAlignment: MainAxisAlignment.start,
163 onItemSelected: _changeSeedType,
164 isSeparated: false,
@@ -168,7 +177,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
177 ),
178 ),
179 ),
171 - if (widget.displayLanguageSelector)
180 + if (!seedTypeController.value.text.contains("14") && widget.displayLanguageSelector)
181 GestureDetector(
182 onTap: () async {
183 await showPopUp<void>(
@@ -192,12 +201,14 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
201 ),
202 ),
203 ),
195 - if (!isPolyseed && widget.displayBlockHeightSelector)
204 + if ((!isPolyseed) && widget.displayBlockHeightSelector)
205 BlockchainHeightWidget(
197 - focusNode: widget.blockHeightFocusNode,
198 - key: blockchainHeightKey,
199 - onHeightOrDateEntered: widget.onHeightOrDateEntered,
200 - hasDatePicker: widget.type == WalletType.monero),
206 + focusNode: widget.blockHeightFocusNode,
207 + key: blockchainHeightKey,
208 + onHeightOrDateEntered: widget.onHeightOrDateEntered,
209 + hasDatePicker: widget.type == WalletType.monero || widget.type == WalletType.wownero,
210 + walletType: widget.type,
211 + ),
212 if (widget.displayPassphrase) ...[
213 const SizedBox(height: 10),
214 BaseTextFormField(
@@ -209,7 +220,9 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
220 ]));
221 }
222
212 - bool get isPolyseed => widget.seedTypeViewModel.moneroSeedType == SeedType.polyseed;
223 + bool get isPolyseed =>
224 + widget.seedTypeViewModel.moneroSeedType == SeedType.polyseed &&
225 + (widget.type == WalletType.monero || widget.type == WalletType.wownero);
226
227 Widget get expandIcon => Container(
228 padding: EdgeInsets.all(18),
@@ -223,7 +236,11 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
236 );
237
238 void _changeLanguage(String language) {
226 - final setLang = isPolyseed ? "POLYSEED_$language" : language;
239 + final setLang = isPolyseed
240 + ? "POLYSEED_$language"
241 + : seedTypeController.value.text.contains("14")
242 + ? "WOWSEED_" + language
243 + : language;
244 setState(() {
245 this.language = setLang;
246 seedWidgetStateKey.currentState!.changeSeedLanguage(setLang);
@@ -244,4 +261,15 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
261 void _setSeedType(SeedType item) {
262 seedTypeController.text = item.toString();
263 }
264 +
265 + List<SeedType> _getItems() {
266 + switch (widget.type) {
267 + case WalletType.monero:
268 + return [SeedType.legacy, SeedType.polyseed];
269 + case WalletType.wownero:
270 + return [SeedType.legacy, SeedType.polyseed, SeedType.wowneroSeed];
271 + default:
272 + return [SeedType.legacy];
273 + }
274 + }
275 }
lib/src/screens/restore/wallet_restore_page.dart
+10 -10
@@ -20,7 +20,6 @@ import 'package:flutter/material.dart';
20 import 'package:flutter_mobx/flutter_mobx.dart';
21 import 'package:keyboard_actions/keyboard_actions.dart';
22 import 'package:mobx/mobx.dart';
23 -import 'package:polyseed/polyseed.dart';
23 import 'package:smooth_page_indicator/smooth_page_indicator.dart';
24
25 class WalletRestorePage extends BasePage {
@@ -48,8 +47,7 @@ class WalletRestorePage extends BasePage {
47 }
48 },
49 onSeedChange: (String seed) {
51 - final isPolyseed =
52 - walletRestoreViewModel.type == WalletType.monero && Polyseed.isValidSeed(seed);
50 + final isPolyseed = walletRestoreViewModel.isPolyseed(seed);
51 _validateOnChange(isPolyseed: isPolyseed);
52 },
53 onLanguageChange: (String language) {
@@ -103,11 +101,11 @@ class WalletRestorePage extends BasePage {
101
102 @override
103 Function(BuildContext)? get pushToNextWidget => (context) {
106 - FocusScopeNode currentFocus = FocusScope.of(context);
107 - if (!currentFocus.hasPrimaryFocus) {
108 - currentFocus.focusedChild?.unfocus();
109 - }
110 - };
104 + FocusScopeNode currentFocus = FocusScope.of(context);
105 + if (!currentFocus.hasPrimaryFocus) {
106 + currentFocus.focusedChild?.unfocus();
107 + }
108 + };
109
110 @override
111 Widget body(BuildContext context) {
@@ -253,12 +251,14 @@ class WalletRestorePage extends BasePage {
251 bool _isValidSeed() {
252 final seedPhrase =
253 walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text;
256 - if (walletRestoreViewModel.type == WalletType.monero && Polyseed.isValidSeed(seedPhrase))
257 - return true;
254 + if (walletRestoreViewModel.isPolyseed(seedPhrase)) return true;
255
256 final seedWords = seedPhrase.split(' ');
257
258 + if (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) return true;
259 +
260 if ((walletRestoreViewModel.type == WalletType.monero ||
261 + walletRestoreViewModel.type == WalletType.wownero ||
262 walletRestoreViewModel.type == WalletType.haven) &&
263 seedWords.length != WalletRestoreViewModelBase.moneroSeedMnemonicLength) {
264 return false;
lib/src/screens/wallet_list/wallet_list_page.dart
+5 -1
@@ -106,6 +106,7 @@ class WalletListBodyState extends State<WalletListBody> {
106 final polygonIcon = Image.asset('assets/images/matic_icon.png', height: 24, width: 24);
107 final solanaIcon = Image.asset('assets/images/sol_icon.png', height: 24, width: 24);
108 final tronIcon = Image.asset('assets/images/trx_icon.png', height: 24, width: 24);
109 + final wowneroIcon = Image.asset('assets/images/wownero_icon.png', height: 24, width: 24);
110 final scrollController = ScrollController();
111 final double tileHeight = 60;
112 Flushbar<void>? _progressBar;
@@ -319,6 +320,7 @@ class WalletListBodyState extends State<WalletListBody> {
320 case WalletType.bitcoinCash:
321 return bitcoinCashIcon;
322 case WalletType.nano:
323 + case WalletType.banano:
324 return nanoIcon;
325 case WalletType.polygon:
326 return polygonIcon;
@@ -326,7 +328,9 @@ class WalletListBodyState extends State<WalletListBody> {
328 return solanaIcon;
329 case WalletType.tron:
330 return tronIcon;
329 - default:
331 + case WalletType.wownero:
332 + return wowneroIcon;
333 + case WalletType.none:
334 return nonWalletTypeIcon;
335 }
336 }
lib/src/widgets/blockchain_height_widget.dart
+11 -1
@@ -2,6 +2,8 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/src/widgets/standard_switch.dart';
3 import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
4 import 'package:cake_wallet/utils/date_picker.dart';
5 +import 'package:cake_wallet/wownero/wownero.dart';
6 +import 'package:cw_core/wallet_type.dart';
7 import 'package:flutter/material.dart';
8 import 'package:intl/intl.dart';
9 import 'package:cake_wallet/generated/i18n.dart';
@@ -18,6 +20,7 @@ class BlockchainHeightWidget extends StatefulWidget {
20 this.isSilentPaymentsScan = false,
21 this.toggleSingleScan,
22 this.doSingleScan = false,
23 + required this.walletType,
24 }) : super(key: key);
25
26 final Function(int)? onHeightChange;
@@ -27,6 +30,7 @@ class BlockchainHeightWidget extends StatefulWidget {
30 final bool isSilentPaymentsScan;
31 final bool doSingleScan;
32 final Function()? toggleSingleScan;
33 + final WalletType walletType;
34
35 @override
36 State<StatefulWidget> createState() => BlockchainHeightState();
@@ -160,7 +164,13 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
164 if (widget.isSilentPaymentsScan) {
165 height = bitcoin!.getHeightByDate(date: date);
166 } else {
163 - height = monero!.getHeightByDate(date: date);
167 + if (widget.walletType == WalletType.monero) {
168 + height = monero!.getHeightByDate(date: date);
169 + } else {
170 + assert(widget.walletType == WalletType.wownero,
171 + "unknown currency in BlockchainHeightWidget");
172 + height = wownero!.getHeightByDate(date: date);
173 + }
174 }
175 setState(() {
176 dateController.text = DateFormat('yyyy-MM-dd').format(date);
lib/src/widgets/haven_wallet_removal_popup.dart new
+91
@@ -0,0 +1,91 @@
1 +import 'package:cake_wallet/src/widgets/alert_background.dart';
2 +import 'package:cake_wallet/src/widgets/alert_close_button.dart';
3 +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
4 +import 'package:flutter/material.dart';
5 +
6 +class HavenWalletRemovalPopup extends StatelessWidget {
7 + final List<String> affectedWalletNames;
8 +
9 + const HavenWalletRemovalPopup(this.affectedWalletNames, {Key? key}) : super(key: key);
10 +
11 + @override
12 + Widget build(BuildContext context) {
13 + return Stack(
14 + alignment: Alignment.center,
15 + children: [
16 + AlertBackground(
17 + child: AlertDialog(
18 + insetPadding: EdgeInsets.only(left: 16, right: 16, bottom: 48),
19 + elevation: 0.0,
20 + contentPadding: EdgeInsets.zero,
21 + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(30))),
22 + content: Container(
23 + decoration: BoxDecoration(
24 + borderRadius: BorderRadius.circular(30.0),
25 + gradient: LinearGradient(colors: [
26 + Theme.of(context).extension<DashboardPageTheme>()!.firstGradientBackgroundColor,
27 + Theme.of(context)
28 + .extension<DashboardPageTheme>()!
29 + .secondGradientBackgroundColor,
30 + ], begin: Alignment.centerLeft, end: Alignment.centerRight)),
31 + child: Padding(
32 + padding: const EdgeInsets.symmetric(horizontal: 24.0),
33 + child: Stack(
34 + children: [
35 + SingleChildScrollView(
36 + child: Padding(
37 + padding: const EdgeInsets.only(top: 16.0),
38 + child: Container(
39 + alignment: Alignment.bottomCenter,
40 + child: DefaultTextStyle(
41 + style: TextStyle(
42 + decoration: TextDecoration.none,
43 + fontSize: 24.0,
44 + fontWeight: FontWeight.bold,
45 + fontFamily: 'Lato',
46 + color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
47 + ),
48 + child: Text("Emergency Notice"),
49 + ),
50 + ),
51 + ),
52 + ),
53 + SingleChildScrollView(
54 + child: Padding(
55 + padding: EdgeInsets.only(top: 48, bottom: 16),
56 + child: Container(
57 + width: double.maxFinite,
58 + child: Column(
59 + children: <Widget>[
60 + ConstrainedBox(
61 + constraints: BoxConstraints(
62 + maxHeight: MediaQuery.of(context).size.height * 0.7,
63 + ),
64 + child: Text(
65 + "It looks like you have Haven wallets in your list. Haven is getting removed in next release of Cake Wallet, and you currently have Haven in the following wallets:\n\n[${affectedWalletNames.join(", ")}]\n\nPlease move your funds to other wallet, as you will lose access to your Haven funds in next update.\n\nFor assistance, please use the in-app support or email support@cakewallet.com",
66 + style: TextStyle(
67 + decoration: TextDecoration.none,
68 + fontSize: 16.0,
69 + fontFamily: 'Lato',
70 + color: Theme.of(context)
71 + .extension<DashboardPageTheme>()!
72 + .textColor,
73 + ),
74 + ),
75 + )
76 + ],
77 + ),
78 + ),
79 + ),
80 + ),
81 + ],
82 + ),
83 + ),
84 + ),
85 + ),
86 + ),
87 + AlertCloseButton(bottom: 30)
88 + ],
89 + );
90 + }
91 +}
lib/store/settings_store.dart
+34 -1
@@ -20,6 +20,7 @@ import 'package:cake_wallet/view_model/settings/sync_mode.dart';
20 import 'package:cake_wallet/utils/device_info.dart';
21 import 'package:cake_wallet/ethereum/ethereum.dart';
22 import 'package:cake_wallet/wallet_type_utils.dart';
23 +import 'package:cake_wallet/wownero/wownero.dart';
24 import 'package:cw_core/transaction_priority.dart';
25 import 'package:cake_wallet/themes/theme_base.dart';
26 import 'package:cake_wallet/themes/theme_list.dart';
@@ -27,7 +28,7 @@ import 'package:device_info_plus/device_info_plus.dart';
28 import 'package:flutter/material.dart';
29 import 'package:hive/hive.dart';
30 import 'package:mobx/mobx.dart';
30 -import 'package:package_info/package_info.dart';
31 +import 'package:cake_wallet/utils/package_info.dart';
32 import 'package:cake_wallet/di.dart';
33 import 'package:cw_core/wallet_type.dart';
34 import 'package:shared_preferences/shared_preferences.dart';
@@ -111,6 +112,7 @@ abstract class SettingsStoreBase with Store {
112 required this.silentPaymentsAlwaysScan,
113 TransactionPriority? initialBitcoinTransactionPriority,
114 TransactionPriority? initialMoneroTransactionPriority,
115 + TransactionPriority? initialWowneroTransactionPriority,
116 TransactionPriority? initialHavenTransactionPriority,
117 TransactionPriority? initialLitecoinTransactionPriority,
118 TransactionPriority? initialEthereumTransactionPriority,
@@ -168,6 +170,10 @@ abstract class SettingsStoreBase with Store {
170 priority[WalletType.monero] = initialMoneroTransactionPriority;
171 }
172
173 + if (initialWowneroTransactionPriority != null) {
174 + priority[WalletType.wownero] = initialWowneroTransactionPriority;
175 + }
176 +
177 if (initialBitcoinTransactionPriority != null) {
178 priority[WalletType.bitcoin] = initialBitcoinTransactionPriority;
179 }
@@ -249,6 +255,7 @@ abstract class SettingsStoreBase with Store {
255 final String? key;
256 switch (change.key) {
257 case WalletType.monero:
258 + case WalletType.wownero:
259 key = PreferencesKey.moneroTransactionPriority;
260 break;
261 case WalletType.bitcoin:
@@ -789,6 +796,7 @@ abstract class SettingsStoreBase with Store {
796 TransactionPriority? ethereumTransactionPriority;
797 TransactionPriority? polygonTransactionPriority;
798 TransactionPriority? bitcoinCashTransactionPriority;
799 + TransactionPriority? wowneroTransactionPriority;
800
801 if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
802 havenTransactionPriority = monero?.deserializeMoneroTransactionPriority(
@@ -810,6 +818,10 @@ abstract class SettingsStoreBase with Store {
818 bitcoinCashTransactionPriority = bitcoinCash?.deserializeBitcoinCashTransactionPriority(
819 sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority)!);
820 }
821 + if (sharedPreferences.getInt(PreferencesKey.wowneroTransactionPriority) != null) {
822 + wowneroTransactionPriority = wownero?.deserializeWowneroTransactionPriority(
823 + raw: sharedPreferences.getInt(PreferencesKey.wowneroTransactionPriority)!);
824 + }
825
826 moneroTransactionPriority ??= monero?.getDefaultTransactionPriority();
827 bitcoinTransactionPriority ??= bitcoin?.getMediumTransactionPriority();
@@ -817,6 +829,7 @@ abstract class SettingsStoreBase with Store {
829 litecoinTransactionPriority ??= bitcoin?.getLitecoinTransactionPriorityMedium();
830 ethereumTransactionPriority ??= ethereum?.getDefaultTransactionPriority();
831 bitcoinCashTransactionPriority ??= bitcoinCash?.getDefaultTransactionPriority();
832 + wowneroTransactionPriority ??= wownero?.getDefaultTransactionPriority();
833 polygonTransactionPriority ??= polygon?.getDefaultTransactionPriority();
834
835 final currentBalanceDisplayMode = BalanceDisplayMode.deserialize(
@@ -902,6 +915,7 @@ abstract class SettingsStoreBase with Store {
915 final nanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
916 final solanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
917 final tronNodeId = sharedPreferences.getInt(PreferencesKey.currentTronNodeIdKey);
918 + final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
919 final moneroNode = nodeSource.get(nodeId);
920 final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
921 final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
@@ -913,6 +927,7 @@ abstract class SettingsStoreBase with Store {
927 final nanoPowNode = powNodeSource.get(nanoPowNodeId);
928 final solanaNode = nodeSource.get(solanaNodeId);
929 final tronNode = nodeSource.get(tronNodeId);
930 + final wowneroNode = nodeSource.get(wowneroNodeId);
931 final packageInfo = await PackageInfo.fromPlatform();
932 final deviceName = await _getDeviceName() ?? '';
933 final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
@@ -979,6 +994,10 @@ abstract class SettingsStoreBase with Store {
994 nodes[WalletType.tron] = tronNode;
995 }
996
997 + if (wowneroNode != null) {
998 + nodes[WalletType.wownero] = wowneroNode;
999 + }
1000 +
1001 final savedSyncMode = SyncMode.all.firstWhere((element) {
1002 return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 0);
1003 });
@@ -1127,6 +1146,7 @@ abstract class SettingsStoreBase with Store {
1146 silentPaymentsCardDisplay: silentPaymentsCardDisplay,
1147 silentPaymentsAlwaysScan: silentPaymentsAlwaysScan,
1148 initialMoneroTransactionPriority: moneroTransactionPriority,
1149 + initialWowneroTransactionPriority: wowneroTransactionPriority,
1150 initialBitcoinTransactionPriority: bitcoinTransactionPriority,
1151 initialHavenTransactionPriority: havenTransactionPriority,
1152 initialLitecoinTransactionPriority: litecoinTransactionPriority,
@@ -1164,6 +1184,10 @@ abstract class SettingsStoreBase with Store {
1184 raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
1185 priority[WalletType.monero]!;
1186
1187 + priority[WalletType.wownero] = wownero?.deserializeWowneroTransactionPriority(
1188 + raw: sharedPreferences.getInt(PreferencesKey.wowneroTransactionPriority)!) ??
1189 + priority[WalletType.wownero]!;
1190 +
1191 if (bitcoin != null &&
1192 sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority) != null) {
1193 priority[WalletType.bitcoin] = bitcoin!.deserializeBitcoinTransactionPriority(
@@ -1282,6 +1306,7 @@ abstract class SettingsStoreBase with Store {
1306 final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
1307 final solanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
1308 final tronNodeId = sharedPreferences.getInt(PreferencesKey.currentTronNodeIdKey);
1309 + final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
1310 final moneroNode = nodeSource.get(nodeId);
1311 final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
1312 final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
@@ -1292,6 +1317,7 @@ abstract class SettingsStoreBase with Store {
1317 final nanoNode = nodeSource.get(nanoNodeId);
1318 final solanaNode = nodeSource.get(solanaNodeId);
1319 final tronNode = nodeSource.get(tronNodeId);
1320 + final wowneroNode = nodeSource.get(wowneroNodeId);
1321 if (moneroNode != null) {
1322 nodes[WalletType.monero] = moneroNode;
1323 }
@@ -1332,6 +1358,10 @@ abstract class SettingsStoreBase with Store {
1358 nodes[WalletType.tron] = tronNode;
1359 }
1360
1361 + if (wowneroNode != null) {
1362 + nodes[WalletType.wownero] = wowneroNode;
1363 + }
1364 +
1365 // MIGRATED:
1366
1367 useTOTP2FA = await SecureKey.getBool(
@@ -1465,6 +1495,9 @@ abstract class SettingsStoreBase with Store {
1495 case WalletType.tron:
1496 await _sharedPreferences.setInt(PreferencesKey.currentTronNodeIdKey, node.key as int);
1497 break;
1498 + case WalletType.wownero:
1499 + await _sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, node.key as int);
1500 + break;
1501 default:
1502 break;
1503 }
lib/utils/distribution_info.dart
+1 -1
@@ -1,5 +1,5 @@
1 import 'dart:io';
2 -import 'package:package_info/package_info.dart';
2 +import 'package:cake_wallet/utils/package_info.dart';
3
4 enum DistributionType { googleplay, github, appstore, fdroid }
5
lib/utils/exception_handler.dart
+4 -4
@@ -5,12 +5,12 @@ import 'package:cake_wallet/generated/i18n.dart';
5 import 'package:cake_wallet/main.dart';
6 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
7 import 'package:cake_wallet/utils/show_pop_up.dart';
8 +import 'package:cw_core/root_dir.dart';
9 import 'package:device_info_plus/device_info_plus.dart';
10 import 'package:flutter/foundation.dart';
11 import 'package:flutter/material.dart';
12 import 'package:flutter_mailer/flutter_mailer.dart';
12 -import 'package:package_info/package_info.dart';
13 -import 'package:path_provider/path_provider.dart';
13 +import 'package:cake_wallet/utils/package_info.dart';
14 import 'package:shared_preferences/shared_preferences.dart';
15
16 class ExceptionHandler {
@@ -20,7 +20,7 @@ class ExceptionHandler {
20
21 static void _saveException(String? error, StackTrace? stackTrace, {String? library}) async {
22 if (_file == null) {
23 - final appDocDir = await getApplicationDocumentsDirectory();
23 + final appDocDir = await getAppDir();
24
25 _file = File('${appDocDir.path}/error.txt');
26 }
@@ -53,7 +53,7 @@ class ExceptionHandler {
53 static void _sendExceptionFile() async {
54 try {
55 if (_file == null) {
56 - final appDocDir = await getApplicationDocumentsDirectory();
56 + final appDocDir = await getAppDir();
57
58 _file = File('${appDocDir.path}/error.txt');
59 }
lib/utils/package_info.dart new
+54
@@ -0,0 +1,54 @@
1 +import 'dart:io';
2 +import 'package:package_info/package_info.dart' as __package_info__;
3 +
4 +abstract class _EnvKeys {
5 + static const kWinAppName = 'CW_WIN_APP_NAME';
6 + static const kWinAppPackageName = 'CW_WIN_APP_PACKAGE_NAME';
7 + static const kWinAppVersion = 'CW_WIN_APP_VERSION';
8 + static const kWinAppBuildNumber = 'CW_WIN_APP_BUILD_NUMBER';
9 +}
10 +
11 +class PackageInfo {
12 + static Future<PackageInfo> fromPlatform() async {
13 + if (Platform.isWindows) {
14 + return _windowsPackageInfo;
15 + }
16 +
17 + final packageInfo = await __package_info__.PackageInfo.fromPlatform();
18 + return PackageInfo._(
19 + appName: packageInfo.appName,
20 + packageName: packageInfo.packageName,
21 + version: packageInfo.version,
22 + buildNumber: packageInfo.buildNumber);
23 + }
24 +
25 + static const _defaultCWAppName = 'Cake Wallet';
26 + static const _defaultCWAppPackageName = 'com.cakewallet.cake_wallet';
27 + static const _defaultCWAppVersion = '1.0.0';
28 + static const _defaultCWAppBuildNumber = '1';
29 +
30 + static const _windowsPackageInfo = PackageInfo._(
31 + appName: const String
32 + .fromEnvironment(_EnvKeys.kWinAppName,
33 + defaultValue: _defaultCWAppName),
34 + packageName: const String
35 + .fromEnvironment(_EnvKeys.kWinAppPackageName,
36 + defaultValue: _defaultCWAppPackageName),
37 + version: const String
38 + .fromEnvironment(_EnvKeys.kWinAppVersion,
39 + defaultValue: _defaultCWAppVersion),
40 + buildNumber: const String
41 + .fromEnvironment(_EnvKeys.kWinAppBuildNumber,
42 + defaultValue: _defaultCWAppBuildNumber));
43 +
44 + final String appName;
45 + final String packageName;
46 + final String version;
47 + final String buildNumber;
48 +
49 + const PackageInfo._({
50 + required this.appName,
51 + required this.packageName,
52 + required this.version,
53 + required this.buildNumber});
54 +}
lib/view_model/advanced_privacy_settings_view_model.dart
+2 -1
@@ -41,6 +41,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
41 case WalletType.tron:
42 return true;
43 case WalletType.monero:
44 + case WalletType.wownero:
45 case WalletType.none:
46 case WalletType.bitcoin:
47 case WalletType.litecoin:
@@ -51,7 +52,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
52 }
53 }
54
54 - bool get hasSeedTypeOption => type == WalletType.monero;
55 + bool get hasSeedTypeOption => type == WalletType.monero || type == WalletType.wownero;
56
57 @computed
58 bool get addCustomNode => _addCustomNode;
lib/view_model/backup_view_model.dart
+4 -2
@@ -4,6 +4,8 @@ import 'package:cake_wallet/core/execution_state.dart';
4 import 'package:cake_wallet/core/secure_storage.dart';
5 import 'package:cake_wallet/entities/secret_store_key.dart';
6 import 'package:cake_wallet/store/secret_store.dart';
7 +import 'package:cw_core/root_dir.dart';
8 +import 'package:flutter/foundation.dart';
9 import 'package:mobx/mobx.dart';
10 import 'package:intl/intl.dart';
11 import 'package:cake_wallet/wallet_type_utils.dart';
@@ -72,7 +74,7 @@ abstract class BackupViewModelBase with Store {
74 }
75
76 Future<String> saveBackupFileLocally(BackupExportFile backup) async {
75 - final appDir = await getApplicationDocumentsDirectory();
77 + final appDir = await getAppDir();
78 final path = '${appDir.path}/${backup.name}';
79 final backupFile = File(path);
80 await backupFile.writeAsBytes(backup.content);
@@ -80,7 +82,7 @@ abstract class BackupViewModelBase with Store {
82 }
83
84 Future<void> removeBackupFileLocally(BackupExportFile backup) async {
83 - final appDir = await getApplicationDocumentsDirectory();
85 + final appDir = await getAppDir();
86 final path = '${appDir.path}/${backup.name}';
87 final backupFile = File(path);
88 await backupFile.delete();
lib/view_model/dashboard/balance_view_model.dart
+2
@@ -125,6 +125,7 @@ abstract class BalanceViewModelBase with Store {
125 String get availableBalanceLabel {
126 switch (wallet.type) {
127 case WalletType.monero:
128 + case WalletType.wownero:
129 case WalletType.haven:
130 case WalletType.ethereum:
131 case WalletType.polygon:
@@ -142,6 +143,7 @@ abstract class BalanceViewModelBase with Store {
143 String get additionalBalanceLabel {
144 switch (wallet.type) {
145 case WalletType.monero:
146 + case WalletType.wownero:
147 case WalletType.haven:
148 case WalletType.ethereum:
149 case WalletType.polygon:
lib/view_model/dashboard/dashboard_view_model.dart
+6
@@ -303,6 +303,7 @@ abstract class DashboardViewModelBase with Store {
303 bool get hasRescan =>
304 wallet.type == WalletType.bitcoin ||
305 wallet.type == WalletType.monero ||
306 + wallet.type == WalletType.wownero ||
307 wallet.type == WalletType.haven;
308
309 @computed
@@ -532,6 +533,11 @@ abstract class DashboardViewModelBase with Store {
533 @action
534 void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
535
536 + Future<List<String>> checkForHavenWallets() async {
537 + final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
538 + return walletInfoSource.values.where((element) => element.type == WalletType.haven).map((e) => e.name).toList();
539 + }
540 +
541 Future<List<String>> checkAffectedWallets() async {
542 try {
543 // await load file
lib/view_model/dashboard/transaction_list_item.dart
+16 -3
@@ -7,6 +7,7 @@ import 'package:cake_wallet/polygon/polygon.dart';
7 import 'package:cake_wallet/reactions/wallet_connect.dart';
8 import 'package:cake_wallet/solana/solana.dart';
9 import 'package:cake_wallet/tron/tron.dart';
10 +import 'package:cake_wallet/wownero/wownero.dart';
11 import 'package:cw_core/crypto_currency.dart';
12 import 'package:cw_core/transaction_direction.dart';
13 import 'package:cw_core/transaction_info.dart';
@@ -55,8 +56,14 @@ class TransactionListItem extends ActionListItem with Keyable {
56 }
57
58 String get formattedPendingStatus {
58 - if (transaction.confirmations >= 0 && transaction.confirmations < 10) {
59 - return ' (${transaction.confirmations}/10)';
59 + if (balanceViewModel.wallet.type == WalletType.monero || balanceViewModel.wallet.type == WalletType.haven) {
60 + if (transaction.confirmations >= 0 && transaction.confirmations < 10) {
61 + return ' (${transaction.confirmations}/10)';
62 + }
63 + } else if (balanceViewModel.wallet.type == WalletType.wownero) {
64 + if (transaction.confirmations >= 0 && transaction.confirmations < 3) {
65 + return ' (${transaction.confirmations}/3)';
66 + }
67 }
68 return '';
69 }
@@ -64,6 +71,7 @@ class TransactionListItem extends ActionListItem with Keyable {
71 String get formattedStatus {
72 if (transaction.direction == TransactionDirection.incoming) {
73 if (balanceViewModel.wallet.type == WalletType.monero ||
74 + balanceViewModel.wallet.type == WalletType.wownero ||
75 balanceViewModel.wallet.type == WalletType.haven) {
76 return formattedPendingStatus;
77 }
@@ -95,7 +103,7 @@ class TransactionListItem extends ActionListItem with Keyable {
103 } catch (e) {
104 return null;
105 }
98 -
106 +
107 return null;
108 }
109
@@ -108,6 +116,11 @@ class TransactionListItem extends ActionListItem with Keyable {
116 cryptoAmount: monero!.formatterMoneroAmountToDouble(amount: transaction.amount),
117 price: price);
118 break;
119 + case WalletType.wownero:
120 + amount = calculateFiatAmountRaw(
121 + cryptoAmount: wownero!.formatterWowneroAmountToDouble(amount: transaction.amount),
122 + price: price);
123 + break;
124 case WalletType.bitcoin:
125 case WalletType.litecoin:
126 case WalletType.bitcoinCash:
lib/view_model/exchange/exchange_view_model.dart
+11 -1
@@ -287,6 +287,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
287 bool get isLowFee {
288 switch (wallet.type) {
289 case WalletType.monero:
290 + case WalletType.wownero:
291 case WalletType.haven:
292 return transactionPriority == monero!.getMoneroTransactionPrioritySlow();
293 case WalletType.bitcoin:
@@ -670,6 +671,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
671 depositCurrency = CryptoCurrency.nano;
672 receiveCurrency = CryptoCurrency.xmr;
673 break;
674 + case WalletType.banano:
675 + depositCurrency = CryptoCurrency.banano;
676 + receiveCurrency = CryptoCurrency.xmr;
677 + break;
678 case WalletType.polygon:
679 depositCurrency = CryptoCurrency.maticpoly;
680 receiveCurrency = CryptoCurrency.xmr;
@@ -682,7 +687,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
687 depositCurrency = CryptoCurrency.trx;
688 receiveCurrency = CryptoCurrency.xmr;
689 break;
685 - default:
690 + case WalletType.wownero:
691 + depositCurrency = CryptoCurrency.wow;
692 + receiveCurrency = CryptoCurrency.xmr;
693 + break;
694 + case WalletType.none:
695 break;
696 }
697 }
@@ -755,6 +764,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
764 switch (wallet.type) {
765 case WalletType.monero:
766 case WalletType.haven:
767 + case WalletType.wownero:
768 _settingsStore.priority[wallet.type] = monero!.getMoneroTransactionPriorityAutomatic();
769 break;
770 case WalletType.bitcoin:
lib/view_model/node_list/node_create_or_edit_view_model.dart
+1
@@ -80,6 +80,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
80 return true;
81 case WalletType.none:
82 case WalletType.monero:
83 + case WalletType.wownero:
84 case WalletType.haven:
85 case WalletType.litecoin:
86 case WalletType.bitcoinCash:
lib/view_model/node_list/node_list_view_model.dart
+3
@@ -85,6 +85,9 @@ abstract class NodeListViewModelBase with Store {
85 case WalletType.tron:
86 node = getTronDefaultNode(nodes: _nodeSource)!;
87 break;
88 + case WalletType.wownero:
89 + node = getWowneroDefaultNode(nodes: _nodeSource);
90 + break;
91 default:
92 throw Exception('Unexpected wallet type: ${_appStore.wallet!.type}');
93 }
lib/view_model/restore/restore_from_qr_vm.dart
+18 -1
@@ -7,6 +7,7 @@ import 'package:cake_wallet/solana/solana.dart';
7 import 'package:cake_wallet/tron/tron.dart';
8 import 'package:cake_wallet/view_model/restore/restore_mode.dart';
9 import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
10 +import 'package:cake_wallet/wownero/wownero.dart';
11 import 'package:hive/hive.dart';
12 import 'package:mobx/mobx.dart';
13 import 'package:cake_wallet/monero/monero.dart';
@@ -48,7 +49,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
49 @observable
50 String address;
51
51 - bool get hasRestorationHeight => type == WalletType.monero;
52 + bool get hasRestorationHeight => type == WalletType.monero || type == WalletType.wownero;
53
54 @override
55 WalletCredentials getCredentialsFromRestoredWallet(
@@ -74,6 +75,15 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
75 viewKey: restoreWallet.viewKey ?? '',
76 spendKey: restoreWallet.spendKey ?? '',
77 height: restoreWallet.height ?? 0);
78 + case WalletType.wownero:
79 + return wownero!.createWowneroRestoreWalletFromKeysCredentials(
80 + name: name,
81 + password: password,
82 + language: 'English',
83 + address: restoreWallet.address ?? '',
84 + viewKey: restoreWallet.viewKey ?? '',
85 + spendKey: restoreWallet.spendKey ?? '',
86 + height: restoreWallet.height ?? 0);
87 case WalletType.bitcoin:
88 case WalletType.litecoin:
89 return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
@@ -137,6 +147,13 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
147 case WalletType.tron:
148 return tron!.createTronRestoreWalletFromSeedCredentials(
149 name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
150 + case WalletType.wownero:
151 + return wownero!.createWowneroRestoreWalletFromSeedCredentials(
152 + name: name,
153 + height: restoreWallet.height ?? 0,
154 + mnemonic: restoreWallet.mnemonicSeed ?? '',
155 + password: password,
156 + );
157 default:
158 throw Exception('Unexpected type: ${type.toString()}');
159 }
lib/view_model/restore/wallet_restore_from_qr_code.dart
+8 -2
@@ -36,6 +36,9 @@ class WalletRestoreFromQRCode {
36 'tron': WalletType.tron,
37 'tron-wallet': WalletType.tron,
38 'tron_wallet': WalletType.tron,
39 + 'wownero': WalletType.wownero,
40 + 'wownero-wallet': WalletType.wownero,
41 + 'wownero_wallet': WalletType.wownero,
42 };
43
44 static bool _containsAssetSpecifier(String code) => _extractWalletType(code) != null;
@@ -57,7 +60,9 @@ class WalletRestoreFromQRCode {
60 RegExp _getPattern(int wordCount) =>
61 RegExp(r'(?<=\W|^)((?:\w+\s+){' + (wordCount - 1).toString() + r'}\w+)(?=\W|$)');
62
60 - List<int> patternCounts = walletType == WalletType.monero ? [25, 16, 14, 13] : [24, 18, 12];
63 + List<int> patternCounts = walletType == WalletType.monero || walletType == WalletType.wownero
64 + ? [25, 16, 14, 13]
65 + : [24, 18, 12];
66
67 for (final count in patternCounts) {
68 final pattern = _getPattern(count);
@@ -132,7 +137,8 @@ class WalletRestoreFromQRCode {
137 final seedValue = credentials['seed'] as String;
138 final words = SeedValidator.getWordList(type: type, language: 'english');
139
135 - if (type == WalletType.monero && Polyseed.isValidSeed(seedValue)) {
140 + if ((type == WalletType.monero || type == WalletType.wownero) &&
141 + Polyseed.isValidSeed(seedValue)) {
142 return WalletRestoreMode.seed;
143 }
144
lib/view_model/send/output.dart
+11
@@ -9,6 +9,7 @@ import 'package:cake_wallet/reactions/wallet_connect.dart';
9 import 'package:cake_wallet/solana/solana.dart';
10 import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
11 import 'package:cake_wallet/tron/tron.dart';
12 +import 'package:cake_wallet/wownero/wownero.dart';
13 import 'package:cw_core/crypto_currency.dart';
14 import 'package:flutter/material.dart';
15 import 'package:intl/intl.dart';
@@ -100,6 +101,9 @@ abstract class OutputBase with Store {
101 case WalletType.polygon:
102 _amount = polygon!.formatterPolygonParseAmount(_cryptoAmount);
103 break;
104 + case WalletType.wownero:
105 + _amount = wownero!.formatterWowneroParseAmount(amount: _cryptoAmount);
106 + break;
107 default:
108 break;
109 }
@@ -154,6 +158,10 @@ abstract class OutputBase with Store {
158 return monero!.formatterMoneroAmountToDouble(amount: fee);
159 }
160
161 + if (_wallet.type == WalletType.wownero) {
162 + return wownero!.formatterWowneroAmountToDouble(amount: fee);
163 + }
164 +
165 if (_wallet.type == WalletType.haven) {
166 return haven!.formatterMoneroAmountToDouble(amount: fee);
167 }
@@ -287,6 +295,9 @@ abstract class OutputBase with Store {
295 case WalletType.tron:
296 maximumFractionDigits = 12;
297 break;
298 + case WalletType.wownero:
299 + maximumFractionDigits = 11;
300 + break;
301 default:
302 break;
303 }
lib/view_model/send/send_view_model.dart
+6
@@ -16,6 +16,7 @@ import 'package:cake_wallet/tron/tron.dart';
16 import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
17 import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
18 import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
19 +import 'package:cake_wallet/wownero/wownero.dart';
20 import 'package:cw_core/exceptions.dart';
21 import 'package:cw_core/transaction_priority.dart';
22 import 'package:cake_wallet/view_model/send/output.dart';
@@ -244,6 +245,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
245 wallet.type == WalletType.bitcoin ||
246 wallet.type == WalletType.litecoin ||
247 wallet.type == WalletType.monero ||
248 + wallet.type == WalletType.wownero ||
249 wallet.type == WalletType.bitcoinCash;
250
251 @computed
@@ -478,6 +480,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
480 return monero!
481 .createMoneroTransactionCreationCredentials(outputs: outputs, priority: priority!);
482
483 + case WalletType.wownero:
484 + return wownero!
485 + .createWowneroTransactionCreationCredentials(outputs: outputs, priority: priority!);
486 +
487 case WalletType.haven:
488 return haven!.createHavenTransactionCreationCredentials(
489 outputs: outputs, priority: priority!, assetType: selectedCryptoCurrency.title);
lib/view_model/settings/other_settings_view_model.dart
+26 -18
@@ -1,8 +1,11 @@
1 import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 -import 'package:cake_wallet/entities/provider_types.dart';
2 import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
3 +import 'package:cake_wallet/entities/provider_types.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
5 import 'package:cake_wallet/store/settings_store.dart';
6 +import 'package:cake_wallet/utils/package_info.dart';
7 +// import 'package:package_info/package_info.dart';
8 +import 'package:collection/collection.dart';
9 import 'package:cw_core/balance.dart';
10 import 'package:cw_core/transaction_history.dart';
11 import 'package:cw_core/transaction_info.dart';
@@ -10,19 +13,18 @@ import 'package:cw_core/transaction_priority.dart';
13 import 'package:cw_core/wallet_base.dart';
14 import 'package:cw_core/wallet_type.dart';
15 import 'package:mobx/mobx.dart';
13 -import 'package:package_info/package_info.dart';
14 -import 'package:collection/collection.dart';
16
17 part 'other_settings_view_model.g.dart';
18
18 -class OtherSettingsViewModel = OtherSettingsViewModelBase with _$OtherSettingsViewModel;
19 +class OtherSettingsViewModel = OtherSettingsViewModelBase
20 + with _$OtherSettingsViewModel;
21
22 abstract class OtherSettingsViewModelBase with Store {
23 OtherSettingsViewModelBase(this._settingsStore, this._wallet)
24 : walletType = _wallet.type,
25 currentVersion = '' {
24 - PackageInfo.fromPlatform()
25 - .then((PackageInfo packageInfo) => currentVersion = packageInfo.version);
26 + PackageInfo.fromPlatform().then(
27 + (PackageInfo packageInfo) => currentVersion = packageInfo.version);
28
29 final priority = _settingsStore.priority[_wallet.type];
30 final priorities = priorityForWalletType(_wallet.type);
@@ -33,7 +35,8 @@ abstract class OtherSettingsViewModelBase with Store {
35 }
36
37 final WalletType walletType;
36 - final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
38 + final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
39 + TransactionInfo> _wallet;
40
41 @observable
42 String currentVersion;
@@ -61,10 +64,12 @@ abstract class OtherSettingsViewModelBase with Store {
64 _wallet.type == WalletType.tron);
65
66 @computed
64 - bool get isEnabledBuyAction => !_settingsStore.disableBuy && _wallet.type != WalletType.haven;
67 + bool get isEnabledBuyAction =>
68 + !_settingsStore.disableBuy && _wallet.type != WalletType.haven;
69
70 @computed
67 - bool get isEnabledSellAction => !_settingsStore.disableSell && _wallet.type != WalletType.haven;
71 + bool get isEnabledSellAction =>
72 + !_settingsStore.disableSell && _wallet.type != WalletType.haven;
73
74 List<ProviderType> get availableBuyProvidersTypes {
75 return ProvidersHelper.getAvailableBuyProviderTypes(walletType);
@@ -74,12 +79,12 @@ abstract class OtherSettingsViewModelBase with Store {
79 ProvidersHelper.getAvailableSellProviderTypes(walletType);
80
81 ProviderType get buyProviderType =>
77 - _settingsStore.defaultBuyProviders[walletType] ?? ProviderType.askEachTime;
82 + _settingsStore.defaultBuyProviders[walletType] ??
83 + ProviderType.askEachTime;
84
85 ProviderType get sellProviderType =>
80 - _settingsStore.defaultSellProviders[walletType] ?? ProviderType.askEachTime;
81 -
82 -
86 + _settingsStore.defaultSellProviders[walletType] ??
87 + ProviderType.askEachTime;
88
89 String getDisplayPriority(dynamic priority) {
90 final _priority = priority as TransactionPriority;
@@ -101,7 +106,8 @@ abstract class OtherSettingsViewModelBase with Store {
106 _wallet.type == WalletType.litecoin ||
107 _wallet.type == WalletType.bitcoinCash) {
108 final rate = bitcoin!.getFeeRate(_wallet, _priority);
104 - return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate, customRate: customValue);
109 + return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate,
110 + customRate: customValue);
111 }
112
113 return priority.toString();
@@ -124,7 +130,8 @@ abstract class OtherSettingsViewModelBase with Store {
130 void onDisplayPrioritySelected(TransactionPriority priority) =>
131 _settingsStore.priority[walletType] = priority;
132
127 - void onDisplayBitcoinPrioritySelected(TransactionPriority priority, double customValue) {
133 + void onDisplayBitcoinPrioritySelected(
134 + TransactionPriority priority, double customValue) {
135 if (_wallet.type == WalletType.bitcoin) {
136 _settingsStore.customBitcoinFeeRate = customValue.round();
137 }
@@ -132,12 +139,13 @@ abstract class OtherSettingsViewModelBase with Store {
139 }
140
141 @computed
135 - double get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate.toDouble();
142 + double get customBitcoinFeeRate =>
143 + _settingsStore.customBitcoinFeeRate.toDouble();
144
145 int? get customPriorityItemIndex {
146 final priorities = priorityForWalletType(walletType);
139 - final customItem = priorities
140 - .firstWhereOrNull((element) => element == bitcoin!.getBitcoinTransactionPriorityCustom());
147 + final customItem = priorities.firstWhereOrNull(
148 + (element) => element == bitcoin!.getBitcoinTransactionPriorityCustom());
149 return customItem != null ? priorities.indexOf(customItem) : null;
150 }
151
lib/view_model/settings/privacy_settings_view_model.dart
+1
@@ -41,6 +41,7 @@ abstract class PrivacySettingsViewModelBase with Store {
41
42 bool get isAutoGenerateSubaddressesVisible =>
43 _wallet.type == WalletType.monero ||
44 + _wallet.type == WalletType.wownero ||
45 _wallet.type == WalletType.bitcoin ||
46 _wallet.type == WalletType.litecoin ||
47 _wallet.type == WalletType.bitcoinCash;
lib/view_model/transaction_details_view_model.dart
+50 -2
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/tron/tron.dart';
2 +import 'package:cake_wallet/wownero/wownero.dart';
3 import 'package:cw_core/wallet_base.dart';
4 import 'package:cw_core/transaction_info.dart';
5 import 'package:cw_core/wallet_type.dart';
@@ -75,6 +76,9 @@ abstract class TransactionDetailsViewModelBase with Store {
76 case WalletType.tron:
77 _addTronListItems(tx, dateFormat);
78 break;
79 + case WalletType.wownero:
80 + _addWowneroListItems(tx, dateFormat);
81 + break;
82 default:
83 break;
84 }
@@ -166,7 +170,9 @@ abstract class TransactionDetailsViewModelBase with Store {
170 return 'https://solscan.io/tx/${txId}';
171 case WalletType.tron:
172 return 'https://tronscan.org/#/transaction/${txId}';
169 - default:
173 + case WalletType.wownero:
174 + return 'https://explore.wownero.com/tx/${txId}';
175 + case WalletType.none:
176 return '';
177 }
178 }
@@ -194,7 +200,9 @@ abstract class TransactionDetailsViewModelBase with Store {
200 return S.current.view_transaction_on + 'solscan.io';
201 case WalletType.tron:
202 return S.current.view_transaction_on + 'tronscan.org';
197 - default:
203 + case WalletType.wownero:
204 + return S.current.view_transaction_on + 'Wownero.com';
205 + case WalletType.none:
206 return '';
207 }
208 }
@@ -439,4 +447,44 @@ abstract class TransactionDetailsViewModelBase with Store {
447 String get pendingTransactionFeeFiatAmountFormatted => sendViewModel.isFiatDisabled
448 ? ''
449 : sendViewModel.pendingTransactionFeeFiatAmount + ' ' + sendViewModel.fiat.title;
450 +
451 + void _addWowneroListItems(TransactionInfo tx, DateFormat dateFormat) {
452 + final key = tx.additionalInfo['key'] as String?;
453 + final accountIndex = tx.additionalInfo['accountIndex'] as int;
454 + final addressIndex = tx.additionalInfo['addressIndex'] as int;
455 + final feeFormatted = tx.feeFormatted();
456 + final _items = [
457 + StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
458 + StandartListItem(
459 + title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
460 + StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
461 + StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
462 + if (feeFormatted != null)
463 + StandartListItem(title: S.current.transaction_details_fee, value: feeFormatted),
464 + if (key?.isNotEmpty ?? false) StandartListItem(title: S.current.transaction_key, value: key!),
465 + ];
466 +
467 + if (tx.direction == TransactionDirection.incoming) {
468 + try {
469 + final address = wownero!.getTransactionAddress(wallet, accountIndex, addressIndex);
470 + final label = wownero!.getSubaddressLabel(wallet, accountIndex, addressIndex);
471 +
472 + if (address.isNotEmpty) {
473 + isRecipientAddressShown = true;
474 + _items.add(StandartListItem(
475 + title: S.current.transaction_details_recipient_address,
476 + value: address,
477 + ));
478 + }
479 +
480 + if (label.isNotEmpty) {
481 + _items.add(StandartListItem(title: S.current.address_label, value: label));
482 + }
483 + } catch (e) {
484 + print(e.toString());
485 + }
486 + }
487 +
488 + items.addAll(_items);
489 + }
490 }
lib/view_model/unspent_coins/unspent_coins_list_view_model.dart
+7
@@ -2,6 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/monero/monero.dart';
3 import 'package:cake_wallet/utils/exception_handler.dart';
4 import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
5 +import 'package:cake_wallet/wownero/wownero.dart';
6 import 'package:cw_core/unspent_coins_info.dart';
7 import 'package:cw_core/unspent_transaction_output.dart';
8 import 'package:cw_core/wallet_base.dart';
@@ -62,6 +63,8 @@ abstract class UnspentCoinsListViewModelBase with Store {
63 String formatAmountToString(int fullBalance) {
64 if (wallet.type == WalletType.monero)
65 return monero!.formatterMoneroAmountToString(amount: fullBalance);
66 + if (wallet.type == WalletType.wownero)
67 + return wownero!.formatterWowneroAmountToString(amount: fullBalance);
68 if ([WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(wallet.type))
69 return bitcoin!.formatterBitcoinAmountToString(amount: fullBalance);
70 return '';
@@ -71,6 +74,9 @@ abstract class UnspentCoinsListViewModelBase with Store {
74 if (wallet.type == WalletType.monero) {
75 await monero!.updateUnspents(wallet);
76 }
77 + if (wallet.type == WalletType.wownero) {
78 + await wownero!.updateUnspents(wallet);
79 + }
80 if ([WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(wallet.type)) {
81 await bitcoin!.updateUnspents(wallet);
82 }
@@ -80,6 +86,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
86
87 List<Unspent> _getUnspents() {
88 if (wallet.type == WalletType.monero) return monero!.getUnspents(wallet);
89 + if (wallet.type == WalletType.wownero) return wownero!.getUnspents(wallet);
90 if ([WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(wallet.type))
91 return bitcoin!.getUnspents(wallet);
92 return List.empty();
lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
+35
@@ -17,6 +17,7 @@ import 'package:cake_wallet/utils/list_item.dart';
17 import 'package:cake_wallet/view_model/wallet_address_list/wallet_account_list_header.dart';
18 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_header.dart';
19 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
20 +import 'package:cake_wallet/wownero/wownero.dart';
21 import 'package:cw_core/amount_converter.dart';
22 import 'package:cw_core/currency.dart';
23 import 'package:cw_core/wallet_type.dart';
@@ -191,6 +192,22 @@ class TronURI extends PaymentURI {
192 }
193 }
194
195 +class WowneroURI extends PaymentURI {
196 + WowneroURI({required String amount, required String address})
197 + : super(amount: amount, address: address);
198 +
199 + @override
200 + String toString() {
201 + var base = 'wownero:' + address;
202 +
203 + if (amount.isNotEmpty) {
204 + base += '?tx_amount=${amount.replaceAll(',', '.')}';
205 + }
206 +
207 + return base;
208 + }
209 +}
210 +
211 abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
212 WalletAddressListViewModelBase({
213 required AppStore appStore,
@@ -293,6 +310,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
310 return TronURI(amount: amount, address: address.address);
311 }
312
313 + if (wallet.type == WalletType.wownero) {
314 + return WowneroURI(amount: amount, address: address.address);
315 + }
316 +
317 throw Exception('Unexpected type: ${type.toString()}');
318 }
319
@@ -409,6 +430,20 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
430 addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
431 }
432
433 + if (wallet.type == WalletType.wownero) {
434 + final primaryAddress = wownero!.getSubaddressList(wallet).subaddresses.first;
435 + final addressItems = wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
436 + final isPrimary = subaddress == primaryAddress;
437 +
438 + return WalletAddressListItem(
439 + id: subaddress.id,
440 + isPrimary: isPrimary,
441 + name: subaddress.label,
442 + address: subaddress.address);
443 + });
444 + addressList.addAll(addressItems);
445 + }
446 +
447 if (searchText.isNotEmpty) {
448 return ObservableList.of(addressList.where((item) {
449 if (item is WalletAddressListItem) {
lib/view_model/wallet_creation_vm.dart
+8 -1
@@ -13,6 +13,7 @@ import 'package:cw_core/wallet_info.dart';
13 import 'package:cw_core/wallet_type.dart';
14 import 'package:cake_wallet/store/app_store.dart';
15 import 'package:cake_wallet/entities/generate_name.dart';
16 +import 'package:polyseed/polyseed.dart';
17
18 part 'wallet_creation_vm.g.dart';
19
@@ -42,6 +43,10 @@ abstract class WalletCreationVMBase with Store {
43 final Box<WalletInfo> _walletInfoSource;
44 final AppStore _appStore;
45
46 + bool isPolyseed(String seed) =>
47 + (type == WalletType.monero || type == WalletType.wownero) &&
48 + (Polyseed.isValidSeed(seed) || (seed.split(" ").length == 14));
49 +
50 bool nameExists(String name) => walletCreationService.exists(name);
51
52 bool typeExists(WalletType type) => walletCreationService.typeExists(type);
@@ -86,7 +91,9 @@ abstract class WalletCreationVMBase with Store {
91 getIt.get<BackgroundTasks>().registerSyncTask();
92 _appStore.authenticationStore.allowed();
93 state = ExecutedSuccessfullyState();
89 - } catch (e) {
94 + } catch (e, s) {
95 + print("@@@@@@@@");
96 + print(s);
97 state = FailureState(e.toString());
98 }
99 }
lib/view_model/wallet_keys_view_model.dart
+114 -34
@@ -4,11 +4,13 @@ import 'package:cake_wallet/monero/monero.dart';
4 import 'package:cake_wallet/reactions/wallet_connect.dart';
5 import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
6 import 'package:cake_wallet/store/app_store.dart';
7 +import 'package:cake_wallet/wownero/wownero.dart';
8 import 'package:cw_core/transaction_direction.dart';
9 import 'package:cw_core/transaction_info.dart';
10 import 'package:cw_core/wallet_base.dart';
11 import 'package:cw_core/wallet_type.dart';
11 -import 'package:cw_monero/api/wallet.dart' as monero_wallet;
12 +import 'package:cw_monero/monero_wallet.dart';
13 +import 'package:cw_wownero/wownero_wallet.dart';
14 import 'package:mobx/mobx.dart';
15 import 'package:polyseed/polyseed.dart';
16
@@ -32,13 +34,17 @@ abstract class WalletKeysViewModelBase with Store {
34 _populateItems();
35 });
36
35 - if (_appStore.wallet!.type == WalletType.monero || _appStore.wallet!.type == WalletType.haven) {
37 + if (_appStore.wallet!.type == WalletType.monero ||
38 + _appStore.wallet!.type == WalletType.haven ||
39 + _appStore.wallet!.type == WalletType.wownero) {
40 final accountTransactions = _getWalletTransactions(_appStore.wallet!);
41 if (accountTransactions.isNotEmpty) {
38 - final incomingAccountTransactions =
39 - accountTransactions.where((tx) => tx.direction == TransactionDirection.incoming);
42 + final incomingAccountTransactions = accountTransactions
43 + .where((tx) => tx.direction == TransactionDirection.incoming);
44 if (incomingAccountTransactions.isNotEmpty) {
41 - incomingAccountTransactions.toList().sort((a, b) => a.date.compareTo(b.date));
45 + incomingAccountTransactions
46 + .toList()
47 + .sort((a, b) => a.date.compareTo(b.date));
48 _restoreHeightByTransactions = _getRestoreHeightByTransactions(
49 _appStore.wallet!.type, incomingAccountTransactions.first.date);
50 }
@@ -64,29 +70,38 @@ abstract class WalletKeysViewModelBase with Store {
70
71 items.addAll([
72 if (keys['publicSpendKey'] != null)
67 - StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!),
73 + StandartListItem(
74 + title: S.current.spend_key_public,
75 + value: keys['publicSpendKey']!),
76 if (keys['privateSpendKey'] != null)
69 - StandartListItem(title: S.current.spend_key_private, value: keys['privateSpendKey']!),
77 + StandartListItem(
78 + title: S.current.spend_key_private,
79 + value: keys['privateSpendKey']!),
80 if (keys['publicViewKey'] != null)
71 - StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!),
81 + StandartListItem(
82 + title: S.current.view_key_public, value: keys['publicViewKey']!),
83 if (keys['privateViewKey'] != null)
73 - StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
74 - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
84 + StandartListItem(
85 + title: S.current.view_key_private,
86 + value: keys['privateViewKey']!),
87 + StandartListItem(
88 + title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
89 ]);
90
77 - if (_appStore.wallet?.seed != null && Polyseed.isValidSeed(_appStore.wallet!.seed!)) {
91 + if (_appStore.wallet?.seed != null &&
92 + Polyseed.isValidSeed(_appStore.wallet!.seed!)) {
93 final lang = PolyseedLang.getByPhrase(_appStore.wallet!.seed!);
79 - final legacyLang = _getLegacySeedLang(lang);
80 - final legacySeed =
81 - Polyseed.decode(_appStore.wallet!.seed!, lang, PolyseedCoin.POLYSEED_MONERO)
82 - .toLegacySeed(legacyLang);
83 - items.add(StandartListItem(title: S.current.wallet_seed_legacy, value: legacySeed));
94 + items.add(StandartListItem(
95 + title: S.current.wallet_seed_legacy,
96 + value: (_appStore.wallet as MoneroWalletBase)
97 + .seedLegacy(lang.nameEnglish)));
98 }
99
100 final restoreHeight = monero!.getRestoreHeight(_appStore.wallet!);
101 if (restoreHeight != null) {
102 items.add(StandartListItem(
89 - title: S.current.wallet_recovery_height, value: restoreHeight.toString()));
103 + title: S.current.wallet_recovery_height,
104 + value: restoreHeight.toString()));
105 }
106 }
107
@@ -95,17 +110,58 @@ abstract class WalletKeysViewModelBase with Store {
110
111 items.addAll([
112 if (keys['publicSpendKey'] != null)
98 - StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!),
113 + StandartListItem(
114 + title: S.current.spend_key_public,
115 + value: keys['publicSpendKey']!),
116 if (keys['privateSpendKey'] != null)
100 - StandartListItem(title: S.current.spend_key_private, value: keys['privateSpendKey']!),
117 + StandartListItem(
118 + title: S.current.spend_key_private,
119 + value: keys['privateSpendKey']!),
120 if (keys['publicViewKey'] != null)
102 - StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!),
121 + StandartListItem(
122 + title: S.current.view_key_public, value: keys['publicViewKey']!),
123 if (keys['privateViewKey'] != null)
104 - StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
105 - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
124 + StandartListItem(
125 + title: S.current.view_key_private,
126 + value: keys['privateViewKey']!),
127 + StandartListItem(
128 + title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
129 ]);
130 }
131
132 + if (_appStore.wallet!.type == WalletType.wownero) {
133 + final keys = wownero!.getKeys(_appStore.wallet!);
134 +
135 + items.addAll([
136 + if (keys['publicSpendKey'] != null)
137 + StandartListItem(
138 + title: S.current.spend_key_public,
139 + value: keys['publicSpendKey']!),
140 + if (keys['privateSpendKey'] != null)
141 + StandartListItem(
142 + title: S.current.spend_key_private,
143 + value: keys['privateSpendKey']!),
144 + if (keys['publicViewKey'] != null)
145 + StandartListItem(
146 + title: S.current.view_key_public, value: keys['publicViewKey']!),
147 + if (keys['privateViewKey'] != null)
148 + StandartListItem(
149 + title: S.current.view_key_private,
150 + value: keys['privateViewKey']!),
151 + StandartListItem(
152 + title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
153 + ]);
154 +
155 + if (_appStore.wallet?.seed != null &&
156 + Polyseed.isValidSeed(_appStore.wallet!.seed!)) {
157 + final lang = PolyseedLang.getByPhrase(_appStore.wallet!.seed!);
158 + items.add(StandartListItem(
159 + title: S.current.wallet_seed_legacy,
160 + value: (_appStore.wallet as WowneroWalletBase)
161 + .seedLegacy(lang.nameEnglish)));
162 + }
163 + }
164 +
165 if (_appStore.wallet!.type == WalletType.bitcoin ||
166 _appStore.wallet!.type == WalletType.litecoin ||
167 _appStore.wallet!.type == WalletType.bitcoinCash) {
@@ -118,7 +174,8 @@ abstract class WalletKeysViewModelBase with Store {
174 // StandartListItem(title: S.current.private_key, value: keys['privateKey']!),
175 // if (keys['publicKey'] != null)
176 // StandartListItem(title: S.current.public_key, value: keys['publicKey']!),
121 - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
177 + StandartListItem(
178 + title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
179 ]);
180 }
181
@@ -127,24 +184,32 @@ abstract class WalletKeysViewModelBase with Store {
184 _appStore.wallet!.type == WalletType.tron) {
185 items.addAll([
186 if (_appStore.wallet!.privateKey != null)
130 - StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!),
187 + StandartListItem(
188 + title: S.current.private_key,
189 + value: _appStore.wallet!.privateKey!),
190 if (_appStore.wallet!.seed != null)
132 - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
191 + StandartListItem(
192 + title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
193 ]);
194 }
195
136 - bool nanoBased =
137 - _appStore.wallet!.type == WalletType.nano || _appStore.wallet!.type == WalletType.banano;
196 + bool nanoBased = _appStore.wallet!.type == WalletType.nano ||
197 + _appStore.wallet!.type == WalletType.banano;
198
199 if (nanoBased) {
200 // we always have the hex version of the seed and private key:
201 items.addAll([
202 if (_appStore.wallet!.seed != null)
143 - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
203 + StandartListItem(
204 + title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
205 if (_appStore.wallet!.hexSeed != null)
145 - StandartListItem(title: S.current.seed_hex_form, value: _appStore.wallet!.hexSeed!),
206 + StandartListItem(
207 + title: S.current.seed_hex_form,
208 + value: _appStore.wallet!.hexSeed!),
209 if (_appStore.wallet!.privateKey != null)
147 - StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!),
210 + StandartListItem(
211 + title: S.current.private_key,
212 + value: _appStore.wallet!.privateKey!),
213 ]);
214 }
215 }
@@ -154,7 +219,10 @@ abstract class WalletKeysViewModelBase with Store {
219 return await haven!.getCurrentHeight();
220 }
221 if (_appStore.wallet!.type == WalletType.monero) {
157 - return monero_wallet.getCurrentHeight();
222 + return await monero!.getCurrentHeight();
223 + }
224 + if (_appStore.wallet!.type == WalletType.wownero) {
225 + return await wownero!.getCurrentHeight();
226 }
227 return null;
228 }
@@ -183,8 +251,10 @@ abstract class WalletKeysViewModelBase with Store {
251 return 'solana-wallet';
252 case WalletType.tron:
253 return 'tron-wallet';
254 + case WalletType.wownero:
255 + return 'wownero-wallet';
256 default:
187 - throw Exception('Unexpected wallet type: ${_appStore.wallet!.toString()}');
257 + throw Exception('Unexpected wallet type: ${_appStore.wallet!.type.toString()}');
258 }
259 }
260
@@ -205,7 +275,8 @@ abstract class WalletKeysViewModelBase with Store {
275 if (_appStore.wallet!.seed != null) 'seed': _appStore.wallet!.seed!,
276 if (_appStore.wallet!.seed == null && _appStore.wallet!.hexSeed != null)
277 'hexSeed': _appStore.wallet!.hexSeed!,
208 - if (_appStore.wallet!.seed == null && _appStore.wallet!.privateKey != null)
278 + if (_appStore.wallet!.seed == null &&
279 + _appStore.wallet!.privateKey != null)
280 'private_key': _appStore.wallet!.privateKey!,
281 if (restoreHeightResult != null) ...{'height': restoreHeightResult}
282 };
@@ -221,6 +292,12 @@ abstract class WalletKeysViewModelBase with Store {
292 return monero!.getTransactionHistory(wallet).transactions.values.toList();
293 } else if (wallet.type == WalletType.haven) {
294 return haven!.getTransactionHistory(wallet).transactions.values.toList();
295 + } else if (wallet.type == WalletType.wownero) {
296 + return wownero!
297 + .getTransactionHistory(wallet)
298 + .transactions
299 + .values
300 + .toList();
301 }
302 return [];
303 }
@@ -230,11 +307,14 @@ abstract class WalletKeysViewModelBase with Store {
307 return monero!.getHeightByDate(date: date);
308 } else if (type == WalletType.haven) {
309 return haven!.getHeightByDate(date: date);
310 + } else if (type == WalletType.wownero) {
311 + return wownero!.getHeightByDate(date: date);
312 }
313 return 0;
314 }
315
237 - String getRoundedRestoreHeight(int height) => ((height / 1000).floor() * 1000).toString();
316 + String getRoundedRestoreHeight(int height) =>
317 + ((height / 1000).floor() * 1000).toString();
318
319 LegacySeedLang _getLegacySeedLang(PolyseedLang lang) {
320 switch (lang.nameEnglish) {
lib/view_model/wallet_new_vm.dart
+10 -3
@@ -2,6 +2,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
2 import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
3 import 'package:cake_wallet/solana/solana.dart';
4 import 'package:cake_wallet/tron/tron.dart';
5 +import 'package:cake_wallet/wownero/wownero.dart';
6 import 'package:hive/hive.dart';
7 import 'package:mobx/mobx.dart';
8 import 'package:cake_wallet/monero/monero.dart';
@@ -35,11 +36,13 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
36 @observable
37 String selectedMnemonicLanguage;
38
38 - bool get hasLanguageSelector => type == WalletType.monero || type == WalletType.haven;
39 + bool get hasLanguageSelector =>
40 + type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero;
41
42 int get seedPhraseWordsLength {
43 switch (type) {
44 case WalletType.monero:
45 + case WalletType.wownero:
46 if (advancedPrivacySettingsViewModel.isPolySeed) {
47 return 16;
48 }
@@ -55,7 +58,7 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
58 }
59 }
60
58 - bool get hasSeedType => type == WalletType.monero;
61 + bool get hasSeedType => type == WalletType.monero || type == WalletType.wownero;
62
63 @override
64 WalletCredentials getCredentials(dynamic _options) {
@@ -76,6 +79,7 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
79 case WalletType.bitcoinCash:
80 return bitcoinCash!.createBitcoinCashNewWalletCredentials(name: name);
81 case WalletType.nano:
82 + case WalletType.banano:
83 return nano!.createNanoNewWalletCredentials(name: name);
84 case WalletType.polygon:
85 return polygon!.createPolygonNewWalletCredentials(name: name);
@@ -83,7 +87,10 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
87 return solana!.createSolanaNewWalletCredentials(name: name);
88 case WalletType.tron:
89 return tron!.createTronNewWalletCredentials(name: name);
86 - default:
90 + case WalletType.wownero:
91 + return wownero!.createWowneroNewWalletCredentials(
92 + name: name, language: options!.first as String, isPolyseed: options.last as bool);
93 + case WalletType.none:
94 throw Exception('Unexpected type: ${type.toString()}');
95 }
96 }
lib/view_model/wallet_restore_view_model.dart
+32 -8
@@ -2,7 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/di.dart';
3 import 'package:cake_wallet/nano/nano.dart';
4 import 'package:cake_wallet/ethereum/ethereum.dart';
5 -import 'package:cw_core/nano_account_info_response.dart';
5 +import 'package:cake_wallet/wownero/wownero.dart';
6 import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
7 import 'package:cake_wallet/polygon/polygon.dart';
8 import 'package:cake_wallet/solana/solana.dart';
@@ -29,8 +29,10 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
29 WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,
30 Box<WalletInfo> walletInfoSource,
31 {required WalletType type})
32 - : hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
33 - hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
32 + : hasSeedLanguageSelector =
33 + type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
34 + hasBlockchainHeightLanguageSelector =
35 + type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
36 hasRestoreFromPrivateKey = type == WalletType.ethereum ||
37 type == WalletType.polygon ||
38 type == WalletType.nano ||
@@ -42,18 +44,22 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
44 super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true) {
45 switch (type) {
46 case WalletType.monero:
45 - case WalletType.haven:
46 - case WalletType.ethereum:
47 - case WalletType.polygon:
47 availableModes = WalletRestoreMode.values;
48 break;
49 case WalletType.nano:
50 case WalletType.banano:
51 case WalletType.solana:
52 case WalletType.tron:
53 + case WalletType.wownero:
54 + case WalletType.haven:
55 + case WalletType.ethereum:
56 + case WalletType.polygon:
57 availableModes = [WalletRestoreMode.seed, WalletRestoreMode.keys];
58 break;
56 - default:
59 + case WalletType.bitcoin:
60 + case WalletType.litecoin:
61 + case WalletType.bitcoinCash:
62 + case WalletType.none:
63 availableModes = [WalletRestoreMode.seed];
64 break;
65 }
@@ -112,6 +118,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
118 return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials(
119 name: name, mnemonic: seed, password: password);
120 case WalletType.nano:
121 + case WalletType.banano:
122 return nano!.createNanoRestoreWalletFromSeedCredentials(
123 name: name,
124 mnemonic: seed,
@@ -136,7 +143,14 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
143 mnemonic: seed,
144 password: password,
145 );
139 - default:
146 + case WalletType.wownero:
147 + return wownero!.createWowneroRestoreWalletFromSeedCredentials(
148 + name: name,
149 + mnemonic: seed,
150 + password: password,
151 + height: height,
152 + );
153 + case WalletType.none:
154 break;
155 }
156 }
@@ -200,6 +214,16 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
214 password: password,
215 privateKey: options['private_key'] as String,
216 );
217 + case WalletType.wownero:
218 + return wownero!.createWowneroRestoreWalletFromKeysCredentials(
219 + name: name,
220 + height: height,
221 + spendKey: spendKey!,
222 + viewKey: viewKey!,
223 + address: address!,
224 + password: password,
225 + language: 'English',
226 + );
227 default:
228 break;
229 }
lib/wallet_type_utils.dart
+5 -1
@@ -16,6 +16,10 @@ bool get isSingleCoin {
16 return availableWalletTypes.length == 1;
17 }
18
19 +bool get hasMonero {
20 + return availableWalletTypes.contains(WalletType.monero);
21 +}
22 +
23 String get approximatedAppName {
24 if (isMoneroOnly) {
25 return 'Monero.com';
@@ -26,4 +30,4 @@ String get approximatedAppName {
30 }
31
32 return 'Cake Wallet';
29 -}
\ No newline at end of file
33 +}
lib/wownero/cw_wownero.dart new
+347
@@ -0,0 +1,347 @@
1 +part of 'wownero.dart';
2 +
3 +class CWWowneroAccountList extends WowneroAccountList {
4 + CWWowneroAccountList(this._wallet);
5 +
6 + final Object _wallet;
7 +
8 + @override
9 + @computed
10 + ObservableList<Account> get accounts {
11 + final wowneroWallet = _wallet as WowneroWallet;
12 + final accounts = wowneroWallet.walletAddresses.accountList.accounts
13 + .map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
14 + .toList();
15 + return ObservableList<Account>.of(accounts);
16 + }
17 +
18 + @override
19 + void update(Object wallet) {
20 + final wowneroWallet = wallet as WowneroWallet;
21 + wowneroWallet.walletAddresses.accountList.update();
22 + }
23 +
24 + @override
25 + void refresh(Object wallet) {
26 + final wowneroWallet = wallet as WowneroWallet;
27 + wowneroWallet.walletAddresses.accountList.refresh();
28 + }
29 +
30 + @override
31 + List<Account> getAll(Object wallet) {
32 + final wowneroWallet = wallet as WowneroWallet;
33 + return wowneroWallet.walletAddresses.accountList
34 + .getAll()
35 + .map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
36 + .toList();
37 + }
38 +
39 + @override
40 + Future<void> addAccount(Object wallet, {required String label}) async {
41 + final wowneroWallet = wallet as WowneroWallet;
42 + await wowneroWallet.walletAddresses.accountList.addAccount(label: label);
43 + }
44 +
45 + @override
46 + Future<void> setLabelAccount(Object wallet,
47 + {required int accountIndex, required String label}) async {
48 + final wowneroWallet = wallet as WowneroWallet;
49 + await wowneroWallet.walletAddresses.accountList
50 + .setLabelAccount(accountIndex: accountIndex, label: label);
51 + }
52 +}
53 +
54 +class CWWowneroSubaddressList extends WowneroSubaddressList {
55 + CWWowneroSubaddressList(this._wallet);
56 +
57 + final Object _wallet;
58 +
59 + @override
60 + @computed
61 + ObservableList<Subaddress> get subaddresses {
62 + final wowneroWallet = _wallet as WowneroWallet;
63 + final subAddresses = wowneroWallet.walletAddresses.subaddressList.subaddresses
64 + .map((sub) => Subaddress(id: sub.id, address: sub.address, label: sub.label))
65 + .toList();
66 + return ObservableList<Subaddress>.of(subAddresses);
67 + }
68 +
69 + @override
70 + void update(Object wallet, {required int accountIndex}) {
71 + final wowneroWallet = wallet as WowneroWallet;
72 + wowneroWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
73 + }
74 +
75 + @override
76 + void refresh(Object wallet, {required int accountIndex}) {
77 + final wowneroWallet = wallet as WowneroWallet;
78 + wowneroWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
79 + }
80 +
81 + @override
82 + List<Subaddress> getAll(Object wallet) {
83 + final wowneroWallet = wallet as WowneroWallet;
84 + return wowneroWallet.walletAddresses.subaddressList
85 + .getAll()
86 + .map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
87 + .toList();
88 + }
89 +
90 + @override
91 + Future<void> addSubaddress(Object wallet,
92 + {required int accountIndex, required String label}) async {
93 + final wowneroWallet = wallet as WowneroWallet;
94 + await wowneroWallet.walletAddresses.subaddressList
95 + .addSubaddress(accountIndex: accountIndex, label: label);
96 + }
97 +
98 + @override
99 + Future<void> setLabelSubaddress(Object wallet,
100 + {required int accountIndex, required int addressIndex, required String label}) async {
101 + final wowneroWallet = wallet as WowneroWallet;
102 + await wowneroWallet.walletAddresses.subaddressList
103 + .setLabelSubaddress(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
104 + }
105 +}
106 +
107 +class CWWowneroWalletDetails extends WowneroWalletDetails {
108 + CWWowneroWalletDetails(this._wallet);
109 +
110 + final Object _wallet;
111 +
112 + @computed
113 + @override
114 + Account get account {
115 + final wowneroWallet = _wallet as WowneroWallet;
116 + final acc = wowneroWallet.walletAddresses.account;
117 + return Account(id: acc!.id, label: acc.label, balance: acc.balance);
118 + }
119 +
120 + @computed
121 + @override
122 + WowneroBalance get balance {
123 + throw Exception('Unimplemented');
124 + // return WowneroBalance();
125 + //return WowneroBalance(
126 + // fullBalance: balance.fullBalance,
127 + // unlockedBalance: balance.unlockedBalance);
128 + }
129 +}
130 +
131 +class CWWownero extends Wownero {
132 + @override
133 + WowneroAccountList getAccountList(Object wallet) => CWWowneroAccountList(wallet);
134 +
135 + @override
136 + WowneroSubaddressList getSubaddressList(Object wallet) => CWWowneroSubaddressList(wallet);
137 +
138 + @override
139 + TransactionHistoryBase getTransactionHistory(Object wallet) {
140 + final wowneroWallet = wallet as WowneroWallet;
141 + return wowneroWallet.transactionHistory;
142 + }
143 +
144 + @override
145 + WowneroWalletDetails getWowneroWalletDetails(Object wallet) => CWWowneroWalletDetails(wallet);
146 +
147 + @override
148 + int getHeightByDate({required DateTime date}) => getWowneroHeightByDate(date: date);
149 +
150 + @override
151 + TransactionPriority getDefaultTransactionPriority() => MoneroTransactionPriority.automatic;
152 +
153 + @override
154 + TransactionPriority getWowneroTransactionPrioritySlow() => MoneroTransactionPriority.slow;
155 +
156 + @override
157 + TransactionPriority getWowneroTransactionPriorityAutomatic() =>
158 + MoneroTransactionPriority.automatic;
159 +
160 + @override
161 + TransactionPriority deserializeWowneroTransactionPriority({required int raw}) =>
162 + MoneroTransactionPriority.deserialize(raw: raw);
163 +
164 + @override
165 + List<TransactionPriority> getTransactionPriorities() => MoneroTransactionPriority.all;
166 +
167 + @override
168 + List<String> getWowneroWordList(String language) {
169 + if (language.startsWith("POLYSEED_")) {
170 + final lang = language.replaceAll("POLYSEED_", "");
171 + return PolyseedLang.getByEnglishName(lang).words;
172 + }
173 + if (language.startsWith("WOWSEED_")) {
174 + final lang = language.replaceAll("WOWSEED_", "");
175 + return PolyseedLang.getByEnglishName(lang).words;
176 + }
177 + switch (language.toLowerCase()) {
178 + case 'english':
179 + return EnglishMnemonics.words;
180 + case 'chinese (simplified)':
181 + return ChineseSimplifiedMnemonics.words;
182 + case 'dutch':
183 + return DutchMnemonics.words;
184 + case 'german':
185 + return GermanMnemonics.words;
186 + case 'japanese':
187 + return JapaneseMnemonics.words;
188 + case 'portuguese':
189 + return PortugueseMnemonics.words;
190 + case 'russian':
191 + return RussianMnemonics.words;
192 + case 'spanish':
193 + return SpanishMnemonics.words;
194 + case 'french':
195 + return FrenchMnemonics.words;
196 + case 'italian':
197 + return ItalianMnemonics.words;
198 + default:
199 + return EnglishMnemonics.words;
200 + }
201 + }
202 +
203 + @override
204 + WalletCredentials createWowneroRestoreWalletFromKeysCredentials(
205 + {required String name,
206 + required String spendKey,
207 + required String viewKey,
208 + required String address,
209 + required String password,
210 + required String language,
211 + required int height}) =>
212 + WowneroRestoreWalletFromKeysCredentials(
213 + name: name,
214 + spendKey: spendKey,
215 + viewKey: viewKey,
216 + address: address,
217 + password: password,
218 + language: language,
219 + height: height);
220 +
221 + @override
222 + WalletCredentials createWowneroRestoreWalletFromSeedCredentials(
223 + {required String name,
224 + required String password,
225 + required int height,
226 + required String mnemonic}) =>
227 + WowneroRestoreWalletFromSeedCredentials(
228 + name: name, password: password, height: height, mnemonic: mnemonic);
229 +
230 + @override
231 + WalletCredentials createWowneroNewWalletCredentials(
232 + {required String name,
233 + required String language,
234 + required bool isPolyseed,
235 + String? password}) =>
236 + WowneroNewWalletCredentials(
237 + name: name, password: password, language: language, isPolyseed: isPolyseed);
238 +
239 + @override
240 + Map<String, String> getKeys(Object wallet) {
241 + final wowneroWallet = wallet as WowneroWallet;
242 + final keys = wowneroWallet.keys;
243 + return <String, String>{
244 + 'privateSpendKey': keys.privateSpendKey,
245 + 'privateViewKey': keys.privateViewKey,
246 + 'publicSpendKey': keys.publicSpendKey,
247 + 'publicViewKey': keys.publicViewKey
248 + };
249 + }
250 +
251 + @override
252 + Object createWowneroTransactionCreationCredentials(
253 + {required List<Output> outputs, required TransactionPriority priority}) =>
254 + WowneroTransactionCreationCredentials(
255 + outputs: outputs
256 + .map((out) => OutputInfo(
257 + fiatAmount: out.fiatAmount,
258 + cryptoAmount: out.cryptoAmount,
259 + address: out.address,
260 + note: out.note,
261 + sendAll: out.sendAll,
262 + extractedAddress: out.extractedAddress,
263 + isParsedAddress: out.isParsedAddress,
264 + formattedCryptoAmount: out.formattedCryptoAmount))
265 + .toList(),
266 + priority: priority as MoneroTransactionPriority);
267 +
268 + @override
269 + Object createWowneroTransactionCreationCredentialsRaw(
270 + {required List<OutputInfo> outputs, required TransactionPriority priority}) =>
271 + WowneroTransactionCreationCredentials(
272 + outputs: outputs, priority: priority as MoneroTransactionPriority);
273 +
274 + @override
275 + String formatterWowneroAmountToString({required int amount}) =>
276 + wowneroAmountToString(amount: amount);
277 +
278 + @override
279 + double formatterWowneroAmountToDouble({required int amount}) =>
280 + wowneroAmountToDouble(amount: amount);
281 +
282 + @override
283 + int formatterWowneroParseAmount({required String amount}) => wowneroParseAmount(amount: amount);
284 +
285 + @override
286 + Account getCurrentAccount(Object wallet) {
287 + final wowneroWallet = wallet as WowneroWallet;
288 + final acc = wowneroWallet.walletAddresses.account;
289 + return Account(id: acc!.id, label: acc.label, balance: acc.balance);
290 + }
291 +
292 + @override
293 + void setCurrentAccount(Object wallet, int id, String label, String? balance) {
294 + final wowneroWallet = wallet as WowneroWallet;
295 + wowneroWallet.walletAddresses.account =
296 + wownero_account.Account(id: id, label: label, balance: balance);
297 + }
298 +
299 + @override
300 + void onStartup() => wownero_wallet_api.onStartup();
301 +
302 + @override
303 + int getTransactionInfoAccountId(TransactionInfo tx) {
304 + final wowneroTransactionInfo = tx as WowneroTransactionInfo;
305 + return wowneroTransactionInfo.accountIndex;
306 + }
307 +
308 + @override
309 + WalletService createWowneroWalletService(
310 + Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) =>
311 + WowneroWalletService(walletInfoSource, unspentCoinSource);
312 +
313 + @override
314 + String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
315 + final wowneroWallet = wallet as WowneroWallet;
316 + return wowneroWallet.getTransactionAddress(accountIndex, addressIndex);
317 + }
318 +
319 + @override
320 + String getSubaddressLabel(Object wallet, int accountIndex, int addressIndex) {
321 + final wowneroWallet = wallet as WowneroWallet;
322 + return wowneroWallet.getSubaddressLabel(accountIndex, addressIndex);
323 + }
324 +
325 + @override
326 + Map<String, String> pendingTransactionInfo(Object transaction) {
327 + final ptx = transaction as PendingWowneroTransaction;
328 + return {'id': ptx.id, 'hex': ptx.hex, 'key': ptx.txKey};
329 + }
330 +
331 + @override
332 + List<Unspent> getUnspents(Object wallet) {
333 + final wowneroWallet = wallet as WowneroWallet;
334 + return wowneroWallet.unspentCoins;
335 + }
336 +
337 + @override
338 + Future<void> updateUnspents(Object wallet) async {
339 + final wowneroWallet = wallet as WowneroWallet;
340 + await wowneroWallet.updateUnspent();
341 + }
342 +
343 + @override
344 + Future<int> getCurrentHeight() async {
345 + return wownero_wallet_api.getCurrentHeight();
346 + }
347 +}
macos/Flutter/GeneratedPluginRegistrant.swift
-4
@@ -6,12 +6,10 @@ import FlutterMacOS
6 import Foundation
7
8 import connectivity_plus
9 -import cw_monero
9 import device_info_plus
10 import devicelocale
11 import flutter_inappwebview_macos
12 import flutter_local_authentication
14 -import flutter_secure_storage_macos
13 import in_app_review
14 import package_info
15 import package_info_plus
@@ -23,12 +21,10 @@ import wakelock_plus
21
22 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
23 ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
26 - CwMoneroPlugin.register(with: registry.registrar(forPlugin: "CwMoneroPlugin"))
24 DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
25 DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
26 InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
27 FlutterLocalAuthenticationPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalAuthenticationPlugin"))
31 - FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
28 InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
29 FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
30 FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
macos/Podfile.lock
-21
@@ -2,23 +2,6 @@ PODS:
2 - connectivity_plus (0.0.1):
3 - FlutterMacOS
4 - ReachabilitySwift
5 - - cw_monero (0.0.1):
6 - - cw_monero/Boost (= 0.0.1)
7 - - cw_monero/Monero (= 0.0.1)
8 - - cw_monero/OpenSSL (= 0.0.1)
9 - - cw_monero/Sodium (= 0.0.1)
10 - - cw_monero/Unbound (= 0.0.1)
11 - - FlutterMacOS
12 - - cw_monero/Boost (0.0.1):
13 - - FlutterMacOS
14 - - cw_monero/Monero (0.0.1):
15 - - FlutterMacOS
16 - - cw_monero/OpenSSL (0.0.1):
17 - - FlutterMacOS
18 - - cw_monero/Sodium (0.0.1):
19 - - FlutterMacOS
20 - - cw_monero/Unbound (0.0.1):
21 - - FlutterMacOS
5 - device_info_plus (0.0.1):
6 - FlutterMacOS
7 - devicelocale (0.0.1):
@@ -56,7 +39,6 @@ PODS:
39
40 DEPENDENCIES:
41 - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`)
59 - - cw_monero (from `Flutter/ephemeral/.symlinks/plugins/cw_monero/macos`)
42 - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
43 - devicelocale (from `Flutter/ephemeral/.symlinks/plugins/devicelocale/macos`)
44 - flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`)
@@ -81,8 +63,6 @@ SPEC REPOS:
63 EXTERNAL SOURCES:
64 connectivity_plus:
65 :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos
84 - cw_monero:
85 - :path: Flutter/ephemeral/.symlinks/plugins/cw_monero/macos
66 device_info_plus:
67 :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
68 devicelocale:
@@ -116,7 +96,6 @@ EXTERNAL SOURCES:
96
97 SPEC CHECKSUMS:
98 connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747
119 - cw_monero: ec03de55a19c4a2b174ea687e0f4202edc716fa4
99 device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
100 devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225
101 flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d
macos/Runner.xcodeproj/project.pbxproj
+56 -33
@@ -26,8 +26,10 @@
26 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
27 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
28 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
29 - 4171CB1F5A4EA2E4DC33F52F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B38D1DBC56DBD386923BC063 /* Pods_Runner.framework */; };
29 + 83FF6BF911B29965D3589BE7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD06F8F6E3797AC031038136 /* Pods_Runner.framework */; };
30 9F565D5929954F53009A75FB /* secRandom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F565D5729954F53009A75FB /* secRandom.swift */; };
31 + CE75FC4A2C147EBA00CCC46E /* wownero_libwallet2_api_c.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE75FC492C147EBA00CCC46E /* wownero_libwallet2_api_c.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
32 + CED5DBE42BE59BBF0065028F /* monero_libwallet2_api_c.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = CED5DBE32BE59BBF0065028F /* monero_libwallet2_api_c.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
33 /* End PBXBuildFile section */
34
35 /* Begin PBXContainerItemProxy section */
@@ -51,12 +53,22 @@
53 name = "Bundle Framework";
54 runOnlyForDeploymentPostprocessing = 0;
55 };
56 + CED5DBE02BE59B230065028F /* CopyFiles */ = {
57 + isa = PBXCopyFilesBuildPhase;
58 + buildActionMask = 2147483647;
59 + dstPath = "";
60 + dstSubfolderSpec = 10;
61 + files = (
62 + CE75FC4A2C147EBA00CCC46E /* wownero_libwallet2_api_c.dylib in CopyFiles */,
63 + CED5DBE42BE59BBF0065028F /* monero_libwallet2_api_c.dylib in CopyFiles */,
64 + );
65 + runOnlyForDeploymentPostprocessing = 0;
66 + };
67 /* End PBXCopyFilesBuildPhase section */
68
69 /* Begin PBXFileReference section */
57 - 094BF982245FD1012D60A103 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
70 0C090639294D3AAC00954DC9 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
59 - 2A820A13B0719E9E0CD6686F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
71 + 3294B60E86F47055290F9DFC /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
72 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
73 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
74 33CC10ED2044A3C60003C045 /* Cake Wallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Cake Wallet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -72,10 +84,14 @@
84 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
85 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
86 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
75 - 9646C67C7114830A5ACFF5DF /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
87 + 81434A9891ECC211D4A12B7B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
88 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
89 + 981E08F6A19E64F1F4D21DB8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
90 + 9F1E7BFB2BF2D27500C28C9A /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
91 9F565D5729954F53009A75FB /* secRandom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = secRandom.swift; path = CakeWallet/secRandom.swift; sourceTree = "<group>"; };
78 - B38D1DBC56DBD386923BC063 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
92 + BD06F8F6E3797AC031038136 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
93 + CE75FC492C147EBA00CCC46E /* wownero_libwallet2_api_c.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = wownero_libwallet2_api_c.dylib; sourceTree = "<group>"; };
94 + CED5DBE32BE59BBF0065028F /* monero_libwallet2_api_c.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = monero_libwallet2_api_c.dylib; sourceTree = "<group>"; };
95 /* End PBXFileReference section */
96
97 /* Begin PBXFrameworksBuildPhase section */
@@ -83,7 +99,7 @@
99 isa = PBXFrameworksBuildPhase;
100 buildActionMask = 2147483647;
101 files = (
86 - 4171CB1F5A4EA2E4DC33F52F /* Pods_Runner.framework in Frameworks */,
102 + 83FF6BF911B29965D3589BE7 /* Pods_Runner.framework in Frameworks */,
103 );
104 runOnlyForDeploymentPostprocessing = 0;
105 };
@@ -104,6 +120,8 @@
120 33CC10E42044A3C60003C045 = {
121 isa = PBXGroup;
122 children = (
123 + CE75FC492C147EBA00CCC46E /* wownero_libwallet2_api_c.dylib */,
124 + CED5DBE32BE59BBF0065028F /* monero_libwallet2_api_c.dylib */,
125 9F565D5729954F53009A75FB /* secRandom.swift */,
126 33FAB671232836740065AC1E /* Runner */,
127 33CEB47122A05771004F2AC0 /* Flutter */,
@@ -146,6 +164,7 @@
164 33FAB671232836740065AC1E /* Runner */ = {
165 isa = PBXGroup;
166 children = (
167 + 9F1E7BFB2BF2D27500C28C9A /* Runner.entitlements */,
168 33CC10F02044A3C60003C045 /* AppDelegate.swift */,
169 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
170 33E51913231747F40026EE4D /* DebugProfile.entitlements */,
@@ -159,9 +178,9 @@
178 9B6E7CA3983216A9E173F00F /* Pods */ = {
179 isa = PBXGroup;
180 children = (
162 - 9646C67C7114830A5ACFF5DF /* Pods-Runner.debug.xcconfig */,
163 - 2A820A13B0719E9E0CD6686F /* Pods-Runner.release.xcconfig */,
164 - 094BF982245FD1012D60A103 /* Pods-Runner.profile.xcconfig */,
181 + 81434A9891ECC211D4A12B7B /* Pods-Runner.debug.xcconfig */,
182 + 3294B60E86F47055290F9DFC /* Pods-Runner.release.xcconfig */,
183 + 981E08F6A19E64F1F4D21DB8 /* Pods-Runner.profile.xcconfig */,
184 );
185 path = Pods;
186 sourceTree = "<group>";
@@ -170,7 +189,7 @@
189 isa = PBXGroup;
190 children = (
191 0C090639294D3AAC00954DC9 /* libiconv.tbd */,
173 - B38D1DBC56DBD386923BC063 /* Pods_Runner.framework */,
192 + BD06F8F6E3797AC031038136 /* Pods_Runner.framework */,
193 );
194 name = Frameworks;
195 sourceTree = "<group>";
@@ -182,13 +201,14 @@
201 isa = PBXNativeTarget;
202 buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
203 buildPhases = (
185 - 93B711AB4B96E7C8C5C5B844 /* [CP] Check Pods Manifest.lock */,
204 + 88D0DCAF0B588F71DC405272 /* [CP] Check Pods Manifest.lock */,
205 33CC10E92044A3C60003C045 /* Sources */,
206 33CC10EA2044A3C60003C045 /* Frameworks */,
207 33CC10EB2044A3C60003C045 /* Resources */,
208 33CC110E2044A8840003C045 /* Bundle Framework */,
209 3399D490228B24CF009A79C7 /* ShellScript */,
191 - 5592D00118C2EA3C5E0B5FDF /* [CP] Embed Pods Frameworks */,
210 + CED5DBE02BE59B230065028F /* CopyFiles */,
211 + 283A25C672FDD605ACF2FDFC /* [CP] Embed Pods Frameworks */,
212 );
213 buildRules = (
214 );
@@ -257,6 +277,23 @@
277 /* End PBXResourcesBuildPhase section */
278
279 /* Begin PBXShellScriptBuildPhase section */
280 + 283A25C672FDD605ACF2FDFC /* [CP] Embed Pods Frameworks */ = {
281 + isa = PBXShellScriptBuildPhase;
282 + buildActionMask = 2147483647;
283 + files = (
284 + );
285 + inputFileListPaths = (
286 + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
287 + );
288 + name = "[CP] Embed Pods Frameworks";
289 + outputFileListPaths = (
290 + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
291 + );
292 + runOnlyForDeploymentPostprocessing = 0;
293 + shellPath = /bin/sh;
294 + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
295 + showEnvVarsInLog = 0;
296 + };
297 3399D490228B24CF009A79C7 /* ShellScript */ = {
298 isa = PBXShellScriptBuildPhase;
299 alwaysOutOfDate = 1;
@@ -295,24 +332,7 @@
332 shellPath = /bin/sh;
333 shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
334 };
298 - 5592D00118C2EA3C5E0B5FDF /* [CP] Embed Pods Frameworks */ = {
299 - isa = PBXShellScriptBuildPhase;
300 - buildActionMask = 2147483647;
301 - files = (
302 - );
303 - inputFileListPaths = (
304 - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
305 - );
306 - name = "[CP] Embed Pods Frameworks";
307 - outputFileListPaths = (
308 - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
309 - );
310 - runOnlyForDeploymentPostprocessing = 0;
311 - shellPath = /bin/sh;
312 - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
313 - showEnvVarsInLog = 0;
314 - };
315 - 93B711AB4B96E7C8C5C5B844 /* [CP] Check Pods Manifest.lock */ = {
335 + 88D0DCAF0B588F71DC405272 /* [CP] Check Pods Manifest.lock */ = {
336 isa = PBXShellScriptBuildPhase;
337 buildActionMask = 2147483647;
338 files = (
@@ -424,8 +444,9 @@
444 ARCHS = "$(ARCHS_STANDARD)";
445 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
446 CLANG_ENABLE_MODULES = YES;
427 - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
447 + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
448 CODE_SIGN_IDENTITY = "Apple Development";
449 + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
450 CODE_SIGN_STYLE = Automatic;
451 COMBINE_HIDPI_IMAGES = YES;
452 CURRENT_PROJECT_VERSION = 10;
@@ -558,8 +579,9 @@
579 ARCHS = "$(ARCHS_STANDARD)";
580 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
581 CLANG_ENABLE_MODULES = YES;
561 - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
582 + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
583 CODE_SIGN_IDENTITY = "Apple Development";
584 + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
585 CODE_SIGN_STYLE = Automatic;
586 COMBINE_HIDPI_IMAGES = YES;
587 CURRENT_PROJECT_VERSION = 10;
@@ -586,8 +608,9 @@
608 ARCHS = "$(ARCHS_STANDARD)";
609 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
610 CLANG_ENABLE_MODULES = YES;
589 - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
611 + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
612 CODE_SIGN_IDENTITY = "Apple Development";
613 + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
614 CODE_SIGN_STYLE = Automatic;
615 COMBINE_HIDPI_IMAGES = YES;
616 CURRENT_PROJECT_VERSION = 10;
macos/Runner/RunnerBase.entitlements renamed
+5 -1
@@ -4,9 +4,13 @@
4 <dict>
5 <key>com.apple.security.app-sandbox</key>
6 <true/>
7 - <key>com.apple.security.cs.allow-jit</key>
7 + <key>com.apple.security.network.client</key>
8 <true/>
9 <key>com.apple.security.network.server</key>
10 <true/>
11 + <key>keychain-access-groups</key>
12 + <array>
13 + <string>$(AppIdentifierPrefix)${BUNDLE_ID}</string>
14 + </array>
15 </dict>
16 </plist>
macos/monero_libwallet2_api_c.dylib new
+1
@@ -0,0 +1 @@
1 +../scripts/monero_c/release/monero/host-apple-darwin_libwallet2_api_c.dylib
\ No newline at end of file
macos/wownero_libwallet2_api_c.dylib new
+1
@@ -0,0 +1 @@
1 +../scripts/monero_c/release/wownero/host-apple-darwin_libwallet2_api_c.dylib
\ No newline at end of file
model_generator.sh
+1
@@ -7,6 +7,7 @@ cd cw_nano; flutter pub get; flutter packages pub run build_runner build --delet
7 cd cw_bitcoin_cash; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
8 cd cw_solana; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
9 cd cw_tron; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
10 +cd cw_wownero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
11 cd cw_polygon; flutter pub get; cd ..
12 cd cw_ethereum; flutter pub get; cd ..
13 flutter packages pub run build_runner build --delete-conflicting-outputs
pubspec_base.yaml
+1
@@ -163,6 +163,7 @@ flutter:
163 - assets/polygon_node_list.yml
164 - assets/solana_node_list.yml
165 - assets/tron_node_list.yml
166 + - assets/wownero_node_list.yml
167 - assets/text/
168 - assets/faq/
169 - assets/animation/
res/values/strings_en.arb
+1
@@ -585,6 +585,7 @@
585 "seedtype": "Seedtype",
586 "seedtype_legacy": "Legacy (25 words)",
587 "seedtype_polyseed": "Polyseed (16 words)",
588 + "seedtype_wownero": "Wownero (14 words)",
589 "select_backup_file": "Select backup file",
590 "select_buy_provider_notice": "Select a buy provider above. You can skip this screen by setting your default buy provider in app settings.",
591 "select_destination": "Please select destination for the backup file.",
run-android.sh
+3 -3
@@ -4,8 +4,7 @@
4 get_current_branch() {
5 if git rev-parse --git-dir > /dev/null 2>&1; then
6 branch=$(git rev-parse --abbrev-ref HEAD)
7 - branch=${branch//[-]/_} # Replace all dashes with underscores
8 - echo "$branch"
7 + echo "$branch" | tr '-' '_'
8 else
9 echo "Error: Not a git repository."
10 return 1
@@ -16,6 +15,7 @@ get_current_branch() {
15 update_app_properties() {
16 local branch=$1
17 local file_path="./android/app.properties"
18 +
19 sed -i "s/^id=.*/id=com.cakewallet.$branch/" "$file_path"
20 sed -i "s/^name=.*/name=$branch-Cake Wallet/" "$file_path"
21 }
@@ -27,4 +27,4 @@ if [[ $? -eq 0 ]]; then
27 fi
28
29 # run the app
30 -flutter run
\ No newline at end of file
30 +flutter run
scripts/android/app_config.sh
+1 -1
@@ -8,5 +8,5 @@ fi
8 ./app_properties.sh
9 ./app_icon.sh
10 ./pubspec_gen.sh
11 -./manifest.sh
11 +./manifest.sh true #force overwrite manifest
12 ./inject_app_details.sh
scripts/android/build_all.sh
+1 -1
@@ -10,6 +10,6 @@ DIR=$(dirname "$0")
10 case $APP_ANDROID_TYPE in
11 "monero.com") $DIR/build_monero_all.sh ;;
12 "cakewallet") $DIR/build_monero_all.sh
13 - $DIR/build_haven.sh ;;
13 + $DIR/build_haven_all.sh ;;
14 "haven") $DIR/build_haven_all.sh ;;
15 esac
scripts/android/build_monero.sh deleted
-68
@@ -1,68 +0,0 @@
1 -#!/bin/sh
2 -
3 -. ./config.sh
4 -MONERO_BRANCH=release-v0.18.3.2-android
5 -MONERO_SRC_DIR=${WORKDIR}/monero
6 -
7 -git clone https://github.com/cake-tech/monero.git ${MONERO_SRC_DIR} --branch ${MONERO_BRANCH}
8 -cd $MONERO_SRC_DIR
9 -git submodule update --init --force
10 -
11 -for arch in "aarch" "aarch64" "i686" "x86_64"
12 -do
13 -FLAGS=""
14 -PREFIX=${WORKDIR}/prefix_${arch}
15 -DEST_LIB_DIR=${PREFIX}/lib/monero
16 -DEST_INCLUDE_DIR=${PREFIX}/include/monero
17 -export CMAKE_INCLUDE_PATH="${PREFIX}/include"
18 -export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
19 -ANDROID_STANDALONE_TOOLCHAIN_PATH="${TOOLCHAIN_BASE_DIR}_${arch}"
20 -PATH="${ANDROID_STANDALONE_TOOLCHAIN_PATH}/bin:${ORIGINAL_PATH}"
21 -
22 -mkdir -p $DEST_LIB_DIR
23 -mkdir -p $DEST_INCLUDE_DIR
24 -
25 -case $arch in
26 - "aarch" )
27 - CLANG=arm-linux-androideabi-clang
28 - CXXLANG=arm-linux-androideabi-clang++
29 - BUILD_64=OFF
30 - TAG="android-armv7"
31 - ARCH="armv7-a"
32 - ARCH_ABI="armeabi-v7a"
33 - FLAGS="-D CMAKE_ANDROID_ARM_MODE=ON -D NO_AES=true";;
34 - "aarch64" )
35 - CLANG=aarch64-linux-androideabi-clang
36 - CXXLANG=aarch64-linux-androideabi-clang++
37 - BUILD_64=ON
38 - TAG="android-armv8"
39 - ARCH="armv8-a"
40 - ARCH_ABI="arm64-v8a";;
41 - "i686" )
42 - CLANG=i686-linux-androideabi-clang
43 - CXXLANG=i686-linux-androideabi-clang++
44 - BUILD_64=OFF
45 - TAG="android-x86"
46 - ARCH="i686"
47 - ARCH_ABI="x86";;
48 - "x86_64" )
49 - CLANG=x86_64-linux-androideabi-clang
50 - CXXLANG=x86_64-linux-androideabi-clang++
51 - BUILD_64=ON
52 - TAG="android-x86_64"
53 - ARCH="x86-64"
54 - ARCH_ABI="x86_64";;
55 -esac
56 -
57 -cd $MONERO_SRC_DIR
58 -rm -rf ./build/release
59 -mkdir -p ./build/release
60 -cd ./build/release
61 -CC=${CLANG} CXX=${CXXLANG} cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH=${ARCH} -D STATIC=ON -D BUILD_64=${BUILD_64} -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG=${TAG} -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI=${ARCH_ABI} -D MANUAL_SUBMODULES=1 $FLAGS ../..
62 -
63 -make wallet_api -j$THREADS
64 -find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
65 -
66 -cp -r ./lib/* $DEST_LIB_DIR
67 -cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
68 -done
scripts/android/build_monero_all.sh
+55 -7
@@ -1,9 +1,57 @@
1 #!/bin/bash
2
3 -./build_iconv.sh
4 -./build_boost.sh
5 -./build_openssl.sh
6 -./build_sodium.sh
7 -./build_unbound.sh
8 -./build_zmq.sh
9 -./build_monero.sh
3 +# Usage: env USE_DOCKER= ./build_all.sh
4 +
5 +set -x -e
6 +
7 +cd "$(dirname "$0")"
8 +
9 +NPROC="-j$(nproc)"
10 +
11 +if [[ "x$(uname)" == "xDarwin" ]];
12 +then
13 + USE_DOCKER="ON"
14 + NPROC="-j1"
15 +fi
16 +
17 +../prepare_moneroc.sh
18 +
19 +if [[ ! "x$RUNNER_OS" == "x" ]];
20 +then
21 + REMOVE_CACHES=ON
22 +fi
23 +
24 +# NOTE: -j1 is intentional. Otherwise you will run into weird behaviour on macos
25 +if [[ ! "x$USE_DOCKER" == "x" ]];
26 +then
27 + for COIN in monero wownero;
28 + do
29 + pushd ../monero_c
30 + docker run --platform linux/amd64 -v$HOME/.cache/ccache:/root/.ccache -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc g++ libtinfo5 gperf; ./build_single.sh ${COIN} x86_64-linux-android $NPROC"
31 + # docker run --platform linux/amd64 -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc g++ libtinfo5 gperf; ./build_single.sh ${COIN} i686-linux-android $NPROC"
32 + docker run --platform linux/amd64 -v$HOME/.cache/ccache:/root/.ccache -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc g++ libtinfo5 gperf; ./build_single.sh ${COIN} armv7a-linux-androideabi $NPROC"
33 + docker run --platform linux/amd64 -v$HOME/.cache/ccache:/root/.ccache -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc g++ libtinfo5 gperf; ./build_single.sh ${COIN} aarch64-linux-android $NPROC"
34 + popd
35 + done
36 +else
37 + for COIN in monero wownero;
38 + do
39 + pushd ../monero_c
40 + env -i ./build_single.sh ${COIN} x86_64-linux-android $NPROC
41 + [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/x86_64-linux-android
42 + # ./build_single.sh ${COIN} i686-linux-android $NPROC
43 + # [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/i686-linux-android
44 + env -i ./build_single.sh ${COIN} armv7a-linux-androideabi $NPROC
45 + [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/armv7a-linux-androideabi
46 + env -i ./build_single.sh ${COIN} aarch64-linux-android $NPROC
47 + [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/aarch64-linux-android
48 +
49 + popd
50 + unxz -f ../monero_c/release/${COIN}/x86_64-linux-android_libwallet2_api_c.so.xz
51 +
52 + unxz -f ../monero_c/release/${COIN}/armv7a-linux-androideabi_libwallet2_api_c.so.xz
53 +
54 + unxz -f ../monero_c/release/${COIN}/aarch64-linux-android_libwallet2_api_c.so.xz
55 + [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/{built,sources}
56 + done
57 +fi
scripts/android/build_openssl.sh
+1 -2
@@ -1,6 +1,6 @@
1 #!/bin/sh
2
3 -set -e
3 +set -e -x
4
5 . ./config.sh
6 OPENSSL_FILENAME=openssl-1.1.1q.tar.gz
@@ -26,7 +26,6 @@ do
26 PREFIX=$WORKDIR/prefix_${arch}
27 TOOLCHAIN=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
28 PATH="${TOOLCHAIN}/bin:${ORIGINAL_PATH}"
29 -
29 case $arch in
30 "aarch") X_ARCH="android-arm";;
31 "aarch64") X_ARCH="android-arm64";;
scripts/android/build_unbound.sh
+2 -2
@@ -14,7 +14,7 @@ PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
14
15 cd $WORKDIR
16 rm -rf $EXPAT_SRC_DIR
17 -git clone https://github.com/libexpat/libexpat.git -b ${EXPAT_VERSION} ${EXPAT_SRC_DIR}
17 +git clone https://github.com/libexpat/libexpat.git --depth=1 -b ${EXPAT_VERSION} ${EXPAT_SRC_DIR}
18 cd $EXPAT_SRC_DIR
19 test `git rev-parse HEAD` = ${EXPAT_HASH} || exit 1
20 cd $EXPAT_SRC_DIR/expat
@@ -49,7 +49,7 @@ PATH="${TOOLCHAIN_BIN_PATH}:${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
49 echo $PATH
50 cd $WORKDIR
51 rm -rf $UNBOUND_SRC_DIR
52 -git clone https://github.com/NLnetLabs/unbound.git -b ${UNBOUND_VERSION} ${UNBOUND_SRC_DIR}
52 +git clone https://github.com/NLnetLabs/unbound.git --depth=1 -b ${UNBOUND_VERSION} ${UNBOUND_SRC_DIR}
53 cd $UNBOUND_SRC_DIR
54 test `git rev-parse HEAD` = ${UNBOUND_HASH} || exit 1
55
scripts/android/copy_monero_deps.sh
-1
@@ -41,5 +41,4 @@ done
41 mkdir -p ${CW_HAVEN_EXTERNAL_DIR}/include
42 mkdir -p ${CW_MONERO_EXTERNAL_DIR}/include
43
44 -cp $CW_EXRTERNAL_DIR/x86/include/monero/wallet2_api.h ${CW_MONERO_EXTERNAL_DIR}/include
44 cp $CW_EXRTERNAL_DIR/x86/include/haven/wallet2_api.h ${CW_HAVEN_EXTERNAL_DIR}/include
scripts/android/init_boost.sh
+2 -2
@@ -17,6 +17,6 @@ echo $BOOST_SHA256 $BOOST_FILE_PATH | sha256sum -c - || exit 1
17 cd $WORKDIR
18 rm -rf $BOOST_SRC_DIR
19 rm -rf $PREFIX/include/boost
20 -tar -xvf $BOOST_FILE_PATH -C $WORKDIR
20 +tar -xf $BOOST_FILE_PATH -C $WORKDIR
21 cd $BOOST_SRC_DIR
22 -./bootstrap.sh --prefix=${PREFIX}
22 +./bootstrap.sh --prefix=${PREFIX} --with-toolset=gcc
scripts/android/inject_app_details.sh
+1
@@ -6,6 +6,7 @@ if [ -z "$APP_ANDROID_TYPE" ]; then
6 fi
7
8 cd ../..
9 +set -x
10 sed -i "0,/version:/{s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/}" ./pubspec.yaml
11 sed -i "0,/version:/{s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/}" ./android/app/src/main/AndroidManifest.xml
12 sed -i "0,/__APP_SCHEME__/s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/" ./android/app/src/main/AndroidManifest.xml
scripts/android/install_ndk.sh
+3 -3
@@ -8,9 +8,9 @@ TOOLCHAIN_x86_DIR=${TOOLCHAIN_DIR}_i686
8 TOOLCHAIN_x86_64_DIR=${TOOLCHAIN_DIR}_x86_64
9 ANDROID_NDK_SHA256="3f541adbd0330a9205ba12697f6d04ec90752c53d6b622101a2a8a856e816589"
10
11 -curl https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip -o ${ANDROID_NDK_ZIP}
12 -echo $ANDROID_NDK_SHA256 $ANDROID_NDK_ZIP | sha256sum -c || exit 1
13 -unzip $ANDROID_NDK_ZIP -d $WORKDIR
11 + curl https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip -o ${ANDROID_NDK_ZIP}
12 + echo $ANDROID_NDK_SHA256 $ANDROID_NDK_ZIP | sha256sum -c || exit 1
13 + unzip $ANDROID_NDK_ZIP -d $WORKDIR
14
15 ${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch arm64 --api $API --install-dir ${TOOLCHAIN_A64_DIR} --stl=libc++
16 ${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch arm --api $API --install-dir ${TOOLCHAIN_A32_DIR} --stl=libc++
scripts/android/manifest.sh
+7 -2
@@ -1,5 +1,10 @@
1 #!/bin/bash
2
3 cd ../..
4 -cp -rf ./android/app/src/main/AndroidManifestBase.xml ./android/app/src/main/AndroidManifest.xml
5 -cd scripts/android
\ No newline at end of file
4 +
5 +if [ "$1" = true ]; then
6 + cp -rf ./android/app/src/main/AndroidManifestBase.xml ./android/app/src/main/AndroidManifest.xml
7 +else
8 + cp -n ./android/app/src/main/AndroidManifestBase.xml ./android/app/src/main/AndroidManifest.xml
9 +fi
10 +cd scripts/android
scripts/android/pubspec_gen.sh
+4 -1
@@ -10,7 +10,10 @@ case $APP_ANDROID_TYPE in
10 CONFIG_ARGS="--monero"
11 ;;
12 $CAKEWALLET)
13 - CONFIG_ARGS="--monero --bitcoin --haven --ethereum --polygon --nano --bitcoinCash --solana --tron"
13 + CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero"
14 + if [ "$CW_WITH_HAVEN" = true ];then
15 + CONFIG_ARGS="$CONFIG_ARGS --haven"
16 + fi
17 ;;
18 $HAVEN)
19 CONFIG_ARGS="--haven"
scripts/docker/.gitignore
+1
@@ -1 +1,2 @@
1 output/
2 +cache/
\ No newline at end of file
scripts/docker/Dockerfile
+40 -4
@@ -4,23 +4,59 @@ LABEL authors="konsti"
4 ENV MONERO_BRANCH=release-v0.18.2.2-android
5 RUN apt-get update && \
6 echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections && \
7 - apt-get install -y dialog apt-utils curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
7 + apt-get install -y dialog apt-utils curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang bison ccache
8
9 RUN mkdir /opt/android/
10
11 -COPY . /opt/android/cakewallet/
12 -
11 WORKDIR /opt/android/cakewallet/
12
15 -
13 +# build_all.sh
14 +# build_boost.sh
15 +# build_haven.sh
16 +# build_haven_all.sh
17 +# build_iconv.sh
18 +# build_monero.sh
19 +# build_openssl.sh
20 +# build_sodium.sh
21 +# build_unbound.sh
22 +# build_zmq.sh
23 +# config.sh
24 +# copy_haven_deps.sh
25 +# copy_monero_deps.sh
26 +# docker-compose.yml
27 +# entrypoint.sh
28 +# finish_boost.sh
29 +# init_boost.sh
30 +# install_ndk.sh
31 +
32 +COPY config.sh /opt/android/cakewallet/
33 +COPY install_ndk.sh /opt/android/cakewallet/
34 RUN ./install_ndk.sh
35
36 +COPY build_iconv.sh /opt/android/cakewallet/
37 RUN ./build_iconv.sh
38 +
39 +COPY build_boost.sh /opt/android/cakewallet/
40 +COPY init_boost.sh /opt/android/cakewallet/
41 +COPY finish_boost.sh /opt/android/cakewallet/
42 RUN ./build_boost.sh
43 +
44 +COPY build_openssl.sh /opt/android/cakewallet/
45 RUN ./build_openssl.sh
46 +
47 +COPY build_sodium.sh /opt/android/cakewallet/
48 RUN ./build_sodium.sh
49 +
50 +COPY build_unbound.sh /opt/android/cakewallet/
51 RUN ./build_unbound.sh
52 +
53 +COPY build_zmq.sh /opt/android/cakewallet/
54 RUN ./build_zmq.sh
55
56 +COPY entrypoint.sh /opt/android/cakewallet/
57 +COPY build_monero.sh /opt/android/cakewallet/
58 +COPY copy_monero_deps.sh /opt/android/cakewallet/
59 +COPY build_haven.sh /opt/android/cakewallet/
60 +COPY copy_haven_deps.sh /opt/android/cakewallet/
61
62 ENTRYPOINT ["./entrypoint.sh"]
scripts/docker/build_all.sh
+17 -1
@@ -1 +1,17 @@
1 -#!/bin/sh if [ -z "$APP_ANDROID_TYPE" ]; then echo "Please set APP_ANDROID_TYPE" exit 1 fi DIR=$(dirname "$0") case $APP_ANDROID_TYPE in "monero.com") $DIR/build_monero_all.sh ;; "cakewallet") $DIR/build_monero_all.sh $DIR/build_haven.sh ;; "haven") $DIR/build_haven_all.sh ;; esac
\ No newline at end of file
1 +#!/bin/sh
2 +
3 +set -x -e
4 +
5 +if [ -z "$APP_ANDROID_TYPE" ]; then
6 + echo "Please set APP_ANDROID_TYPE"
7 + exit 1
8 +fi
9 +
10 +DIR=$(dirname "$0")
11 +
12 +case $APP_ANDROID_TYPE in
13 + "monero.com") $DIR/build_monero_all.sh ;;
14 + "cakewallet") $DIR/build_monero_all.sh
15 + $DIR/build_haven.sh ;;
16 + "haven") $DIR/build_haven_all.sh ;;
17 +esac
scripts/docker/build_boost.sh
+1 -1
@@ -1,5 +1,5 @@
1 #!/bin/bash
2 -
2 +set -x -e
3 . ./config.sh
4 BOOST_SRC_DIR=$WORKDIR/boost_1_72_0
5 BOOST_FILENAME=boost_1_72_0.tar.bz2
scripts/docker/build_haven.sh
+71 -1
@@ -1 +1,71 @@
1 -#!/bin/sh . ./config.sh HAVEN_VERSION=tags/v3.0.7 HAVEN_SRC_DIR=${WORKDIR}/haven git clone https://github.com/haven-protocol-org/haven-main.git ${HAVEN_SRC_DIR} git checkout ${HAVEN_VERSION} cd $HAVEN_SRC_DIR git submodule init git submodule update for arch in "aarch" "aarch64" "i686" "x86_64" do FLAGS="" PREFIX=${WORKDIR}/prefix_${arch} DEST_LIB_DIR=${PREFIX}/lib/haven DEST_INCLUDE_DIR=${PREFIX}/include/haven export CMAKE_INCLUDE_PATH="${PREFIX}/include" export CMAKE_LIBRARY_PATH="${PREFIX}/lib" ANDROID_STANDALONE_TOOLCHAIN_PATH="${TOOLCHAIN_BASE_DIR}_${arch}" PATH="${ANDROID_STANDALONE_TOOLCHAIN_PATH}/bin:${ORIGINAL_PATH}" mkdir -p $DEST_LIB_DIR mkdir -p $DEST_INCLUDE_DIR case $arch in "aarch" ) CLANG=arm-linux-androideabi-clang CXXLANG=arm-linux-androideabi-clang++ BUILD_64=OFF TAG="android-armv7" ARCH="armv7-a" ARCH_ABI="armeabi-v7a" FLAGS="-D CMAKE_ANDROID_ARM_MODE=ON -D NO_AES=true";; "aarch64" ) CLANG=aarch64-linux-androideabi-clang CXXLANG=aarch64-linux-androideabi-clang++ BUILD_64=ON TAG="android-armv8" ARCH="armv8-a" ARCH_ABI="arm64-v8a";; "i686" ) CLANG=i686-linux-androideabi-clang CXXLANG=i686-linux-androideabi-clang++ BUILD_64=OFF TAG="android-x86" ARCH="i686" ARCH_ABI="x86";; "x86_64" ) CLANG=x86_64-linux-androideabi-clang CXXLANG=x86_64-linux-androideabi-clang++ BUILD_64=ON TAG="android-x86_64" ARCH="x86-64" ARCH_ABI="x86_64";; esac cd $HAVEN_SRC_DIR rm -rf ./build/release mkdir -p ./build/release cd ./build/release CC=${CLANG} CXX=${CXXLANG} cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH=${ARCH} -D STATIC=ON -D BUILD_64=${BUILD_64} -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG=${TAG} -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI=${ARCH_ABI} $FLAGS ../.. make wallet_api -j$THREADS find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \; cp -r ./lib/* $DEST_LIB_DIR cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR done
\ No newline at end of file
1 +#!/bin/sh
2 +set -x -e
3 +
4 +. ./config.sh
5 +HAVEN_VERSION=tags/v3.0.7
6 +HAVEN_SRC_DIR=${WORKDIR}/haven
7 +
8 +git clone https://github.com/haven-protocol-org/haven-main.git ${HAVEN_SRC_DIR}
9 +cd $HAVEN_SRC_DIR
10 +git checkout ${HAVEN_VERSION}
11 +git submodule init
12 +git submodule update
13 +
14 +for arch in "aarch" "aarch64" "i686" "x86_64"
15 +do
16 +FLAGS=""
17 +PREFIX=${WORKDIR}/prefix_${arch}
18 +DEST_LIB_DIR=${PREFIX}/lib/haven
19 +DEST_INCLUDE_DIR=${PREFIX}/include/haven
20 +export CMAKE_INCLUDE_PATH="${PREFIX}/include"
21 +export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
22 +ANDROID_STANDALONE_TOOLCHAIN_PATH="${TOOLCHAIN_BASE_DIR}_${arch}"
23 +PATH="${ANDROID_STANDALONE_TOOLCHAIN_PATH}/bin:${ORIGINAL_PATH}"
24 +
25 +mkdir -p $DEST_LIB_DIR
26 +mkdir -p $DEST_INCLUDE_DIR
27 +
28 +case $arch in
29 + "aarch" )
30 + CLANG=arm-linux-androideabi-clang
31 + CXXLANG=arm-linux-androideabi-clang++
32 + BUILD_64=OFF
33 + TAG="android-armv7"
34 + ARCH="armv7-a"
35 + ARCH_ABI="armeabi-v7a"
36 + FLAGS="-D CMAKE_ANDROID_ARM_MODE=ON -D NO_AES=true";;
37 + "aarch64" )
38 + CLANG=aarch64-linux-androideabi-clang
39 + CXXLANG=aarch64-linux-androideabi-clang++
40 + BUILD_64=ON
41 + TAG="android-armv8"
42 + ARCH="armv8-a"
43 + ARCH_ABI="arm64-v8a";;
44 + "i686" )
45 + CLANG=i686-linux-androideabi-clang
46 + CXXLANG=i686-linux-androideabi-clang++
47 + BUILD_64=OFF
48 + TAG="android-x86"
49 + ARCH="i686"
50 + ARCH_ABI="x86";;
51 + "x86_64" )
52 + CLANG=x86_64-linux-androideabi-clang
53 + CXXLANG=x86_64-linux-androideabi-clang++
54 + BUILD_64=ON
55 + TAG="android-x86_64"
56 + ARCH="x86-64"
57 + ARCH_ABI="x86_64";;
58 +esac
59 +
60 +cd $HAVEN_SRC_DIR
61 +rm -rf ./build/release
62 +mkdir -p ./build/release
63 +cd ./build/release
64 +CC=${CLANG} CXX=${CXXLANG} cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH=${ARCH} -D STATIC=ON -D BUILD_64=${BUILD_64} -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG=${TAG} -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI=${ARCH_ABI} $FLAGS ../..
65 +
66 +make wallet_api -j$THREADS
67 +find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
68 +
69 +cp -r ./lib/* $DEST_LIB_DIR
70 +cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
71 +done
scripts/docker/build_haven_all.sh
+9 -1
@@ -1 +1,9 @@
1 -#!/bin/bash ./build_iconv.sh ./build_boost.sh ./build_openssl.sh ./build_sodium.sh ./build_zmq.sh ./build_haven.sh
\ No newline at end of file
1 +#!/bin/bash
2 +set -x -e
3 +
4 +./build_iconv.sh
5 +./build_boost.sh
6 +./build_openssl.sh
7 +./build_sodium.sh
8 +./build_zmq.sh
9 +./build_haven.sh
scripts/docker/build_iconv.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x -e
3
4 . ./config.sh
5 export ICONV_FILENAME=libiconv-1.16.tar.gz
scripts/docker/build_monero.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x -e
3
4 . ./config.sh
5
scripts/docker/build_openssl.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x -e
3
4 set -e
5
scripts/docker/build_sodium.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x -e
3
4 . ./config.sh
5 SODIUM_SRC_DIR=${WORKDIR}/libsodium
scripts/docker/build_unbound.sh
+1 -1
@@ -1,7 +1,7 @@
1 #!/bin/bash
2 +set -x -e
3
4 . ./config.sh
4 -
5 EXPAT_VERSION=R_2_4_8
6 EXPAT_HASH="3bab6c09bbe8bf42d84b81563ddbcf4cca4be838"
7 EXPAT_SRC_DIR=$WORKDIR/libexpat
scripts/docker/build_zmq.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x -e
3
4 . ./config.sh
5 ZMQ_SRC_DIR=$WORKDIR/libzmq
scripts/docker/config.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x -e
3
4 export API=21
5 export WORKDIR=/opt/android
scripts/docker/copy_haven_deps.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x
3
4 WORKDIR=/opt/android
5 CW_DIR=${WORKDIR}/cake_wallet
scripts/docker/copy_monero_deps.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x
3
4 WORKDIR=/opt/android
5 CW_EXRTERNAL_DIR=${WORKDIR}/output/android
scripts/docker/docker-compose.yml
+2
@@ -7,3 +7,5 @@ services:
7 MONERO_BRANCH: release-v0.18.2.2-android
8 volumes:
9 - ./output:/opt/android/output
10 + - ./cache/dotcache:/root/.cache
11 + - ./cache/dotccache:/root/.ccache
scripts/docker/entrypoint.sh
+7
@@ -1,4 +1,11 @@
1 #!/bin/bash
2 +set -x -e
3 +
4 +ls /opt/android
5 +
6 +rm -rf monero haven
7
8 ./build_monero.sh
9 +./build_haven.sh
10 ./copy_monero_deps.sh
11 +./copy_haven_deps.sh
scripts/docker/finish_boost.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x -e
3
4 ARCH=$1
5 PREFIX=$2
scripts/docker/init_boost.sh
+4 -2
@@ -1,4 +1,6 @@
1 #!/bin/bash
2 +set -x -e
3 +
4
5 ARCH=$1
6 PREFIX=$2
@@ -17,6 +19,6 @@ echo $BOOST_SHA256 $BOOST_FILE_PATH | sha256sum -c - || exit 1
19 cd $WORKDIR
20 rm -rf $BOOST_SRC_DIR
21 rm -rf $PREFIX/include/boost
20 -tar -xvf $BOOST_FILE_PATH -C $WORKDIR
22 +tar -xf $BOOST_FILE_PATH -C $WORKDIR
23 cd $BOOST_SRC_DIR
22 -./bootstrap.sh --prefix=${PREFIX}
24 +./bootstrap.sh --prefix=${PREFIX} --with-toolset=gcc
scripts/docker/install_ndk.sh
+1
@@ -1,4 +1,5 @@
1 #!/bin/bash
2 +set -x -e
3
4 . ./config.sh
5 TOOLCHAIN_DIR=${WORKDIR}/toolchain
scripts/gen_android_manifest.sh new
+10
@@ -0,0 +1,10 @@
1 +#!/bin/bash
2 +
3 +ANDROID_SCRIPTS_DIR=`pwd`/android
4 +if [ ! -d $ANDROID_SCRIPTS_DIR ]; then
5 + echo "no android scripts directory found at ${ANDROID_SCRIPTS_DIR}"
6 + exit 0
7 +fi
8 +
9 +cd $ANDROID_SCRIPTS_DIR
10 +./manifest.sh
scripts/ios/app_config.sh
+9 -3
@@ -9,8 +9,10 @@ if [ -z "$APP_IOS_TYPE" ]; then
9 echo "Please set APP_IOS_TYPE"
10 exit 1
11 fi
12 -
13 -cd ../.. # go to root
12 +./gen_framework.sh
13 +cd .. # go to scipts
14 +./gen_android_manifest.sh
15 +cd .. # go to root
16 cp -rf ./ios/Runner/InfoBase.plist ./ios/Runner/Info.plist
17 /usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName ${APP_IOS_NAME}" ./ios/Runner/Info.plist
18 /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier ${APP_IOS_BUNDLE_ID}" ./ios/Runner/Info.plist
@@ -20,6 +22,7 @@ cp -rf ./ios/Runner/InfoBase.plist ./ios/Runner/Info.plist
22 /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLName string ${APP_IOS_TYPE}" ./ios/Runner/Info.plist
23 /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLSchemes array" ./ios/Runner/Info.plist
24 /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLSchemes: string ${APP_IOS_TYPE}" ./ios/Runner/Info.plist
25 +sed -i '' "s/\${PRODUCT_BUNDLE_IDENTIFIER}/${APP_IOS_BUNDLE_ID}/g" ./ios/Runner.xcodeproj/project.pbxproj
26
27 CONFIG_ARGS=""
28
@@ -28,7 +31,10 @@ case $APP_IOS_TYPE in
31 CONFIG_ARGS="--monero"
32 ;;
33 $CAKEWALLET)
31 - CONFIG_ARGS="--monero --bitcoin --haven --ethereum --polygon --nano --bitcoinCash --solana --tron"
34 + CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero"
35 + if [ "$CW_WITH_HAVEN" = true ];then
36 + CONFIG_ARGS="$CONFIG_ARGS --haven"
37 + fi
38 ;;
39 $HAVEN)
40
scripts/ios/app_env.sh
+4 -4
@@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
13 APP_IOS_TYPE=$1
14
15 MONERO_COM_NAME="Monero.com"
16 -MONERO_COM_VERSION="1.15.2"
17 -MONERO_COM_BUILD_NUMBER=90
16 +MONERO_COM_VERSION="1.16.0"
17 +MONERO_COM_BUILD_NUMBER=91
18 MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
19
20 CAKEWALLET_NAME="Cake Wallet"
21 -CAKEWALLET_VERSION="4.18.2"
22 -CAKEWALLET_BUILD_NUMBER=250
21 +CAKEWALLET_VERSION="4.19.0"
22 +CAKEWALLET_BUILD_NUMBER=251
23 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
24
25 HAVEN_NAME="Haven"
scripts/ios/build_monero_all.sh
+24 -7
@@ -1,10 +1,27 @@
1 #!/bin/sh
2
3 . ./config.sh
4 -./install_missing_headers.sh
5 -./build_openssl.sh
6 -./build_boost.sh
7 -./build_sodium.sh
8 -./build_zmq.sh
9 -./build_unbound.sh
10 -./build_monero.sh
\ No newline at end of file
4 +# ./install_missing_headers.sh
5 +# ./build_openssl.sh
6 +# ./build_boost.sh
7 +# ./build_sodium.sh
8 +# ./build_zmq.sh
9 +# ./build_unbound.sh
10 +
11 +set -x -e
12 +
13 +cd "$(dirname "$0")"
14 +
15 +NPROC="-j$(sysctl -n hw.logicalcpu)"
16 +
17 +../prepare_moneroc.sh
18 +
19 +for COIN in monero wownero;
20 +do
21 + pushd ../monero_c
22 + ./build_single.sh ${COIN} host-apple-ios $NPROC
23 + popd
24 +done
25 +
26 +unxz -f ../monero_c/release/monero/host-apple-ios_libwallet2_api_c.dylib.xz
27 +unxz -f ../monero_c/release/wownero/host-apple-ios_libwallet2_api_c.dylib.xz
scripts/ios/build_openssl.sh
+3 -1
@@ -12,6 +12,8 @@ git clone $OPEN_SSL_URL $OPEN_SSL_DIR_PATH
12 cd $OPEN_SSL_DIR_PATH
13 ./build-libssl.sh --version=1.1.1q --targets="ios-cross-arm64" --deprecated
14
15 -mv ${OPEN_SSL_DIR_PATH}/include/* $EXTERNAL_IOS_INCLUDE_DIR
15 +# copy and then remove because mv is not working when there is subdirectories
16 +cp -R ${OPEN_SSL_DIR_PATH}/include/* $EXTERNAL_IOS_INCLUDE_DIR
17 +rm -rf ${OPEN_SSL_DIR_PATH}/include/
18 mv ${OPEN_SSL_DIR_PATH}/lib/libcrypto-iOS.a ${EXTERNAL_IOS_LIB_DIR}/libcrypto.a
19 mv ${OPEN_SSL_DIR_PATH}/lib/libssl-iOS.a ${EXTERNAL_IOS_LIB_DIR}/libssl.a
\ No newline at end of file
scripts/ios/gen_framework.sh new
+31
@@ -0,0 +1,31 @@
1 +#!/bin/sh
2 +# Assume we are in scripts/ios
3 +IOS_DIR="$(pwd)/../../ios"
4 +DYLIB_NAME="monero_libwallet2_api_c.dylib"
5 +DYLIB_LINK_PATH="${IOS_DIR}/${DYLIB_NAME}"
6 +FRWK_DIR="${IOS_DIR}/MoneroWallet.framework"
7 +
8 +if [ ! -f $DYLIB_LINK_PATH ]; then
9 + echo "Dylib is not found by the link: ${DYLIB_LINK_PATH}"
10 + exit 0
11 +fi
12 +
13 +cd $FRWK_DIR # go to iOS framework dir
14 +lipo -create $DYLIB_LINK_PATH -output MoneroWallet
15 +
16 +echo "Generated ${FRWK_DIR}"
17 +# also generate for wownero
18 +IOS_DIR="$(pwd)/../../ios"
19 +DYLIB_NAME="wownero_libwallet2_api_c.dylib"
20 +DYLIB_LINK_PATH="${IOS_DIR}/${DYLIB_NAME}"
21 +FRWK_DIR="${IOS_DIR}/WowneroWallet.framework"
22 +
23 +if [ ! -f $DYLIB_LINK_PATH ]; then
24 + echo "Dylib is not found by the link: ${DYLIB_LINK_PATH}"
25 + exit 0
26 +fi
27 +
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
scripts/macos/app_config.sh
+7 -3
@@ -9,7 +9,9 @@ if [ -z "$APP_MACOS_TYPE" ]; then
9 exit 1
10 fi
11
12 -cd ../.. # go to root
12 +cd .. # go to scipts
13 +./gen_android_manifest.sh
14 +cd .. # go to root
15 cp -rf ./macos/Runner/InfoBase.plist ./macos/Runner/Info.plist
16 /usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName ${APP_MACOS_NAME}" ./macos/Runner/Info.plist
17 /usr/libexec/PlistBuddy -c "Set :CFBundleName ${APP_MACOS_NAME}" ./macos/Runner/Info.plist
@@ -20,9 +22,11 @@ cp -rf ./macos/Runner/InfoBase.plist ./macos/Runner/Info.plist
22 # Fill entitlements Bundle ID
23 cp -rf ./macos/Runner/DebugProfileBase.entitlements ./macos/Runner/DebugProfile.entitlements
24 cp -rf ./macos/Runner/ReleaseBase.entitlements ./macos/Runner/Release.entitlements
25 +cp -rf ./macos/Runner/RunnerBase.entitlements ./macos/Runner/Runner.entitlements
26 cp -rf ./macos/Runner/Configs/AppInfoBase.xcconfig ./macos/Runner/Configs/AppInfo.xcconfig
27 sed -i '' "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/DebugProfile.entitlements
28 sed -i '' "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/Release.entitlements
29 +sed -i '' "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/Runner.entitlements
30 sed -i '' "s/\${PRODUCT_NAME}/${APP_MACOS_NAME}/g" ./macos/Runner/Configs/AppInfo.xcconfig
31 sed -i '' "s/\${PRODUCT_BUNDLE_IDENTIFIER}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/Configs/AppInfo.xcconfig
32 CONFIG_ARGS=""
@@ -31,7 +35,7 @@ case $APP_MACOS_TYPE in
35 $MONERO_COM)
36 CONFIG_ARGS="--monero";;
37 $CAKEWALLET)
34 - CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron";; #--haven
38 + CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero";; #--haven
39 esac
40
41 cp -rf pubspec_description.yaml pubspec.yaml
@@ -40,4 +44,4 @@ flutter pub run tool/generate_pubspec.dart
44 flutter pub get
45 flutter packages pub run tool/configure.dart $CONFIG_ARGS
46 cd $DIR
43 -$DIR/app_icon.sh
\ No newline at end of file
47 +$DIR/app_icon.sh
scripts/macos/build_monero_all.sh
+54 -15
@@ -1,20 +1,59 @@
1 #!/bin/sh
2 +set -x -e
3
3 -ARCH=`uname -m`
4 +cd "$(dirname "$0")"
5
5 -. ./config.sh
6 +NPROC="-j$(sysctl -n hw.logicalcpu)"
7 +MONERO_LIBS=""
8 +WOWNERO_LIBS=""
9 +MONEROC_RELEASE_DIR="../monero_c/release/monero"
10 +WOWNEROC_RELEASE_DIR="../monero_c/release/wownero"
11
7 -case $ARCH in
8 - arm64)
9 - ./build_openssl_arm64.sh
10 - ./build_boost_arm64.sh;;
11 - x86_64)
12 - ./build_openssl_x86_64.sh
13 - ./build_boost_x86_64.sh;;
14 -esac
12 +../prepare_moneroc.sh
13
16 -./build_zmq.sh
17 -./build_expat.sh
18 -./build_unbound.sh
19 -./build_sodium.sh
20 -./build_monero.sh
\ No newline at end of file
14 +# NOTE: -j1 is intentional. Otherwise you will run into weird behaviour on macos
15 +if [[ ! "x$USE_DOCKER" == "x" ]];
16 +then
17 + for COIN in monero wownero;
18 + do
19 + pushd ../monero_c
20 + echo "unsupported!"
21 + exit 1
22 + popd
23 + done
24 +else
25 + if [[ "x$1" == "xuniversal" ]]; then
26 + ARCHS=(arm64 x86_64)
27 + else
28 + ARCHS=$(uname -m)
29 + fi
30 + for COIN in monero wownero;
31 + do
32 + for ARCH in "${ARCHS[@]}";
33 + do
34 + if [[ "$ARCH" == "arm64" ]]; then
35 + export HOMEBREW_PREFIX=/opt/homebrew
36 + HOST="aarch64-host-apple-darwin"
37 + else
38 + export HOMEBREW_PREFIX=/usr/local
39 + HOST="${ARCH}-host-apple-darwin"
40 + fi
41 +
42 + MONERO_LIBS=" -arch ${ARCH} ${MONEROC_RELEASE_DIR}/${HOST}_libwallet2_api_c.dylib"
43 + WOWNERO_LIBS=" -arch ${ARCH} ${WOWNEROC_RELEASE_DIR}/${HOST}_libwallet2_api_c.dylib"
44 +
45 + if [[ ! $(uname -m) == $ARCH ]]; then
46 + PRC="arch -${ARCH}"
47 + fi
48 +
49 + pushd ../monero_c
50 + $PRC ./build_single.sh ${COIN} ${HOST} $NPROC
51 + unxz -f ./release/${COIN}/${HOST}_libwallet2_api_c.dylib.xz
52 +
53 + popd
54 + done
55 + done
56 +fi
57 +
58 +lipo -create ${MONERO_LIBS} -output "${MONEROC_RELEASE_DIR}/host-apple-darwin_libwallet2_api_c.dylib"
59 +lipo -create ${WOWNERO_LIBS} -output "${WOWNEROC_RELEASE_DIR}/host-apple-darwin_libwallet2_api_c.dylib"
scripts/prepare_moneroc.sh new
+31
@@ -0,0 +1,31 @@
1 +#!/bin/bash
2 +
3 +set -x -e
4 +
5 +cd "$(dirname "$0")"
6 +
7 +if [[ ! -d "monero_c" ]];
8 +then
9 + git clone https://github.com/mrcyjanek/monero_c --branch rewrite-wip
10 + cd monero_c
11 + git checkout eaa7bdb8be3479418445ddb18bf33d453f64afcf
12 + git reset --hard
13 + git submodule update --init --force --recursive
14 + ./apply_patches.sh monero
15 + ./apply_patches.sh wownero
16 +else
17 + cd monero_c
18 +fi
19 +
20 +if [[ ! -f "monero/.patch-applied" ]];
21 +then
22 + ./apply_patches.sh monero
23 +fi
24 +
25 +if [[ ! -f "wownero/.patch-applied" ]];
26 +then
27 + ./apply_patches.sh wownero
28 +fi
29 +cd ..
30 +
31 +echo "monero_c source prepared".
scripts/windows/build_all.sh new
+37
@@ -0,0 +1,37 @@
1 +set -x -e
2 +
3 +cd "$(dirname "$0")"
4 +
5 +if [[ ! "x$(uname)" == "xLinux" ]];
6 +then
7 + echo "Only Linux hosts can build windows (yes, i know)";
8 + exit 1
9 +fi
10 +
11 +../prepare_moneroc.sh
12 +
13 +# export USE_DOCKER="ON"
14 +
15 +pushd ../monero_c
16 + set +e
17 + command -v sudo && export SUDO=sudo
18 + set -e
19 + NPROC="-j$(nproc)"
20 + if [[ ! "x$USE_DOCKER" == "x" ]];
21 + then
22 + for COIN in monero wownero;
23 + do
24 + $SUDO docker run --platform linux/amd64 -v$HOME/.cache/ccache:/root/.ccache -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 gperf libtinfo5; ./build_single.sh ${COIN} x86_64-w64-mingw32 $NPROC"
25 + # $SUDO docker run --platform linux/amd64 -v$HOME/.cache/ccache:/root/.ccache -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc-mingw-w64-i686 g++-mingw-w64-i686 gperf libtinfo5; ./build_single.sh ${COIN} i686-w64-mingw32 $NPROC"
26 + done
27 + else
28 + for COIN in monero wownero;
29 + do
30 + $SUDO ./build_single.sh ${COIN} x86_64-w64-mingw32 $NPROC
31 + # $SUDO ./build_single.sh ${COIN} i686-w64-mingw32 $NPROC
32 + done
33 + fi
34 +popd
35 +
36 +$SUDO unxz -f ../monero_c/release/monero/*.dll.xz
37 +$SUDO unxz -f ../monero_c/release/wownero/*.dll.xz
scripts/windows/build_exe_installer.iss new
+44
@@ -0,0 +1,44 @@
1 +#define MyAppName "Cake Wallet"
2 +#define MyAppVersion "0.0.1"
3 +#define MyAppPublisher "Cake Labs LLC"
4 +#define MyAppURL "https://cakewallet.com/"
5 +#define MyAppExeName "CakeWallet.exe"
6 +
7 +[Setup]
8 +AppId=com.cakewallet.cakewallet
9 +AppName={#MyAppName}
10 +AppVersion={#MyAppVersion}
11 +;AppVerName={#MyAppName} {#MyAppVersion}
12 +AppPublisher={#MyAppPublisher}
13 +AppPublisherURL={#MyAppURL}
14 +AppSupportURL={#MyAppURL}
15 +AppUpdatesURL={#MyAppURL}
16 +DefaultDirName={autopf}\CakeWallet
17 +DisableProgramGroupPage=yes
18 +LicenseFile=..\..\LICENSE.md
19 +; Uncomment the following line to run in non administrative install mode (install for current user only.)
20 +; PrivilegesRequired=lowest
21 +OutputDir=..\..\
22 +OutputBaseFilename=cakewallet_setup
23 +SetupIconFile=..\..\windows\runner\resources\app_icon.ico
24 +Compression=lzma
25 +SolidCompression=yes
26 +WizardStyle=modern
27 +
28 +[Languages]
29 +Name: "english"; MessagesFile: "compiler:Default.isl"
30 +
31 +[Tasks]
32 +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
33 +
34 +[Files]
35 +Source: "..\..\build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
36 +; NOTE: Don't use "Flags: ignoreversion" on any shared system files
37 +
38 +[Icons]
39 +Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
40 +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
41 +
42 +[Run]
43 +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
44 +
scripts/windows/cakewallet.sh new
+7
@@ -0,0 +1,7 @@
1 +#!/bin/bash
2 +# This (wrapper) script should be run in wsl with installed (windows "side") flutter
3 +# and available cmd.exe in PATH
4 +# Assume that we are in scripts/windows dir
5 +CW_ROOT=`pwd`/../..
6 +cd $CW_ROOT
7 +cmd.exe /c cakewallet.bat $1
\ No newline at end of file
tool/configure.dart
+236 -32
@@ -9,6 +9,7 @@ const nanoOutputPath = 'lib/nano/nano.dart';
9 const polygonOutputPath = 'lib/polygon/polygon.dart';
10 const solanaOutputPath = 'lib/solana/solana.dart';
11 const tronOutputPath = 'lib/tron/tron.dart';
12 +const wowneroOutputPath = 'lib/wownero/wownero.dart';
13 const walletTypesPath = 'lib/wallet_types.g.dart';
14 const secureStoragePath = 'lib/core/secure_storage.dart';
15 const pubspecDefaultPath = 'pubspec_default.yaml';
@@ -26,6 +27,7 @@ Future<void> main(List<String> args) async {
27 final hasPolygon = args.contains('${prefix}polygon');
28 final hasSolana = args.contains('${prefix}solana');
29 final hasTron = args.contains('${prefix}tron');
30 + final hasWownero = args.contains('${prefix}wownero');
31 final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage');
32
33 await generateBitcoin(hasBitcoin);
@@ -37,6 +39,7 @@ Future<void> main(List<String> args) async {
39 await generatePolygon(hasPolygon);
40 await generateSolana(hasSolana);
41 await generateTron(hasTron);
42 + await generateWownero(hasWownero);
43 // await generateBanano(hasEthereum);
44
45 await generatePubspec(
@@ -51,6 +54,7 @@ Future<void> main(List<String> args) async {
54 hasPolygon: hasPolygon,
55 hasSolana: hasSolana,
56 hasTron: hasTron,
57 + hasWownero: hasWownero,
58 );
59 await generateWalletTypes(
60 hasMonero: hasMonero,
@@ -63,6 +67,7 @@ Future<void> main(List<String> args) async {
67 hasPolygon: hasPolygon,
68 hasSolana: hasSolana,
69 hasTron: hasTron,
70 + hasWownero: hasWownero,
71 );
72 await injectSecureStorage(!excludeFlutterSecureStorage);
73 }
@@ -239,7 +244,6 @@ Future<void> generateMonero(bool hasImplementation) async {
244 const moneroCommonHeaders = """
245 import 'package:cw_core/unspent_transaction_output.dart';
246 import 'package:cw_core/unspent_coins_info.dart';
242 -import 'package:cw_monero/monero_unspent.dart';
247 import 'package:mobx/mobx.dart';
248 import 'package:cw_core/wallet_credentials.dart';
249 import 'package:cw_core/wallet_info.dart';
@@ -256,6 +260,7 @@ import 'package:polyseed/polyseed.dart';""";
260 import 'package:cw_core/get_height_by_date.dart';
261 import 'package:cw_core/monero_amount_format.dart';
262 import 'package:cw_core/monero_transaction_priority.dart';
263 +import 'package:cw_monero/monero_unspent.dart';
264 import 'package:cw_monero/monero_wallet_service.dart';
265 import 'package:cw_monero/monero_wallet.dart';
266 import 'package:cw_monero/monero_transaction_info.dart';
@@ -352,6 +357,8 @@ abstract class Monero {
357 List<Unspent> getUnspents(Object wallet);
358 Future<void> updateUnspents(Object wallet);
359
360 + Future<int> getCurrentHeight();
361 +
362 WalletCredentials createMoneroRestoreWalletFromKeysCredentials({
363 required String name,
364 required String spendKey,
@@ -414,6 +421,187 @@ abstract class MoneroAccountList {
421 await outputFile.writeAsString(output);
422 }
423
424 +Future<void> generateWownero(bool hasImplementation) async {
425 + final outputFile = File(wowneroOutputPath);
426 + const wowneroCommonHeaders = """
427 +import 'package:cw_core/unspent_transaction_output.dart';
428 +import 'package:cw_core/unspent_coins_info.dart';
429 +import 'package:mobx/mobx.dart';
430 +import 'package:cw_core/wallet_credentials.dart';
431 +import 'package:cw_core/wallet_info.dart';
432 +import 'package:cw_core/transaction_priority.dart';
433 +import 'package:cw_core/transaction_history.dart';
434 +import 'package:cw_core/transaction_info.dart';
435 +import 'package:cw_core/balance.dart';
436 +import 'package:cw_core/output_info.dart';
437 +import 'package:cake_wallet/view_model/send/output.dart';
438 +import 'package:cw_core/wallet_service.dart';
439 +import 'package:hive/hive.dart';
440 +import 'package:polyseed/polyseed.dart';""";
441 + const wowneroCWHeaders = """
442 +import 'package:cw_core/get_height_by_date.dart';
443 +import 'package:cw_core/wownero_amount_format.dart';
444 +import 'package:cw_core/monero_transaction_priority.dart';
445 +import 'package:cw_wownero/wownero_unspent.dart';
446 +import 'package:cw_wownero/wownero_wallet_service.dart';
447 +import 'package:cw_wownero/wownero_wallet.dart';
448 +import 'package:cw_wownero/wownero_transaction_info.dart';
449 +import 'package:cw_wownero/wownero_transaction_creation_credentials.dart';
450 +import 'package:cw_core/account.dart' as wownero_account;
451 +import 'package:cw_wownero/api/wallet.dart' as wownero_wallet_api;
452 +import 'package:cw_wownero/mnemonics/english.dart';
453 +import 'package:cw_wownero/mnemonics/chinese_simplified.dart';
454 +import 'package:cw_wownero/mnemonics/dutch.dart';
455 +import 'package:cw_wownero/mnemonics/german.dart';
456 +import 'package:cw_wownero/mnemonics/japanese.dart';
457 +import 'package:cw_wownero/mnemonics/russian.dart';
458 +import 'package:cw_wownero/mnemonics/spanish.dart';
459 +import 'package:cw_wownero/mnemonics/portuguese.dart';
460 +import 'package:cw_wownero/mnemonics/french.dart';
461 +import 'package:cw_wownero/mnemonics/italian.dart';
462 +import 'package:cw_wownero/pending_wownero_transaction.dart';
463 +""";
464 + const wowneroCwPart = "part 'cw_wownero.dart';";
465 + const wowneroContent = """
466 +class Account {
467 + Account({required this.id, required this.label, this.balance});
468 + final int id;
469 + final String label;
470 + final String? balance;
471 +}
472 +
473 +class Subaddress {
474 + Subaddress({
475 + required this.id,
476 + required this.label,
477 + required this.address});
478 + final int id;
479 + final String label;
480 + final String address;
481 +}
482 +
483 +class WowneroBalance extends Balance {
484 + WowneroBalance({required this.fullBalance, required this.unlockedBalance})
485 + : formattedFullBalance = wownero!.formatterWowneroAmountToString(amount: fullBalance),
486 + formattedUnlockedBalance =
487 + wownero!.formatterWowneroAmountToString(amount: unlockedBalance),
488 + super(unlockedBalance, fullBalance);
489 +
490 + WowneroBalance.fromString(
491 + {required this.formattedFullBalance,
492 + required this.formattedUnlockedBalance})
493 + : fullBalance = wownero!.formatterWowneroParseAmount(amount: formattedFullBalance),
494 + unlockedBalance = wownero!.formatterWowneroParseAmount(amount: formattedUnlockedBalance),
495 + super(wownero!.formatterWowneroParseAmount(amount: formattedUnlockedBalance),
496 + wownero!.formatterWowneroParseAmount(amount: formattedFullBalance));
497 +
498 + final int fullBalance;
499 + final int unlockedBalance;
500 + final String formattedFullBalance;
501 + final String formattedUnlockedBalance;
502 +
503 + @override
504 + String get formattedAvailableBalance => formattedUnlockedBalance;
505 +
506 + @override
507 + String get formattedAdditionalBalance => formattedFullBalance;
508 +}
509 +
510 +abstract class WowneroWalletDetails {
511 + @observable
512 + late Account account;
513 +
514 + @observable
515 + late WowneroBalance balance;
516 +}
517 +
518 +abstract class Wownero {
519 + WowneroAccountList getAccountList(Object wallet);
520 +
521 + WowneroSubaddressList getSubaddressList(Object wallet);
522 +
523 + TransactionHistoryBase getTransactionHistory(Object wallet);
524 +
525 + WowneroWalletDetails getWowneroWalletDetails(Object wallet);
526 +
527 + String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
528 +
529 + String getSubaddressLabel(Object wallet, int accountIndex, int addressIndex);
530 +
531 + int getHeightByDate({required DateTime date});
532 + TransactionPriority getDefaultTransactionPriority();
533 + TransactionPriority getWowneroTransactionPrioritySlow();
534 + TransactionPriority getWowneroTransactionPriorityAutomatic();
535 + TransactionPriority deserializeWowneroTransactionPriority({required int raw});
536 + List<TransactionPriority> getTransactionPriorities();
537 + List<String> getWowneroWordList(String language);
538 +
539 + List<Unspent> getUnspents(Object wallet);
540 + Future<void> updateUnspents(Object wallet);
541 +
542 + Future<int> getCurrentHeight();
543 +
544 + WalletCredentials createWowneroRestoreWalletFromKeysCredentials({
545 + required String name,
546 + required String spendKey,
547 + required String viewKey,
548 + required String address,
549 + required String password,
550 + required String language,
551 + required int height});
552 + WalletCredentials createWowneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
553 + WalletCredentials createWowneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String password});
554 + Map<String, String> getKeys(Object wallet);
555 + Object createWowneroTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority});
556 + Object createWowneroTransactionCreationCredentialsRaw({required List<OutputInfo> outputs, required TransactionPriority priority});
557 + String formatterWowneroAmountToString({required int amount});
558 + double formatterWowneroAmountToDouble({required int amount});
559 + int formatterWowneroParseAmount({required String amount});
560 + Account getCurrentAccount(Object wallet);
561 + void setCurrentAccount(Object wallet, int id, String label, String? balance);
562 + void onStartup();
563 + int getTransactionInfoAccountId(TransactionInfo tx);
564 + WalletService createWowneroWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
565 + Map<String, String> pendingTransactionInfo(Object transaction);
566 +}
567 +
568 +abstract class WowneroSubaddressList {
569 + ObservableList<Subaddress> get subaddresses;
570 + void update(Object wallet, {required int accountIndex});
571 + void refresh(Object wallet, {required int accountIndex});
572 + List<Subaddress> getAll(Object wallet);
573 + Future<void> addSubaddress(Object wallet, {required int accountIndex, required String label});
574 + Future<void> setLabelSubaddress(Object wallet,
575 + {required int accountIndex, required int addressIndex, required String label});
576 +}
577 +
578 +abstract class WowneroAccountList {
579 + ObservableList<Account> get accounts;
580 + void update(Object wallet);
581 + void refresh(Object wallet);
582 + List<Account> getAll(Object wallet);
583 + Future<void> addAccount(Object wallet, {required String label});
584 + Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label});
585 +}
586 + """;
587 +
588 + const wowneroEmptyDefinition = 'Wownero? wownero;\n';
589 + const wowneroCWDefinition = 'Wownero? wownero = CWWownero();\n';
590 +
591 + final output = '$wowneroCommonHeaders\n' +
592 + (hasImplementation ? '$wowneroCWHeaders\n' : '\n') +
593 + (hasImplementation ? '$wowneroCwPart\n\n' : '\n') +
594 + (hasImplementation ? wowneroCWDefinition : wowneroEmptyDefinition) +
595 + '\n' +
596 + wowneroContent;
597 +
598 + if (outputFile.existsSync()) {
599 + await outputFile.delete();
600 + }
601 +
602 + await outputFile.writeAsString(output);
603 +}
604 +
605 Future<void> generateHaven(bool hasImplementation) async {
606 final outputFile = File(havenOutputPath);
607 const havenCommonHeaders = """
@@ -1154,18 +1342,20 @@ abstract class Tron {
1342 await outputFile.writeAsString(output);
1343 }
1344
1157 -Future<void> generatePubspec(
1158 - {required bool hasMonero,
1159 - required bool hasBitcoin,
1160 - required bool hasHaven,
1161 - required bool hasEthereum,
1162 - required bool hasNano,
1163 - required bool hasBanano,
1164 - required bool hasBitcoinCash,
1165 - required bool hasFlutterSecureStorage,
1166 - required bool hasPolygon,
1167 - required bool hasSolana,
1168 - required bool hasTron}) async {
1345 +Future<void> generatePubspec({
1346 + required bool hasMonero,
1347 + required bool hasBitcoin,
1348 + required bool hasHaven,
1349 + required bool hasEthereum,
1350 + required bool hasNano,
1351 + required bool hasBanano,
1352 + required bool hasBitcoinCash,
1353 + required bool hasFlutterSecureStorage,
1354 + required bool hasPolygon,
1355 + required bool hasSolana,
1356 + required bool hasTron,
1357 + required bool hasWownero,
1358 +}) async {
1359 const cwCore = """
1360 cw_core:
1361 path: ./cw_core
@@ -1191,8 +1381,8 @@ Future<void> generatePubspec(
1381 git:
1382 url: https://github.com/cake-tech/flutter_secure_storage.git
1383 path: flutter_secure_storage
1194 - ref: cake-8.0.0
1195 - version: 8.0.0
1384 + ref: cake-8.1.0
1385 + version: 8.1.0
1386 """;
1387 const cwEthereum = """
1388 cw_ethereum:
@@ -1226,15 +1416,21 @@ Future<void> generatePubspec(
1416 cw_tron:
1417 path: ./cw_tron
1418 """;
1419 + const cwWownero = """
1420 + cw_wownero:
1421 + path: ./cw_wownero
1422 + """;
1423 final inputFile = File(pubspecOutputPath);
1424 final inputText = await inputFile.readAsString();
1425 final inputLines = inputText.split('\n');
1232 - final dependenciesIndex =
1233 - inputLines.indexWhere((line) => line.toLowerCase().contains('dependencies:'));
1426 + final dependenciesIndex = inputLines.indexWhere((line) => Platform.isWindows
1427 + // On Windows it could contains `\r` (Carriage Return). It could be fixed in newer dart versions.
1428 + ? line.toLowerCase() == 'dependencies:\r' || line.toLowerCase() == 'dependencies:'
1429 + : line.toLowerCase() == 'dependencies:');
1430 var output = cwCore;
1431
1432 if (hasMonero) {
1237 - output += '\n$cwMonero\n$cwSharedExternal';
1433 + output += '\n$cwMonero';
1434 }
1435
1436 if (hasBitcoin) {
@@ -1269,10 +1465,8 @@ Future<void> generatePubspec(
1465 output += '\n$cwTron';
1466 }
1467
1272 - if (hasHaven && !hasMonero) {
1468 + if (hasHaven) {
1469 output += '\n$cwSharedExternal\n$cwHaven';
1274 - } else if (hasHaven) {
1275 - output += '\n$cwHaven';
1470 }
1471
1472 if (hasFlutterSecureStorage) {
@@ -1283,6 +1477,10 @@ Future<void> generatePubspec(
1477 output += '\n$cwEVM';
1478 }
1479
1480 + if (hasWownero) {
1481 + output += '\n$cwWownero';
1482 + }
1483 +
1484 final outputLines = output.split('\n');
1485 inputLines.insertAll(dependenciesIndex + 1, outputLines);
1486 final outputContent = inputLines.join('\n');
@@ -1295,17 +1493,19 @@ Future<void> generatePubspec(
1493 await outputFile.writeAsString(outputContent);
1494 }
1495
1298 -Future<void> generateWalletTypes(
1299 - {required bool hasMonero,
1300 - required bool hasBitcoin,
1301 - required bool hasHaven,
1302 - required bool hasEthereum,
1303 - required bool hasNano,
1304 - required bool hasBanano,
1305 - required bool hasBitcoinCash,
1306 - required bool hasPolygon,
1307 - required bool hasSolana,
1308 - required bool hasTron}) async {
1496 +Future<void> generateWalletTypes({
1497 + required bool hasMonero,
1498 + required bool hasBitcoin,
1499 + required bool hasHaven,
1500 + required bool hasEthereum,
1501 + required bool hasNano,
1502 + required bool hasBanano,
1503 + required bool hasBitcoinCash,
1504 + required bool hasPolygon,
1505 + required bool hasSolana,
1506 + required bool hasTron,
1507 + required bool hasWownero,
1508 +}) async {
1509 final walletTypesFile = File(walletTypesPath);
1510
1511 if (walletTypesFile.existsSync()) {
@@ -1356,6 +1556,10 @@ Future<void> generateWalletTypes(
1556 outputContent += '\tWalletType.banano,\n';
1557 }
1558
1559 + if (hasWownero) {
1560 + outputContent += '\tWalletType.wownero,\n';
1561 + }
1562 +
1563 if (hasHaven) {
1564 outputContent += '\tWalletType.haven,\n';
1565 }
tool/import_secrets_config.dart
+1
@@ -16,6 +16,7 @@ const tronOutputPath = 'cw_tron/lib/.secrets.g.dart';
16
17 const nanoConfigPath = 'tool/.nano-secrets-config.json';
18 const nanoOutputPath = 'cw_nano/lib/.secrets.g.dart';
19 +
20 Future<void> main(List<String> args) async => importSecretsConfig();
21
22 Future<void> importSecretsConfig() async {
windows/.gitignore new
+17
@@ -0,0 +1,17 @@
1 +flutter/ephemeral/
2 +
3 +# Visual Studio user-specific files.
4 +*.suo
5 +*.user
6 +*.userosscache
7 +*.sln.docstates
8 +
9 +# Visual Studio build-related files.
10 +x64/
11 +x86/
12 +
13 +# Visual Studio cache files
14 +# files ending in .cache can be ignored
15 +*.[Cc]ache
16 +# but keep track of directories ending in .cache
17 +!*.[Cc]ache/
windows/CMakeLists.txt new
+123
@@ -0,0 +1,123 @@
1 +# Project-level configuration.
2 +cmake_minimum_required(VERSION 3.14)
3 +project(cake_wallet 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 "CakeWallet")
8 +
9 +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
10 +# versions of CMake.
11 +cmake_policy(VERSION 3.14...3.25)
12 +
13 +# Define build configuration option.
14 +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
15 +if(IS_MULTICONFIG)
16 + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
17 + CACHE STRING "" FORCE)
18 +else()
19 + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
20 + set(CMAKE_BUILD_TYPE "Debug" CACHE
21 + STRING "Flutter build mode" FORCE)
22 + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
23 + "Debug" "Profile" "Release")
24 + endif()
25 +endif()
26 +# Define settings for the Profile build mode.
27 +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
28 +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
29 +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
30 +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
31 +
32 +# Use Unicode for all projects.
33 +add_definitions(-DUNICODE -D_UNICODE)
34 +
35 +# Compilation settings that should be applied to most targets.
36 +#
37 +# Be cautious about adding new options here, as plugins use this function by
38 +# default. In most cases, you should add new options to specific targets instead
39 +# of modifying this function.
40 +function(APPLY_STANDARD_SETTINGS TARGET)
41 + target_compile_features(${TARGET} PUBLIC cxx_std_17)
42 + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
43 + target_compile_options(${TARGET} PRIVATE /EHsc)
44 + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
45 + target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
46 +endfunction()
47 +
48 +# Flutter library and tool build rules.
49 +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
50 +add_subdirectory(${FLUTTER_MANAGED_DIR})
51 +
52 +# Application build; see runner/CMakeLists.txt.
53 +add_subdirectory("runner")
54 +
55 +
56 +# Generated plugin build rules, which manage building the plugins and adding
57 +# them to the application.
58 +include(flutter/generated_plugins.cmake)
59 +
60 +
61 +# === Installation ===
62 +# Support files are copied into place next to the executable, so that it can
63 +# run in place. This is done instead of making a separate bundle (as on Linux)
64 +# so that building and running from within Visual Studio will work.
65 +set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
66 +# Make the "install" step default, as it's required to run.
67 +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
68 +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
69 + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
70 +endif()
71 +
72 +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
73 +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
74 +
75 +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
76 + COMPONENT Runtime)
77 +
78 +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
79 + COMPONENT Runtime)
80 +
81 +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
82 + COMPONENT Runtime)
83 +
84 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/monero/x86_64-w64-mingw32_libwallet2_api_c.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "monero_libwallet2_api_c.dll"
85 + COMPONENT Runtime)
86 +
87 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/wownero/x86_64-w64-mingw32_libwallet2_api_c.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "wownero_libwallet2_api_c.dll"
88 + COMPONENT Runtime)
89 +
90 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/monero/x86_64-w64-mingw32_libgcc_s_seh-1.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libgcc_s_seh-1.dll"
91 + COMPONENT Runtime)
92 +
93 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/monero/x86_64-w64-mingw32_libpolyseed.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libpolyseed.dll"
94 + COMPONENT Runtime)
95 +
96 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/monero/x86_64-w64-mingw32_libssp-0.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libssp-0.dll"
97 + COMPONENT Runtime)
98 +
99 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/monero/x86_64-w64-mingw32_libstdc++-6.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libstdc++-6.dll"
100 + COMPONENT Runtime)
101 +
102 +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/monero_c/release/monero/x86_64-w64-mingw32_libwinpthread-1.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libwinpthread-1.dll"
103 + COMPONENT Runtime)
104 +
105 +if(PLUGIN_BUNDLED_LIBRARIES)
106 + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
107 + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
108 + COMPONENT Runtime)
109 +endif()
110 +
111 +# Fully re-copy the assets directory on each build to avoid having stale files
112 +# from a previous install.
113 +set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
114 +install(CODE "
115 + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
116 + " COMPONENT Runtime)
117 +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
118 + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
119 +
120 +# Install the AOT library on non-Debug builds only.
121 +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
122 + CONFIGURATIONS Profile;Release
123 + COMPONENT Runtime)
windows/flutter/CMakeLists.txt new
+109
@@ -0,0 +1,109 @@
1 +# This file controls Flutter-level build steps. It should not be edited.
2 +cmake_minimum_required(VERSION 3.14)
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 +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
12 +
13 +# Set fallback configurations for older versions of the flutter tool.
14 +if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
15 + set(FLUTTER_TARGET_PLATFORM "windows-x64")
16 +endif()
17 +
18 +# === Flutter Library ===
19 +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
20 +
21 +# Published to parent scope for install step.
22 +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
23 +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
24 +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
25 +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
26 +
27 +list(APPEND FLUTTER_LIBRARY_HEADERS
28 + "flutter_export.h"
29 + "flutter_windows.h"
30 + "flutter_messenger.h"
31 + "flutter_plugin_registrar.h"
32 + "flutter_texture_registrar.h"
33 +)
34 +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
35 +add_library(flutter INTERFACE)
36 +target_include_directories(flutter INTERFACE
37 + "${EPHEMERAL_DIR}"
38 +)
39 +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
40 +add_dependencies(flutter flutter_assemble)
41 +
42 +# === Wrapper ===
43 +list(APPEND CPP_WRAPPER_SOURCES_CORE
44 + "core_implementations.cc"
45 + "standard_codec.cc"
46 +)
47 +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
48 +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
49 + "plugin_registrar.cc"
50 +)
51 +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
52 +list(APPEND CPP_WRAPPER_SOURCES_APP
53 + "flutter_engine.cc"
54 + "flutter_view_controller.cc"
55 +)
56 +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
57 +
58 +# Wrapper sources needed for a plugin.
59 +add_library(flutter_wrapper_plugin STATIC
60 + ${CPP_WRAPPER_SOURCES_CORE}
61 + ${CPP_WRAPPER_SOURCES_PLUGIN}
62 +)
63 +apply_standard_settings(flutter_wrapper_plugin)
64 +set_target_properties(flutter_wrapper_plugin PROPERTIES
65 + POSITION_INDEPENDENT_CODE ON)
66 +set_target_properties(flutter_wrapper_plugin PROPERTIES
67 + CXX_VISIBILITY_PRESET hidden)
68 +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
69 +target_include_directories(flutter_wrapper_plugin PUBLIC
70 + "${WRAPPER_ROOT}/include"
71 +)
72 +add_dependencies(flutter_wrapper_plugin flutter_assemble)
73 +
74 +# Wrapper sources needed for the runner.
75 +add_library(flutter_wrapper_app STATIC
76 + ${CPP_WRAPPER_SOURCES_CORE}
77 + ${CPP_WRAPPER_SOURCES_APP}
78 +)
79 +apply_standard_settings(flutter_wrapper_app)
80 +target_link_libraries(flutter_wrapper_app PUBLIC flutter)
81 +target_include_directories(flutter_wrapper_app PUBLIC
82 + "${WRAPPER_ROOT}/include"
83 +)
84 +add_dependencies(flutter_wrapper_app flutter_assemble)
85 +
86 +# === Flutter tool backend ===
87 +# _phony_ is a non-existent file to force this command to run every time,
88 +# since currently there's no way to get a full input/output list from the
89 +# flutter tool.
90 +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
91 +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
92 +add_custom_command(
93 + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
94 + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
95 + ${CPP_WRAPPER_SOURCES_APP}
96 + ${PHONY_OUTPUT}
97 + COMMAND ${CMAKE_COMMAND} -E env
98 + ${FLUTTER_TOOL_ENVIRONMENT}
99 + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
100 + ${FLUTTER_TARGET_PLATFORM} $<CONFIG>
101 + VERBATIM
102 +)
103 +add_custom_target(flutter_assemble DEPENDS
104 + "${FLUTTER_LIBRARY}"
105 + ${FLUTTER_LIBRARY_HEADERS}
106 + ${CPP_WRAPPER_SOURCES_CORE}
107 + ${CPP_WRAPPER_SOURCES_PLUGIN}
108 + ${CPP_WRAPPER_SOURCES_APP}
109 +)
windows/flutter/generated_plugin_registrant.cc new
+26
@@ -0,0 +1,26 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +// clang-format off
6 +
7 +#include "generated_plugin_registrant.h"
8 +
9 +#include <connectivity_plus/connectivity_plus_windows_plugin.h>
10 +#include <flutter_local_authentication/flutter_local_authentication_plugin_c_api.h>
11 +#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
12 +#include <permission_handler_windows/permission_handler_windows_plugin.h>
13 +#include <url_launcher_windows/url_launcher_windows.h>
14 +
15 +void RegisterPlugins(flutter::PluginRegistry* registry) {
16 + ConnectivityPlusWindowsPluginRegisterWithRegistrar(
17 + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
18 + FlutterLocalAuthenticationPluginCApiRegisterWithRegistrar(
19 + registry->GetRegistrarForPlugin("FlutterLocalAuthenticationPluginCApi"));
20 + FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
21 + registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
22 + PermissionHandlerWindowsPluginRegisterWithRegistrar(
23 + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
24 + UrlLauncherWindowsRegisterWithRegistrar(
25 + registry->GetRegistrarForPlugin("UrlLauncherWindows"));
26 +}
windows/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/plugin_registry.h>
11 +
12 +// Registers Flutter plugins.
13 +void RegisterPlugins(flutter::PluginRegistry* registry);
14 +
15 +#endif // GENERATED_PLUGIN_REGISTRANT_
windows/flutter/generated_plugins.cmake new
+29
@@ -0,0 +1,29 @@
1 +#
2 +# Generated file, do not edit.
3 +#
4 +
5 +list(APPEND FLUTTER_PLUGIN_LIST
6 + connectivity_plus
7 + flutter_local_authentication
8 + flutter_secure_storage_windows
9 + permission_handler_windows
10 + url_launcher_windows
11 +)
12 +
13 +list(APPEND FLUTTER_FFI_PLUGIN_LIST
14 + sp_scanner
15 +)
16 +
17 +set(PLUGIN_BUNDLED_LIBRARIES)
18 +
19 +foreach(plugin ${FLUTTER_PLUGIN_LIST})
20 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
21 + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
22 + list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
23 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
24 +endforeach(plugin)
25 +
26 +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
27 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
28 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
29 +endforeach(ffi_plugin)
windows/runner/CMakeLists.txt new
+40
@@ -0,0 +1,40 @@
1 +cmake_minimum_required(VERSION 3.14)
2 +project(runner LANGUAGES CXX)
3 +
4 +# Define the application target. To change its name, change BINARY_NAME in the
5 +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
6 +# work.
7 +#
8 +# Any new source files that you add to the application should be added here.
9 +add_executable(${BINARY_NAME} WIN32
10 + "flutter_window.cpp"
11 + "main.cpp"
12 + "utils.cpp"
13 + "win32_window.cpp"
14 + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
15 + "Runner.rc"
16 + "runner.exe.manifest"
17 +)
18 +
19 +# Apply the standard set of build settings. This can be removed for applications
20 +# that need different build settings.
21 +apply_standard_settings(${BINARY_NAME})
22 +
23 +# Add preprocessor definitions for the build version.
24 +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
25 +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
26 +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
27 +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
28 +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
29 +
30 +# Disable Windows macros that collide with C++ standard library functions.
31 +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
32 +
33 +# Add dependency libraries and include directories. Add any application-specific
34 +# dependencies here.
35 +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
36 +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
37 +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
38 +
39 +# Run the Flutter tool portions of the build. This must not be removed.
40 +add_dependencies(${BINARY_NAME} flutter_assemble)
windows/runner/Runner.rc new
+121
@@ -0,0 +1,121 @@
1 +// Microsoft Visual C++ generated resource script.
2 +//
3 +#pragma code_page(65001)
4 +#include "resource.h"
5 +
6 +#define APSTUDIO_READONLY_SYMBOLS
7 +/////////////////////////////////////////////////////////////////////////////
8 +//
9 +// Generated from the TEXTINCLUDE 2 resource.
10 +//
11 +#include "winres.h"
12 +
13 +/////////////////////////////////////////////////////////////////////////////
14 +#undef APSTUDIO_READONLY_SYMBOLS
15 +
16 +/////////////////////////////////////////////////////////////////////////////
17 +// English (United States) resources
18 +
19 +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
20 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
21 +
22 +#ifdef APSTUDIO_INVOKED
23 +/////////////////////////////////////////////////////////////////////////////
24 +//
25 +// TEXTINCLUDE
26 +//
27 +
28 +1 TEXTINCLUDE
29 +BEGIN
30 + "resource.h\0"
31 +END
32 +
33 +2 TEXTINCLUDE
34 +BEGIN
35 + "#include ""winres.h""\r\n"
36 + "\0"
37 +END
38 +
39 +3 TEXTINCLUDE
40 +BEGIN
41 + "\r\n"
42 + "\0"
43 +END
44 +
45 +#endif // APSTUDIO_INVOKED
46 +
47 +
48 +/////////////////////////////////////////////////////////////////////////////
49 +//
50 +// Icon
51 +//
52 +
53 +// Icon with lowest ID value placed first to ensure application icon
54 +// remains consistent on all systems.
55 +IDI_APP_ICON ICON "resources\\app_icon.ico"
56 +
57 +
58 +/////////////////////////////////////////////////////////////////////////////
59 +//
60 +// Version
61 +//
62 +
63 +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
64 +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
65 +#else
66 +#define VERSION_AS_NUMBER 1,0,0,0
67 +#endif
68 +
69 +#if defined(FLUTTER_VERSION)
70 +#define VERSION_AS_STRING FLUTTER_VERSION
71 +#else
72 +#define VERSION_AS_STRING "1.0.0"
73 +#endif
74 +
75 +VS_VERSION_INFO VERSIONINFO
76 + FILEVERSION VERSION_AS_NUMBER
77 + PRODUCTVERSION VERSION_AS_NUMBER
78 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
79 +#ifdef _DEBUG
80 + FILEFLAGS VS_FF_DEBUG
81 +#else
82 + FILEFLAGS 0x0L
83 +#endif
84 + FILEOS VOS__WINDOWS32
85 + FILETYPE VFT_APP
86 + FILESUBTYPE 0x0L
87 +BEGIN
88 + BLOCK "StringFileInfo"
89 + BEGIN
90 + BLOCK "040904e4"
91 + BEGIN
92 + VALUE "CompanyName", "com.cakewallet.cake_wallet" "\0"
93 + VALUE "FileDescription", "Cake Wallet" "\0"
94 + VALUE "FileVersion", VERSION_AS_STRING "\0"
95 + VALUE "InternalName", "Cake Wallet" "\0"
96 + VALUE "LegalCopyright", "Copyright (C) 2023 Cake Wallet. All rights reserved." "\0"
97 + VALUE "OriginalFilename", "Cake Wallet.exe" "\0"
98 + VALUE "ProductName", "Cake Wallet" "\0"
99 + VALUE "ProductVersion", VERSION_AS_STRING "\0"
100 + END
101 + END
102 + BLOCK "VarFileInfo"
103 + BEGIN
104 + VALUE "Translation", 0x409, 1252
105 + END
106 +END
107 +
108 +#endif // English (United States) resources
109 +/////////////////////////////////////////////////////////////////////////////
110 +
111 +
112 +
113 +#ifndef APSTUDIO_INVOKED
114 +/////////////////////////////////////////////////////////////////////////////
115 +//
116 +// Generated from the TEXTINCLUDE 3 resource.
117 +//
118 +
119 +
120 +/////////////////////////////////////////////////////////////////////////////
121 +#endif // not APSTUDIO_INVOKED
windows/runner/flutter_window.cpp new
+71
@@ -0,0 +1,71 @@
1 +#include "flutter_window.h"
2 +
3 +#include <optional>
4 +
5 +#include "flutter/generated_plugin_registrant.h"
6 +
7 +FlutterWindow::FlutterWindow(const flutter::DartProject& project)
8 + : project_(project) {}
9 +
10 +FlutterWindow::~FlutterWindow() {}
11 +
12 +bool FlutterWindow::OnCreate() {
13 + if (!Win32Window::OnCreate()) {
14 + return false;
15 + }
16 +
17 + RECT frame = GetClientArea();
18 +
19 + // The size here must match the window dimensions to avoid unnecessary surface
20 + // creation / destruction in the startup path.
21 + flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
22 + frame.right - frame.left, frame.bottom - frame.top, project_);
23 + // Ensure that basic setup of the controller was successful.
24 + if (!flutter_controller_->engine() || !flutter_controller_->view()) {
25 + return false;
26 + }
27 + RegisterPlugins(flutter_controller_->engine());
28 + SetChildContent(flutter_controller_->view()->GetNativeWindow());
29 +
30 + flutter_controller_->engine()->SetNextFrameCallback([&]() {
31 + this->Show();
32 + });
33 +
34 + // Flutter can complete the first frame before the "show window" callback is
35 + // registered. The following call ensures a frame is pending to ensure the
36 + // window is shown. It is a no-op if the first frame hasn't completed yet.
37 + flutter_controller_->ForceRedraw();
38 +
39 + return true;
40 +}
41 +
42 +void FlutterWindow::OnDestroy() {
43 + if (flutter_controller_) {
44 + flutter_controller_ = nullptr;
45 + }
46 +
47 + Win32Window::OnDestroy();
48 +}
49 +
50 +LRESULT
51 +FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
52 + WPARAM const wparam,
53 + LPARAM const lparam) noexcept {
54 + // Give Flutter, including plugins, an opportunity to handle window messages.
55 + if (flutter_controller_) {
56 + std::optional<LRESULT> result =
57 + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
58 + lparam);
59 + if (result) {
60 + return *result;
61 + }
62 + }
63 +
64 + switch (message) {
65 + case WM_FONTCHANGE:
66 + flutter_controller_->engine()->ReloadSystemFonts();
67 + break;
68 + }
69 +
70 + return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
71 +}
windows/runner/flutter_window.h new
+33
@@ -0,0 +1,33 @@
1 +#ifndef RUNNER_FLUTTER_WINDOW_H_
2 +#define RUNNER_FLUTTER_WINDOW_H_
3 +
4 +#include <flutter/dart_project.h>
5 +#include <flutter/flutter_view_controller.h>
6 +
7 +#include <memory>
8 +
9 +#include "win32_window.h"
10 +
11 +// A window that does nothing but host a Flutter view.
12 +class FlutterWindow : public Win32Window {
13 + public:
14 + // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 + explicit FlutterWindow(const flutter::DartProject& project);
16 + virtual ~FlutterWindow();
17 +
18 + protected:
19 + // Win32Window:
20 + bool OnCreate() override;
21 + void OnDestroy() override;
22 + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 + LPARAM const lparam) noexcept override;
24 +
25 + private:
26 + // The project to run.
27 + flutter::DartProject project_;
28 +
29 + // The Flutter instance hosted by this window.
30 + std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
31 +};
32 +
33 +#endif // RUNNER_FLUTTER_WINDOW_H_
windows/runner/main.cpp new
+43
@@ -0,0 +1,43 @@
1 +#include <flutter/dart_project.h>
2 +#include <flutter/flutter_view_controller.h>
3 +#include <windows.h>
4 +
5 +#include "flutter_window.h"
6 +#include "utils.h"
7 +
8 +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 + _In_ wchar_t *command_line, _In_ int show_command) {
10 + // Attach to console when present (e.g., 'flutter run') or create a
11 + // new console when running with a debugger.
12 + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 + CreateAndAttachConsole();
14 + }
15 +
16 + // Initialize COM, so that it is available for use in the library and/or
17 + // plugins.
18 + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 +
20 + flutter::DartProject project(L"data");
21 +
22 + std::vector<std::string> command_line_arguments =
23 + GetCommandLineArguments();
24 +
25 + project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 +
27 + FlutterWindow window(project);
28 + Win32Window::Point origin(10, 10);
29 + Win32Window::Size size(1280, 720);
30 + if (!window.Create(L"Cake Wallet", origin, size)) {
31 + return EXIT_FAILURE;
32 + }
33 + window.SetQuitOnClose(true);
34 +
35 + ::MSG msg;
36 + while (::GetMessage(&msg, nullptr, 0, 0)) {
37 + ::TranslateMessage(&msg);
38 + ::DispatchMessage(&msg);
39 + }
40 +
41 + ::CoUninitialize();
42 + return EXIT_SUCCESS;
43 +}
windows/runner/resource.h new
+16
@@ -0,0 +1,16 @@
1 +//{{NO_DEPENDENCIES}}
2 +// Microsoft Visual C++ generated include file.
3 +// Used by Runner.rc
4 +//
5 +#define IDI_APP_ICON 101
6 +
7 +// Next default values for new objects
8 +//
9 +#ifdef APSTUDIO_INVOKED
10 +#ifndef APSTUDIO_READONLY_SYMBOLS
11 +#define _APS_NEXT_RESOURCE_VALUE 102
12 +#define _APS_NEXT_COMMAND_VALUE 40001
13 +#define _APS_NEXT_CONTROL_VALUE 1001
14 +#define _APS_NEXT_SYMED_VALUE 101
15 +#endif
16 +#endif
windows/runner/resources/app_icon.ico
Binary files /dev/null and b/windows/runner/resources/app_icon.ico differ
windows/runner/runner.exe.manifest new
+20
@@ -0,0 +1,20 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3 + <application xmlns="urn:schemas-microsoft-com:asm.v3">
4 + <windowsSettings>
5 + <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
6 + </windowsSettings>
7 + </application>
8 + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
9 + <application>
10 + <!-- Windows 10 and Windows 11 -->
11 + <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
12 + <!-- Windows 8.1 -->
13 + <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
14 + <!-- Windows 8 -->
15 + <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
16 + <!-- Windows 7 -->
17 + <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
18 + </application>
19 + </compatibility>
20 +</assembly>
windows/runner/utils.cpp new
+65
@@ -0,0 +1,65 @@
1 +#include "utils.h"
2 +
3 +#include <flutter_windows.h>
4 +#include <io.h>
5 +#include <stdio.h>
6 +#include <windows.h>
7 +
8 +#include <iostream>
9 +
10 +void CreateAndAttachConsole() {
11 + if (::AllocConsole()) {
12 + FILE *unused;
13 + if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 + _dup2(_fileno(stdout), 1);
15 + }
16 + if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 + _dup2(_fileno(stdout), 2);
18 + }
19 + std::ios::sync_with_stdio();
20 + FlutterDesktopResyncOutputStreams();
21 + }
22 +}
23 +
24 +std::vector<std::string> GetCommandLineArguments() {
25 + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 + int argc;
27 + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 + if (argv == nullptr) {
29 + return std::vector<std::string>();
30 + }
31 +
32 + std::vector<std::string> command_line_arguments;
33 +
34 + // Skip the first argument as it's the binary name.
35 + for (int i = 1; i < argc; i++) {
36 + command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 + }
38 +
39 + ::LocalFree(argv);
40 +
41 + return command_line_arguments;
42 +}
43 +
44 +std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 + if (utf16_string == nullptr) {
46 + return std::string();
47 + }
48 + int target_length = ::WideCharToMultiByte(
49 + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 + -1, nullptr, 0, nullptr, nullptr)
51 + -1; // remove the trailing null character
52 + int input_length = (int)wcslen(utf16_string);
53 + std::string utf8_string;
54 + if (target_length <= 0 || target_length > utf8_string.max_size()) {
55 + return utf8_string;
56 + }
57 + utf8_string.resize(target_length);
58 + int converted_length = ::WideCharToMultiByte(
59 + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
60 + input_length, utf8_string.data(), target_length, nullptr, nullptr);
61 + if (converted_length == 0) {
62 + return std::string();
63 + }
64 + return utf8_string;
65 +}
windows/runner/utils.h new
+19
@@ -0,0 +1,19 @@
1 +#ifndef RUNNER_UTILS_H_
2 +#define RUNNER_UTILS_H_
3 +
4 +#include <string>
5 +#include <vector>
6 +
7 +// Creates a console for the process, and redirects stdout and stderr to
8 +// it for both the runner and the Flutter library.
9 +void CreateAndAttachConsole();
10 +
11 +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 +// encoded in UTF-8. Returns an empty std::string on failure.
13 +std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 +
15 +// Gets the command line arguments passed in as a std::vector<std::string>,
16 +// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
17 +std::vector<std::string> GetCommandLineArguments();
18 +
19 +#endif // RUNNER_UTILS_H_
windows/runner/win32_window.cpp new
+288
@@ -0,0 +1,288 @@
1 +#include "win32_window.h"
2 +
3 +#include <dwmapi.h>
4 +#include <flutter_windows.h>
5 +
6 +#include "resource.h"
7 +
8 +namespace {
9 +
10 +/// Window attribute that enables dark mode window decorations.
11 +///
12 +/// Redefined in case the developer's machine has a Windows SDK older than
13 +/// version 10.0.22000.0.
14 +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
15 +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
16 +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
17 +#endif
18 +
19 +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
20 +
21 +/// Registry key for app theme preference.
22 +///
23 +/// A value of 0 indicates apps should use dark mode. A non-zero or missing
24 +/// value indicates apps should use light mode.
25 +constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
26 + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
27 +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
28 +
29 +// The number of Win32Window objects that currently exist.
30 +static int g_active_window_count = 0;
31 +
32 +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
33 +
34 +// Scale helper to convert logical scaler values to physical using passed in
35 +// scale factor
36 +int Scale(int source, double scale_factor) {
37 + return static_cast<int>(source * scale_factor);
38 +}
39 +
40 +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
41 +// This API is only needed for PerMonitor V1 awareness mode.
42 +void EnableFullDpiSupportIfAvailable(HWND hwnd) {
43 + HMODULE user32_module = LoadLibraryA("User32.dll");
44 + if (!user32_module) {
45 + return;
46 + }
47 + auto enable_non_client_dpi_scaling =
48 + reinterpret_cast<EnableNonClientDpiScaling*>(
49 + GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
50 + if (enable_non_client_dpi_scaling != nullptr) {
51 + enable_non_client_dpi_scaling(hwnd);
52 + }
53 + FreeLibrary(user32_module);
54 +}
55 +
56 +} // namespace
57 +
58 +// Manages the Win32Window's window class registration.
59 +class WindowClassRegistrar {
60 + public:
61 + ~WindowClassRegistrar() = default;
62 +
63 + // Returns the singleton registrar instance.
64 + static WindowClassRegistrar* GetInstance() {
65 + if (!instance_) {
66 + instance_ = new WindowClassRegistrar();
67 + }
68 + return instance_;
69 + }
70 +
71 + // Returns the name of the window class, registering the class if it hasn't
72 + // previously been registered.
73 + const wchar_t* GetWindowClass();
74 +
75 + // Unregisters the window class. Should only be called if there are no
76 + // instances of the window.
77 + void UnregisterWindowClass();
78 +
79 + private:
80 + WindowClassRegistrar() = default;
81 +
82 + static WindowClassRegistrar* instance_;
83 +
84 + bool class_registered_ = false;
85 +};
86 +
87 +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
88 +
89 +const wchar_t* WindowClassRegistrar::GetWindowClass() {
90 + if (!class_registered_) {
91 + WNDCLASS window_class{};
92 + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
93 + window_class.lpszClassName = kWindowClassName;
94 + window_class.style = CS_HREDRAW | CS_VREDRAW;
95 + window_class.cbClsExtra = 0;
96 + window_class.cbWndExtra = 0;
97 + window_class.hInstance = GetModuleHandle(nullptr);
98 + window_class.hIcon =
99 + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
100 + window_class.hbrBackground = 0;
101 + window_class.lpszMenuName = nullptr;
102 + window_class.lpfnWndProc = Win32Window::WndProc;
103 + RegisterClass(&window_class);
104 + class_registered_ = true;
105 + }
106 + return kWindowClassName;
107 +}
108 +
109 +void WindowClassRegistrar::UnregisterWindowClass() {
110 + UnregisterClass(kWindowClassName, nullptr);
111 + class_registered_ = false;
112 +}
113 +
114 +Win32Window::Win32Window() {
115 + ++g_active_window_count;
116 +}
117 +
118 +Win32Window::~Win32Window() {
119 + --g_active_window_count;
120 + Destroy();
121 +}
122 +
123 +bool Win32Window::Create(const std::wstring& title,
124 + const Point& origin,
125 + const Size& size) {
126 + Destroy();
127 +
128 + const wchar_t* window_class =
129 + WindowClassRegistrar::GetInstance()->GetWindowClass();
130 +
131 + const POINT target_point = {static_cast<LONG>(origin.x),
132 + static_cast<LONG>(origin.y)};
133 + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
134 + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
135 + double scale_factor = dpi / 96.0;
136 +
137 + HWND window = CreateWindow(
138 + window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
139 + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
140 + Scale(size.width, scale_factor), Scale(size.height, scale_factor),
141 + nullptr, nullptr, GetModuleHandle(nullptr), this);
142 +
143 + if (!window) {
144 + return false;
145 + }
146 +
147 + UpdateTheme(window);
148 +
149 + return OnCreate();
150 +}
151 +
152 +bool Win32Window::Show() {
153 + return ShowWindow(window_handle_, SW_SHOWNORMAL);
154 +}
155 +
156 +// static
157 +LRESULT CALLBACK Win32Window::WndProc(HWND const window,
158 + UINT const message,
159 + WPARAM const wparam,
160 + LPARAM const lparam) noexcept {
161 + if (message == WM_NCCREATE) {
162 + auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
163 + SetWindowLongPtr(window, GWLP_USERDATA,
164 + reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
165 +
166 + auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
167 + EnableFullDpiSupportIfAvailable(window);
168 + that->window_handle_ = window;
169 + } else if (Win32Window* that = GetThisFromHandle(window)) {
170 + return that->MessageHandler(window, message, wparam, lparam);
171 + }
172 +
173 + return DefWindowProc(window, message, wparam, lparam);
174 +}
175 +
176 +LRESULT
177 +Win32Window::MessageHandler(HWND hwnd,
178 + UINT const message,
179 + WPARAM const wparam,
180 + LPARAM const lparam) noexcept {
181 + switch (message) {
182 + case WM_DESTROY:
183 + window_handle_ = nullptr;
184 + Destroy();
185 + if (quit_on_close_) {
186 + PostQuitMessage(0);
187 + }
188 + return 0;
189 +
190 + case WM_DPICHANGED: {
191 + auto newRectSize = reinterpret_cast<RECT*>(lparam);
192 + LONG newWidth = newRectSize->right - newRectSize->left;
193 + LONG newHeight = newRectSize->bottom - newRectSize->top;
194 +
195 + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
196 + newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
197 +
198 + return 0;
199 + }
200 + case WM_SIZE: {
201 + RECT rect = GetClientArea();
202 + if (child_content_ != nullptr) {
203 + // Size and position the child window.
204 + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
205 + rect.bottom - rect.top, TRUE);
206 + }
207 + return 0;
208 + }
209 +
210 + case WM_ACTIVATE:
211 + if (child_content_ != nullptr) {
212 + SetFocus(child_content_);
213 + }
214 + return 0;
215 +
216 + case WM_DWMCOLORIZATIONCOLORCHANGED:
217 + UpdateTheme(hwnd);
218 + return 0;
219 + }
220 +
221 + return DefWindowProc(window_handle_, message, wparam, lparam);
222 +}
223 +
224 +void Win32Window::Destroy() {
225 + OnDestroy();
226 +
227 + if (window_handle_) {
228 + DestroyWindow(window_handle_);
229 + window_handle_ = nullptr;
230 + }
231 + if (g_active_window_count == 0) {
232 + WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
233 + }
234 +}
235 +
236 +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
237 + return reinterpret_cast<Win32Window*>(
238 + GetWindowLongPtr(window, GWLP_USERDATA));
239 +}
240 +
241 +void Win32Window::SetChildContent(HWND content) {
242 + child_content_ = content;
243 + SetParent(content, window_handle_);
244 + RECT frame = GetClientArea();
245 +
246 + MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
247 + frame.bottom - frame.top, true);
248 +
249 + SetFocus(child_content_);
250 +}
251 +
252 +RECT Win32Window::GetClientArea() {
253 + RECT frame;
254 + GetClientRect(window_handle_, &frame);
255 + return frame;
256 +}
257 +
258 +HWND Win32Window::GetHandle() {
259 + return window_handle_;
260 +}
261 +
262 +void Win32Window::SetQuitOnClose(bool quit_on_close) {
263 + quit_on_close_ = quit_on_close;
264 +}
265 +
266 +bool Win32Window::OnCreate() {
267 + // No-op; provided for subclasses.
268 + return true;
269 +}
270 +
271 +void Win32Window::OnDestroy() {
272 + // No-op; provided for subclasses.
273 +}
274 +
275 +void Win32Window::UpdateTheme(HWND const window) {
276 + DWORD light_mode;
277 + DWORD light_mode_size = sizeof(light_mode);
278 + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
279 + kGetPreferredBrightnessRegValue,
280 + RRF_RT_REG_DWORD, nullptr, &light_mode,
281 + &light_mode_size);
282 +
283 + if (result == ERROR_SUCCESS) {
284 + BOOL enable_dark_mode = light_mode == 0;
285 + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
286 + &enable_dark_mode, sizeof(enable_dark_mode));
287 + }
288 +}
windows/runner/win32_window.h new
+102
@@ -0,0 +1,102 @@
1 +#ifndef RUNNER_WIN32_WINDOW_H_
2 +#define RUNNER_WIN32_WINDOW_H_
3 +
4 +#include <windows.h>
5 +
6 +#include <functional>
7 +#include <memory>
8 +#include <string>
9 +
10 +// A class abstraction for a high DPI-aware Win32 Window. Intended to be
11 +// inherited from by classes that wish to specialize with custom
12 +// rendering and input handling
13 +class Win32Window {
14 + public:
15 + struct Point {
16 + unsigned int x;
17 + unsigned int y;
18 + Point(unsigned int x, unsigned int y) : x(x), y(y) {}
19 + };
20 +
21 + struct Size {
22 + unsigned int width;
23 + unsigned int height;
24 + Size(unsigned int width, unsigned int height)
25 + : width(width), height(height) {}
26 + };
27 +
28 + Win32Window();
29 + virtual ~Win32Window();
30 +
31 + // Creates a win32 window with |title| that is positioned and sized using
32 + // |origin| and |size|. New windows are created on the default monitor. Window
33 + // sizes are specified to the OS in physical pixels, hence to ensure a
34 + // consistent size this function will scale the inputted width and height as
35 + // as appropriate for the default monitor. The window is invisible until
36 + // |Show| is called. Returns true if the window was created successfully.
37 + bool Create(const std::wstring& title, const Point& origin, const Size& size);
38 +
39 + // Show the current window. Returns true if the window was successfully shown.
40 + bool Show();
41 +
42 + // Release OS resources associated with window.
43 + void Destroy();
44 +
45 + // Inserts |content| into the window tree.
46 + void SetChildContent(HWND content);
47 +
48 + // Returns the backing Window handle to enable clients to set icon and other
49 + // window properties. Returns nullptr if the window has been destroyed.
50 + HWND GetHandle();
51 +
52 + // If true, closing this window will quit the application.
53 + void SetQuitOnClose(bool quit_on_close);
54 +
55 + // Return a RECT representing the bounds of the current client area.
56 + RECT GetClientArea();
57 +
58 + protected:
59 + // Processes and route salient window messages for mouse handling,
60 + // size change and DPI. Delegates handling of these to member overloads that
61 + // inheriting classes can handle.
62 + virtual LRESULT MessageHandler(HWND window,
63 + UINT const message,
64 + WPARAM const wparam,
65 + LPARAM const lparam) noexcept;
66 +
67 + // Called when CreateAndShow is called, allowing subclass window-related
68 + // setup. Subclasses should return false if setup fails.
69 + virtual bool OnCreate();
70 +
71 + // Called when Destroy is called.
72 + virtual void OnDestroy();
73 +
74 + private:
75 + friend class WindowClassRegistrar;
76 +
77 + // OS callback called by message pump. Handles the WM_NCCREATE message which
78 + // is passed when the non-client area is being created and enables automatic
79 + // non-client DPI scaling so that the non-client area automatically
80 + // responds to changes in DPI. All other messages are handled by
81 + // MessageHandler.
82 + static LRESULT CALLBACK WndProc(HWND const window,
83 + UINT const message,
84 + WPARAM const wparam,
85 + LPARAM const lparam) noexcept;
86 +
87 + // Retrieves a class instance pointer for |window|
88 + static Win32Window* GetThisFromHandle(HWND const window) noexcept;
89 +
90 + // Update the window frame's theme to match the system theme.
91 + static void UpdateTheme(HWND const window);
92 +
93 + bool quit_on_close_ = false;
94 +
95 + // window handle for top level window.
96 + HWND window_handle_ = nullptr;
97 +
98 + // window handle for hosted content.
99 + HWND child_content_ = nullptr;
100 +};
101 +
102 +#endif // RUNNER_WIN32_WINDOW_H_