diff --git a/.github/ISSUE_TEMPLATE/bug-report-🪲-.md b/.github/ISSUE_TEMPLATE/bug-report.md
similarity index 100%
rename from .github/ISSUE_TEMPLATE/bug-report-🪲-.md
rename to .github/ISSUE_TEMPLATE/bug-report.md
diff --git a/.github/ISSUE_TEMPLATE/feature-or-enhancement-request-✨.md b/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md
similarity index 100%
rename from .github/ISSUE_TEMPLATE/feature-or-enhancement-request-✨.md
rename to .github/ISSUE_TEMPLATE/feature-or-enhancement-request.md
diff --git a/.github/workflows/cache_dependencies.yml b/.github/workflows/cache_dependencies.yml
index bf0d0f7bc..4654ac033 100644
--- a/.github/workflows/cache_dependencies.yml
+++ b/.github/workflows/cache_dependencies.yml
@@ -46,6 +46,7 @@ jobs:
/opt/android/cake_wallet/cw_monero/android/.cxx
/opt/android/cake_wallet/cw_monero/ios/External
/opt/android/cake_wallet/cw_shared_external/ios/External
+ /opt/android/cake_wallet/scripts/monero_c/release
key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml
index b4ddcfefe..788d02126 100644
--- a/.github/workflows/pr_test_build.yml
+++ b/.github/workflows/pr_test_build.yml
@@ -27,18 +27,25 @@ jobs:
if: github.event_name != 'pull_request'
run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENV
- - name: Free Up GitHub Actions Ubuntu Runner Disk Space
- run: |
- sudo rm -rf /usr/share/dotnet
- sudo rm -rf /opt/ghc
- sudo rm -rf "/usr/local/share/boost"
- sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+ - name: Free Disk Space (Ubuntu)
+ uses: insightsengineering/disk-space-reclaimer@v1
+ with:
+ tools-cache: true
+ android: false
+ dotnet: true
+ haskell: true
+ large-packages: true
+ swap-storage: true
+ docker-images: true
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: "11.x"
-
+ - name: Configure placeholder git details
+ run: |
+ git config --global user.email "CI@cakewallet.com"
+ git config --global user.name "Cake Github Actions"
- name: Flutter action
uses: subosito/flutter-action@v1
with:
@@ -72,7 +79,8 @@ jobs:
/opt/android/cake_wallet/cw_monero/android/.cxx
/opt/android/cake_wallet/cw_monero/ios/External
/opt/android/cake_wallet/cw_shared_external/ios/External
- key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
+ /opt/android/cake_wallet/scripts/monero_c/release
+ key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
name: Generate Externals
@@ -113,6 +121,8 @@ jobs:
touch lib/.secrets.g.dart
touch cw_evm/lib/.secrets.g.dart
touch cw_solana/lib/.secrets.g.dart
+ touch cw_core/lib/.secrets.g.dart
+ touch cw_nano/lib/.secrets.g.dart
touch cw_tron/lib/.secrets.g.dart
echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
@@ -151,9 +161,15 @@ jobs:
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
+ echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
+ echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
+ echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart
echo "const quantexExchangeMarkup = '${{ secrets.QUANTEX_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
+ echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
+ echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
- name: Rename app
run: |
diff --git a/.gitignore b/.gitignore
index d0952ca98..77441e66f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,6 +136,7 @@ lib/nano/nano.dart
lib/polygon/polygon.dart
lib/solana/solana.dart
lib/tron/tron.dart
+lib/wownero/wownero.dart
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png
@@ -156,6 +157,7 @@ assets/images/app_logo.png
macos/Runner/Info.plist
macos/Runner/DebugProfile.entitlements
macos/Runner/Release.entitlements
+macos/Runner/Runner.entitlements
lib/core/secure_storage.dart
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
@@ -166,3 +168,9 @@ macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
macos/Runner/Configs/AppInfo.xcconfig
+
+# Monero.dart (Monero_C)
+scripts/monero_c
+# iOS generated framework bin
+ios/MoneroWallet.framework/MoneroWallet
+ios/WowneroWallet.framework/WowneroWallet
diff --git a/.metadata b/.metadata
index cdddb9350..7d00ca21a 100644
--- a/.metadata
+++ b/.metadata
@@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
-# This file should be version controlled.
+# This file should be version controlled and should not be manually edited.
version:
- revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
- channel: stable
+ revision: "367f9ea16bfae1ca451b9cc27c1366870b187ae2"
+ channel: "stable"
project_type: app
@@ -13,11 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
- create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
- base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
- - platform: macos
- create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
- base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
+ create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
+ base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
+ - platform: windows
+ create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
+ base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2
# User provided section
diff --git a/android/app/src/main/AndroidManifestBase.xml b/android/app/src/main/AndroidManifestBase.xml
index 57462099c..b03c8a925 100644
--- a/android/app/src/main/AndroidManifestBase.xml
+++ b/android/app/src/main/AndroidManifestBase.xml
@@ -38,7 +38,8 @@
android:fullBackupContent="false"
android:versionCode="__versionCode__"
android:versionName="__versionName__"
- android:requestLegacyExternalStorage="true">
+ android:requestLegacyExternalStorage="true"
+ android:extractNativeLibs="true">
+
+
+
diff --git a/cw_monero/ios/Assets/.gitkeep b/android/app/src/main/jniLibs/arm64-v8a/.gitkeep
similarity index 100%
rename from cw_monero/ios/Assets/.gitkeep
rename to android/app/src/main/jniLibs/arm64-v8a/.gitkeep
diff --git a/android/app/src/main/jniLibs/arm64-v8a/libmonero_libwallet2_api_c.so b/android/app/src/main/jniLibs/arm64-v8a/libmonero_libwallet2_api_c.so
new file mode 120000
index 000000000..6cdcd70a2
--- /dev/null
+++ b/android/app/src/main/jniLibs/arm64-v8a/libmonero_libwallet2_api_c.so
@@ -0,0 +1 @@
+../../../../../../scripts/monero_c/release/monero/aarch64-linux-android_libwallet2_api_c.so
\ No newline at end of file
diff --git a/android/app/src/main/jniLibs/arm64-v8a/libwownero_libwallet2_api_c.so b/android/app/src/main/jniLibs/arm64-v8a/libwownero_libwallet2_api_c.so
new file mode 120000
index 000000000..8f6150ee3
--- /dev/null
+++ b/android/app/src/main/jniLibs/arm64-v8a/libwownero_libwallet2_api_c.so
@@ -0,0 +1 @@
+../../../../../../scripts/monero_c/release/wownero/aarch64-linux-android_libwallet2_api_c.so
\ No newline at end of file
diff --git a/android/app/src/main/jniLibs/armeabi-v7a/.gitkeep b/android/app/src/main/jniLibs/armeabi-v7a/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/android/app/src/main/jniLibs/armeabi-v7a/libmonero_libwallet2_api_c.so b/android/app/src/main/jniLibs/armeabi-v7a/libmonero_libwallet2_api_c.so
new file mode 120000
index 000000000..c0d56dd3b
--- /dev/null
+++ b/android/app/src/main/jniLibs/armeabi-v7a/libmonero_libwallet2_api_c.so
@@ -0,0 +1 @@
+../../../../../../scripts/monero_c/release/monero/armv7a-linux-androideabi_libwallet2_api_c.so
\ No newline at end of file
diff --git a/android/app/src/main/jniLibs/armeabi-v7a/libwownero_libwallet2_api_c.so b/android/app/src/main/jniLibs/armeabi-v7a/libwownero_libwallet2_api_c.so
new file mode 120000
index 000000000..5a71e87b1
--- /dev/null
+++ b/android/app/src/main/jniLibs/armeabi-v7a/libwownero_libwallet2_api_c.so
@@ -0,0 +1 @@
+../../../../../../scripts/monero_c/release/wownero/armv7a-linux-androideabi_libwallet2_api_c.so
\ No newline at end of file
diff --git a/android/app/src/main/jniLibs/x86/.gitkeep b/android/app/src/main/jniLibs/x86/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/android/app/src/main/jniLibs/x86_64/.gitkeep b/android/app/src/main/jniLibs/x86_64/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/android/app/src/main/jniLibs/x86_64/libmonero_libwallet2_api_c.so b/android/app/src/main/jniLibs/x86_64/libmonero_libwallet2_api_c.so
new file mode 120000
index 000000000..654be50b9
--- /dev/null
+++ b/android/app/src/main/jniLibs/x86_64/libmonero_libwallet2_api_c.so
@@ -0,0 +1 @@
+../../../../../../scripts/monero_c/release/monero/x86_64-linux-android_libwallet2_api_c.so
\ No newline at end of file
diff --git a/android/app/src/main/jniLibs/x86_64/libwownero_libwallet2_api_c.so b/android/app/src/main/jniLibs/x86_64/libwownero_libwallet2_api_c.so
new file mode 120000
index 000000000..bb3da908f
--- /dev/null
+++ b/android/app/src/main/jniLibs/x86_64/libwownero_libwallet2_api_c.so
@@ -0,0 +1 @@
+../../../../../../scripts/monero_c/release/wownero/x86_64-linux-android_libwallet2_api_c.so
\ No newline at end of file
diff --git a/assets/bitcoin_electrum_server_list.yml b/assets/bitcoin_electrum_server_list.yml
index 2b6649271..8b734a7bb 100644
--- a/assets/bitcoin_electrum_server_list.yml
+++ b/assets/bitcoin_electrum_server_list.yml
@@ -1,2 +1,8 @@
-
- uri: electrum.cakewallet.com:50002
\ No newline at end of file
+ uri: electrum.cakewallet.com:50002
+ useSSL: true
+-
+ uri: btc-electrum.cakewallet.com:50002
+ isDefault: true
+-
+ uri: electrs.cakewallet.com:50001
diff --git a/assets/images/wownero_icon.png b/assets/images/wownero_icon.png
new file mode 100644
index 000000000..a3da77b9e
Binary files /dev/null and b/assets/images/wownero_icon.png differ
diff --git a/assets/images/wownero_menu.png b/assets/images/wownero_menu.png
new file mode 100644
index 000000000..a3da77b9e
Binary files /dev/null and b/assets/images/wownero_menu.png differ
diff --git a/assets/nano_node_list.yml b/assets/nano_node_list.yml
index 2e4d1ec3c..be550177e 100644
--- a/assets/nano_node_list.yml
+++ b/assets/nano_node_list.yml
@@ -1,7 +1,10 @@
+-
+ uri: nano.nownodes.io
+ useSSL: true
+ is_default: true
-
uri: rpc.nano.to
useSSL: true
- is_default: true
-
uri: node.nautilus.io
path: /api
diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt
index faad67777..551d775ef 100644
--- a/assets/text/Monerocom_Release_Notes.txt
+++ b/assets/text/Monerocom_Release_Notes.txt
@@ -1 +1,2 @@
-Bug fixes and generic enhancements
\ No newline at end of file
+Monero enhancements
+Bug fixes
\ No newline at end of file
diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt
index 557dd8b26..551d775ef 100644
--- a/assets/text/Release_Notes.txt
+++ b/assets/text/Release_Notes.txt
@@ -1,2 +1,2 @@
-Bitcoin Silent Payments
-Bug fixes and generic enhancements
+Monero enhancements
+Bug fixes
\ No newline at end of file
diff --git a/assets/tron_node_list.yml b/assets/tron_node_list.yml
index d28e38f2e..f9fd91179 100644
--- a/assets/tron_node_list.yml
+++ b/assets/tron_node_list.yml
@@ -1,8 +1,12 @@
-
uri: tron-rpc.publicnode.com:443
- is_default: true
+ is_default: false
useSSL: true
-
uri: api.trongrid.io
is_default: false
+ useSSL: true
+-
+ uri: trx.nownodes.io
+ is_default: true
useSSL: true
\ No newline at end of file
diff --git a/assets/wownero_node_list.yml b/assets/wownero_node_list.yml
new file mode 100644
index 000000000..a4873b3e4
--- /dev/null
+++ b/assets/wownero_node_list.yml
@@ -0,0 +1,12 @@
+-
+ uri: node3.monerodevs.org:34568
+ is_default: true
+ useSSL: false
+-
+ uri: node2.monerodevs.org:34568
+ is_default: false
+ useSSL: false
+-
+ uri: node.monerodevs.org:34568
+ is_default: false
+ useSSL: false
diff --git a/build-guide-win.md b/build-guide-win.md
new file mode 100644
index 000000000..6ace961af
--- /dev/null
+++ b/build-guide-win.md
@@ -0,0 +1,38 @@
+# Building CakeWallet for Windows
+
+## Requirements and Setup
+
+The following are the system requirements to build CakeWallet for your Windows PC.
+
+```
+Windows 10 or later (64-bit), x86-64 based
+Flutter 3 or above
+```
+
+## Building CakeWallet on Windows
+
+These steps will help you configure and execute a build of CakeWallet from its source code.
+
+### 1. Installing Package Dependencies
+
+For build CakeWallet windows application from sources you will be needed to have:
+> [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`.
+> [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):
+`$ sudo apt update `
+`$ sudo apt build-essential cmake gcc-mingw-w64 g++-mingw-w64 autoconf libtool pkg-config`
+
+### 2. Pull CakeWallet source code
+
+You can downlaod CakeWallet source code from our [GitHub repository](github.com/cake-tech/cake_wallet) via git by following next command:
+`$ git clone https://github.com/cake-tech/cake_wallet.git --branch MrCyjaneK-cyjan-monerodart`
+OR you can download it as [Zip archive](https://github.com/cake-tech/cake_wallet/archive/refs/heads/MrCyjaneK-cyjan-monerodart.zip)
+
+### 3. Build Monero, Monero_c and their dependencies
+
+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`.
+
+### 4. Configure and build CakeWallet application
+
+To configure the application open directory where you have downloaded or unarchived CakeWallet sources and run `cakewallet.bat`.
+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.
+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.
diff --git a/cakewallet.bat b/cakewallet.bat
new file mode 100644
index 000000000..1904c5710
--- /dev/null
+++ b/cakewallet.bat
@@ -0,0 +1,51 @@
+@echo off
+set cw_win_app_config=--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron
+set cw_root=%cd%
+set cw_archive_name=Cake Wallet.zip
+set cw_archive_path=%cw_root%\%cw_archive_name%
+set secrets_file_path=lib\.secrets.g.dart
+set release_dir=build\windows\x64\runner\Release
+@REM Path could be different
+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)
+@REM Generate android manifest file
+cd scripts
+bash.exe gen_android_manifest.sh
+cd /d %cw_root%
+echo === Generating pubspec.yaml ===
+copy /Y pubspec_description.yaml pubspec.yaml > nul
+call flutter pub get > nul
+call dart run tool\generate_pubspec.dart
+call flutter pub get > nul
+call dart run tool\configure.dart %cw_win_app_config%
+
+IF NOT EXIST "%secrets_file_path%" (
+ echo === Generating new secrets file ===
+ call dart run tool\generate_new_secrets.dart
+) ELSE (echo === Using previously/already generated secrets file: %secrets_file_path% ===)
+
+echo === Generating mobx models ===
+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 (
+ cd %%i
+ call flutter pub get > nul
+ call dart run build_runner build --delete-conflicting-outputs > nul
+ cd /d %cw_root%
+)
+
+echo === Generating localization files ===
+call dart run tool\generate_localization.dart
+
+echo === Building the application executable file ===
+call flutter build windows --dart-define-from-file=env.json --release
+
+echo === Prepare distribution actions. Copy needed files to the application bundle ===
+copy /Y "%tools_root%\msvcp140.dll" "%release_dir%\" > nul
+copy /Y "%tools_root%\vcruntime140.dll" "%release_dir%\" > nul
+copy /Y "%tools_root%\vcruntime140_1.dll" "%release_dir%\" > nul
+
+echo === Generate the application archive ===
+xcopy /s /e /v /Y "%release_dir%\*.*" "build\Cake Wallet\" > nul
+tar acf "%cw_archive_name%" -C build\ "Cake Wallet"
+
+echo === Open Explorer with the application archive ===
+echo Cake Wallet created archive at: %cw_archive_path%
+%SystemRoot%\explorer.exe /select, %cw_archive_path%
diff --git a/configure_cake_wallet.sh b/configure_cake_wallet.sh
index 837a002e9..0539221a3 100755
--- a/configure_cake_wallet.sh
+++ b/configure_cake_wallet.sh
@@ -1,11 +1,14 @@
+#!/bin/bash
+
IOS="ios"
ANDROID="android"
+MACOS="macos"
-PLATFORMS=($IOS $ANDROID)
+PLATFORMS=($IOS $ANDROID $MACOS)
PLATFORM=$1
if ! [[ " ${PLATFORMS[*]} " =~ " ${PLATFORM} " ]]; then
- echo "specify platform: ./configure_cake_wallet.sh ios|android"
+ echo "specify platform: ./configure_cake_wallet.sh ios|android|macos"
exit 1
fi
@@ -14,6 +17,11 @@ if [ "$PLATFORM" == "$IOS" ]; then
cd scripts/ios
fi
+if [ "$PLATFORM" == "$MACOS" ]; then
+ echo "Configuring for macOS"
+ cd scripts/macos
+fi
+
if [ "$PLATFORM" == "$ANDROID" ]; then
echo "Configuring for Android"
cd scripts/android
@@ -22,5 +30,6 @@ fi
source ./app_env.sh cakewallet
./app_config.sh
cd ../.. && flutter pub get
-flutter packages pub run tool/generate_localization.dart
+#flutter packages pub run tool/generate_localization.dart
./model_generator.sh
+#cd macos && pod install
\ No newline at end of file
diff --git a/cw_bitcoin/lib/bitcoin_mnemonic.dart b/cw_bitcoin/lib/bitcoin_mnemonic.dart
index 4a01d6ddc..905aece28 100644
--- a/cw_bitcoin/lib/bitcoin_mnemonic.dart
+++ b/cw_bitcoin/lib/bitcoin_mnemonic.dart
@@ -2,9 +2,9 @@ import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
-import 'package:unorm_dart/unorm_dart.dart' as unorm;
import 'package:cryptography/cryptography.dart' as cryptography;
import 'package:cw_core/sec_random_native.dart';
+import 'package:cw_core/utils/text_normalizer.dart';
const segwit = '100';
final wordlist = englishWordlist;
@@ -137,121 +137,6 @@ bool validateMnemonic(String mnemonic, {String prefix = segwit}) {
}
}
-final COMBININGCODEPOINTS = combiningcodepoints();
-
-List combiningcodepoints() {
- final source = '300:34e|350:36f|483:487|591:5bd|5bf|5c1|5c2|5c4|5c5|5c7|610:61a|64b:65f|670|' +
- '6d6:6dc|6df:6e4|6e7|6e8|6ea:6ed|711|730:74a|7eb:7f3|816:819|81b:823|825:827|' +
- '829:82d|859:85b|8d4:8e1|8e3:8ff|93c|94d|951:954|9bc|9cd|a3c|a4d|abc|acd|b3c|' +
- 'b4d|bcd|c4d|c55|c56|cbc|ccd|d4d|dca|e38:e3a|e48:e4b|eb8|eb9|ec8:ecb|f18|f19|' +
- 'f35|f37|f39|f71|f72|f74|f7a:f7d|f80|f82:f84|f86|f87|fc6|1037|1039|103a|108d|' +
- '135d:135f|1714|1734|17d2|17dd|18a9|1939:193b|1a17|1a18|1a60|1a75:1a7c|1a7f|' +
- '1ab0:1abd|1b34|1b44|1b6b:1b73|1baa|1bab|1be6|1bf2|1bf3|1c37|1cd0:1cd2|' +
- '1cd4:1ce0|1ce2:1ce8|1ced|1cf4|1cf8|1cf9|1dc0:1df5|1dfb:1dff|20d0:20dc|20e1|' +
- '20e5:20f0|2cef:2cf1|2d7f|2de0:2dff|302a:302f|3099|309a|a66f|a674:a67d|a69e|' +
- 'a69f|a6f0|a6f1|a806|a8c4|a8e0:a8f1|a92b:a92d|a953|a9b3|a9c0|aab0|aab2:aab4|' +
- 'aab7|aab8|aabe|aabf|aac1|aaf6|abed|fb1e|fe20:fe2f|101fd|102e0|10376:1037a|' +
- '10a0d|10a0f|10a38:10a3a|10a3f|10ae5|10ae6|11046|1107f|110b9|110ba|11100:11102|' +
- '11133|11134|11173|111c0|111ca|11235|11236|112e9|112ea|1133c|1134d|11366:1136c|' +
- '11370:11374|11442|11446|114c2|114c3|115bf|115c0|1163f|116b6|116b7|1172b|11c3f|' +
- '16af0:16af4|16b30:16b36|1bc9e|1d165:1d169|1d16d:1d172|1d17b:1d182|1d185:1d18b|' +
- '1d1aa:1d1ad|1d242:1d244|1e000:1e006|1e008:1e018|1e01b:1e021|1e023|1e024|' +
- '1e026:1e02a|1e8d0:1e8d6|1e944:1e94a';
-
- return source.split('|').map((e) {
- if (e.contains(':')) {
- return e.split(':').map((hex) => int.parse(hex, radix: 16));
- }
-
- return int.parse(e, radix: 16);
- }).fold([], (List acc, element) {
- if (element is List) {
- for (var i = element[0] as int; i <= (element[1] as int); i++) {}
- } else if (element is int) {
- acc.add(element);
- }
-
- return acc;
- }).toList();
-}
-
-String removeCombiningCharacters(String source) {
- return source
- .split('')
- .where((char) => !COMBININGCODEPOINTS.contains(char.codeUnits.first))
- .join('');
-}
-
-bool isCJK(String char) {
- final n = char.codeUnitAt(0);
-
- for (var x in CJKINTERVALS) {
- final imin = x[0] as num;
- final imax = x[1] as num;
-
- if (n >= imin && n <= imax) return true;
- }
-
- return false;
-}
-
-String removeCJKSpaces(String source) {
- final splitted = source.split('');
- final filtered = [];
-
- for (var i = 0; i < splitted.length; i++) {
- final char = splitted[i];
- final isSpace = char.trim() == '';
- final prevIsCJK = i != 0 && isCJK(splitted[i - 1]);
- final nextIsCJK = i != splitted.length - 1 && isCJK(splitted[i + 1]);
-
- if (!(isSpace && prevIsCJK && nextIsCJK)) {
- filtered.add(char);
- }
- }
-
- return filtered.join('');
-}
-
-String normalizeText(String source) {
- final res =
- removeCombiningCharacters(unorm.nfkd(source).toLowerCase()).trim().split('/\s+/').join(' ');
-
- return removeCJKSpaces(res);
-}
-
-const CJKINTERVALS = [
- [0x4e00, 0x9fff, 'CJK Unified Ideographs'],
- [0x3400, 0x4dbf, 'CJK Unified Ideographs Extension A'],
- [0x20000, 0x2a6df, 'CJK Unified Ideographs Extension B'],
- [0x2a700, 0x2b73f, 'CJK Unified Ideographs Extension C'],
- [0x2b740, 0x2b81f, 'CJK Unified Ideographs Extension D'],
- [0xf900, 0xfaff, 'CJK Compatibility Ideographs'],
- [0x2f800, 0x2fa1d, 'CJK Compatibility Ideographs Supplement'],
- [0x3190, 0x319f, 'Kanbun'],
- [0x2e80, 0x2eff, 'CJK Radicals Supplement'],
- [0x2f00, 0x2fdf, 'CJK Radicals'],
- [0x31c0, 0x31ef, 'CJK Strokes'],
- [0x2ff0, 0x2fff, 'Ideographic Description Characters'],
- [0xe0100, 0xe01ef, 'Variation Selectors Supplement'],
- [0x3100, 0x312f, 'Bopomofo'],
- [0x31a0, 0x31bf, 'Bopomofo Extended'],
- [0xff00, 0xffef, 'Halfwidth and Fullwidth Forms'],
- [0x3040, 0x309f, 'Hiragana'],
- [0x30a0, 0x30ff, 'Katakana'],
- [0x31f0, 0x31ff, 'Katakana Phonetic Extensions'],
- [0x1b000, 0x1b0ff, 'Kana Supplement'],
- [0xac00, 0xd7af, 'Hangul Syllables'],
- [0x1100, 0x11ff, 'Hangul Jamo'],
- [0xa960, 0xa97f, 'Hangul Jamo Extended A'],
- [0xd7b0, 0xd7ff, 'Hangul Jamo Extended B'],
- [0x3130, 0x318f, 'Hangul Compatibility Jamo'],
- [0xa4d0, 0xa4ff, 'Lisu'],
- [0x16f00, 0x16f9f, 'Miao'],
- [0xa000, 0xa48f, 'Yi Syllables'],
- [0xa490, 0xa4cf, 'Yi Radicals'],
-];
-
final englishWordlist = [
'abandon',
'ability',
@@ -2301,4 +2186,4 @@ final englishWordlist = [
'zero',
'zone',
'zoo'
-];
\ No newline at end of file
+];
diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart
index 3954631e8..d061480ed 100644
--- a/cw_bitcoin/lib/bitcoin_wallet.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet.dart
@@ -6,6 +6,7 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:convert/convert.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
+import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
@@ -150,7 +151,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
);
// set the default if not present:
- walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? "m/0'/0";
+ walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? electrum_path;
walletInfo.derivationInfo!.derivationType = snp.derivationType ?? DerivationType.electrum;
Uint8List? seedBytes = null;
diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart
index afd5e2440..b52015794 100644
--- a/cw_bitcoin/lib/electrum.dart
+++ b/cw_bitcoin/lib/electrum.dart
@@ -64,7 +64,7 @@ class ElectrumClient {
await socket?.close();
} catch (_) {}
- if (useSSL == false) {
+ if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) {
socket = await Socket.connect(host, port, timeout: connectionTimeout);
} else {
socket = await SecureSocket.connect(host, port,
diff --git a/cw_bitcoin/lib/electrum_derivations.dart b/cw_bitcoin/lib/electrum_derivations.dart
index 7e19f1cb4..749e5c7af 100644
--- a/cw_bitcoin/lib/electrum_derivations.dart
+++ b/cw_bitcoin/lib/electrum_derivations.dart
@@ -108,3 +108,6 @@ Map> electrum_derivations = {
),
],
};
+
+
+String electrum_path = electrum_derivations[DerivationType.electrum]!.first.derivationPath!;
\ No newline at end of file
diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart
index 96f871a4b..db42e2356 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -17,6 +17,7 @@ import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_bitcoin/bitcoin_wallet_keys.dart';
import 'package:cw_bitcoin/electrum.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
+import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/electrum_transaction_history.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
@@ -96,13 +97,17 @@ abstract class ElectrumWalletBase
this.walletInfo = walletInfo;
transactionHistory = ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
- reaction((_) => syncStatus, (SyncStatus syncStatus) {
- if (syncStatus is! AttemptingSyncStatus && syncStatus is! SyncedTipSyncStatus)
+ reaction((_) => syncStatus, (SyncStatus syncStatus) async {
+ if (syncStatus is! AttemptingSyncStatus && syncStatus is! SyncedTipSyncStatus) {
silentPaymentsScanningActive = syncStatus is SyncingSyncStatus;
+ }
if (syncStatus is NotConnectedSyncStatus) {
// Needs to re-subscribe to all scripthashes when reconnected
_scripthashesUpdateSubject = {};
+
+ // TODO: double check this and make sure it doesn't cause any un-necessary calls
+ // await this.electrumClient.connectToUri(node!.uri, useSSL: node!.useSSL);
}
// Message is shown on the UI for 3 seconds, revert to synced
@@ -129,7 +134,7 @@ abstract class ElectrumWalletBase
return currency == CryptoCurrency.bch
? bitcoinCashHDWallet(seedBytes)
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
- .derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? "m/0'"));
+ .derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path));
}
return bitcoin.HDWallet.fromBase58(xpub!);
@@ -197,7 +202,7 @@ abstract class ElectrumWalletBase
bool silentPaymentsScanningActive = false;
@action
- Future setSilentPaymentsScanning(bool active) async {
+ Future setSilentPaymentsScanning(bool active, bool usingElectrs) async {
silentPaymentsScanningActive = active;
if (active) {
@@ -210,18 +215,22 @@ abstract class ElectrumWalletBase
}
if (tip > walletInfo.restoreHeight) {
- _setListeners(walletInfo.restoreHeight, chainTipParam: _currentChainTip);
+ _setListeners(
+ walletInfo.restoreHeight,
+ chainTipParam: _currentChainTip,
+ usingElectrs: usingElectrs,
+ );
}
} else {
alwaysScan = false;
- (await _isolate)?.kill(priority: Isolate.immediate);
+ _isolate?.then((value) => value.kill(priority: Isolate.immediate));
if (electrumClient.isConnected) {
syncStatus = SyncedSyncStatus();
} else {
if (electrumClient.uri != null) {
- await electrumClient.connectToUri(electrumClient.uri!);
+ await electrumClient.connectToUri(electrumClient.uri!, useSSL: electrumClient.useSSL);
startSync();
}
}
@@ -277,7 +286,12 @@ abstract class ElectrumWalletBase
}
@action
- Future _setListeners(int height, {int? chainTipParam, bool? doSingleScan}) async {
+ Future _setListeners(
+ int height, {
+ int? chainTipParam,
+ bool? doSingleScan,
+ bool? usingElectrs,
+ }) async {
final chainTip = chainTipParam ?? await getUpdatedChainTip();
if (chainTip == height) {
@@ -303,7 +317,7 @@ abstract class ElectrumWalletBase
chainTip: chainTip,
electrumClient: ElectrumClient(),
transactionHistoryIds: transactionHistory.transactions.keys.toList(),
- node: ScanNode(node!.uri, node!.useSSL),
+ node: usingElectrs == true ? ScanNode(node!.uri, node!.useSSL) : null,
labels: walletAddresses.labels,
labelIndexes: walletAddresses.silentAddresses
.where((addr) => addr.type == SilentPaymentsAddresType.p2sp && addr.index >= 1)
@@ -454,17 +468,7 @@ abstract class ElectrumWalletBase
await electrumClient.close();
- electrumClient.onConnectionStatusChange = (bool? isConnected) async {
- if (syncStatus is SyncingSyncStatus) return;
-
- if (isConnected == true && syncStatus is! SyncedSyncStatus) {
- syncStatus = ConnectedSyncStatus();
- } else if (isConnected == false) {
- syncStatus = LostConnectionSyncStatus();
- } else if (!(isConnected ?? false) && syncStatus is! ConnectingSyncStatus) {
- syncStatus = NotConnectedSyncStatus();
- }
- };
+ electrumClient.onConnectionStatusChange = _onConnectionStatusChange;
await electrumClient.connectToUri(node.uri, useSSL: node.useSSL);
} catch (e) {
@@ -1122,10 +1126,15 @@ abstract class ElectrumWalletBase
@action
@override
- Future rescan(
- {required int height, int? chainTip, ScanData? scanData, bool? doSingleScan}) async {
+ Future rescan({
+ required int height,
+ int? chainTip,
+ ScanData? scanData,
+ bool? doSingleScan,
+ bool? usingElectrs,
+ }) async {
silentPaymentsScanningActive = true;
- _setListeners(height, doSingleScan: doSingleScan);
+ _setListeners(height, doSingleScan: doSingleScan, usingElectrs: usingElectrs);
}
@override
@@ -1465,7 +1474,7 @@ abstract class ElectrumWalletBase
time = status["block_time"] as int?;
final height = status["block_height"] as int? ?? 0;
- final tip = await getCurrentChainTip();
+ final tip = await getUpdatedChainTip();
if (tip > 0) confirmations = height > 0 ? tip - height + 1 : 0;
} else {
final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
@@ -1519,6 +1528,23 @@ abstract class ElectrumWalletBase
await fetchTransactionsForAddressType(historiesWithDetails, SegwitAddresType.p2wpkh);
}
+ transactionHistory.transactions.values.forEach((tx) async {
+ final isPendingSilentPaymentUtxo =
+ (tx.isPending || tx.confirmations == 0) && historiesWithDetails[tx.id] == null;
+
+ if (isPendingSilentPaymentUtxo) {
+ final info =
+ await fetchTransactionInfo(hash: tx.id, height: tx.height, retryOnFailure: true);
+
+ if (info != null) {
+ tx.confirmations = info.confirmations;
+ tx.isPending = tx.confirmations == 0;
+ transactionHistory.addOne(tx);
+ await transactionHistory.save();
+ }
+ }
+ });
+
return historiesWithDetails;
} catch (e) {
print(e.toString());
@@ -1626,6 +1652,7 @@ abstract class ElectrumWalletBase
if (_isTransactionUpdating) {
return;
}
+ await getCurrentChainTip();
transactionHistory.transactions.values.forEach((tx) async {
if (tx.unspents != null && tx.unspents!.isNotEmpty && tx.height > 0) {
@@ -1790,6 +1817,19 @@ abstract class ElectrumWalletBase
static String _hardenedDerivationPath(String derivationPath) =>
derivationPath.substring(0, derivationPath.lastIndexOf("'") + 1);
+
+ @action
+ void _onConnectionStatusChange(bool? isConnected) {
+ if (syncStatus is SyncingSyncStatus) return;
+
+ if (isConnected == true && syncStatus is! SyncedSyncStatus) {
+ syncStatus = ConnectedSyncStatus();
+ } else if (isConnected == false) {
+ syncStatus = LostConnectionSyncStatus();
+ } else if (isConnected != true && syncStatus is! ConnectingSyncStatus) {
+ syncStatus = NotConnectedSyncStatus();
+ }
+ }
}
class ScanNode {
@@ -1803,7 +1843,7 @@ class ScanData {
final SendPort sendPort;
final SilentPaymentOwner silentAddress;
final int height;
- final ScanNode node;
+ final ScanNode? node;
final BasedUtxoNetwork network;
final int chainTip;
final ElectrumClient electrumClient;
@@ -1864,7 +1904,10 @@ Future startRefresh(ScanData scanData) async {
scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus));
final electrumClient = scanData.electrumClient;
- await electrumClient.connectToUri(scanData.node.uri, useSSL: scanData.node.useSSL);
+ await electrumClient.connectToUri(
+ scanData.node?.uri ?? Uri.parse("tcp://electrs.cakewallet.com:50001"),
+ useSSL: scanData.node?.useSSL ?? false,
+ );
if (tweaksSubscription == null) {
final count = scanData.isSingleScan ? 1 : TWEAKS_COUNT;
diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart
index 3e3f39131..15ad1cf63 100644
--- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart
+++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart
@@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
+import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/utils/file.dart';
@@ -71,7 +72,7 @@ class ElectrumWalletSnapshot {
final derivationType = DerivationType
.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
- final derivationPath = data['derivationPath'] as String? ?? "m/0'/0";
+ final derivationPath = data['derivationPath'] as String? ?? electrum_path;
try {
regularAddressIndexByType = {
diff --git a/cw_bitcoin/lib/utils.dart b/cw_bitcoin/lib/utils.dart
index b3707e764..e3ebc00db 100644
--- a/cw_bitcoin/lib/utils.dart
+++ b/cw_bitcoin/lib/utils.dart
@@ -5,58 +5,64 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
import 'package:hex/hex.dart';
-bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, int? index}) {
- final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+bitcoin.PaymentData generatePaymentData({
+ required bitcoin.HDWallet hd,
+ required int index,
+}) {
+ final pubKey = hd.derive(index).pubKey!;
return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey)));
}
-ECPrivate generateECPrivate(
- {required bitcoin.HDWallet hd, required BasedUtxoNetwork network, int? index}) {
- final wif = index != null ? hd.derive(index).wif! : hd.wif!;
+ECPrivate generateECPrivate({
+ required bitcoin.HDWallet hd,
+ required BasedUtxoNetwork network,
+ required int index,
+}) {
+ final wif = hd.derive(index).wif!;
return ECPrivate.fromWif(wif, netVersion: network.wifNetVer);
}
String generateP2WPKHAddress({
required bitcoin.HDWallet hd,
required BasedUtxoNetwork network,
- int? index,
+ required int index,
}) {
- final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+ final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network);
}
String generateP2SHAddress({
required bitcoin.HDWallet hd,
required BasedUtxoNetwork network,
- int? index,
+ required int index,
}) {
- final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+ final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network);
}
String generateP2WSHAddress({
required bitcoin.HDWallet hd,
required BasedUtxoNetwork network,
- int? index,
+ required int index,
}) {
- final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+ final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network);
}
String generateP2PKHAddress({
required bitcoin.HDWallet hd,
required BasedUtxoNetwork network,
- int? index,
+ required int index,
}) {
- final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+ final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network);
}
String generateP2TRAddress({
required bitcoin.HDWallet hd,
required BasedUtxoNetwork network,
- int? index,
+ required int index,
}) {
- final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+ final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network);
}
diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock
index 3eadcb112..ffc224e93 100644
--- a/cw_bitcoin/pubspec.lock
+++ b/cw_bitcoin/pubspec.lock
@@ -793,8 +793,8 @@ packages:
dependency: "direct main"
description:
path: "."
- ref: "sp_v1.0.0"
- resolved-ref: a9a4c6d051f37a15a3a52cc2a0094f24c68b62c5
+ ref: "sp_v2.0.0"
+ resolved-ref: "62c152b9086cd968019128845371072f7e1168de"
url: "https://github.com/cake-tech/sp_scanner"
source: git
version: "0.0.1"
@@ -863,7 +863,7 @@ packages:
source: hosted
version: "1.3.2"
unorm_dart:
- dependency: "direct main"
+ dependency: transitive
description:
name: unorm_dart
sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b"
diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml
index 40f3c6e29..66c5729e8 100644
--- a/cw_bitcoin/pubspec.yaml
+++ b/cw_bitcoin/pubspec.yaml
@@ -28,7 +28,6 @@ dependencies:
url: https://github.com/cake-tech/bitbox-flutter.git
ref: Add-Support-For-OP-Return-data
rxdart: ^0.27.5
- unorm_dart: ^0.2.0
cryptography: ^2.0.5
bitcoin_base:
git:
diff --git a/cw_core/lib/amount_converter.dart b/cw_core/lib/amount_converter.dart
index 249b87bd3..1c5456b07 100644
--- a/cw_core/lib/amount_converter.dart
+++ b/cw_core/lib/amount_converter.dart
@@ -4,10 +4,8 @@ import 'package:cw_core/crypto_currency.dart';
class AmountConverter {
static const _moneroAmountLength = 12;
static const _moneroAmountDivider = 1000000000000;
- static const _litecoinAmountDivider = 100000000;
- static const _ethereumAmountDivider = 1000000000000000000;
- static const _dashAmountDivider = 100000000;
- static const _bitcoinCashAmountDivider = 100000000;
+ static const _wowneroAmountLength = 11;
+ static const _wowneroAmountDivider = 100000000000;
static const _bitcoinAmountDivider = 100000000;
static const _bitcoinAmountLength = 8;
static final _bitcoinAmountFormat = NumberFormat()
@@ -16,69 +14,16 @@ class AmountConverter {
static final _moneroAmountFormat = NumberFormat()
..maximumFractionDigits = _moneroAmountLength
..minimumFractionDigits = 1;
-
- static double amountIntToDouble(CryptoCurrency cryptoCurrency, int amount) {
- switch (cryptoCurrency) {
- case CryptoCurrency.xmr:
- return _moneroAmountToDouble(amount);
- case CryptoCurrency.btc:
- return _bitcoinAmountToDouble(amount);
- case CryptoCurrency.bch:
- return _bitcoinCashAmountToDouble(amount);
- case CryptoCurrency.dash:
- return _dashAmountToDouble(amount);
- case CryptoCurrency.eth:
- return _ethereumAmountToDouble(amount);
- case CryptoCurrency.ltc:
- return _litecoinAmountToDouble(amount);
- case CryptoCurrency.xhv:
- case CryptoCurrency.xag:
- case CryptoCurrency.xau:
- case CryptoCurrency.xaud:
- case CryptoCurrency.xbtc:
- case CryptoCurrency.xcad:
- case CryptoCurrency.xchf:
- case CryptoCurrency.xcny:
- case CryptoCurrency.xeur:
- case CryptoCurrency.xgbp:
- case CryptoCurrency.xjpy:
- case CryptoCurrency.xnok:
- case CryptoCurrency.xnzd:
- case CryptoCurrency.xusd:
- return _moneroAmountToDouble(amount);
- default:
- return 0.0;
- }
- }
-
- static int amountStringToInt(CryptoCurrency cryptoCurrency, String amount) {
- switch (cryptoCurrency) {
- case CryptoCurrency.xmr:
- return _moneroParseAmount(amount);
- case CryptoCurrency.xhv:
- case CryptoCurrency.xag:
- case CryptoCurrency.xau:
- case CryptoCurrency.xaud:
- case CryptoCurrency.xbtc:
- case CryptoCurrency.xcad:
- case CryptoCurrency.xchf:
- case CryptoCurrency.xcny:
- case CryptoCurrency.xeur:
- case CryptoCurrency.xgbp:
- case CryptoCurrency.xjpy:
- case CryptoCurrency.xnok:
- case CryptoCurrency.xnzd:
- case CryptoCurrency.xusd:
- return _moneroParseAmount(amount);
- default:
- return 0;
- }
- }
+ static final _wowneroAmountFormat = NumberFormat()
+ ..maximumFractionDigits = _wowneroAmountLength
+ ..minimumFractionDigits = 1;
static String amountIntToString(CryptoCurrency cryptoCurrency, int amount) {
switch (cryptoCurrency) {
case CryptoCurrency.xmr:
return _moneroAmountToString(amount);
+ case CryptoCurrency.wow:
+ return _wowneroAmountToString(amount);
case CryptoCurrency.btc:
case CryptoCurrency.bch:
case CryptoCurrency.ltc:
@@ -106,34 +51,12 @@ class AmountConverter {
static double cryptoAmountToDouble({required num amount, required num divider}) =>
amount / divider;
- static String _moneroAmountToString(int amount) => _moneroAmountFormat.format(
- cryptoAmountToDouble(amount: amount, divider: _moneroAmountDivider));
+ static String _moneroAmountToString(int amount) => _moneroAmountFormat
+ .format(cryptoAmountToDouble(amount: amount, divider: _moneroAmountDivider));
- static double _moneroAmountToDouble(int amount) =>
- cryptoAmountToDouble(amount: amount, divider: _moneroAmountDivider);
+ static String _bitcoinAmountToString(int amount) => _bitcoinAmountFormat
+ .format(cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));
- static int _moneroParseAmount(String amount) =>
- _moneroAmountFormat.parse(amount).toInt();
-
- static String _bitcoinAmountToString(int amount) =>
- _bitcoinAmountFormat.format(
- cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));
-
- static double _bitcoinAmountToDouble(int amount) =>
- cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider);
-
- static int _doubleToBitcoinAmount(double amount) =>
- (amount * _bitcoinAmountDivider).toInt();
-
- static double _bitcoinCashAmountToDouble(int amount) =>
- cryptoAmountToDouble(amount: amount, divider: _bitcoinCashAmountDivider);
-
- static double _dashAmountToDouble(int amount) =>
- cryptoAmountToDouble(amount: amount, divider: _dashAmountDivider);
-
- static double _ethereumAmountToDouble(num amount) =>
- cryptoAmountToDouble(amount: amount, divider: _ethereumAmountDivider);
-
- static double _litecoinAmountToDouble(int amount) =>
- cryptoAmountToDouble(amount: amount, divider: _litecoinAmountDivider);
+ static String _wowneroAmountToString(int amount) => _wowneroAmountFormat
+ .format(cryptoAmountToDouble(amount: amount, divider: _wowneroAmountDivider));
}
diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart
index 2bd4eaf91..6881393ed 100644
--- a/cw_core/lib/crypto_currency.dart
+++ b/cw_core/lib/crypto_currency.dart
@@ -105,6 +105,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen
CryptoCurrency.usdtSol,
CryptoCurrency.usdcTrc20,
CryptoCurrency.tbtc,
+ CryptoCurrency.wow,
];
static const havenCurrencies = [
@@ -221,6 +222,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen
static const usdtSol = CryptoCurrency(title: 'USDT', tag: 'SOL', fullName: 'USDT Tether', raw: 91, name: 'usdtsol', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
static const usdcTrc20 = CryptoCurrency(title: 'USDC', tag: 'TRX', fullName: 'USDC Coin', raw: 92, name: 'usdctrc20', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
static const tbtc = CryptoCurrency(title: 'tBTC', fullName: 'Testnet Bitcoin', raw: 93, name: 'tbtc', iconPath: 'assets/images/tbtc.png', decimals: 8);
+ static const wow = CryptoCurrency(title: 'WOW', fullName: 'Wownero', raw: 94, name: 'wow', iconPath: 'assets/images/wownero_icon.png', decimals: 11);
static final Map _rawCurrencyMap =
diff --git a/cw_core/lib/currency_for_wallet_type.dart b/cw_core/lib/currency_for_wallet_type.dart
index 8cf438769..630078949 100644
--- a/cw_core/lib/currency_for_wallet_type.dart
+++ b/cw_core/lib/currency_for_wallet_type.dart
@@ -28,7 +28,9 @@ CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
return CryptoCurrency.sol;
case WalletType.tron:
return CryptoCurrency.trx;
- default:
+ case WalletType.wownero:
+ return CryptoCurrency.wow;
+ case WalletType.none:
throw Exception(
'Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
}
diff --git a/cw_core/lib/get_height_by_date.dart b/cw_core/lib/get_height_by_date.dart
index a3dd51b68..6f1b4078b 100644
--- a/cw_core/lib/get_height_by_date.dart
+++ b/cw_core/lib/get_height_by_date.dart
@@ -245,6 +245,7 @@ Future getHavenCurrentHeight() async {
// Data taken from https://timechaincalendar.com/
const bitcoinDates = {
+ "2024-06": 846005,
"2024-05": 841590,
"2024-04": 837182,
"2024-03": 832623,
@@ -296,3 +297,81 @@ DateTime getDateByBitcoinHeight(int height) {
return estimatedDate;
}
+
+// TODO: enhance all of this global const lists
+const wowDates = {
+ "2023-12": 583048,
+ "2023-11": 575048,
+ "2023-10": 566048,
+ "2023-09": 558048,
+ "2023-08": 549048,
+ "2023-07": 540048,
+ "2023-06": 532048,
+ "2023-05": 523048,
+ "2023-04": 514048,
+ "2023-03": 505048,
+ "2023-02": 497048,
+ "2023-01": 488048,
+ "2022-12": 479048,
+ "2022-11": 471048,
+ "2022-10": 462048,
+ "2022-09": 453048,
+ "2022-08": 444048,
+ "2022-07": 435048,
+ "2022-06": 427048,
+ "2022-05": 418048,
+ "2022-04": 410048,
+ "2022-03": 401048,
+ "2022-02": 393048,
+ "2022-01": 384048,
+ "2021-12": 375048,
+ "2021-11": 367048,
+ "2021-10": 358048,
+ "2021-09": 349048,
+ "2021-08": 340048,
+ "2021-07": 331048,
+ "2021-06": 322048,
+ "2021-05": 313048,
+ "2021-04": 305048,
+ "2021-03": 295048,
+ "2021-02": 287048,
+ "2021-01": 279148,
+ "2020-10": 252000,
+ "2020-09": 243000,
+ "2020-08": 234000,
+ "2020-07": 225000,
+ "2020-06": 217500,
+ "2020-05": 208500,
+ "2020-04": 199500,
+ "2020-03": 190500,
+ "2020-02": 183000,
+ "2020-01": 174000,
+ "2019-12": 165000,
+ "2019-11": 156000,
+ "2019-10": 147000,
+ "2019-09": 138000,
+ "2019-08": 129000,
+ "2019-07": 120000,
+ "2019-06": 112500,
+ "2019-05": 103500,
+ "2019-04": 94500,
+ "2019-03": 85500,
+ "2019-02": 79500,
+ "2019-01": 73500,
+ "2018-12": 67500,
+ "2018-11": 61500,
+ "2018-10": 52500,
+ "2018-09": 45000,
+ "2018-08": 36000,
+ "2018-07": 27000,
+ "2018-06": 18000,
+ "2018-05": 9000,
+ "2018-04": 1
+};
+
+int getWowneroHeightByDate({required DateTime date}) {
+ String closestKey =
+ wowDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
+
+ return wowDates[closestKey] ?? 0;
+}
\ No newline at end of file
diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart
index 00b2c51f1..a82479c86 100644
--- a/cw_core/lib/node.dart
+++ b/cw_core/lib/node.dart
@@ -6,6 +6,7 @@ import 'package:hive/hive.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:http/io_client.dart' as ioc;
+
// import 'package:tor/tor.dart';
part 'node.g.dart';
@@ -79,6 +80,7 @@ class Node extends HiveObject with Keyable {
switch (type) {
case WalletType.monero:
case WalletType.haven:
+ case WalletType.wownero:
return Uri.http(uriRaw, '');
case WalletType.bitcoin:
case WalletType.litecoin:
@@ -96,7 +98,7 @@ class Node extends HiveObject with Keyable {
case WalletType.solana:
case WalletType.tron:
return Uri.https(uriRaw, path ?? '');
- default:
+ case WalletType.none:
throw Exception('Unexpected type ${type.toString()} for Node uri');
}
}
@@ -143,10 +145,10 @@ class Node extends HiveObject with Keyable {
switch (type) {
case WalletType.monero:
case WalletType.haven:
+ case WalletType.wownero:
return requestMoneroNode();
case WalletType.nano:
case WalletType.banano:
- return requestNanoNode();
case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.bitcoinCash:
@@ -155,7 +157,7 @@ class Node extends HiveObject with Keyable {
case WalletType.solana:
case WalletType.tron:
return requestElectrumServer();
- default:
+ case WalletType.none:
return false;
}
} catch (_) {
@@ -201,23 +203,6 @@ class Node extends HiveObject with Keyable {
}
}
- Future requestNanoNode() async {
- http.Response response = await http.post(
- uri,
- headers: {'Content-type': 'application/json'},
- body: json.encode(
- {
- "action": "block_count",
- },
- ),
- );
- if (response.statusCode == 200) {
- return true;
- } else {
- return false;
- }
- }
-
Future requestNodeWithProxy() async {
if (!isValidProxyAddress /* && !Tor.instance.enabled*/) {
return false;
diff --git a/cw_core/lib/pathForWallet.dart b/cw_core/lib/pathForWallet.dart
index cfc33ef21..9aa721923 100644
--- a/cw_core/lib/pathForWallet.dart
+++ b/cw_core/lib/pathForWallet.dart
@@ -1,9 +1,10 @@
import 'dart:io';
+import 'package:cw_core/root_dir.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:path_provider/path_provider.dart';
Future pathForWalletDir({required String name, required WalletType type}) async {
- final root = await getApplicationDocumentsDirectory();
+ final root = await getAppDir();
final prefix = walletTypeToString(type).toLowerCase();
final walletsDir = Directory('${root.path}/wallets');
final walletDire = Directory('${walletsDir.path}/$prefix/$name');
@@ -20,8 +21,8 @@ Future pathForWallet({required String name, required WalletType type}) a
.then((path) => path + '/$name');
Future outdatedAndroidPathForWalletDir({required String name}) async {
- final directory = await getApplicationDocumentsDirectory();
+ final directory = await getAppDir();
final pathDir = directory.path + '/$name';
return pathDir;
-}
\ No newline at end of file
+}
diff --git a/cw_core/lib/root_dir.dart b/cw_core/lib/root_dir.dart
new file mode 100644
index 000000000..c2a8170bc
--- /dev/null
+++ b/cw_core/lib/root_dir.dart
@@ -0,0 +1,35 @@
+import 'dart:io';
+import 'package:path_provider/path_provider.dart';
+
+String? _rootDirPath;
+
+void setRootDirFromEnv() => _rootDirPath = Platform.environment['CAKE_WALLET_DIR'];
+
+Future getAppDir({String appName = 'cake_wallet'}) async {
+ Directory dir;
+
+ if (_rootDirPath != null && _rootDirPath!.isNotEmpty) {
+ dir = Directory.fromUri(Uri.file(_rootDirPath!));
+ dir.create(recursive: true);
+ } else {
+ if (Platform.isWindows) {
+ dir = await getApplicationSupportDirectory();
+ } else if (Platform.isLinux) {
+ String appDirPath;
+
+ try {
+ dir = await getApplicationDocumentsDirectory();
+ appDirPath = '${dir.path}/$appName';
+ } catch (e) {
+ appDirPath = '/home/${Platform.environment['USER']}/.$appName';
+ }
+
+ dir = Directory.fromUri(Uri.file(appDirPath));
+ await dir.create(recursive: true);
+ } else {
+ dir = await getApplicationDocumentsDirectory();
+ }
+ }
+
+ return dir;
+}
diff --git a/cw_core/lib/sec_random_native.dart b/cw_core/lib/sec_random_native.dart
index ce251efc0..2011602bf 100644
--- a/cw_core/lib/sec_random_native.dart
+++ b/cw_core/lib/sec_random_native.dart
@@ -1,3 +1,5 @@
+import 'dart:io';
+import 'dart:math';
import 'dart:typed_data';
import 'package:flutter/services.dart';
@@ -6,6 +8,12 @@ const utils = const MethodChannel('com.cake_wallet/native_utils');
Future secRandom(int count) async {
try {
+ if (Platform.isWindows || Platform.isLinux) {
+ // Used method to get securely generated random bytes from cake backups
+ const byteSize = 256;
+ final rng = Random.secure();
+ return Uint8List.fromList(List.generate(count, (_) => rng.nextInt(byteSize)));
+ }
return await utils.invokeMethod('sec_random', {'count': count}) ?? Uint8List.fromList([]);
} on PlatformException catch (_) {
return Uint8List.fromList([]);
diff --git a/cw_core/lib/transaction_info.dart b/cw_core/lib/transaction_info.dart
index 992582ff8..7b02bf1ff 100644
--- a/cw_core/lib/transaction_info.dart
+++ b/cw_core/lib/transaction_info.dart
@@ -16,6 +16,7 @@ abstract class TransactionInfo extends Object with Keyable {
void changeFiatAmount(String amount);
String? to;
String? from;
+ String? evmSignatureName;
List? inputAddresses;
List? outputAddresses;
diff --git a/cw_core/lib/utils/text_normalizer.dart b/cw_core/lib/utils/text_normalizer.dart
new file mode 100644
index 000000000..5aeb5fd21
--- /dev/null
+++ b/cw_core/lib/utils/text_normalizer.dart
@@ -0,0 +1,117 @@
+import 'package:unorm_dart/unorm_dart.dart' as unorm;
+
+const CJKINTERVALS = [
+ [0x4e00, 0x9fff, 'CJK Unified Ideographs'],
+ [0x3400, 0x4dbf, 'CJK Unified Ideographs Extension A'],
+ [0x20000, 0x2a6df, 'CJK Unified Ideographs Extension B'],
+ [0x2a700, 0x2b73f, 'CJK Unified Ideographs Extension C'],
+ [0x2b740, 0x2b81f, 'CJK Unified Ideographs Extension D'],
+ [0xf900, 0xfaff, 'CJK Compatibility Ideographs'],
+ [0x2f800, 0x2fa1d, 'CJK Compatibility Ideographs Supplement'],
+ [0x3190, 0x319f, 'Kanbun'],
+ [0x2e80, 0x2eff, 'CJK Radicals Supplement'],
+ [0x2f00, 0x2fdf, 'CJK Radicals'],
+ [0x31c0, 0x31ef, 'CJK Strokes'],
+ [0x2ff0, 0x2fff, 'Ideographic Description Characters'],
+ [0xe0100, 0xe01ef, 'Variation Selectors Supplement'],
+ [0x3100, 0x312f, 'Bopomofo'],
+ [0x31a0, 0x31bf, 'Bopomofo Extended'],
+ [0xff00, 0xffef, 'Halfwidth and Fullwidth Forms'],
+ [0x3040, 0x309f, 'Hiragana'],
+ [0x30a0, 0x30ff, 'Katakana'],
+ [0x31f0, 0x31ff, 'Katakana Phonetic Extensions'],
+ [0x1b000, 0x1b0ff, 'Kana Supplement'],
+ [0xac00, 0xd7af, 'Hangul Syllables'],
+ [0x1100, 0x11ff, 'Hangul Jamo'],
+ [0xa960, 0xa97f, 'Hangul Jamo Extended A'],
+ [0xd7b0, 0xd7ff, 'Hangul Jamo Extended B'],
+ [0x3130, 0x318f, 'Hangul Compatibility Jamo'],
+ [0xa4d0, 0xa4ff, 'Lisu'],
+ [0x16f00, 0x16f9f, 'Miao'],
+ [0xa000, 0xa48f, 'Yi Syllables'],
+ [0xa490, 0xa4cf, 'Yi Radicals'],
+];
+
+final COMBININGCODEPOINTS = combiningcodepoints();
+
+List combiningcodepoints() {
+ final source = '300:34e|350:36f|483:487|591:5bd|5bf|5c1|5c2|5c4|5c5|5c7|610:61a|64b:65f|670|' +
+ '6d6:6dc|6df:6e4|6e7|6e8|6ea:6ed|711|730:74a|7eb:7f3|816:819|81b:823|825:827|' +
+ '829:82d|859:85b|8d4:8e1|8e3:8ff|93c|94d|951:954|9bc|9cd|a3c|a4d|abc|acd|b3c|' +
+ 'b4d|bcd|c4d|c55|c56|cbc|ccd|d4d|dca|e38:e3a|e48:e4b|eb8|eb9|ec8:ecb|f18|f19|' +
+ 'f35|f37|f39|f71|f72|f74|f7a:f7d|f80|f82:f84|f86|f87|fc6|1037|1039|103a|108d|' +
+ '135d:135f|1714|1734|17d2|17dd|18a9|1939:193b|1a17|1a18|1a60|1a75:1a7c|1a7f|' +
+ '1ab0:1abd|1b34|1b44|1b6b:1b73|1baa|1bab|1be6|1bf2|1bf3|1c37|1cd0:1cd2|' +
+ '1cd4:1ce0|1ce2:1ce8|1ced|1cf4|1cf8|1cf9|1dc0:1df5|1dfb:1dff|20d0:20dc|20e1|' +
+ '20e5:20f0|2cef:2cf1|2d7f|2de0:2dff|302a:302f|3099|309a|a66f|a674:a67d|a69e|' +
+ 'a69f|a6f0|a6f1|a806|a8c4|a8e0:a8f1|a92b:a92d|a953|a9b3|a9c0|aab0|aab2:aab4|' +
+ 'aab7|aab8|aabe|aabf|aac1|aaf6|abed|fb1e|fe20:fe2f|101fd|102e0|10376:1037a|' +
+ '10a0d|10a0f|10a38:10a3a|10a3f|10ae5|10ae6|11046|1107f|110b9|110ba|11100:11102|' +
+ '11133|11134|11173|111c0|111ca|11235|11236|112e9|112ea|1133c|1134d|11366:1136c|' +
+ '11370:11374|11442|11446|114c2|114c3|115bf|115c0|1163f|116b6|116b7|1172b|11c3f|' +
+ '16af0:16af4|16b30:16b36|1bc9e|1d165:1d169|1d16d:1d172|1d17b:1d182|1d185:1d18b|' +
+ '1d1aa:1d1ad|1d242:1d244|1e000:1e006|1e008:1e018|1e01b:1e021|1e023|1e024|' +
+ '1e026:1e02a|1e8d0:1e8d6|1e944:1e94a';
+
+ return source.split('|').map((e) {
+ if (e.contains(':')) {
+ return e.split(':').map((hex) => int.parse(hex, radix: 16));
+ }
+
+ return int.parse(e, radix: 16);
+ }).fold([], (List acc, element) {
+ if (element is List) {
+ for (var i = element[0] as int; i <= (element[1] as int); i++) {}
+ } else if (element is int) {
+ acc.add(element);
+ }
+
+ return acc;
+ }).toList();
+}
+
+String _removeCombiningCharacters(String source) {
+ return source
+ .split('')
+ .where((char) => !COMBININGCODEPOINTS.contains(char.codeUnits.first))
+ .join('');
+}
+
+String _removeCJKSpaces(String source) {
+ final splitted = source.split('');
+ final filtered = [];
+
+ for (var i = 0; i < splitted.length; i++) {
+ final char = splitted[i];
+ final isSpace = char.trim() == '';
+ final prevIsCJK = i != 0 && _isCJK(splitted[i - 1]);
+ final nextIsCJK = i != splitted.length - 1 && _isCJK(splitted[i + 1]);
+
+ if (!(isSpace && prevIsCJK && nextIsCJK)) {
+ filtered.add(char);
+ }
+ }
+
+ return filtered.join('');
+}
+
+bool _isCJK(String char) {
+ final n = char.codeUnitAt(0);
+
+ for (var x in CJKINTERVALS) {
+ final imin = x[0] as num;
+ final imax = x[1] as num;
+
+ if (n >= imin && n <= imax) return true;
+ }
+
+ return false;
+}
+
+/// This method normalize text which transforms Unicode text into an equivalent decomposed form, allowing for easier sorting and searching of text.
+String normalizeText(String source) {
+ final res =
+ _removeCombiningCharacters(unorm.nfkd(source).toLowerCase()).trim().split('/\s+/').join(' ');
+
+ return _removeCJKSpaces(res);
+}
diff --git a/cw_core/lib/wallet_type.dart b/cw_core/lib/wallet_type.dart
index b3e41a989..e3957b4e7 100644
--- a/cw_core/lib/wallet_type.dart
+++ b/cw_core/lib/wallet_type.dart
@@ -54,7 +54,10 @@ enum WalletType {
solana,
@HiveField(11)
- tron
+ tron,
+
+ @HiveField(12)
+ wownero,
}
int serializeToInt(WalletType type) {
@@ -81,7 +84,9 @@ int serializeToInt(WalletType type) {
return 9;
case WalletType.tron:
return 10;
- default:
+ case WalletType.wownero:
+ return 11;
+ case WalletType.none:
return -1;
}
}
@@ -110,6 +115,8 @@ WalletType deserializeFromInt(int raw) {
return WalletType.solana;
case 10:
return WalletType.tron;
+ case 11:
+ return WalletType.wownero;
default:
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
}
@@ -139,7 +146,9 @@ String walletTypeToString(WalletType type) {
return 'Solana';
case WalletType.tron:
return 'Tron';
- default:
+ case WalletType.wownero:
+ return 'Wownero';
+ case WalletType.none:
return '';
}
}
@@ -168,7 +177,9 @@ String walletTypeToDisplayName(WalletType type) {
return 'Solana (SOL)';
case WalletType.tron:
return 'Tron (TRX)';
- default:
+ case WalletType.wownero:
+ return 'Wownero (WOW)';
+ case WalletType.none:
return '';
}
}
@@ -200,7 +211,9 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
return CryptoCurrency.sol;
case WalletType.tron:
return CryptoCurrency.trx;
- default:
+ case WalletType.wownero:
+ return CryptoCurrency.wow;
+ case WalletType.none:
throw Exception(
'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
}
diff --git a/cw_core/lib/wownero_amount_format.dart b/cw_core/lib/wownero_amount_format.dart
new file mode 100644
index 000000000..96d2797e8
--- /dev/null
+++ b/cw_core/lib/wownero_amount_format.dart
@@ -0,0 +1,18 @@
+import 'package:intl/intl.dart';
+import 'package:cw_core/crypto_amount_format.dart';
+
+const wowneroAmountLength = 11;
+const wowneroAmountDivider = 100000000000;
+final wowneroAmountFormat = NumberFormat()
+ ..maximumFractionDigits = wowneroAmountLength
+ ..minimumFractionDigits = 1;
+
+String wowneroAmountToString({required int amount}) => wowneroAmountFormat
+ .format(cryptoAmountToDouble(amount: amount, divider: wowneroAmountDivider))
+ .replaceAll(',', '');
+
+double wowneroAmountToDouble({required int amount}) =>
+ cryptoAmountToDouble(amount: amount, divider: wowneroAmountDivider);
+
+int wowneroParseAmount({required String amount}) =>
+ (double.parse(amount) * wowneroAmountDivider).round();
\ No newline at end of file
diff --git a/cw_core/lib/wownero_balance.dart b/cw_core/lib/wownero_balance.dart
new file mode 100644
index 000000000..2820659f2
--- /dev/null
+++ b/cw_core/lib/wownero_balance.dart
@@ -0,0 +1,38 @@
+import 'package:cw_core/balance.dart';
+import 'package:cw_core/wownero_amount_format.dart';
+
+class WowneroBalance extends Balance {
+ WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
+ : formattedFullBalance = wowneroAmountToString(amount: fullBalance),
+ formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
+ formattedLockedBalance =
+ wowneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
+ super(unlockedBalance, fullBalance);
+
+ WowneroBalance.fromString(
+ {required this.formattedFullBalance,
+ required this.formattedUnlockedBalance,
+ this.formattedLockedBalance = '0.0'})
+ : fullBalance = wowneroParseAmount(amount: formattedFullBalance),
+ unlockedBalance = wowneroParseAmount(amount: formattedUnlockedBalance),
+ frozenBalance = wowneroParseAmount(amount: formattedLockedBalance),
+ super(wowneroParseAmount(amount: formattedUnlockedBalance),
+ wowneroParseAmount(amount: formattedFullBalance));
+
+ final int fullBalance;
+ final int unlockedBalance;
+ final int frozenBalance;
+ final String formattedFullBalance;
+ final String formattedUnlockedBalance;
+ final String formattedLockedBalance;
+
+ @override
+ String get formattedUnAvailableBalance =>
+ formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
+
+ @override
+ String get formattedAvailableBalance => formattedUnlockedBalance;
+
+ @override
+ String get formattedAdditionalBalance => formattedFullBalance;
+}
\ No newline at end of file
diff --git a/cw_core/pubspec.lock b/cw_core/pubspec.lock
index abfdbfc58..518c71b94 100644
--- a/cw_core/pubspec.lock
+++ b/cw_core/pubspec.lock
@@ -656,6 +656,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.2"
+ unorm_dart:
+ dependency: "direct main"
+ description:
+ name: unorm_dart
+ sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.0"
vector_math:
dependency: transitive
description:
diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml
index 51d671dc7..0513b122c 100644
--- a/cw_core/pubspec.yaml
+++ b/cw_core/pubspec.yaml
@@ -20,6 +20,7 @@ dependencies:
intl: ^0.18.0
encrypt: ^5.0.1
socks5_proxy: ^1.0.4
+ unorm_dart: ^0.3.0
# tor:
# git:
# url: https://github.com/cake-tech/tor.git
diff --git a/cw_ethereum/lib/ethereum_client.dart b/cw_ethereum/lib/ethereum_client.dart
index f2b25bcdd..9d50fdd5b 100644
--- a/cw_ethereum/lib/ethereum_client.dart
+++ b/cw_ethereum/lib/ethereum_client.dart
@@ -29,6 +29,11 @@ class EthereumClient extends EVMChainClient {
final jsonResponse = json.decode(response.body) as Map;
+ if (jsonResponse['result'] is String) {
+ log(jsonResponse['result']);
+ return [];
+ }
+
if (response.statusCode >= 200 && response.statusCode < 300 && jsonResponse['status'] != 0) {
return (jsonResponse['result'] as List)
.map((e) => EVMChainTransactionModel.fromJson(e as Map, 'ETH'))
diff --git a/cw_ethereum/lib/ethereum_transaction_info.dart b/cw_ethereum/lib/ethereum_transaction_info.dart
index d5d3fea8d..7a62c0b6a 100644
--- a/cw_ethereum/lib/ethereum_transaction_info.dart
+++ b/cw_ethereum/lib/ethereum_transaction_info.dart
@@ -14,6 +14,7 @@ class EthereumTransactionInfo extends EVMChainTransactionInfo {
required super.confirmations,
required super.to,
required super.from,
+ super.evmSignatureName,
super.exponent,
});
@@ -31,6 +32,7 @@ class EthereumTransactionInfo extends EVMChainTransactionInfo {
tokenSymbol: data['tokenSymbol'] as String,
to: data['to'],
from: data['from'],
+ evmSignatureName: data['evmSignatureName'],
);
}
diff --git a/cw_ethereum/lib/ethereum_wallet.dart b/cw_ethereum/lib/ethereum_wallet.dart
index 4604db662..2c58cd31d 100644
--- a/cw_ethereum/lib/ethereum_wallet.dart
+++ b/cw_ethereum/lib/ethereum_wallet.dart
@@ -94,6 +94,7 @@ class EthereumWallet extends EVMChainWallet {
tokenSymbol: transactionModel.tokenSymbol ?? "ETH",
to: transactionModel.to,
from: transactionModel.from,
+ evmSignatureName: transactionModel.evmSignatureName,
);
return model;
}
diff --git a/cw_evm/lib/evm_chain_formatter.dart b/cw_evm/lib/evm_chain_formatter.dart
index cb9b7346c..797728885 100644
--- a/cw_evm/lib/evm_chain_formatter.dart
+++ b/cw_evm/lib/evm_chain_formatter.dart
@@ -1,15 +1,13 @@
-import 'package:intl/intl.dart';
-
-const evmChainAmountLength = 12;
-const evmChainAmountDivider = 1000000000000;
-final evmChainAmountFormat = NumberFormat()
- ..maximumFractionDigits = evmChainAmountLength
- ..minimumFractionDigits = 1;
+import 'dart:math';
class EVMChainFormatter {
+ static int _divider = 0;
+
static int parseEVMChainAmount(String amount) {
try {
- return (double.parse(amount) * evmChainAmountDivider).round();
+ final decimalLength = _getDividerForInput(amount);
+ _divider = decimalLength;
+ return (double.parse(amount) * pow(10, decimalLength)).round();
} catch (_) {
return 0;
}
@@ -17,9 +15,19 @@ class EVMChainFormatter {
static double parseEVMChainAmountToDouble(int amount) {
try {
- return amount / evmChainAmountDivider;
+ return amount / pow(10, _divider);
} catch (_) {
return 0;
}
}
+
+ static int _getDividerForInput(String amount) {
+ final result = amount.split('.');
+ if (result.length > 1) {
+ final decimalLength = result[1].length;
+ return decimalLength;
+ } else {
+ return 0;
+ }
+ }
}
diff --git a/cw_evm/lib/evm_chain_transaction_info.dart b/cw_evm/lib/evm_chain_transaction_info.dart
index 329061db2..fb6cf6b52 100644
--- a/cw_evm/lib/evm_chain_transaction_info.dart
+++ b/cw_evm/lib/evm_chain_transaction_info.dart
@@ -20,6 +20,7 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
required this.confirmations,
required this.to,
required this.from,
+ this.evmSignatureName,
}) : amount = ethAmount.toInt(),
fee = ethFee.toInt();
@@ -38,6 +39,7 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
String? _fiatAmount;
final String? to;
final String? from;
+ final String? evmSignatureName;
//! Getter to be overridden in child classes
String get feeCurrency;
@@ -73,5 +75,6 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
'tokenSymbol': tokenSymbol,
'to': to,
'from': from,
+ 'evmSignatureName': evmSignatureName,
};
}
diff --git a/cw_evm/lib/evm_chain_transaction_model.dart b/cw_evm/lib/evm_chain_transaction_model.dart
index dfdeab8f5..ca4fb0864 100644
--- a/cw_evm/lib/evm_chain_transaction_model.dart
+++ b/cw_evm/lib/evm_chain_transaction_model.dart
@@ -12,6 +12,8 @@ class EVMChainTransactionModel {
final String? tokenSymbol;
final int? tokenDecimal;
final bool isError;
+ final String input;
+ String? evmSignatureName;
EVMChainTransactionModel({
required this.date,
@@ -27,6 +29,8 @@ class EVMChainTransactionModel {
required this.tokenSymbol,
required this.tokenDecimal,
required this.isError,
+ required this.input,
+ this.evmSignatureName,
});
factory EVMChainTransactionModel.fromJson(Map json, String defaultSymbol) =>
@@ -44,5 +48,7 @@ class EVMChainTransactionModel {
tokenSymbol: json["tokenSymbol"] ?? defaultSymbol,
tokenDecimal: int.tryParse(json["tokenDecimal"] ?? ""),
isError: json["isError"] == "1",
+ input: json["input"] ?? "",
+ evmSignatureName: json["evmSignatureName"],
);
}
diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart
index 56b58d400..2adb54746 100644
--- a/cw_evm/lib/evm_chain_wallet.dart
+++ b/cw_evm/lib/evm_chain_wallet.dart
@@ -39,6 +39,20 @@ import 'evm_erc20_balance.dart';
part 'evm_chain_wallet.g.dart';
+const Map methodSignatureToType = {
+ '0x095ea7b3': 'approval',
+ '0xa9059cbb': 'transfer',
+ '0x23b872dd': 'transferFrom',
+ '0x574da717': 'transferOut',
+ '0x2e1a7d4d': 'withdraw',
+ '0x7ff36ab5': 'swapExactETHForTokens',
+ '0x40c10f19': 'mint',
+ '0x44bc937b': 'depositWithExpiry',
+ '0xd0e30db0': 'deposit',
+ '0xe8e33700': 'addLiquidity',
+ '0xd505accf': 'permit',
+};
+
abstract class EVMChainWallet = EVMChainWalletBase with _$EVMChainWallet;
abstract class EVMChainWalletBase
@@ -235,7 +249,8 @@ abstract class EVMChainWalletBase
String? hexOpReturnMemo;
if (opReturnMemo != null) {
- hexOpReturnMemo = '0x${opReturnMemo.codeUnits.map((char) => char.toRadixString(16).padLeft(2, '0')).join()}';
+ hexOpReturnMemo =
+ '0x${opReturnMemo.codeUnits.map((char) => char.toRadixString(16).padLeft(2, '0')).join()}';
}
final CryptoCurrency transactionCurrency =
@@ -337,11 +352,21 @@ abstract class EVMChainWalletBase
@override
Future