Merge branch 'main' of https://github.com/cake-tech/cake_wallet into Integrate-Seed-Verification-Flow-To-Integration-Tests

This commit is contained in:
Blazebrain 2025-03-24 08:39:49 +01:00
commit aad7320f5c
337 changed files with 9647 additions and 23902 deletions

View file

@ -1,8 +1,6 @@
name: No print statements in dart files
on:
pull_request:
branches: [main]
on: [pull_request]
jobs:
PR_test_build:

View file

@ -9,7 +9,7 @@ jobs:
PR_test_build:
runs-on: linux-amd64
container:
image: ghcr.io/cake-tech/cake_wallet:main-linux
image: ghcr.io/cake-tech/cake_wallet:3.27.4-linux
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
@ -47,6 +47,7 @@ jobs:
echo "message<<EOF" >> $GITHUB_ENV
echo "$FULL_MESSAGE" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Add secrets
run: |
touch lib/.secrets.g.dart
@ -244,6 +245,13 @@ jobs:
./build_mwebd.sh --dont-install
popd
- name: Build Decred
run: |
set -x -e
pushd scripts/android
./build_decred.sh
popd
- name: Build generated code
run: |
./model_generator.sh async
@ -282,7 +290,7 @@ jobs:
set -x
apk_file=$(ls build/app/outputs/flutter-apk/test-apk/${BRANCH_NAME}.apk || exit 1)
echo "APK_FILE=$apk_file" >> $GITHUB_ENV
- name: Upload artifact to slack
if: ${{ !contains(env.message, 'skip slack') }}
continue-on-error: true
@ -295,9 +303,9 @@ jobs:
- name: cleanup
run: rm -rf build/app/outputs/flutter-apk/test-apk/
- name: Upload Artifact to github
uses: actions/upload-artifact@v4
with:
path: ${{ github.workspace }}/build/app/outputs/flutter-apk
name: "android apk"
name: "android apk"

View file

@ -9,7 +9,7 @@ jobs:
PR_test_build:
runs-on: linux-amd64
container:
image: ghcr.io/cake-tech/cake_wallet:main-linux
image: ghcr.io/cake-tech/cake_wallet:3.27.4-linux
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
@ -32,6 +32,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: configure git
run: |
git config --global --add safe.directory '*'

3
.gitignore vendored
View file

@ -9,6 +9,7 @@
.history
.svn/
.fvm/
.fvmrc
# IntelliJ related
*.iml
@ -138,6 +139,7 @@ lib/solana/solana.dart
lib/tron/tron.dart
lib/wownero/wownero.dart
lib/zano/zano.dart
lib/decred/decred.dart
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png
@ -171,6 +173,7 @@ 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
macos/Runner.xcodeproj/project.pbxproj
integration_test/playground.dart

View file

@ -1,6 +1,5 @@
# Usage:
# docker build . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:main-linux
# docker push ghcr.io/cake-tech/cake_wallet:main-linux
# docker build . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:3.27.4-linux
# docker push ghcr.io/cake-tech/cake_wallet:3.27.4-linux
# Heavily inspired by cirrusci images
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile
@ -17,13 +16,13 @@ LABEL org.opencontainers.image.source=https://github.com/cake-tech/cake_wallet
ENV GOLANG_VERSION=1.23.4
# Pin Flutter version to latest known-working version
ENV FLUTTER_VERSION=3.24.4
ENV FLUTTER_VERSION=3.27.4
# Pin Android Studio, platform, and build tools versions to latest known-working version
# Comes from https://developer.android.com/studio/#command-tools
ENV ANDROID_SDK_TOOLS_VERSION=11076708
# Comes from https://developer.android.com/studio/releases/build-tools
ENV ANDROID_PLATFORM_VERSION=34
ENV ANDROID_PLATFORM_VERSION=35
ENV ANDROID_BUILD_TOOLS_VERSION=34.0.0
# If we ever need to migrate the home directory...
@ -106,6 +105,8 @@ RUN yes | sdkmanager \
"platforms;android-$ANDROID_PLATFORM_VERSION" \
"build-tools;$ANDROID_BUILD_TOOLS_VERSION" \
"platforms;android-33" \
"platforms;android-34" \
"platforms;android-35" \
"build-tools;33.0.2" \
"build-tools;33.0.1" \
"build-tools;33.0.0" \
@ -118,10 +119,11 @@ RUN yes | sdkmanager "ndk;$ANDROID_NDK_VERSION" \
# Install dependencies for tests
# Comes from https://github.com/ReactiveCircus/android-emulator-runner
RUN yes | sdkmanager "system-images;android-29;default;x86" \
RUN yes | sdkmanager \
"system-images;android-29;default;x86_64" \
"system-images;android-31;default;x86_64" \
"platforms;android-29"
"platforms;android-29" \
"platforms;android-31"
# Fake the KVM status so the Android emulator doesn't complain (that much)
RUN (addgroup kvm || true) && \

View file

@ -1,3 +1,9 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
@ -6,11 +12,6 @@ if (localPropertiesFile.exists()) {
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
@ -21,9 +22,6 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
@ -37,8 +35,8 @@ if (appPropertiesFile.exists()) {
}
android {
compileSdkVersion 34
buildToolsVersion "34.0.0"
compileSdkVersion 35
buildToolsVersion "35.0.0"
lintOptions {
disable 'InvalidPackage'
@ -81,6 +79,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.release
}
}
ndkVersion "27.0.12077973"

View file

@ -92,6 +92,9 @@
<data android:scheme="zano" />
<data android:scheme="zano-wallet" />
<data android:scheme="zano_wallet" />
<data android:scheme="decred" />
<data android:scheme="decred-wallet" />
<data android:scheme="decred_wallet" />
</intent-filter>
<!-- nano-gpt link scheme -->
<intent-filter android:autoVerify="true">

View file

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

View file

@ -1,15 +1,26 @@
include ':app'
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.7.1" apply false
id "org.jetbrains.kotlin.android" version "2.0.21" apply false
id "com.google.gms.google-services" version "4.3.8" apply false
}
include ":app"

View file

@ -0,0 +1,6 @@
-
uri: default-spv-nodes
is_default: true
-
uri: dcrd.sethforprivacy.com:9108
useSSL: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,31 @@
<svg width="163" height="178" viewBox="0 0 163 178" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M47.5763 28.5814C46.1363 28.5814 44.9689 27.414 44.9689 25.974V22.2461C44.9689 20.8061 46.1363 19.6387 47.5763 19.6387C49.0163 19.6387 50.1837 20.8061 50.1837 22.2461V25.974C50.1837 27.414 49.0163 28.5814 47.5763 28.5814Z" fill="#14C846"/>
<path d="M81.252 28.5814C79.812 28.5814 78.6445 27.414 78.6445 25.974V22.2461C78.6445 20.8061 79.812 19.6387 81.252 19.6387C82.6919 19.6387 83.8594 20.8061 83.8594 22.2461V25.974C83.8594 27.414 82.6919 28.5814 81.252 28.5814Z" fill="#14C846"/>
<path d="M114.928 28.5814C113.488 28.5814 112.32 27.414 112.32 25.974V22.2461C112.32 20.8061 113.488 19.6387 114.928 19.6387C116.368 19.6387 117.535 20.8061 117.535 22.2461V25.974C117.535 27.414 116.368 28.5814 114.928 28.5814Z" fill="#14C846"/>
<path d="M119.675 5.23777C118.208 2.28443 115.374 -2.62586 112.117 1.72088C109.646 5.02118 107.251 11.045 111.084 14.2782C113.143 16.0161 116.707 16.0196 118.771 14.2782C121.501 11.9753 121.084 8.07603 119.675 5.23777Z" fill="#FC914A"/>
<path d="M85.9992 5.23777C84.5328 2.28443 81.698 -2.62586 78.4419 1.72088C75.9701 5.02118 73.5754 11.045 77.408 14.2782C79.4678 16.0161 83.0317 16.0196 85.0957 14.2782C87.8255 11.9753 87.4086 8.07603 85.9992 5.23777Z" fill="#FC914A"/>
<path d="M147.295 113.917H15.2089V60.2027C15.2089 54.4747 19.8525 49.8311 25.5805 49.8311H136.923C142.651 49.8311 147.295 54.4747 147.295 60.2027V113.917Z" fill="#A06047"/>
<path d="M120.67 56.9909H109.185C108.196 56.9909 107.395 56.1892 107.395 55.2005V27.7645C107.395 26.7758 108.196 25.9741 109.185 25.9741H120.67C121.659 25.9741 122.461 26.7758 122.461 27.7645V55.2008C122.461 56.1896 121.659 56.9909 120.67 56.9909Z" fill="#14C846"/>
<path d="M86.9945 56.9909H75.5094C74.5206 56.9909 73.7189 56.1892 73.7189 55.2005V27.7645C73.7189 26.7758 74.5206 25.9741 75.5094 25.9741H86.9945C87.9832 25.9741 88.7849 26.7758 88.7849 27.7645V55.2008C88.7846 56.1896 87.9832 56.9909 86.9945 56.9909Z" fill="#14C846"/>
<path d="M52.3235 5.23777C50.8571 2.28443 48.0223 -2.62586 44.7662 1.72088C42.2943 5.02118 39.8997 11.045 43.7322 14.2782C45.7921 16.0161 49.3559 16.0196 51.4199 14.2782C54.1497 11.9753 53.7326 8.07603 52.3235 5.23777Z" fill="#FC914A"/>
<path d="M51.4183 14.2785C49.8107 15.6354 47.2898 15.9327 45.2776 15.1737C45.8432 14.9589 46.3696 14.6616 46.8243 14.2785C49.5527 11.9764 49.1373 8.07705 47.7265 5.2374C47.1 3.96985 46.2191 2.34421 45.1591 1.24145C48.249 -2.23546 50.9131 2.40158 52.3239 5.2374C53.7316 8.07705 54.1505 11.9764 51.4183 14.2785Z" fill="#EA7636"/>
<path d="M85.0943 14.2785C83.4867 15.6354 80.9659 15.9327 78.9536 15.1737C79.5193 14.9589 80.0456 14.6616 80.5004 14.2785C83.2288 11.9764 82.8133 8.07705 81.4025 5.2374C80.776 3.96985 79.8951 2.34421 78.8351 1.24145C81.925 -2.23546 84.5891 2.40158 85.9999 5.2374C87.4076 8.07705 87.8265 11.9764 85.0943 14.2785Z" fill="#EA7636"/>
<path d="M118.77 14.2785C117.163 15.6354 114.642 15.9327 112.63 15.1737C113.195 14.9589 113.722 14.6616 114.176 14.2785C116.905 11.9764 116.489 8.07705 115.078 5.2374C114.452 3.96985 113.571 2.34421 112.511 1.24145C115.601 -2.23546 118.265 2.40158 119.676 5.2374C121.083 8.07705 121.502 11.9764 118.77 14.2785Z" fill="#EA7636"/>
<path d="M53.3189 56.9909H41.8338C40.845 56.9909 40.0433 56.1892 40.0433 55.2005V27.7645C40.0433 26.7758 40.845 25.9741 41.8338 25.9741H53.3189C54.3076 25.9741 55.1093 26.7758 55.1093 27.7645V55.2008C55.109 56.1896 54.3076 56.9909 53.3189 56.9909Z" fill="#14C846"/>
<path d="M55.11 27.7659V55.2005C55.11 56.1888 54.3079 56.9909 53.3196 56.9909H48.8331V25.9758H53.3196C54.3079 25.9758 55.11 26.7744 55.11 27.7659Z" fill="#0EA939"/>
<path d="M88.7846 27.7659V55.2005C88.7846 56.1888 87.9826 56.9909 86.9942 56.9909H82.5077V25.9758H86.9942C87.9826 25.9758 88.7846 26.7744 88.7846 27.7659Z" fill="#0EA939"/>
<path d="M122.461 27.7659V55.2005C122.461 56.1888 121.659 56.9909 120.67 56.9909H116.184V25.9758H120.67C121.659 25.9758 122.461 26.7744 122.461 27.7659Z" fill="#0EA939"/>
<path d="M147.295 60.2028V113.916H134.809V60.2028C134.809 54.4738 130.169 49.8298 124.44 49.8298H136.922C142.651 49.8298 147.295 54.4738 147.295 60.2028Z" fill="#824730"/>
<path d="M147.296 60.2028V65.6885C144.844 67.6973 142.502 69.7953 137.607 69.7953C136.569 69.7953 135.645 69.7022 134.811 69.5304V60.2028C134.811 54.4738 130.17 49.8298 124.441 49.8298H136.923C142.652 49.8298 147.296 54.4738 147.296 60.2028Z" fill="#F7D443"/>
<path d="M162.503 178H0.000671387V124.286C0.000671387 118.558 4.64431 113.915 10.3723 113.915H152.131C157.859 113.915 162.503 118.558 162.503 124.286L162.503 178Z" fill="#A06047"/>
<path d="M162.503 124.286V177.999H147.296V124.286C147.296 118.557 142.652 113.916 136.923 113.916H152.13C157.859 113.916 162.503 118.557 162.503 124.286Z" fill="#824730"/>
<path d="M162.503 124.286V129.771C159.488 131.78 156.602 133.882 150.583 133.882C149.37 133.882 148.281 133.796 147.296 133.642V124.286C147.296 118.557 142.652 113.917 136.923 113.917H152.13C157.859 113.916 162.503 118.557 162.503 124.286Z" fill="#F7D443"/>
<path d="M147.293 83.5281H15.2078V96.4157H147.293V83.5281Z" fill="white"/>
<path d="M147.294 83.5281H134.808V96.4157H147.294V83.5281Z" fill="#C7ABA1"/>
<path d="M162.502 147.615H0.000671387V160.502H162.502V147.615Z" fill="white"/>
<path d="M162.504 147.615H147.296V160.502H162.504V147.615Z" fill="#C7ABA1"/>
<path d="M147.295 60.2028V65.6868C144.844 67.6973 142.501 69.7971 137.606 69.7971C128.214 69.7971 128.214 62.0638 118.822 62.0638C109.43 62.0638 109.43 69.7971 100.034 69.7971C90.6422 69.7971 90.6422 62.0638 81.2502 62.0638C71.8583 62.0638 71.8583 69.7971 62.4664 69.7971C53.0745 69.7971 53.0745 62.0638 43.6826 62.0638C34.2907 62.0638 34.2907 69.7971 24.8988 69.7971C20.0076 69.7971 17.6644 67.6976 15.2131 65.6868V60.2028C15.2131 54.4738 19.8574 49.8298 25.5861 49.8298H136.922C142.651 49.8298 147.295 54.4738 147.295 60.2028Z" fill="#2194FF"/>
<path d="M147.296 61.03V65.6883C144.844 67.697 142.502 69.7951 137.607 69.7951C136.569 69.7951 135.645 69.7019 134.811 69.5302V60.2026C134.811 54.4736 130.17 49.8296 124.441 49.8296H136.096C143.689 49.8299 147.296 54.6637 147.296 61.03Z" fill="#1585EC"/>
<path d="M162.504 125.114V129.77C159.488 131.781 156.604 133.881 150.584 133.881C139.026 133.881 139.026 126.148 127.469 126.148C115.916 126.148 115.916 133.881 104.359 133.881C92.8053 133.881 92.8053 126.148 81.2481 126.148C69.6949 126.148 69.6949 133.881 58.1377 133.881C46.5845 133.881 46.5845 126.148 35.0273 126.148C23.4741 126.148 23.4741 133.881 11.9169 133.881C5.89659 133.881 3.01591 131.781 0 129.77V124.287C0 118.558 4.64433 113.914 10.373 113.914H151.305C157.49 113.914 162.504 118.928 162.504 125.114Z" fill="#2194FF"/>
<path d="M162.503 125.113V129.771C159.488 131.78 156.602 133.882 150.583 133.882C149.37 133.882 148.281 133.796 147.296 133.642V124.286C147.296 118.557 142.652 113.916 136.923 113.916H151.593C158.474 113.916 162.503 118.048 162.503 125.113Z" fill="#1585EC"/>
</svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -0,0 +1,3 @@
<svg width="126" height="97" viewBox="0 0 126 97" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.56 0.640015C3.41578 0.640015 0 4.0558 0 8.20001V88.84C0 92.9842 3.41578 96.4 7.56 96.4H25.2V91.36H30.24V96.4H95.76V91.36H100.8V96.4H118.44C122.584 96.4 126 92.9842 126 88.84V18.28C126 14.1358 122.584 10.72 118.44 10.72H65.52V8.20001C65.52 4.0558 62.1042 0.640015 57.96 0.640015H7.56ZM7.56 5.68001H57.96C59.3775 5.68001 60.48 6.78251 60.48 8.20001V15.76H118.44C119.857 15.76 120.96 16.8625 120.96 18.28V88.84C120.96 90.2575 119.857 91.36 118.44 91.36H105.84V86.32H90.72V91.36H35.28V86.32H20.16V91.36H7.56C6.1425 91.36 5.04 90.2575 5.04 88.84V8.20001C5.04 6.78251 6.1425 5.68001 7.56 5.68001ZM33.9412 28.36C25.4756 28.5175 24.4519 34.9553 26.3025 42.3775C25.9777 42.5842 25.4559 43.3225 25.5938 44.5038C25.8497 46.6989 26.6962 47.2108 27.2475 47.26C27.4542 49.3075 28.7536 51.7586 29.4525 52.1425C29.4525 53.5994 29.5116 54.7117 29.3738 56.3163C27.7003 60.992 15.6417 59.6631 15.12 68.68H52.92C52.3983 59.6631 40.4184 60.992 38.745 56.3163C38.6072 54.7117 38.6662 53.5994 38.6662 52.1425C39.3652 51.7586 40.5759 49.3075 40.7925 47.26C41.3438 47.2108 42.1903 46.6989 42.4463 44.5038C42.5841 43.3225 42.0623 42.663 41.7375 42.4563C42.6234 39.6705 44.4445 30.9883 38.2725 30.0925C37.6327 28.931 36.0577 28.36 33.9412 28.36ZM65.52 38.44V43.48H110.88V38.44H65.52ZM65.52 51.04V56.08H110.88V51.04H65.52ZM65.52 63.64V68.68H110.88V63.64H65.52Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before After
Before After

BIN
assets/images/decred.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -92,6 +92,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
});
}
@override
bool get hasRescan => true;
static Future<BitcoinWallet> create({
required String mnemonic,
required String password,

View file

@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:convert/convert.dart' as convert;
import 'dart:math';
@ -156,6 +155,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
@observable
SyncStatus mwebSyncStatus = NotConnectedSyncStatus();
@override
bool get hasRescan => true;
List<int> get scanSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw;
List<int> get spendSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000001)).privateKey.privKey.raw;

View file

@ -17,14 +17,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.7.0"
archive:
dependency: transitive
description:
name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev"
source: hosted
version: "3.6.1"
args:
dependency: transitive
description:
@ -37,10 +29,10 @@ packages:
dependency: transitive
description:
name: asn1lib
sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
sha256: "1c296cd268f486cabcc3930e9b93a8133169305f18d722916e675959a88f6d2c"
url: "https://pub.dev"
source: hosted
version: "1.5.5"
version: "1.5.9"
async:
dependency: transitive
description:
@ -105,10 +97,10 @@ packages:
dependency: transitive
description:
name: bluez
sha256: "203a1924e818a9dd74af2b2c7a8f375ab8e5edf0e486bba8f90a0d8a17ed9fce"
sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545"
url: "https://pub.dev"
source: hosted
version: "0.8.2"
version: "0.8.3"
boolean_selector:
dependency: transitive
description:
@ -137,18 +129,18 @@ packages:
dependency: transitive
description:
name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.0.4"
build_resolvers:
dependency: "direct dev"
description:
@ -185,10 +177,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.4"
cake_backup:
dependency: transitive
description:
@ -218,10 +210,10 @@ packages:
dependency: transitive
description:
name: cli_util
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.1"
version: "0.4.2"
clock:
dependency: transitive
description:
@ -234,18 +226,18 @@ packages:
dependency: transitive
description:
name: code_builder
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.dev"
source: hosted
version: "4.10.0"
version: "4.10.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -312,10 +304,10 @@ packages:
dependency: transitive
description:
name: dbus
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.11"
decimal:
dependency: transitive
description:
@ -381,10 +373,10 @@ packages:
dependency: "direct main"
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.3.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -394,10 +386,10 @@ packages:
dependency: transitive
description:
name: flutter_web_bluetooth
sha256: fcd03e2e5f82edcedcbc940f1b6a0635a50757374183254f447640886c53208e
sha256: "1363831def5eed1e1064d1eca04e8ccb35446e8f758579c3c519e156b77926da"
url: "https://pub.dev"
source: hosted
version: "0.2.4"
version: "1.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
@ -415,18 +407,18 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
google_identity_services_web:
dependency: transitive
description:
name: google_identity_services_web
sha256: "5be191523702ba8d7a01ca97c17fca096822ccf246b0a9f11923a6ded06199b6"
sha256: "55580f436822d64c8ff9a77e37d61f5fb1e6c7ec9d632a43ee324e2a05c3c6c9"
url: "https://pub.dev"
source: hosted
version: "0.3.1+4"
version: "0.3.3"
googleapis_auth:
dependency: transitive
description:
@ -447,10 +439,10 @@ packages:
dependency: "direct main"
description:
name: grpc
sha256: e93ee3bce45c134bf44e9728119102358c7cd69de7832d9a874e2e74eb8cab40
sha256: "5b99b7a420937d4361ece68b798c9af8e04b5bc128a7859f2a4be87427694813"
url: "https://pub.dev"
source: hosted
version: "3.2.4"
version: "4.0.1"
hex:
dependency: transitive
description:
@ -479,34 +471,34 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http2:
dependency: transitive
description:
name: http2
sha256: "9ced024a160b77aba8fb8674e38f70875e321d319e6f303ec18e87bd5a4b0c1d"
sha256: "382d3aefc5bd6dc68c6b892d7664f29b5beb3251611ae946a98d35158a82bbfa"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.3.1"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.1.2"
intl:
dependency: "direct main"
description:
@ -519,10 +511,10 @@ packages:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.0.5"
js:
dependency: transitive
description:
@ -543,18 +535,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -568,7 +560,7 @@ packages:
description:
path: "packages/ledger-bitcoin"
ref: HEAD
resolved-ref: "07cd61ef76a2a017b6d5ef233396740163265457"
resolved-ref: e93254f3ff3f996fb91f65a1e7ceffb9f510b4c8
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
source: git
version: "0.0.3"
@ -576,16 +568,16 @@ packages:
dependency: "direct main"
description:
name: ledger_flutter_plus
sha256: c7b04008553193dbca7e17b430768eecc372a72b0ff3625b5e7fc5e5c8d3231b
sha256: "1c03f3c4a9754b5f0170a9eb9552ec54fa86e985f8ee71a255ee2c5629b53d31"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.5.1"
ledger_litecoin:
dependency: "direct main"
description:
path: "packages/ledger-litecoin"
ref: HEAD
resolved-ref: "3dee36713e6ebec9dceb59b9ccae7f243a53ea9e"
resolved-ref: e93254f3ff3f996fb91f65a1e7ceffb9f510b4c8
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
source: git
version: "0.0.2"
@ -641,10 +633,10 @@ packages:
dependency: "direct main"
description:
name: mobx
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
url: "https://pub.dev"
source: hosted
version: "2.3.3+2"
version: "2.5.0"
mobx_codegen:
dependency: "direct dev"
description:
@ -661,14 +653,23 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
on_chain:
dependency: transitive
description:
path: "."
ref: cake-update-v2
resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
url: "https://github.com/cake-tech/on_chain.git"
source: git
version: "3.7.0"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
path:
dependency: transitive
description:
@ -681,26 +682,26 @@ packages:
dependency: "direct main"
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.15"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@ -785,18 +786,18 @@ packages:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.5.0"
quiver:
dependency: transitive
description:
@ -825,26 +826,26 @@ packages:
dependency: "direct main"
description:
name: shared_preferences
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.5.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.4.6"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
@ -865,10 +866,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
@ -881,23 +882,23 @@ packages:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.0.1"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: transitive
description:
@ -935,7 +936,7 @@ packages:
description:
path: "."
ref: "sp_v4.0.0"
resolved-ref: ca1add293bd1e06920aa049b655832da50d0dab2
resolved-ref: "2554cb8bd3ee1d026bc63e76a30d1226960c7cb4"
url: "https://github.com/cake-tech/sp_scanner"
source: git
version: "0.0.1"
@ -943,10 +944,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -959,18 +960,18 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -983,18 +984,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.2"
tuple:
dependency: transitive
description:
@ -1015,10 +1016,10 @@ packages:
dependency: transitive
description:
name: universal_ble
sha256: "0dfbd6b64bff3ad61ed7a895c232530d9614e9b01ab261a74433a43267edb7f3"
sha256: "1fad089150a29db82b3b7d60327e18c5ad6b3a5bb509defc1c690b0a76b9c098"
url: "https://pub.dev"
source: hosted
version: "0.12.0"
version: "0.15.0"
universal_platform:
dependency: transitive
description:
@ -1047,26 +1048,26 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.4"
version: "14.3.0"
watcher:
dependency: "direct overridden"
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -1079,10 +1080,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
xdg_directories:
dependency: transitive
description:
@ -1103,18 +1104,18 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
yaml_edit:
dependency: transitive
description:
name: yaml_edit
sha256: e9c1a3543d2da0db3e90270dbb1e4eebc985ee5e3ffe468d83224472b2194a5f
sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "2.2.2"
sdks:
dart: ">=3.5.0 <4.0.0"
dart: ">=3.6.0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -32,7 +32,7 @@ dependencies:
ref: cake-update-v2
cw_mweb:
path: ../cw_mweb
grpc: ^3.2.4
grpc: ^4.0.1
sp_scanner:
git:
url: https://github.com/cake-tech/sp_scanner

View file

@ -29,6 +29,7 @@ class AmountConverter {
case CryptoCurrency.btc:
case CryptoCurrency.bch:
case CryptoCurrency.ltc:
case CryptoCurrency.dcr:
return _bitcoinAmountToString(amount);
case CryptoCurrency.xhv:
case CryptoCurrency.xag:

View file

@ -32,9 +32,10 @@ CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
return CryptoCurrency.wow;
case WalletType.zano:
return CryptoCurrency.zano;
case WalletType.decred:
return CryptoCurrency.dcr;
case WalletType.none:
throw Exception(
'Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
}
}
@ -65,6 +66,10 @@ WalletType? walletTypeForCurrency(CryptoCurrency currency) {
return WalletType.tron;
case CryptoCurrency.wow:
return WalletType.wownero;
case CryptoCurrency.zano:
return WalletType.zano;
case CryptoCurrency.dcr:
return WalletType.decred;
default:
return null;
}

View file

@ -103,6 +103,7 @@ class Node extends HiveObject with Keyable {
case WalletType.solana:
case WalletType.tron:
case WalletType.zano:
case WalletType.decred:
return Uri.parse(
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") || path!.isEmpty ? path : "/$path"}");
case WalletType.none:
@ -167,6 +168,8 @@ class Node extends HiveObject with Keyable {
return requestElectrumServer();
case WalletType.zano:
return requestZanoNode();
case WalletType.decred:
return requestDecredNode();
case WalletType.none:
return false;
}
@ -355,6 +358,21 @@ class Node extends HiveObject with Keyable {
return false;
}
}
Future<bool> requestDecredNode() async {
if (uri.host == "default-spv-nodes") {
// Just show default port as ok. The wallet will connect to a list of known
// nodes automatically.
return true;
}
try {
final socket = await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5));
socket.destroy();
return true;
} catch (_) {
return false;
}
}
}
/// https://github.com/ManyMath/digest_auth/

View file

@ -2,6 +2,7 @@ import 'package:cw_core/enumerate.dart';
class ReceivePageOption implements Enumerate {
static const mainnet = ReceivePageOption._('mainnet');
static const testnet = ReceivePageOption._('testnet');
static const anonPayInvoice = ReceivePageOption._('anonPayInvoice');
static const anonPayDonationLink = ReceivePageOption._('anonPayDonationLink');

View file

@ -1,9 +1,9 @@
import 'package:flutter/services.dart';
void setIsAppSecureNative(bool isAppSecure) {
Future<void> setIsAppSecureNative(bool isAppSecure) async {
try {
final utils = const MethodChannel('com.cake_wallet/native_utils');
utils.invokeMethod<Uint8List>('setIsAppSecure', {'isAppSecure': isAppSecure});
await utils.invokeMethod<Uint8List>('setIsAppSecure', {'isAppSecure': isAppSecure});
} catch (_) {}
}

View file

@ -34,6 +34,16 @@ class SyncingSyncStatus extends SyncStatus {
}
}
class ProcessingSyncStatus extends SyncStatus {
final String? message;
ProcessingSyncStatus({this.message});
@override
double progress() => 0.99;
}
class SyncedSyncStatus extends SyncStatus {
@override
double progress() => 1.0;

View file

@ -1,3 +1,5 @@
import 'dart:math';
void printV(dynamic content) {
CustomTrace programInfo = CustomTrace(StackTrace.current);
print("${programInfo.fileName}#${programInfo.lineNumber}:${programInfo.columnNumber} ${programInfo.callerFunctionName}: $content");
@ -29,7 +31,7 @@ class CustomTrace {
var indexOfWhiteSpace = currentTrace.indexOf(' ');
/* Create a substring from the first whitespace index till the end of the string */
var subStr = currentTrace.substring(indexOfWhiteSpace);
var subStr = currentTrace.substring(max(0, indexOfWhiteSpace));
/* Grab the function name using reg expr */
var indexOfFunction = subStr.indexOf(RegExp(r'[A-Za-z0-9_]'));
@ -40,7 +42,7 @@ class CustomTrace {
indexOfWhiteSpace = subStr.indexOf(RegExp(r'[ .]'));
/* Create a new substring from start to the first index of a whitespace. This substring gives us the function name */
subStr = subStr.substring(0, indexOfWhiteSpace);
subStr = subStr.substring(0, max(0, indexOfWhiteSpace));
return subStr;
}
@ -61,7 +63,7 @@ class CustomTrace {
/* Search through the string and find the index of the file name by looking for the '.dart' regex */
var indexOfFileName = traceString.indexOf(RegExp(r'[/A-Za-z_]+.dart'), 1); // 1 to offest and not print the printV function name
var fileInfo = traceString.substring(indexOfFileName);
var fileInfo = traceString.substring(max(0, indexOfFileName));
var listOfInfos = fileInfo.split(":");
@ -78,7 +80,7 @@ class CustomTrace {
columnStr = columnStr.replaceFirst(")", "");
this.columnNumber = int.tryParse(columnStr);
} catch (e) {
print("Unable to parse trace (printV): $e");
}
}
}

View file

@ -60,11 +60,19 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
bool get isHardwareWallet => walletInfo.isHardwareWallet;
bool get hasRescan => false;
Future<void> connectToNode({required Node node});
// there is a default definition here because only coins with a pow node (nano based) need to override this
Future<void> connectToPowNode({required Node node}) async {}
// startBackgroundSync is used to start sync in the background, without doing any
// extra things in the background.
// startSync is used as a fallback.
Future<void> startBackgroundSync() => startSync();
Future<void> stopBackgroundSync(String password) => stopSync();
Future<void> startSync();
Future<void> stopSync() async {}
@ -100,4 +108,6 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
Future<bool> verifyMessage(String message, String signature, {String? address = null});
bool isTestnet = false;
bool canSend() => true;
}

View file

@ -17,6 +17,7 @@ const walletTypes = [
WalletType.solana,
WalletType.tron,
WalletType.zano,
WalletType.decred,
];
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
@ -60,9 +61,11 @@ enum WalletType {
@HiveField(12)
wownero,
@HiveField(13)
@HiveField(13)
zano,
@HiveField(14)
decred
}
int serializeToInt(WalletType type) {
@ -93,6 +96,8 @@ int serializeToInt(WalletType type) {
return 11;
case WalletType.zano:
return 12;
case WalletType.decred:
return 13;
case WalletType.none:
return -1;
}
@ -126,6 +131,8 @@ WalletType deserializeFromInt(int raw) {
return WalletType.wownero;
case 12:
return WalletType.zano;
case 13:
return WalletType.decred;
default:
throw Exception(
'Unexpected token: $raw for WalletType deserializeFromInt');
@ -160,6 +167,8 @@ String walletTypeToString(WalletType type) {
return 'Wownero';
case WalletType.zano:
return 'Zano';
case WalletType.decred:
return 'Decred';
case WalletType.none:
return '';
}
@ -193,6 +202,8 @@ String walletTypeToDisplayName(WalletType type) {
return 'Wownero (WOW)';
case WalletType.zano:
return 'Zano (ZANO)';
case WalletType.decred:
return 'Decred (DCR)';
case WalletType.none:
return '';
}
@ -229,6 +240,8 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
return CryptoCurrency.wow;
case WalletType.zano:
return CryptoCurrency.zano;
case WalletType.decred:
return CryptoCurrency.dcr;
case WalletType.none:
throw Exception(
'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');

View file

@ -5,23 +5,23 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
url: "https://pub.dev"
source: hosted
version: "72.0.0"
version: "76.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.2"
version: "0.3.3"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
url: "https://pub.dev"
source: hosted
version: "6.7.0"
version: "6.11.0"
args:
dependency: transitive
description:
@ -34,10 +34,10 @@ packages:
dependency: transitive
description:
name: asn1lib
sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
sha256: "1c296cd268f486cabcc3930e9b93a8133169305f18d722916e675959a88f6d2c"
url: "https://pub.dev"
source: hosted
version: "1.5.5"
version: "1.5.9"
async:
dependency: transitive
description:
@ -46,6 +46,15 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.0"
blockchain_utils:
dependency: transitive
description:
path: "."
ref: cake-update-v2
resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
url: "https://github.com/cake-tech/blockchain_utils"
source: git
version: "3.3.0"
boolean_selector:
dependency: transitive
description:
@ -58,50 +67,50 @@ packages:
dependency: transitive
description:
name: build
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.4.2"
build_config:
dependency: transitive
description:
name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.0.4"
build_resolvers:
dependency: "direct dev"
description:
name: build_resolvers
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.4"
build_runner:
dependency: "direct dev"
description:
name: build_runner
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
url: "https://pub.dev"
source: hosted
version: "2.4.13"
version: "2.4.15"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
url: "https://pub.dev"
source: hosted
version: "7.3.2"
version: "8.0.0"
built_collection:
dependency: transitive
description:
@ -114,10 +123,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.4"
cake_backup:
dependency: "direct main"
description:
@ -155,18 +164,18 @@ packages:
dependency: transitive
description:
name: code_builder
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.dev"
source: hosted
version: "4.10.0"
version: "4.10.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -203,10 +212,10 @@ packages:
dependency: transitive
description:
name: dart_style
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
url: "https://pub.dev"
source: hosted
version: "2.3.7"
version: "2.3.8"
decimal:
dependency: "direct main"
description:
@ -264,10 +273,10 @@ packages:
dependency: "direct main"
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.3.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -285,10 +294,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
graphs:
dependency: transitive
description:
@ -317,26 +326,26 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.1.2"
intl:
dependency: "direct main"
description:
@ -349,10 +358,10 @@ packages:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.0.5"
js:
dependency: transitive
description:
@ -373,18 +382,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -405,10 +414,10 @@ packages:
dependency: transitive
description:
name: macros
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
url: "https://pub.dev"
source: hosted
version: "0.1.2-main.4"
version: "0.1.3-main.0"
matcher:
dependency: transitive
description:
@ -445,18 +454,18 @@ packages:
dependency: "direct main"
description:
name: mobx
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
url: "https://pub.dev"
source: hosted
version: "2.3.3+2"
version: "2.5.0"
mobx_codegen:
dependency: "direct dev"
description:
name: mobx_codegen
sha256: "8e0d8653a0c720ad933cd8358f6f89f740ce89203657c13f25bea772ef1fff7c"
sha256: "990da80722f7d7c0017dec92040b31545d625b15d40204c36a1e63d167c73cdc"
url: "https://pub.dev"
source: hosted
version: "2.6.1"
version: "2.7.0"
nested:
dependency: transitive
description:
@ -465,14 +474,23 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
on_chain:
dependency: "direct main"
description:
path: "."
ref: cake-update-v2
resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
url: "https://github.com/cake-tech/on_chain.git"
source: git
version: "3.7.0"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
path:
dependency: transitive
description:
@ -485,26 +503,26 @@ packages:
dependency: "direct main"
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.15"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@ -573,18 +591,18 @@ packages:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.5.0"
rational:
dependency: transitive
description:
@ -597,23 +615,23 @@ packages:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "3.0.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: "direct main"
description:
@ -634,10 +652,10 @@ packages:
dependency: transitive
description:
name: source_helper
sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
url: "https://pub.dev"
source: hosted
version: "1.3.4"
version: "1.3.5"
source_span:
dependency: transitive
description:
@ -650,10 +668,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -666,18 +684,18 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -690,18 +708,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.2"
tuple:
dependency: transitive
description:
@ -738,26 +756,26 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.4"
version: "14.3.0"
watcher:
dependency: "direct overridden"
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -770,10 +788,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
xdg_directories:
dependency: transitive
description:
@ -786,10 +804,10 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
dart: ">=3.6.0 <4.0.0"
flutter: ">=3.24.0"

39
cw_decred/.gitignore vendored Normal file
View file

@ -0,0 +1,39 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
android/.externalNativeBuild/
android/.cxx/
android/libs
ios/External/
macos/External/
*libdcrwallet.h
libdcrwallet_bindings.dart

36
cw_decred/.metadata Normal file
View file

@ -0,0 +1,36 @@
# 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.
version:
revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
channel: unknown
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: android
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: ios
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: macos
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

3
cw_decred/CHANGELOG.md Normal file
View file

@ -0,0 +1,3 @@
## [0.0.1] - TODO: Add release date.
* TODO: Describe initial release.

3
cw_decred/README.md Normal file
View file

@ -0,0 +1,3 @@
# cw_decred
TODO: Fill this out.

View file

@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View file

@ -6,3 +6,4 @@
.DS_Store
/build
/captures
.cxx

View file

@ -1,4 +1,4 @@
group 'com.cakewallet.cw_haven'
group 'com.cakewallet.cw_decred'
version '1.0-SNAPSHOT'
buildscript {
@ -28,7 +28,7 @@ android {
compileSdkVersion 33
if (project.android.hasProperty("namespace")) {
namespace 'com.cakewallet.cw_haven'
namespace 'com.cakewallet.cw_decred'
}
compileOptions {
@ -40,7 +40,10 @@ android {
jvmTarget = '17'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
main {
java.srcDirs += 'src/main/kotlin'
jniLibs.srcDirs 'libs' // contains libdcrwallet.so shared libraries
}
}
defaultConfig {
minSdkVersion 21

View file

@ -0,0 +1 @@
rootProject.name = 'cw_decred'

View file

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

View file

@ -1,4 +1,4 @@
package com.cakewallet.cw_haven
package com.cakewallet.cw_decred
import androidx.annotation.NonNull
@ -7,10 +7,9 @@ import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
/** CwHavenPlugin */
class CwHavenPlugin: FlutterPlugin, MethodCallHandler {
/** CwDecredPlugin */
class CwDecredPlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
@ -18,7 +17,7 @@ class CwHavenPlugin: FlutterPlugin, MethodCallHandler {
private lateinit var channel : MethodChannel
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cw_haven")
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cw_decred")
channel.setMethodCallHandler(this)
}

View file

@ -34,4 +34,5 @@ Icon?
.tags*
/Flutter/Generated.xcconfig
/Flutter/ephemeral/
/Flutter/flutter_export_environment.sh

View file

@ -0,0 +1,19 @@
import Flutter
import UIKit
public class CwDecredPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "cw_decred", binaryMessenger: registrar.messenger())
let instance = CwDecredPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
result("iOS " + UIDevice.current.systemVersion)
default:
result(FlutterMethodNotImplemented)
}
}
}

View file

@ -0,0 +1,22 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint cw_decred.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'cw_decred'
s.version = '0.0.1'
s.summary = 'Cake Wallet Decred'
s.description = 'Cake Wallet wrapper over Decred project'
s.homepage = 'http://cakewallet.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Cake Wallet' => 'support@cakewallet.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.dependency 'Flutter'
s.platform = :ios, '11.0'
s.vendored_libraries = 'External/lib/libdcrwallet.a'
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/External/lib/libdcrwallet.a -lstdc++" }
s.swift_version = '5.0'
end

View file

@ -0,0 +1,26 @@
import 'package:intl/intl.dart';
import 'package:cw_core/crypto_amount_format.dart';
const decredAmountLength = 8;
const decredAmountDivider = 100000000;
final decredAmountFormat = NumberFormat()
..maximumFractionDigits = decredAmountLength
..minimumFractionDigits = 1;
String decredAmountToString({required int amount}) =>
decredAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: decredAmountDivider));
double decredAmountToDouble({required int amount}) =>
cryptoAmountToDouble(amount: amount, divider: decredAmountDivider);
int stringDoubleToDecredAmount(String amount) {
int result = 0;
try {
result = (double.parse(amount) * decredAmountDivider).round();
} catch (e) {
result = 0;
}
return result;
}

View file

@ -0,0 +1,693 @@
import 'dart:convert';
import 'dart:ffi';
import 'dart:io';
import 'dart:async';
import 'dart:isolate';
import 'package:flutter/foundation.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_decred/api/libdcrwallet_bindings.dart';
import 'package:cw_decred/api/util.dart';
final int ErrCodeNotSynced = 1;
final String libraryName = Platform.isAndroid || Platform.isLinux // TODO: Linux.
? 'libdcrwallet.so'
: 'cw_decred.framework/cw_decred';
class Libwallet {
final SendPort _commands;
final ReceivePort _responses;
final Map<int, Completer<Object?>> _activeRequests = {};
int _idCounter = 0;
bool _closed = false;
static Future<Libwallet> spawn() async {
// Create a receive port and add its initial message handler.
final initPort = RawReceivePort();
final connection = Completer<(ReceivePort, SendPort)>.sync();
initPort.handler = (initialMessage) {
final commandPort = initialMessage as SendPort;
connection.complete((
ReceivePort.fromRawReceivePort(initPort),
commandPort,
));
};
// Spawn the isolate.
try {
await Isolate.spawn(_startRemoteIsolate, (initPort.sendPort));
} on Object {
initPort.close();
rethrow;
}
final (ReceivePort receivePort, SendPort sendPort) = await connection.future;
return Libwallet._(receivePort, sendPort);
}
Libwallet._(this._responses, this._commands) {
_responses.listen(_handleResponsesFromIsolate);
}
void _handleResponsesFromIsolate(dynamic message) {
final (int id, Object? response) = message as (int, Object?);
final completer = _activeRequests.remove(id)!;
if (response is RemoteError) {
completer.completeError(response);
} else {
completer.complete(response);
}
if (_closed && _activeRequests.isEmpty) _responses.close();
}
static void _handleCommandsToIsolate(
ReceivePort receivePort,
SendPort sendPort,
) {
final dcrwalletApi = libdcrwallet(DynamicLibrary.open(libraryName));
receivePort.listen((message) {
if (message == 'shutdown') {
receivePort.close();
return;
}
final (int id, Map<String, String> args) = message as (int, Map<String, String>);
var res = PayloadResult("", "", 0);
final method = args["method"] ?? "";
try {
switch (method) {
case "initlibdcrwallet":
final logDir = args["logdir"] ?? "";
final cLogDir = logDir.toCString();
executePayloadFn(
fn: () => dcrwalletApi.initialize(cLogDir),
ptrsToFree: [cLogDir],
);
break;
case "createwallet":
final config = args["config"] ?? "";
final cConfig = config.toCString();
executePayloadFn(
fn: () => dcrwalletApi.createWallet(cConfig),
ptrsToFree: [cConfig],
);
break;
case "createwatchonlywallet":
final config = args["config"] ?? "";
final cConfig = config.toCString();
executePayloadFn(
fn: () => dcrwalletApi.createWatchOnlyWallet(cConfig),
ptrsToFree: [cConfig],
);
break;
case "loadwallet":
final config = args["config"] ?? "";
final cConfig = config.toCString();
executePayloadFn(
fn: () => dcrwalletApi.loadWallet(cConfig),
ptrsToFree: [cConfig],
);
break;
case "startsync":
final name = args["name"] ?? "";
final peers = args["peers"] ?? "";
final cName = name.toCString();
final cPeers = peers.toCString();
executePayloadFn(
fn: () => dcrwalletApi.syncWallet(cName, cPeers),
ptrsToFree: [cName, cPeers],
);
break;
case "closewallet":
final name = args["name"] ?? "";
final cName = name.toCString();
executePayloadFn(
fn: () => dcrwalletApi.closeWallet(cName),
ptrsToFree: [cName],
);
break;
case "changewalletpassword":
final name = args["name"] ?? "";
final oldPass = args["oldpass"] ?? "";
final newPass = args["newpass"] ?? "";
final cName = name.toCString();
final cOldPass = oldPass.toCString();
final cNewPass = newPass.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.changePassphrase(cName, cOldPass, cNewPass),
ptrsToFree: [cName, cOldPass, cNewPass],
);
break;
case "walletseed":
final name = args["name"] ?? "";
final pass = args["pass"] ?? "";
final cName = name.toCString();
final cPass = pass.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.walletSeed(cName, cPass),
ptrsToFree: [cName, cPass],
);
break;
case "syncstatus":
final name = args["name"] ?? "";
final cName = name.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.syncWalletStatus(cName),
ptrsToFree: [cName],
);
break;
case "balance":
final name = args["name"] ?? "";
final cName = name.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.walletBalance(cName),
ptrsToFree: [cName],
);
break;
case "estimatefee":
final name = args["name"] ?? "";
final numBlocks = args["numblocks"] ?? "";
final cName = name.toCString();
final cNumBlocks = numBlocks.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.estimateFee(cName, cNumBlocks),
ptrsToFree: [cName, cNumBlocks],
);
break;
case "createsignedtransaction":
final name = args["name"] ?? "";
final signReq = args["signreq"] ?? "";
final cName = name.toCString();
final cSignReq = signReq.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.createSignedTransaction(cName, cSignReq),
ptrsToFree: [cName, cSignReq],
);
break;
case "sendrawtransaction":
final name = args["name"] ?? "";
final txHex = args["txhex"] ?? "";
final cName = name.toCString();
final cTxHex = txHex.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.sendRawTransaction(cName, cTxHex),
ptrsToFree: [cName, cTxHex],
);
break;
case "listtransactions":
final name = args["name"] ?? "";
final from = args["from"] ?? "";
final count = args["count"] ?? "";
final cName = name.toCString();
final cFrom = from.toCString();
final cCount = count.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.listTransactions(cName, cFrom, cCount),
ptrsToFree: [cName, cFrom, cCount],
);
break;
case "bestblock":
final name = args["name"] ?? "";
final cName = name.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.bestBlock(cName),
ptrsToFree: [cName],
);
break;
case "listunspents":
final name = args["name"] ?? "";
final cName = name.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.listUnspents(cName),
ptrsToFree: [cName],
);
break;
case "rescanfromheight":
final name = args["name"] ?? "";
final height = args["height"] ?? "";
final cName = name.toCString();
final cHeight = height.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.rescanFromHeight(cName, cHeight),
ptrsToFree: [cName, cHeight],
);
break;
case "signmessage":
final name = args["name"] ?? "";
final message = args["message"] ?? "";
final address = args["address"] ?? "";
final pass = args["pass"] ?? "";
final cName = name.toCString();
final cMessage = message.toCString();
final cAddress = address.toCString();
final cPass = pass.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.signMessage(cName, cMessage, cAddress, cPass),
ptrsToFree: [cName, cMessage, cAddress, cPass],
);
break;
case "verifymessage":
final name = args["name"] ?? "";
final message = args["message"] ?? "";
final address = args["address"] ?? "";
final sig = args["sig"] ?? "";
final cName = name.toCString();
final cMessage = message.toCString();
final cAddress = address.toCString();
final cSig = sig.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.verifyMessage(cName, cMessage, cAddress, cSig),
ptrsToFree: [cName, cMessage, cAddress, cSig],
);
break;
case "newexternaladdress":
final name = args["name"] ?? "";
final cName = name.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.newExternalAddress(cName),
ptrsToFree: [cName],
skipErrorCheck: true,
);
break;
case "defaultpubkey":
final name = args["name"] ?? "";
final cName = name.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.defaultPubkey(cName),
ptrsToFree: [cName],
);
break;
case "addresses":
final name = args["name"] ?? "";
final nUsed = args["nused"] ?? "";
final nUnused = args["nunused"] ?? "";
final cName = name.toCString();
final cNUsed = nUsed.toCString();
final cNUnused = nUnused.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.addresses(cName, cNUsed, cNUnused),
ptrsToFree: [cName, cNUsed, cNUnused],
);
break;
case "birthstate":
final name = args["name"] ?? "";
final cName = name.toCString();
res = executePayloadFn(
fn: () => dcrwalletApi.birthState(cName),
ptrsToFree: [cName],
);
break;
case "shutdown":
final name = args["name"] ?? "";
final cName = name.toCString();
executePayloadFn(
fn: () => dcrwalletApi.shutdown(),
ptrsToFree: [],
);
break;
default:
res = PayloadResult("", "unknown libwallet method ${method}", 0);
}
sendPort.send((id, res));
} catch (e) {
final errMsg = e.toString();
printV("decred libwallet returned an error for method ${method}: ${errMsg}");
sendPort.send((id, PayloadResult("", errMsg, 0)));
}
});
}
static void _startRemoteIsolate(SendPort sendPort) {
final receivePort = ReceivePort();
sendPort.send(receivePort.sendPort);
_handleCommandsToIsolate(receivePort, sendPort);
}
// initLibdcrwallet initializes libdcrwallet using the provided logDir and gets
// it ready for use. This must be done before attempting to create, load or use
// a wallet.
Future<void> initLibdcrwallet(String logDir) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "initlibdcrwallet",
"logdir": logDir,
};
_commands.send((id, req));
await completer.future;
}
Future<void> createWallet(String config) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "createwallet",
"config": config,
};
_commands.send((id, req));
await completer.future;
}
Future<void> createWatchOnlyWallet(String config) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "createwatchonlywallet",
"config": config,
};
_commands.send((id, req));
await completer.future;
}
Future<void> loadWallet(String config) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "loadwallet",
"config": config,
};
_commands.send((id, req));
await completer.future;
}
Future<void> startSync(String walletName, String peers) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "startsync",
"name": walletName,
"peers": peers,
};
_commands.send((id, req));
await completer.future;
}
Future<void> closeWallet(String walletName) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "closewallet",
"name": walletName,
};
_commands.send((id, req));
await completer.future;
}
Future<String> changeWalletPassword(
String walletName, String currentPassword, String newPassword) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "changewalletpassword",
"name": walletName,
"oldpass": currentPassword,
"newpass": newPassword
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String?> walletSeed(String walletName, String walletPassword) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "walletseed",
"name": walletName,
"pass": walletPassword,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> syncStatus(String walletName) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "syncstatus",
"name": walletName,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<Map> balance(String walletName) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "balance",
"name": walletName,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return jsonDecode(res.payload);
}
Future<String> estimateFee(String walletName, int numBlocks) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "estimatefee",
"name": walletName,
"numblocks": numBlocks.toString(),
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> createSignedTransaction(
String walletName, String createSignedTransactionReq) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "createsignedtransaction",
"name": walletName,
"signreq": createSignedTransactionReq,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> sendRawTransaction(String walletName, String txHex) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "sendrawtransaction",
"name": walletName,
"txhex": txHex,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> listTransactions(String walletName, String from, String count) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "listtransactions",
"name": walletName,
"from": from,
"count": count,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> bestBlock(String walletName) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "bestblock",
"name": walletName,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> listUnspents(String walletName) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "listunspents",
"name": walletName,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> rescanFromHeight(String walletName, String height) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "rescanfromheight",
"name": walletName,
"height": height,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> signMessage(
String walletName, String message, String address, String walletPass) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "signmessage",
"name": walletName,
"message": message,
"address": address,
"pass": walletPass,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> verifyMessage(
String walletName, String message, String address, String sig) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "verifymessage",
"name": walletName,
"message": message,
"address": address,
"sig": sig,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String?> newExternalAddress(String walletName) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "newexternaladdress",
"name": walletName,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
if (res.errCode == ErrCodeNotSynced) {
// Wallet is not synced. We do not want to give out a used address so give
// nothing.
return null;
}
checkErr(res.err);
return res.payload;
}
Future<String> defaultPubkey(String walletName) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "defaultpubkey",
"name": walletName,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> addresses(String walletName, String nUsed, String nUnused) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "addresses",
"name": walletName,
"nused": nUsed,
"nunused": nUnused,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<String> birthState(String walletName) async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "birthstate",
"name": walletName,
};
_commands.send((id, req));
final res = await completer.future as PayloadResult;
return res.payload;
}
Future<void> shutdown() async {
if (_closed) throw StateError('Closed');
final completer = Completer<Object?>.sync();
final id = _idCounter++;
_activeRequests[id] = completer;
final req = {
"method": "shutdown",
};
_commands.send((id, req));
await completer.future as PayloadResult;
}
void close() {
if (!_closed) {
_closed = true;
_commands.send('shutdown');
if (_activeRequests.isEmpty) _responses.close();
}
}
}

View file

@ -0,0 +1,64 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'dart:convert';
class PayloadResult {
final String payload;
final String err;
final int errCode;
const PayloadResult(this.payload, this.err, this.errCode);
}
// Executes the provided fn and converts the string response to a PayloadResult.
// Returns payload, error code, and error.
PayloadResult executePayloadFn({
required Pointer<Char> fn(),
required List<Pointer> ptrsToFree,
bool skipErrorCheck = false,
}) {
final jsonStr = fn().toDartString();
freePointers(ptrsToFree);
if (jsonStr == null) throw Exception("no json return from wallet library");
final decoded = json.decode(jsonStr);
final err = decoded["error"] ?? "";
if (!skipErrorCheck) {
checkErr(err);
}
final payload = decoded["payload"] ?? "";
final errCode = decoded["errorcode"] ?? -1;
return new PayloadResult(payload, err, errCode);
}
void freePointers(List<Pointer> ptrsToFree) {
for (final ptr in ptrsToFree) {
malloc.free(ptr);
}
}
void checkErr(String err) {
if (err == "") return;
throw Exception(err);
}
extension StringUtil on String {
Pointer<Char> toCString() => toNativeUtf8().cast<Char>();
}
extension CStringUtil on Pointer<Char> {
bool get isNull => address == nullptr.address;
free() {
malloc.free(this);
}
String? toDartString() {
if (isNull) return null;
final str = cast<Utf8>().toDartString();
free();
return str;
}
}

View file

@ -0,0 +1,25 @@
import 'package:cw_decred/amount_format.dart';
import 'package:cw_core/balance.dart';
class DecredBalance extends Balance {
const DecredBalance({required this.confirmed, required this.unconfirmed, required this.frozen})
: super(confirmed, unconfirmed);
factory DecredBalance.zero() => DecredBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
final int confirmed;
final int unconfirmed;
final int frozen;
@override
String get formattedAvailableBalance => decredAmountToString(amount: confirmed - frozen);
@override
String get formattedAdditionalBalance => decredAmountToString(amount: unconfirmed);
@override
String get formattedUnAvailableBalance {
final frozenFormatted = decredAmountToString(amount: frozen);
return frozenFormatted == '0.0' ? '' : frozenFormatted;
}
}

2050
cw_decred/lib/mnemonic.dart Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_decred/amount_format.dart';
class DecredPendingTransaction with PendingTransaction {
DecredPendingTransaction(
{required this.txid,
required this.amount,
required this.fee,
required this.rawHex,
required this.send});
final int amount;
final int fee;
final String txid;
final String rawHex;
final Future<void> Function() send;
@override
String get id => txid;
@override
String get amountFormatted => decredAmountToString(amount: amount);
@override
String get feeFormatted => decredAmountToString(amount: fee);
@override
String get hex => rawHex;
@override
Future<void> commit() async {
return send();
}
@override
Future<String?> commitUR() {
throw UnimplementedError();
}
}

View file

@ -0,0 +1,10 @@
import 'package:cw_decred/transaction_priority.dart';
import 'package:cw_core/output_info.dart';
class DecredTransactionCredentials {
DecredTransactionCredentials(this.outputs, {required this.priority, this.feeRate});
final List<OutputInfo> outputs;
final DecredTransactionPriority? priority;
final int? feeRate;
}

View file

@ -0,0 +1,31 @@
import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/transaction_history.dart';
class DecredTransactionHistory extends TransactionHistoryBase<TransactionInfo> {
DecredTransactionHistory() {
transactions = ObservableMap<String, TransactionInfo>();
}
@override
void addOne(TransactionInfo transaction) => transactions[transaction.id] = transaction;
@override
void addMany(Map<String, TransactionInfo> transactions) => this.transactions.addAll(transactions);
@override
Future<void> save() async {}
// update returns true if a known transaction that is not pending was found.
bool update(Map<String, TransactionInfo> txs) {
var foundOldTx = false;
txs.forEach((_, tx) {
if (!this.transactions.containsKey(tx.id) || this.transactions[tx.id]!.isPending) {
this.transactions[tx.id] = tx;
} else {
foundOldTx = true;
}
});
return foundOldTx;
}
}

View file

@ -0,0 +1,45 @@
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/format_amount.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_decred/amount_format.dart';
class DecredTransactionInfo extends TransactionInfo {
DecredTransactionInfo({
required String id,
required int amount,
required int fee,
required TransactionDirection direction,
required bool isPending,
required DateTime date,
required int height,
required int confirmations,
required String to,
}) {
this.id = id;
this.amount = amount;
this.fee = fee;
this.height = height;
this.direction = direction;
this.date = date;
this.isPending = isPending;
this.confirmations = confirmations;
this.to = to;
}
String? _fiatAmount;
@override
String amountFormatted() =>
'${formatAmount(decredAmountToString(amount: amount))} ${walletTypeToCryptoCurrency(WalletType.decred).title}';
@override
String? feeFormatted() =>
'${formatAmount(decredAmountToString(amount: fee ?? 0))} ${walletTypeToCryptoCurrency(WalletType.decred).title}';
@override
String fiatAmount() => _fiatAmount ?? '';
@override
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
}

View file

@ -0,0 +1,69 @@
import 'package:cw_core/transaction_priority.dart';
class DecredTransactionPriority extends TransactionPriority {
const DecredTransactionPriority({required String title, required int raw})
: super(title: title, raw: raw);
static const List<DecredTransactionPriority> all = [fast, medium, slow];
static const DecredTransactionPriority slow = DecredTransactionPriority(title: 'Slow', raw: 0);
static const DecredTransactionPriority medium =
DecredTransactionPriority(title: 'Medium', raw: 1);
static const DecredTransactionPriority fast = DecredTransactionPriority(title: 'Fast', raw: 2);
static DecredTransactionPriority deserialize({required int raw}) {
switch (raw) {
case 0:
return slow;
case 1:
return medium;
case 2:
return fast;
default:
throw Exception('Unexpected token: $raw for DecredTransactionPriority deserialize');
}
}
String get units => 'atom';
@override
String toString() {
var label = '';
switch (this) {
case DecredTransactionPriority.slow:
label = 'Slow ~24hrs'; // '${S.current.transaction_priority_slow} ~24hrs';
break;
case DecredTransactionPriority.medium:
label = 'Medium'; // S.current.transaction_priority_medium;
break;
case DecredTransactionPriority.fast:
label = 'Fast'; // S.current.transaction_priority_fast;
break;
default:
break;
}
return label;
}
String labelWithRate(int rate) => '${toString()} ($rate ${units}/byte)';
}
class FeeCache {
int _feeRate;
DateTime stamp;
FeeCache(this._feeRate) : this.stamp = DateTime(0, 0, 0, 0, 0, 0, 0, 0);
bool isOld() {
return this.stamp.add(const Duration(minutes: 30)).isBefore(DateTime.now());
}
void update(int feeRate) {
this._feeRate = feeRate;
this.stamp = DateTime.now();
}
int feeRate() {
return this._feeRate;
}
}

729
cw_decred/lib/wallet.dart Normal file
View file

@ -0,0 +1,729 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:cw_core/exceptions.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_decred/pending_transaction.dart';
import 'package:cw_decred/transaction_credentials.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:hive/hive.dart';
import 'package:cw_decred/api/libdcrwallet.dart';
import 'package:cw_decred/transaction_history.dart';
import 'package:cw_decred/wallet_addresses.dart';
import 'package:cw_decred/transaction_priority.dart';
import 'package:cw_decred/wallet_service.dart';
import 'package:cw_decred/balance.dart';
import 'package:cw_decred/transaction_info.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/unspent_transaction_output.dart';
part 'wallet.g.dart';
class DecredWallet = DecredWalletBase with _$DecredWallet;
abstract class DecredWalletBase
extends WalletBase<DecredBalance, DecredTransactionHistory, DecredTransactionInfo> with Store {
DecredWalletBase(WalletInfo walletInfo, String password, Box<UnspentCoinsInfo> unspentCoinsInfo,
Libwallet libwallet, Function() closeLibwallet)
: _password = password,
_libwallet = libwallet,
_closeLibwallet = closeLibwallet,
this.syncStatus = NotConnectedSyncStatus(),
this.unspentCoinsInfo = unspentCoinsInfo,
this.watchingOnly =
walletInfo.derivationInfo?.derivationPath == DecredWalletService.pubkeyRestorePath ||
walletInfo.derivationInfo?.derivationPath ==
DecredWalletService.pubkeyRestorePathTestnet,
this.balance = ObservableMap.of({CryptoCurrency.dcr: DecredBalance.zero()}),
this.isTestnet = walletInfo.derivationInfo?.derivationPath ==
DecredWalletService.seedRestorePathTestnet ||
walletInfo.derivationInfo?.derivationPath ==
DecredWalletService.pubkeyRestorePathTestnet,
super(walletInfo) {
walletAddresses = DecredWalletAddresses(walletInfo, libwallet);
transactionHistory = DecredTransactionHistory();
reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) {
this.walletAddresses.isEnabledAutoGenerateSubaddress = enabled;
});
}
// NOTE: Hitting this max fee would be unexpected with current on chain use
// but this may need to be updated in the future.
final maxFeeRate = 100000;
// syncIntervalSyncing is used up until synced, then transactions are checked
// every syncIntervalSynced.
final syncIntervalSyncing = 5; // seconds
final syncIntervalSynced = 30; // seconds
static final defaultFeeRate = 10000;
final String _password;
final Libwallet _libwallet;
final Function() _closeLibwallet;
final idPrefix = "decred_";
// TODO: Encrypt this.
var _seed = "";
var _pubkey = "";
var _unspents = <Unspent>[];
// synced is used to set the syncTimer interval.
bool synced = false;
bool watchingOnly;
bool connecting = false;
String persistantPeer = "default-spv-nodes";
FeeCache feeRateFast = FeeCache(defaultFeeRate);
FeeCache feeRateMedium = FeeCache(defaultFeeRate);
FeeCache feeRateSlow = FeeCache(defaultFeeRate);
Timer? syncTimer;
Box<UnspentCoinsInfo> unspentCoinsInfo;
@override
@observable
bool isEnabledAutoGenerateSubaddress = true;
@override
@observable
SyncStatus syncStatus;
@override
@observable
late ObservableMap<CryptoCurrency, DecredBalance> balance;
@override
late DecredWalletAddresses walletAddresses;
@override
String? get seed {
if (watchingOnly) {
return null;
}
return _seed;
}
@override
Object get keys => {};
@override
bool isTestnet;
String get pubkey {
return _pubkey;
}
Future<void> init() async {
final getSeed = () async {
if (!watchingOnly) {
_seed = await _libwallet.walletSeed(walletInfo.name, _password) ?? "";
}
_pubkey = await _libwallet.defaultPubkey(walletInfo.name);
};
await Future.wait([
updateBalance(),
updateTransactionHistory(),
walletAddresses.init(),
fetchTransactions(),
updateFees(),
fetchUnspents(),
getSeed(),
]);
}
Future<void> performBackgroundTasks() async {
if (!await checkSync()) {
if (synced == true) {
synced = false;
if (syncTimer != null) {
syncTimer!.cancel();
}
syncTimer = Timer.periodic(
Duration(seconds: syncIntervalSyncing), (Timer t) => performBackgroundTasks());
}
return;
}
// Set sync check interval lower since we are synced.
if (synced == false) {
synced = true;
if (syncTimer != null) {
syncTimer!.cancel();
}
syncTimer = Timer.periodic(
Duration(seconds: syncIntervalSynced), (Timer t) => performBackgroundTasks());
}
await Future.wait([
updateTransactionHistory(),
updateFees(),
fetchUnspents(),
updateBalance(),
walletAddresses.updateAddressesInBox(),
]);
}
Future<void> updateFees() async {
final feeForNb = (int nb) async {
try {
final feeStr = await _libwallet.estimateFee(walletInfo.name, nb);
var fee = int.parse(feeStr);
if (fee > maxFeeRate) {
throw "dcr fee returned from estimate fee was over max";
} else if (fee <= 0) {
throw "dcr fee returned from estimate fee was zero";
}
return fee;
} catch (e) {
printV(e);
return defaultFeeRate;
}
};
if (feeRateSlow.isOld()) {
feeRateSlow.update(await feeForNb(4));
}
if (feeRateMedium.isOld()) {
feeRateMedium.update(await feeForNb(2));
}
if (feeRateFast.isOld()) {
feeRateFast.update(await feeForNb(1));
}
}
Future<void> updateTransactionHistory() async {
// from is the number of transactions skipped from most recent, not block
// height.
var from = 0;
while (true) {
// Transactions are returned from newest to oldest. Loop fetching 5 txn
// at a time until we find a batch with txn that no longer need to be
// updated.
final txs = await this.fetchFiveTransactions(from);
if (txs.length == 0) {
return;
}
if (this.transactionHistory.update(txs)) {
return;
}
from += 5;
}
}
Future<bool> checkSync() async {
final syncStatusJSON = await _libwallet.syncStatus(walletInfo.name);
final decoded = json.decode(syncStatusJSON);
final syncStatusCode = decoded["syncstatuscode"] ?? 0;
// final syncStatusStr = decoded["syncstatus"] ?? "";
final targetHeight = decoded["targetheight"] ?? 1;
final numPeers = decoded["numpeers"] ?? 0;
// final cFiltersHeight = decoded["cfiltersheight"] ?? 0;
final headersHeight = decoded["headersheight"] ?? 0;
final rescanHeight = decoded["rescanheight"] ?? 0;
if (numPeers == 0) {
syncStatus = NotConnectedSyncStatus();
return false;
}
// Sync codes:
// NotStarted = 0
// FetchingCFilters = 1
// FetchingHeaders = 2
// DiscoveringAddrs = 3
// Rescanning = 4
// Complete = 5
if (syncStatusCode > 4) {
syncStatus = SyncedSyncStatus();
return true;
}
if (syncStatusCode == 0) {
syncStatus = ConnectedSyncStatus();
return false;
}
if (syncStatusCode == 1) {
syncStatus = SyncingSyncStatus(targetHeight, 0.0);
return false;
}
if (syncStatusCode == 2) {
final headersProg = headersHeight / targetHeight;
// Only allow headers progress to go up half way.
syncStatus = SyncingSyncStatus(targetHeight - headersHeight, headersProg);
return false;
}
// TODO: This step takes a while so should really get more info to the UI
// that we are discovering addresses.
if (syncStatusCode == 3) {
// Hover at half.
syncStatus = ProcessingSyncStatus();
return false;
}
if (syncStatusCode == 4) {
// Start at 75%.
final rescanProg = rescanHeight / targetHeight / 4;
syncStatus = SyncingSyncStatus(targetHeight - rescanHeight, .75 + rescanProg);
return false;
}
return false;
}
@action
@override
Future<void> connectToNode({required Node node}) async {
if (connecting) {
return;
}
connecting = true;
String addr = "default-spv-nodes";
if (node.uri.host != addr) {
addr = node.uri.host;
if (node.uri.port != "") {
addr += ":" + node.uri.port.toString();
}
}
if (addr != persistantPeer) {
if (syncTimer != null) {
syncTimer!.cancel();
syncTimer = null;
}
persistantPeer = addr;
await _libwallet.closeWallet(walletInfo.name);
final network = isTestnet ? "testnet" : "mainnet";
final config = {
"name": walletInfo.name,
"datadir": walletInfo.dirPath,
"net": network,
"unsyncedaddrs": true,
};
await _libwallet.loadWallet(jsonEncode(config));
}
await this._startSync();
connecting = false;
}
@action
@override
Future<void> startSync() async {
if (connecting) {
return;
}
connecting = true;
await this._startSync();
connecting = false;
}
Future<void> _startSync() async {
if (syncTimer != null) {
return;
}
try {
syncStatus = ConnectingSyncStatus();
await _libwallet.startSync(
walletInfo.name,
persistantPeer == "default-spv-nodes" ? "" : persistantPeer,
);
syncTimer = Timer.periodic(
Duration(seconds: syncIntervalSyncing), (Timer t) => performBackgroundTasks());
} catch (e) {
printV(e.toString());
syncStatus = FailedSyncStatus();
}
}
@override
Future<PendingTransaction> createTransaction(Object credentials) async {
if (watchingOnly) {
return DecredPendingTransaction(
txid: "",
amount: 0,
fee: 0,
rawHex: "",
send: () async {
throw "unable to send with watching only wallet";
});
}
var totalIn = 0;
final ignoreInputs = [];
this.unspentCoinsInfo.values.forEach((unspent) {
if (unspent.isFrozen || !unspent.isSending) {
final input = {"txid": unspent.hash, "vout": unspent.vout};
ignoreInputs.add(input);
return;
}
totalIn += unspent.value;
});
final creds = credentials as DecredTransactionCredentials;
var totalAmt = 0;
var sendAll = false;
final outputs = [];
for (final out in creds.outputs) {
var amt = 0;
if (out.sendAll) {
if (creds.outputs.length != 1) {
throw "can only send all to one output";
}
sendAll = true;
totalAmt = totalIn;
} else if (out.cryptoAmount != null) {
final coins = double.parse(out.cryptoAmount!);
amt = (coins * 1e8).toInt();
}
totalAmt += amt;
final o = {
"address": out.isParsedAddress ? out.extractedAddress! : out.address,
"amount": amt
};
outputs.add(o);
}
// throw exception if no selected coins under coin control
// or if the total coins selected, is less than the amount the user wants to spend
if (ignoreInputs.length == unspentCoinsInfo.values.length || totalIn < totalAmt) {
throw TransactionNoInputsException();
}
// The inputs are always used. Currently we don't have use for this
// argument. sendall ingores output value and sends everything.
final signReq = {
// "inputs": inputs,
"ignoreInputs": ignoreInputs,
"outputs": outputs,
"feerate": creds.feeRate ?? defaultFeeRate,
"password": _password,
"sendall": sendAll,
};
final res = await _libwallet.createSignedTransaction(walletInfo.name, jsonEncode(signReq));
final decoded = json.decode(res);
final signedHex = decoded["signedhex"];
final send = () async {
await _libwallet.sendRawTransaction(walletInfo.name, signedHex);
await updateBalance();
};
final fee = decoded["fee"] ?? 0;
if (sendAll) {
totalAmt = (totalAmt - fee).toInt();
}
return DecredPendingTransaction(
txid: decoded["txid"] ?? "", amount: totalAmt, fee: fee, rawHex: signedHex, send: send);
}
int feeRate(TransactionPriority priority) {
if (!(priority is DecredTransactionPriority)) {
return defaultFeeRate;
}
final p = priority;
switch (p) {
case DecredTransactionPriority.slow:
return feeRateSlow.feeRate();
case DecredTransactionPriority.medium:
return feeRateMedium.feeRate();
case DecredTransactionPriority.fast:
return feeRateFast.feeRate();
}
return defaultFeeRate;
}
@override
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
if (priority is DecredTransactionPriority) {
final P2PKHOutputSize =
36; // 8 bytes value + 2 bytes version + at least 1 byte varint script size + P2PKHPkScriptSize
// MsgTxOverhead is 4 bytes version (lower 2 bytes for the real transaction
// version and upper 2 bytes for the serialization type) + 4 bytes locktime
// + 4 bytes expiry + 3 bytes of varints for the number of transaction
// inputs (x2 for witness and prefix) and outputs
final MsgTxOverhead = 15;
// TxInOverhead is the overhead for a wire.TxIn with a scriptSig length <
// 254. prefix (41 bytes) + ValueIn (8 bytes) + BlockHeight (4 bytes) +
// BlockIndex (4 bytes) + sig script var int (at least 1 byte)
final TxInOverhead = 57;
final P2PKHInputSize =
TxInOverhead + 109; // TxInOverhead (57) + var int (1) + P2PKHSigScriptSize (108)
int inputsCount = 1;
if (amount != null) {
inputsCount += _unspents.where((e) {
amount = (amount!) - e.value;
return (amount!) > 0;
}).length;
}
// Estimate using a transaction consuming inoutsCount and paying to one address with change.
return (this.feeRate(priority) / 1000).round() *
(MsgTxOverhead + P2PKHInputSize * inputsCount + P2PKHOutputSize * 2);
}
return 0;
}
@override
Future<Map<String, DecredTransactionInfo>> fetchTransactions() async {
return this.fetchFiveTransactions(0);
}
Future<Map<String, DecredTransactionInfo>> fetchFiveTransactions(int from) async {
final res = await _libwallet.listTransactions(walletInfo.name, from.toString(), "5");
final decoded = json.decode(res);
var txs = <String, DecredTransactionInfo>{};
for (final d in decoded) {
final txid = uniqueTxID(d["txid"] ?? "", d["vout"] ?? 0);
var direction = TransactionDirection.outgoing;
if (d["category"] == "receive") {
direction = TransactionDirection.incoming;
}
final amountDouble = d["amount"] ?? 0.0;
final amount = (amountDouble * 1e8).toInt().abs();
final feeDouble = d["fee"] ?? 0.0;
final fee = (feeDouble * 1e8).toInt().abs();
final confs = d["confirmations"] ?? 0;
final sendTime = d["time"] ?? 0;
final height = d["height"] ?? 0;
final txInfo = DecredTransactionInfo(
id: txid,
amount: amount,
fee: fee,
direction: direction,
isPending: confs == 0,
date: DateTime.fromMillisecondsSinceEpoch(sendTime * 1000, isUtc: false),
height: height,
confirmations: confs,
to: d["address"] ?? "",
);
txs[txid] = txInfo;
}
return txs;
}
// uniqueTxID combines the tx id and vout to create a unique id.
String uniqueTxID(String id, int vout) {
return id + ":" + vout.toString();
}
@override
Future<void> save() async {}
@override
bool get hasRescan => walletBirthdayBlockHeight() != -1;
@override
Future<void> rescan({required int height}) async {
// The required height is not used. A birthday time is recorded in the
// mnemonic. As long as not private data is imported into the wallet, we
// can always rescan from there.
var rescanHeight = 0;
if (!watchingOnly) {
rescanHeight = await walletBirthdayBlockHeight();
// Sync has not yet reached the birthday block.
if (rescanHeight == -1) {
return;
}
}
await _libwallet.rescanFromHeight(walletInfo.name, rescanHeight.toString());
}
@override
Future<void> close({bool shouldCleanup = false}) async {
if (syncTimer != null) {
syncTimer!.cancel();
syncTimer = null;
}
await _libwallet.closeWallet(walletInfo.name);
if (shouldCleanup) {
await _libwallet.shutdown();
_closeLibwallet();
}
}
@override
Future<void> changePassword(String password) async {
if (watchingOnly) {
return;
}
return () async {
await _libwallet.changeWalletPassword(walletInfo.name, _password, password);
}();
}
@override
Future<void> updateBalance() async {
final balanceMap = await _libwallet.balance(walletInfo.name);
var totalFrozen = 0;
unspentCoinsInfo.values.forEach((info) {
_unspents.forEach((element) {
if (element.hash == info.hash &&
element.vout == info.vout &&
info.isFrozen &&
element.value == info.value) {
totalFrozen += element.value;
}
});
});
balance[CryptoCurrency.dcr] = DecredBalance(
confirmed: balanceMap["confirmed"] ?? 0,
unconfirmed: balanceMap["unconfirmed"] ?? 0,
frozen: totalFrozen,
);
}
@override
void setExceptionHandler(void Function(FlutterErrorDetails) onError) => onError;
Future<void> renameWalletFiles(String newWalletName) async {
final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type);
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
if (File(newDirPath).existsSync()) {
throw "wallet already exists at $newDirPath";
}
await Directory(currentDirPath).rename(newDirPath);
}
@override
Future<String> signMessage(String message, {String? address = null}) async {
if (watchingOnly) {
throw "a watching only wallet cannot sign";
}
var addr = address;
if (addr == null) {
addr = walletAddresses.address;
}
if (addr == "") {
throw "unable to get an address from unsynced wallet";
}
return await _libwallet.signMessage(walletInfo.name, message, addr, _password);
}
Future<void> fetchUnspents() async {
final res = await _libwallet.listUnspents(walletInfo.name);
final decoded = json.decode(res);
var unspents = <Unspent>[];
for (final d in decoded) {
final spendable = d["spendable"] ?? false;
if (!spendable) {
continue;
}
final amountDouble = d["amount"] ?? 0.0;
final amount = (amountDouble * 1e8).toInt().abs();
final utxo = Unspent(d["address"] ?? "", d["txid"] ?? "", amount, d["vout"] ?? 0, null);
utxo.isChange = d["ischange"] ?? false;
unspents.add(utxo);
}
_unspents = unspents;
}
List<Unspent> unspents() {
this.updateUnspents(_unspents);
return _unspents;
}
void updateUnspents(List<Unspent> unspentCoins) {
if (this.unspentCoinsInfo.isEmpty) {
unspentCoins.forEach((coin) => this.addCoinInfo(coin));
return;
}
if (unspentCoins.isEmpty) {
this.unspentCoinsInfo.clear();
return;
}
final walletID = idPrefix + walletInfo.name;
if (unspentCoins.isNotEmpty) {
unspentCoins.forEach((coin) {
final coinInfoList = this.unspentCoinsInfo.values.where((element) =>
element.walletId == walletID && element.hash == coin.hash && element.vout == coin.vout);
if (coinInfoList.isEmpty) {
this.addCoinInfo(coin);
} else {
final coinInfo = coinInfoList.first;
coin.isFrozen = coinInfo.isFrozen;
coin.isSending = coinInfo.isSending;
coin.note = coinInfo.note;
}
});
}
final List<dynamic> keys = <dynamic>[];
this.unspentCoinsInfo.values.forEach((element) {
final existUnspentCoins = unspentCoins.where((coin) => element.hash.contains(coin.hash));
if (existUnspentCoins.isEmpty) {
keys.add(element.key);
}
});
if (keys.isNotEmpty) {
unspentCoinsInfo.deleteAll(keys);
}
}
void addCoinInfo(Unspent coin) {
final newInfo = UnspentCoinsInfo(
walletId: idPrefix + walletInfo.name,
hash: coin.hash,
isFrozen: false,
isSending: coin.isSending,
noteRaw: "",
address: coin.address,
value: coin.value,
vout: coin.vout,
isChange: coin.isChange,
keyImage: coin.keyImage,
);
unspentCoinsInfo.add(newInfo);
}
// walletBirthdayBlockHeight checks if the wallet birthday is set and returns
// it. Returns -1 if not.
Future<int> walletBirthdayBlockHeight() async {
final res = await _libwallet.birthState(walletInfo.name);
final decoded = json.decode(res);
// Having these values set indicates that sync has not reached the birthday
// yet, so no birthday is set.
if (decoded["setfromheight"] == true || decoded["setfromtime"] == true) {
return -1;
}
return decoded["height"] ?? 0;
}
Future<bool> verifyMessage(String message, String signature, {String? address = null}) async {
var addr = address;
if (addr == null) {
throw "an address is required to verify message";
}
return () async {
final verified = await _libwallet.verifyMessage(walletInfo.name, message, addr, signature);
if (verified == "true") {
return true;
}
return false;
}();
}
@override
String get password => _password;
@override
bool canSend() => seed != null;
}

View file

@ -0,0 +1,137 @@
import 'dart:convert';
import 'package:mobx/mobx.dart';
import 'package:cw_core/address_info.dart';
import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_decred/api/libdcrwallet.dart';
part 'wallet_addresses.g.dart';
class DecredWalletAddresses = DecredWalletAddressesBase with _$DecredWalletAddresses;
abstract class DecredWalletAddressesBase extends WalletAddresses with Store {
DecredWalletAddressesBase(WalletInfo walletInfo, Libwallet libwallet)
: _libwallet = libwallet,
super(walletInfo);
final Libwallet _libwallet;
String currentAddr = '';
@observable
bool isEnabledAutoGenerateSubaddress = true;
@observable
String selectedAddr = '';
@override
@computed
String get address {
return selectedAddr;
}
@override
set address(value) {
selectedAddr = value;
}
@override
Future<void> init() async {
if (walletInfo.addresses != null) {
addressesMap = walletInfo.addresses!;
}
if (walletInfo.addressInfos != null) {
addressInfos = walletInfo.addressInfos!;
}
if (walletInfo.usedAddresses != null) {
usedAddresses = {...walletInfo.usedAddresses!};
}
await updateAddressesInBox();
}
@override
Future<void> updateAddressesInBox() async {
final addrs = await libAddresses();
final allAddrs = new List.from(addrs.usedAddrs)..addAll(addrs.unusedAddrs);
// Add all addresses.
allAddrs.forEach((addr) {
if (addressesMap.containsKey(addr)) {
return;
}
addressesMap[addr] = "";
addressInfos[0] ??= [];
addressInfos[0]?.add(AddressInfo(address: addr, label: "", accountIndex: 0));
});
// Add used addresses.
addrs.usedAddrs.forEach((addr) {
if (!usedAddresses.contains(addr)) {
usedAddresses.add(addr);
}
});
if (addrs.unusedAddrs.length > 0 && addrs.unusedAddrs[0] != currentAddr) {
currentAddr = addrs.unusedAddrs[0];
selectedAddr = currentAddr;
}
await saveAddressesInBox();
}
List<AddressInfo> getAddressInfos() {
if (addressInfos.containsKey(0)) {
return addressInfos[0]!;
}
return <AddressInfo>[];
}
Future<void> updateAddress(String address, String label) async {
if (!addressInfos.containsKey(0)) {
return;
}
addressInfos[0]!.forEach((info) {
if (info.address == address) {
info.label = label;
}
});
await saveAddressesInBox();
}
Future<LibAddresses> libAddresses() async {
final nUsed = "10";
var nUnused = "1";
if (this.isEnabledAutoGenerateSubaddress) {
nUnused = "3";
}
final res = await _libwallet.addresses(walletInfo.name, nUsed, nUnused);
final decoded = json.decode(res);
final usedAddrs = List<String>.from(decoded["used"] ?? []);
final unusedAddrs = List<String>.from(decoded["unused"] ?? []);
// index is the index of the first unused address.
final index = decoded["index"] ?? 0;
return new LibAddresses(usedAddrs, unusedAddrs, index);
}
Future<void> generateNewAddress(String label) async {
// NOTE: This will ignore the gap limit and may cause problems when restoring from seed if too
// many addresses are taken and not used.
final addr = await _libwallet.newExternalAddress(walletInfo.name) ?? '';
if (addr == "") {
return;
}
if (!addressesMap.containsKey(addr)) {
addressesMap[addr] = "";
addressInfos[0] ??= [];
addressInfos[0]?.add(AddressInfo(address: addr, label: label, accountIndex: 0));
}
selectedAddr = addr;
await saveAddressesInBox();
}
}
class LibAddresses {
final List<String> usedAddrs, unusedAddrs;
final int firstUnusedAddrIndex;
LibAddresses(this.usedAddrs, this.unusedAddrs, this.firstUnusedAddrIndex);
}

View file

@ -0,0 +1,40 @@
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/hardware/hardware_account_data.dart';
class DecredNewWalletCredentials extends WalletCredentials {
DecredNewWalletCredentials({required String name, WalletInfo? walletInfo})
: super(name: name, walletInfo: walletInfo);
}
class DecredRestoreWalletFromSeedCredentials extends WalletCredentials {
DecredRestoreWalletFromSeedCredentials(
{required String name,
required String password,
required this.mnemonic,
WalletInfo? walletInfo})
: super(name: name, password: password, walletInfo: walletInfo);
final String mnemonic;
}
class DecredRestoreWalletFromPubkeyCredentials extends WalletCredentials {
DecredRestoreWalletFromPubkeyCredentials(
{required String name,
required String password,
required String this.pubkey,
WalletInfo? walletInfo})
: super(name: name, password: password, walletInfo: walletInfo);
final String pubkey;
}
class DecredRestoreWalletFromHardwareCredentials extends WalletCredentials {
DecredRestoreWalletFromHardwareCredentials(
{required String name, required this.hwAccountData, WalletInfo? walletInfo})
: t = throw UnimplementedError(),
super(name: name, walletInfo: walletInfo);
final HardwareAccountData hwAccountData;
final void t;
}

View file

@ -0,0 +1,186 @@
import 'dart:convert';
import 'dart:io';
import 'package:cw_decred/api/libdcrwallet.dart';
import 'package:cw_decred/wallet_creation_credentials.dart';
import 'package:cw_decred/wallet.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
import 'package:collection/collection.dart';
import 'package:cw_core/unspent_coins_info.dart';
class DecredWalletService extends WalletService<
DecredNewWalletCredentials,
DecredRestoreWalletFromSeedCredentials,
DecredRestoreWalletFromPubkeyCredentials,
DecredRestoreWalletFromHardwareCredentials> {
DecredWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final seedRestorePath = "m/44'/42'";
static final seedRestorePathTestnet = "m/44'/1'";
static final pubkeyRestorePath = "m/44'/42'/0'";
static final pubkeyRestorePathTestnet = "m/44'/1'/0'";
final mainnet = "mainnet";
final testnet = "testnet";
Libwallet? libwallet;
Future<void> init() async {
if (libwallet != null) {
return;
}
libwallet = await Libwallet.spawn();
// Use the general path for all dcr wallets as the general log directory.
// Individual wallet paths may be removed if the wallet is deleted.
final dcrLogDir = await pathForWalletDir(name: '', type: WalletType.decred);
libwallet!.initLibdcrwallet(dcrLogDir);
}
void closeLibwallet() {
if (libwallet == null) {
return;
}
libwallet!.close();
libwallet = null;
}
@override
WalletType getType() => WalletType.decred;
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
@override
Future<DecredWallet> create(DecredNewWalletCredentials credentials, {bool? isTestnet}) async {
await this.init();
final config = {
"name": credentials.walletInfo!.name,
"datadir": credentials.walletInfo!.dirPath,
"pass": credentials.password!,
"net": isTestnet == true ? testnet : mainnet,
"unsyncedaddrs": true,
};
await libwallet!.createWallet(jsonEncode(config));
final di = DerivationInfo(
derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath);
credentials.walletInfo!.derivationInfo = di;
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await wallet.init();
return wallet;
}
@override
Future<DecredWallet> openWallet(String name, String password) async {
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
final network = walletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet ||
walletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
? testnet
: mainnet;
await this.init();
final walletDirExists = Directory(walletInfo.dirPath).existsSync();
if (!walletDirExists) {
walletInfo.dirPath = await pathForWalletDir(name: name, type: getType());
}
final config = {
"name": walletInfo.name,
"datadir": walletInfo.dirPath,
"net": network,
"unsyncedaddrs": true,
};
await libwallet!.loadWallet(jsonEncode(config));
final wallet =
DecredWallet(walletInfo, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await wallet.init();
return wallet;
}
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
final network = currentWalletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet ||
currentWalletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
? testnet
: mainnet;
final currentWallet = DecredWallet(
currentWalletInfo, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await currentWallet.renameWalletFiles(newName);
final newDirPath = await pathForWalletDir(name: newName, type: getType());
final newWalletInfo = currentWalletInfo;
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
newWalletInfo.dirPath = newDirPath;
newWalletInfo.network = network;
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
}
@override
Future<DecredWallet> restoreFromSeed(DecredRestoreWalletFromSeedCredentials credentials,
{bool? isTestnet}) async {
await this.init();
final config = {
"name": credentials.walletInfo!.name,
"datadir": credentials.walletInfo!.dirPath,
"pass": credentials.password!,
"mnemonic": credentials.mnemonic,
"net": isTestnet == true ? testnet : mainnet,
"unsyncedaddrs": true,
};
await libwallet!.createWallet(jsonEncode(config));
final di = DerivationInfo(
derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath);
credentials.walletInfo!.derivationInfo = di;
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await wallet.init();
return wallet;
}
// restoreFromKeys only supports restoring a watch only wallet from an account
// pubkey.
@override
Future<DecredWallet> restoreFromKeys(DecredRestoreWalletFromPubkeyCredentials credentials,
{bool? isTestnet}) async {
await this.init();
final config = {
"name": credentials.walletInfo!.name,
"datadir": credentials.walletInfo!.dirPath,
"pubkey": credentials.pubkey,
"net": isTestnet == true ? testnet : mainnet,
"unsyncedaddrs": true,
};
await libwallet!.createWatchOnlyWallet(jsonEncode(config));
final di = DerivationInfo(
derivationPath: isTestnet == true ? pubkeyRestorePathTestnet : pubkeyRestorePath);
credentials.walletInfo!.derivationInfo = di;
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await wallet.init();
return wallet;
}
@override
Future<DecredWallet> restoreFromHardwareWallet(
DecredRestoreWalletFromHardwareCredentials credentials) async =>
throw UnimplementedError();
}

View file

@ -0,0 +1,19 @@
import Cocoa
import FlutterMacOS
public class CwDecredPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "cw_decred", binaryMessenger: registrar.messenger)
let instance = CwDecredPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString)
default:
result(FlutterMethodNotImplemented)
}
}
}

View file

@ -0,0 +1,22 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint cw_decred.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'cw_decred'
s.version = '0.0.1'
s.summary = 'Cake Wallet Decred'
s.description = 'Cake Wallet wrapper over Decred project'
s.homepage = 'http://cakewallet.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Cake Wallet' => 'support@cakewallet.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.dependency 'FlutterMacOS'
s.platform = :osx, '10.11'
s.vendored_libraries = 'External/lib/libdcrwallet.a'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/External/lib/libdcrwallet.a -lstdc++" }
s.swift_version = '5.0'
end

View file

@ -5,18 +5,23 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
url: "https://pub.dev"
source: hosted
version: "47.0.0"
version: "76.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.3"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
url: "https://pub.dev"
source: hosted
version: "4.7.0"
version: "6.11.0"
args:
dependency: transitive
description:
@ -29,10 +34,10 @@ packages:
dependency: transitive
description:
name: asn1lib
sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
url: "https://pub.dev"
source: hosted
version: "1.5.5"
version: "1.5.8"
async:
dependency: transitive
description:
@ -41,6 +46,15 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.0"
blockchain_utils:
dependency: transitive
description:
path: "."
ref: cake-update-v2
resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
url: "https://github.com/cake-tech/blockchain_utils"
source: git
version: "3.3.0"
boolean_selector:
dependency: transitive
description:
@ -61,26 +75,26 @@ packages:
dependency: transitive
description:
name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.0.4"
build_resolvers:
dependency: "direct dev"
description:
name: build_resolvers
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
url: "https://pub.dev"
source: hosted
version: "2.0.10"
version: "2.4.2"
build_runner:
dependency: "direct dev"
description:
@ -93,10 +107,10 @@ packages:
dependency: transitive
description:
name: build_runner_core
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
url: "https://pub.dev"
source: hosted
version: "7.2.10"
version: "7.3.2"
built_collection:
dependency: transitive
description:
@ -109,10 +123,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.5"
cake_backup:
dependency: transitive
description:
@ -138,6 +152,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.3"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.2"
clock:
dependency: transitive
description:
@ -150,18 +172,18 @@ packages:
dependency: transitive
description:
name: code_builder
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.dev"
source: hosted
version: "4.10.0"
version: "4.10.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -205,10 +227,10 @@ packages:
dependency: transitive
description:
name: dart_style
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
url: "https://pub.dev"
source: hosted
version: "2.2.4"
version: "2.3.7"
decimal:
dependency: transitive
description:
@ -234,13 +256,21 @@ packages:
source: hosted
version: "1.3.1"
ffi:
dependency: "direct main"
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
ffigen:
dependency: "direct dev"
description:
name: ffigen
sha256: "2119b4fe3aad0db94dc9531b90283c4640a6231070e613c400b426a4da08c704"
url: "https://pub.dev"
source: hosted
version: "16.1.0"
file:
dependency: transitive
description:
@ -263,13 +293,13 @@ packages:
source: sdk
version: "0.0.0"
flutter_mobx:
dependency: "direct main"
dependency: transitive
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.3.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -287,10 +317,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
graphs:
dependency: transitive
description:
@ -311,36 +341,36 @@ packages:
dependency: "direct dev"
description:
name: hive_generator
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
url: "https://pub.dev"
source: hosted
version: "1.1.3"
version: "2.0.1"
http:
dependency: "direct main"
dependency: transitive
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.1.2"
intl:
dependency: "direct main"
dependency: transitive
description:
name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
@ -351,10 +381,10 @@ packages:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.0.5"
js:
dependency: transitive
description:
@ -375,18 +405,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -403,6 +433,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.0"
macros:
dependency: transitive
description:
name: macros
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
url: "https://pub.dev"
source: hosted
version: "0.1.3-main.0"
matcher:
dependency: transitive
description:
@ -436,21 +474,21 @@ packages:
source: hosted
version: "2.0.0"
mobx:
dependency: "direct main"
dependency: transitive
description:
name: mobx
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
url: "https://pub.dev"
source: hosted
version: "2.3.3+2"
version: "2.5.0"
mobx_codegen:
dependency: "direct dev"
description:
name: mobx_codegen
sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
sha256: "990da80722f7d7c0017dec92040b31545d625b15d40204c36a1e63d167c73cdc"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.7.0"
nested:
dependency: transitive
description:
@ -459,14 +497,23 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
on_chain:
dependency: transitive
description:
path: "."
ref: cake-update-v2
resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
url: "https://github.com/cake-tech/on_chain.git"
source: git
version: "3.7.0"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
path:
dependency: transitive
description:
@ -476,29 +523,29 @@ packages:
source: hosted
version: "1.9.0"
path_provider:
dependency: "direct main"
dependency: transitive
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.15"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@ -567,18 +614,26 @@ packages:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.2.0"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
quiver:
dependency: transitive
description:
name: quiver
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
url: "https://pub.dev"
source: hosted
version: "3.2.2"
rational:
dependency: transitive
description:
@ -591,23 +646,23 @@ packages:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.0.1"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: transitive
description:
@ -620,18 +675,18 @@ packages:
dependency: transitive
description:
name: source_gen
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
url: "https://pub.dev"
source: hosted
version: "1.2.6"
version: "1.5.0"
source_helper:
dependency: transitive
description:
name: source_helper
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
version: "1.3.5"
source_span:
dependency: transitive
description:
@ -644,10 +699,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -660,18 +715,18 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -684,18 +739,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.2"
tuple:
dependency: transitive
description:
@ -732,26 +787,26 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.4"
version: "14.3.0"
watcher:
dependency: "direct overridden"
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -764,10 +819,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
xdg_directories:
dependency: transitive
description:
@ -780,10 +835,18 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
yaml_edit:
dependency: transitive
description:
name: yaml_edit
sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5
url: "https://pub.dev"
source: hosted
version: "2.2.2"
sdks:
dart: ">=3.5.0 <4.0.0"
dart: ">=3.6.0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -1,53 +1,56 @@
name: cw_haven
description: A new flutter plugin project.
name: cw_decred
description: A new Flutter plugin project.
version: 0.0.1
publish_to: none
author: Cake Wallet
homepage: https://cakewallet.com
environment:
sdk: ">=2.17.5 <3.0.0"
flutter: ">=1.20.0"
sdk: '>=3.2.0-0 <4.0.0'
flutter: ">=3.19.0"
dependencies:
flutter:
sdk: flutter
ffi: ^2.0.1
http: ^1.1.0
path_provider: ^2.0.11
mobx: ^2.0.7+4
flutter_mobx: ^2.0.6+1
intl: ^0.19.0
cw_core:
path: ../cw_core
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.4.7
mobx_codegen: ^2.0.7
build_runner: ^2.1.11
build_resolvers: ^2.0.9
hive_generator: ^1.1.3
mobx_codegen: ^2.0.7
hive_generator: ^2.0.1
ffigen: ^16.1.0
dependency_overrides:
watcher: ^1.1.0
ffigen:
name: libdcrwallet
description: Bindings for dcrwallet go library.
output: "lib/api/libdcrwallet_bindings.dart"
headers:
entry-points:
- "lib/api/libdcrwallet.h"
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
# The following section is specific to Flutter packages.
flutter:
# This section identifies this Flutter project as a plugin project.
# The 'pluginClass' and Android 'package' identifiers should not ordinarily
# The androidPackage and pluginClass identifiers should not ordinarily
# be modified. They are used by the tooling to maintain consistency when
# adding or updating assets for this project.
plugin:
platforms:
android:
package: com.cakewallet.cw_haven
pluginClass: CwHavenPlugin
package: com.cakewallet.cw_decred
pluginClass: CwDecredPlugin
ios:
pluginClass: CwHavenPlugin
pluginClass: CwDecredPlugin
macos:
pluginClass: CwDecredPlugin
# To add assets to your plugin package, add an assets section, like this:
# assets:
@ -58,7 +61,7 @@ flutter:
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# https://flutter.dev/assets-and-images/#resolution-aware
# To add custom fonts to your plugin package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a

7
cw_haven/.gitignore vendored
View file

@ -1,7 +0,0 @@
.DS_Store
.dart_tool/
.packages
.pub/
build/

View file

@ -1,10 +0,0 @@
# 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 and should not be manually edited.
version:
revision: 4d7946a68d26794349189cf21b3f68cc6fe61dcb
channel: stable
project_type: plugin

View file

@ -1,3 +0,0 @@
## 0.0.1
* TODO: Describe initial release.

View file

@ -1,15 +0,0 @@
# cw_haven
A new flutter plugin project.
## Getting Started
This project is a starting point for a Flutter
[plug-in package](https://flutter.dev/developing-packages/),
a specialized package that includes platform-specific implementation code for
Android and/or iOS.
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View file

@ -1,220 +0,0 @@
cmake_minimum_required(VERSION 3.4.1)
add_library( cw_haven
SHARED
../ios/Classes/haven_api.cpp)
find_library( log-lib log )
set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../../cw_shared_external/ios/External/android)
############
# libsodium
############
add_library(sodium STATIC IMPORTED)
set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libsodium.a)
############
# OpenSSL
############
add_library(crypto STATIC IMPORTED)
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libcrypto.a)
add_library(ssl STATIC IMPORTED)
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libssl.a)
############
# Boost
############
add_library(boost_chrono STATIC IMPORTED)
set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_chrono.a)
add_library(boost_date_time STATIC IMPORTED)
set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_date_time.a)
add_library(boost_filesystem STATIC IMPORTED)
set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_filesystem.a)
add_library(boost_program_options STATIC IMPORTED)
set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_program_options.a)
add_library(boost_regex STATIC IMPORTED)
set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_regex.a)
add_library(boost_serialization STATIC IMPORTED)
set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_serialization.a)
add_library(boost_system STATIC IMPORTED)
set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_system.a)
add_library(boost_thread STATIC IMPORTED)
set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_thread.a)
add_library(boost_wserialization STATIC IMPORTED)
set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_wserialization.a)
#############
# Haven
#############
add_library(wallet_api STATIC IMPORTED)
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet_api.a)
add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet.a)
add_library(cryptonote_core STATIC IMPORTED)
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcryptonote_core.a)
add_library(cryptonote_basic STATIC IMPORTED)
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcryptonote_basic.a)
add_library(mnemonics STATIC IMPORTED)
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libmnemonics.a)
add_library(common STATIC IMPORTED)
set_target_properties(common PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcommon.a)
add_library(cncrypto STATIC IMPORTED)
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcncrypto.a)
add_library(ringct STATIC IMPORTED)
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libringct.a)
add_library(ringct_basic STATIC IMPORTED)
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libringct_basic.a)
add_library(blockchain_db STATIC IMPORTED)
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libblockchain_db.a)
add_library(lmdb STATIC IMPORTED)
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/liblmdb.a)
add_library(easylogging STATIC IMPORTED)
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libeasylogging.a)
add_library(unbound STATIC IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libunbound.a)
add_library(epee STATIC IMPORTED)
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libepee.a)
add_library(checkpoints STATIC IMPORTED)
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcheckpoints.a)
add_library(device STATIC IMPORTED)
set_target_properties(device PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libdevice.a)
add_library(device_trezor STATIC IMPORTED)
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libdevice_trezor.a)
add_library(multisig STATIC IMPORTED)
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libmultisig.a)
add_library(version STATIC IMPORTED)
set_target_properties(version PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libversion.a)
add_library(net STATIC IMPORTED)
set_target_properties(net PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libnet.a)
add_library(hardforks STATIC IMPORTED)
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libhardforks.a)
add_library(randomx STATIC IMPORTED)
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/librandomx.a)
add_library(offshore STATIC IMPORTED)
set_target_properties(offshore PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/liboffshore.a)
add_library(rpc_base STATIC IMPORTED)
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/librpc_base.a)
add_library(wallet-crypto STATIC IMPORTED)
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet-crypto.a)
include_directories( ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/include )
target_link_libraries( cw_haven
wallet_api
wallet
cryptonote_core
cryptonote_basic
mnemonics
ringct
ringct_basic
net
common
cncrypto
blockchain_db
lmdb
easylogging
unbound
epee
checkpoints
device
device_trezor
multisig
version
randomx
offshore
hardforks
rpc_base
boost_chrono
boost_date_time
boost_filesystem
boost_program_options
boost_regex
boost_serialization
boost_system
boost_thread
boost_wserialization
ssl
crypto
sodium
${log-lib} )

View file

@ -1,3 +0,0 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

View file

@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

View file

@ -1 +0,0 @@
rootProject.name = 'cw_haven'

View file

@ -1,3 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cakewallet.cw_haven">
</manifest>

View file

@ -1,4 +0,0 @@
#import <Flutter/Flutter.h>
@interface CwHavenPlugin : NSObject<FlutterPlugin>
@end

View file

@ -1,15 +0,0 @@
#import "CwHavenPlugin.h"
#if __has_include(<cw_haven/cw_haven-Swift.h>)
#import <cw_haven/cw_haven-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import "cw_haven-Swift.h"
#endif
@implementation CwHavenPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftCwHavenPlugin registerWithRegistrar:registrar];
}
@end

View file

@ -1,14 +0,0 @@
import Flutter
import UIKit
public class SwiftCwHavenPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "cw_haven", binaryMessenger: registrar.messenger())
let instance = SwiftCwHavenPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
result("iOS " + UIDevice.current.systemVersion)
}
}

View file

@ -1,942 +0,0 @@
#include <stdint.h>
#include "cstdlib"
#include <chrono>
#include <functional>
#include <iostream>
#include <unistd.h>
#include <mutex>
#include "thread"
#if __APPLE__
// Fix for randomx on ios
void __clear_cache(void* start, void* end) { }
#include "../External/ios/include/wallet2_api.h"
#else
#include "../External/android/include/wallet2_api.h"
#endif
using namespace std::chrono_literals;
#ifdef __cplusplus
extern "C"
{
#endif
const uint64_t MONERO_BLOCK_SIZE = 1000;
struct Utf8Box
{
char *value;
Utf8Box(char *_value)
{
value = _value;
}
};
struct SubaddressRow
{
uint64_t id;
char *address;
char *label;
SubaddressRow(std::size_t _id, char *_address, char *_label)
{
id = static_cast<uint64_t>(_id);
address = _address;
label = _label;
}
};
struct AccountRow
{
uint64_t id;
char *label;
AccountRow(std::size_t _id, char *_label)
{
id = static_cast<uint64_t>(_id);
label = _label;
}
};
struct HavenBalance
{
uint64_t amount;
char *assetType;
HavenBalance(char *_assetType, uint64_t _amount)
{
amount = _amount;
assetType = _assetType;
}
};
struct HavenRate
{
uint64_t rate;
char *assetType;
HavenRate(char *_assetType, uint64_t _rate)
{
rate = _rate;
assetType = _assetType;
}
};
struct MoneroWalletListener : Monero::WalletListener
{
uint64_t m_height;
bool m_need_to_refresh;
bool m_new_transaction;
MoneroWalletListener()
{
m_height = 0;
m_need_to_refresh = false;
m_new_transaction = false;
}
void moneySpent(const std::string &txId, uint64_t amount, std::string assetType)
{
m_new_transaction = true;
}
void moneyReceived(const std::string &txId, uint64_t amount, std::string assetType)
{
m_new_transaction = true;
}
void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
{
m_new_transaction = true;
}
void newBlock(uint64_t height)
{
m_height = height;
}
void updated()
{
m_new_transaction = true;
}
void refreshed()
{
m_need_to_refresh = true;
}
void resetNeedToRefresh()
{
m_need_to_refresh = false;
}
bool isNeedToRefresh()
{
return m_need_to_refresh;
}
bool isNewTransactionExist()
{
return m_new_transaction;
}
void resetIsNewTransactionExist()
{
m_new_transaction = false;
}
uint64_t height()
{
return m_height;
}
};
struct TransactionInfoRow
{
uint64_t amount;
uint64_t fee;
uint64_t blockHeight;
uint64_t confirmations;
uint32_t subaddrAccount;
int8_t direction;
int8_t isPending;
uint32_t subaddrIndex;
char *hash;
char *paymentId;
char *assetType;
int64_t datetime;
TransactionInfoRow(Monero::TransactionInfo *transaction)
{
amount = transaction->amount();
fee = transaction->fee();
blockHeight = transaction->blockHeight();
subaddrAccount = transaction->subaddrAccount();
std::set<uint32_t>::iterator it = transaction->subaddrIndex().begin();
subaddrIndex = *it;
confirmations = transaction->confirmations();
datetime = static_cast<int64_t>(transaction->timestamp());
direction = transaction->direction();
isPending = static_cast<int8_t>(transaction->isPending());
std::string *hash_str = new std::string(transaction->hash());
hash = strdup(hash_str->c_str());
paymentId = strdup(transaction->paymentId().c_str());
assetType = strdup(transaction->assetType().c_str());
}
};
struct PendingTransactionRaw
{
uint64_t amount;
uint64_t fee;
char *hash;
Monero::PendingTransaction *transaction;
PendingTransactionRaw(Monero::PendingTransaction *_transaction)
{
transaction = _transaction;
amount = _transaction->amount();
fee = _transaction->fee();
hash = strdup(_transaction->txid()[0].c_str());
}
};
Monero::Wallet *m_wallet;
Monero::TransactionHistory *m_transaction_history;
MoneroWalletListener *m_listener;
Monero::Subaddress *m_subaddress;
Monero::SubaddressAccount *m_account;
uint64_t m_last_known_wallet_height;
uint64_t m_cached_syncing_blockchain_height = 0;
std::mutex store_lock;
bool is_storing = false;
void change_current_wallet(Monero::Wallet *wallet)
{
m_wallet = wallet;
m_listener = nullptr;
if (wallet != nullptr)
{
m_transaction_history = wallet->history();
}
else
{
m_transaction_history = nullptr;
}
if (wallet != nullptr)
{
m_account = wallet->subaddressAccount();
}
else
{
m_account = nullptr;
}
if (wallet != nullptr)
{
m_subaddress = wallet->subaddress();
}
else
{
m_subaddress = nullptr;
}
}
Monero::Wallet *get_current_wallet()
{
return m_wallet;
}
bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error)
{
Monero::WalletManagerFactory::setLogLevel(4);
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
Monero::Wallet *wallet = walletManager->createWallet(path, password, language, _networkType);
int status;
std::string errorString;
wallet->statusWithErrorString(status, errorString);
if (wallet->status() != Monero::Wallet::Status_Ok)
{
error = strdup(wallet->errorString().c_str());
return false;
}
change_current_wallet(wallet);
return true;
}
bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error)
{
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->recoveryWallet(
std::string(path),
std::string(password),
std::string(seed),
_networkType,
(uint64_t)restoreHeight);
int status;
std::string errorString;
wallet->statusWithErrorString(status, errorString);
if (status != Monero::Wallet::Status_Ok || !errorString.empty())
{
error = strdup(errorString.c_str());
return false;
}
change_current_wallet(wallet);
return true;
}
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)
{
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createWalletFromKeys(
std::string(path),
std::string(password),
std::string(language),
_networkType,
(uint64_t)restoreHeight,
std::string(address),
std::string(viewKey),
std::string(spendKey));
int status;
std::string errorString;
wallet->statusWithErrorString(status, errorString);
if (status != Monero::Wallet::Status_Ok || !errorString.empty())
{
error = strdup(errorString.c_str());
return false;
}
change_current_wallet(wallet);
return true;
}
bool load_wallet(char *path, char *password, int32_t nettype)
{
nice(19);
Monero::NetworkType networkType = static_cast<Monero::NetworkType>(nettype);
Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
Monero::Wallet *wallet = walletManager->openWallet(std::string(path), std::string(password), networkType);
int status;
std::string errorString;
wallet->statusWithErrorString(status, errorString);
change_current_wallet(wallet);
return !(status != Monero::Wallet::Status_Ok || !errorString.empty());
}
char *error_string() {
return strdup(get_current_wallet()->errorString().c_str());
}
bool is_wallet_exist(char *path)
{
return Monero::WalletManagerFactory::getWalletManager()->walletExists(std::string(path));
}
void close_current_wallet()
{
Monero::WalletManagerFactory::getWalletManager()->closeWallet(get_current_wallet());
change_current_wallet(nullptr);
}
char *get_filename()
{
return strdup(get_current_wallet()->filename().c_str());
}
char *secret_view_key()
{
return strdup(get_current_wallet()->secretViewKey().c_str());
}
char *public_view_key()
{
return strdup(get_current_wallet()->publicViewKey().c_str());
}
char *secret_spend_key()
{
return strdup(get_current_wallet()->secretSpendKey().c_str());
}
char *public_spend_key()
{
return strdup(get_current_wallet()->publicSpendKey().c_str());
}
char *get_address(uint32_t account_index, uint32_t address_index)
{
return strdup(get_current_wallet()->address(account_index, address_index).c_str());
}
const char *seed()
{
return strdup(get_current_wallet()->seed().c_str());
}
int64_t *get_full_balance(uint32_t account_index)
{
std::map<std::string, uint64_t> accountBalance;
std::map<uint32_t, std::map<std::string, uint64_t>> balanceSubaddresses = get_current_wallet()->balance(account_index);
std::vector<std::string> assetList = Monero::Assets::list();
//prefill balances
for (const auto &asset_type : assetList) {
accountBalance[asset_type] = 0;
}
// balances are mapped to their subaddress
// we compute total balances of account
for (auto const& balanceSubaddress : balanceSubaddresses)
{
std::map<std::string, uint64_t> balanceOfSubaddress = balanceSubaddress.second;
for (auto const& balance : balanceOfSubaddress)
{
const std::string &assetType = balance.first;
const uint64_t &amount = balance.second;
accountBalance[assetType] +=amount;
}
}
size_t size = accountBalance.size();
int64_t *balanceAddresses = (int64_t *)malloc(size * sizeof(int64_t));
int i = 0;
for (auto const& balance : accountBalance)
{
char *assetType = strdup(balance.first.c_str());
HavenBalance *hb = new HavenBalance(assetType, balance.second);
balanceAddresses[i] = reinterpret_cast<int64_t>(hb);
i++;
}
return balanceAddresses;
}
int64_t *get_unlocked_balance(uint32_t account_index)
{
std::map<std::string, uint64_t> accountBalance;
std::map<uint32_t, std::map<std::string, uint64_t>> balanceSubaddresses = get_current_wallet()->unlockedBalance(account_index);
std::vector<std::string> assetList = Monero::Assets::list();
//prefill balances
for (const auto &asset_type : assetList) {
accountBalance[asset_type] = 0;
}
// balances are mapped to their subaddress
// we compute total balances of account
for (auto const& balanceSubaddress : balanceSubaddresses)
{
std::map<std::string, uint64_t> balanceOfSubaddress = balanceSubaddress.second;
for (auto const& balance : balanceOfSubaddress)
{
const std::string &assetType = balance.first;
const uint64_t &amount = balance.second;
accountBalance[assetType] +=amount;
}
}
size_t size = accountBalance.size();
int64_t *balanceAddresses = (int64_t *)malloc(size * sizeof(int64_t));
int i = 0;
for (auto const& balance : accountBalance)
{
char *assetType = strdup(balance.first.c_str());
HavenBalance *hb = new HavenBalance(assetType, balance.second);
balanceAddresses[i] = reinterpret_cast<int64_t>(hb);
i++;
}
return balanceAddresses;
}
uint64_t get_current_height()
{
return get_current_wallet()->blockChainHeight();
}
uint64_t get_node_height()
{
return get_current_wallet()->daemonBlockChainHeight();
}
bool connect_to_node(char *error)
{
nice(19);
bool is_connected = get_current_wallet()->connectToDaemon();
if (!is_connected)
{
error = strdup(get_current_wallet()->errorString().c_str());
}
return is_connected;
}
bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error)
{
nice(19);
Monero::Wallet *wallet = get_current_wallet();
std::string _login = "";
std::string _password = "";
if (login != nullptr)
{
_login = std::string(login);
}
if (password != nullptr)
{
_password = std::string(password);
}
bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet);
if (!inited)
{
error = strdup(wallet->errorString().c_str());
} else if (!wallet->connectToDaemon()) {
error = strdup(wallet->errorString().c_str());
}
return inited;
}
bool is_connected()
{
return get_current_wallet()->connected();
}
void start_refresh()
{
get_current_wallet()->refreshAsync();
get_current_wallet()->startRefresh();
}
void set_refresh_from_block_height(uint64_t height)
{
get_current_wallet()->setRefreshFromBlockHeight(height);
}
void set_recovering_from_seed(bool is_recovery)
{
get_current_wallet()->setRecoveringFromSeed(is_recovery);
}
void store(char *path)
{
store_lock.lock();
if (is_storing) {
return;
}
is_storing = true;
get_current_wallet()->store(std::string(path));
is_storing = false;
store_lock.unlock();
}
bool set_password(char *password, Utf8Box &error) {
bool is_changed = get_current_wallet()->setPassword(std::string(password));
if (!is_changed) {
error = Utf8Box(strdup(get_current_wallet()->errorString().c_str()));
}
return is_changed;
}
bool transaction_create(char *address, char *asset_type, char *payment_id, char *amount,
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
{
nice(19);
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
std::string _payment_id;
Monero::PendingTransaction *transaction;
if (payment_id != nullptr)
{
_payment_id = std::string(payment_id);
}
if (amount != nullptr)
{
uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account, {});
}
else
{
transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(),std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account, {});
}
int status = transaction->status();
if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
{
error = Utf8Box(strdup(transaction->errorString().c_str()));
return false;
}
if (m_listener != nullptr) {
m_listener->m_new_transaction = true;
}
pendingTransaction = PendingTransactionRaw(transaction);
return true;
}
bool transaction_create_mult_dest(char **addresses, char *asset_type, char *payment_id, char **amounts, uint32_t size,
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
{
nice(19);
std::vector<std::string> _addresses;
std::vector<uint64_t> _amounts;
for (int i = 0; i < size; i++) {
_addresses.push_back(std::string(*addresses));
_amounts.push_back(Monero::Wallet::amountFromString(std::string(*amounts)));
addresses++;
amounts++;
}
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
std::string _payment_id;
Monero::PendingTransaction *transaction;
if (payment_id != nullptr)
{
_payment_id = std::string(payment_id);
}
transaction = m_wallet->createTransactionMultDest(_addresses, _payment_id, _amounts,
std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account,{});
int status = transaction->status();
if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
{
error = Utf8Box(strdup(transaction->errorString().c_str()));
return false;
}
if (m_listener != nullptr) {
m_listener->m_new_transaction = true;
}
pendingTransaction = PendingTransactionRaw(transaction);
return true;
}
bool transaction_commit(PendingTransactionRaw *transaction, Utf8Box &error)
{
bool committed = transaction->transaction->commit();
if (!committed)
{
error = Utf8Box(strdup(transaction->transaction->errorString().c_str()));
} else if (m_listener != nullptr) {
m_listener->m_new_transaction = true;
}
return committed;
}
uint64_t get_node_height_or_update(uint64_t base_eight)
{
if (m_cached_syncing_blockchain_height < base_eight) {
m_cached_syncing_blockchain_height = base_eight;
}
return m_cached_syncing_blockchain_height;
}
uint64_t get_syncing_height()
{
if (m_listener == nullptr) {
return 0;
}
uint64_t height = m_listener->height();
if (height <= 1) {
return 0;
}
if (height != m_last_known_wallet_height)
{
m_last_known_wallet_height = height;
}
return height;
}
uint64_t is_needed_to_refresh()
{
if (m_listener == nullptr) {
return false;
}
bool should_refresh = m_listener->isNeedToRefresh();
if (should_refresh) {
m_listener->resetNeedToRefresh();
}
return should_refresh;
}
uint8_t is_new_transaction_exist()
{
if (m_listener == nullptr) {
return false;
}
bool is_new_transaction_exist = m_listener->isNewTransactionExist();
if (is_new_transaction_exist)
{
m_listener->resetIsNewTransactionExist();
}
return is_new_transaction_exist;
}
void set_listener()
{
m_last_known_wallet_height = 0;
if (m_listener != nullptr)
{
free(m_listener);
}
m_listener = new MoneroWalletListener();
get_current_wallet()->setListener(m_listener);
}
int64_t *subaddrress_get_all()
{
std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
size_t size = _subaddresses.size();
int64_t *subaddresses = (int64_t *)malloc(size * sizeof(int64_t));
for (int i = 0; i < size; i++)
{
Monero::SubaddressRow *row = _subaddresses[i];
SubaddressRow *_row = new SubaddressRow(row->getRowId(), strdup(row->getAddress().c_str()), strdup(row->getLabel().c_str()));
subaddresses[i] = reinterpret_cast<int64_t>(_row);
}
return subaddresses;
}
int32_t subaddrress_size()
{
std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
return _subaddresses.size();
}
void subaddress_add_row(uint32_t accountIndex, char *label)
{
m_subaddress->addRow(accountIndex, std::string(label));
}
void subaddress_set_label(uint32_t accountIndex, uint32_t addressIndex, char *label)
{
m_subaddress->setLabel(accountIndex, addressIndex, std::string(label));
}
void subaddress_refresh(uint32_t accountIndex)
{
m_subaddress->refresh(accountIndex);
}
int32_t account_size()
{
std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
return _accocunts.size();
}
int64_t *account_get_all()
{
std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
size_t size = _accocunts.size();
int64_t *accocunts = (int64_t *)malloc(size * sizeof(int64_t));
for (int i = 0; i < size; i++)
{
Monero::SubaddressAccountRow *row = _accocunts[i];
AccountRow *_row = new AccountRow(row->getRowId(), strdup(row->getLabel().c_str()));
accocunts[i] = reinterpret_cast<int64_t>(_row);
}
return accocunts;
}
void account_add_row(char *label)
{
m_account->addRow(std::string(label));
}
void account_set_label_row(uint32_t account_index, char *label)
{
m_account->setLabel(account_index, label);
}
void account_refresh()
{
m_account->refresh();
}
int64_t *transactions_get_all()
{
std::vector<Monero::TransactionInfo *> transactions = m_transaction_history->getAll();
size_t size = transactions.size();
int64_t *transactionAddresses = (int64_t *)malloc(size * sizeof(int64_t));
for (int i = 0; i < size; i++)
{
Monero::TransactionInfo *row = transactions[i];
TransactionInfoRow *tx = new TransactionInfoRow(row);
transactionAddresses[i] = reinterpret_cast<int64_t>(tx);
}
return transactionAddresses;
}
void transactions_refresh()
{
m_transaction_history->refresh();
}
int64_t transactions_count()
{
return m_transaction_history->count();
}
int LedgerExchange(
unsigned char *command,
unsigned int cmd_len,
unsigned char *response,
unsigned int max_resp_len)
{
return -1;
}
int LedgerFind(char *buffer, size_t len)
{
return -1;
}
void on_startup()
{
Monero::Utils::onStartup();
Monero::WalletManagerFactory::setLogLevel(4);
}
void rescan_blockchain()
{
m_wallet->rescanBlockchainAsync();
}
char * get_tx_key(char * txId)
{
return strdup(m_wallet->getTxKey(std::string(txId)).c_str());
}
int32_t asset_types_size()
{
return Monero::Assets::list().size();
}
char **asset_types()
{
size_t size = Monero::Assets::list().size();
std::vector<std::string> assetList = Monero::Assets::list();
char **assetTypesPts;
assetTypesPts = (char **) malloc( size * sizeof(char*));
for (int i = 0; i < size; i++)
{
std::string asset = assetList[i];
//assetTypes[i] = (char *)malloc( 5 * sizeof(char));
assetTypesPts[i] = strdup(asset.c_str());
}
return assetTypesPts;
}
std::map<std::string, uint64_t> rates;
void update_rate()
{
rates = get_current_wallet()->oracleRates();
}
int64_t *get_rate()
{
size_t size = rates.size();
int64_t *havenRates = (int64_t *)malloc(size * sizeof(int64_t));
int i = 0;
for (auto const& rate : rates)
{
char *assetType = strdup(rate.first.c_str());
HavenRate *havenRate = new HavenRate(assetType, rate.second);
havenRates[i] = reinterpret_cast<int64_t>(havenRate);
i++;
}
return havenRates;
}
int32_t size_of_rate()
{
return static_cast<int32_t>(rates.size());
}
void set_trusted_daemon(bool arg)
{
m_wallet->setTrustedDaemon(arg);
}
bool trusted_daemon()
{
return m_wallet->trustedDaemon();
}
#ifdef __cplusplus
}
#endif

View file

@ -1,50 +0,0 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint cw_haven.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'cw_haven'
s.version = '0.0.1'
s.summary = 'Cake Wallet Haven'
s.description = 'Cake Wallet wrapper over Haven project'
s.homepage = 'http://cakewallet.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Cake Wallet' => 'support@cakewallet.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h, Classes/*.h, ../shared_external/ios/libs/monero/include/src/**/*.h, ../shared_external/ios/libs/monero/include/contrib/**/*.h, ../shared_external/ios/libs/monero/include/../shared_external/ios/**/*.h'
s.dependency 'Flutter'
s.dependency 'cw_shared_external'
s.platform = :ios, '10.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
s.swift_version = '5.0'
s.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/Classes/*.h" }
s.subspec 'OpenSSL' do |openssl|
openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
openssl.libraries = 'ssl', 'crypto'
openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Sodium' do |sodium|
sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libsodium.a'
sodium.libraries = 'sodium'
sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Boost' do |boost|
boost.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h',
boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libboost.a',
boost.libraries = 'boost'
boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Haven' do |haven|
haven.preserve_paths = 'External/ios/include/**/*.h'
haven.vendored_libraries = 'External/ios/lib/libhaven.a'
haven.libraries = 'haven'
haven.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
end
end

View file

@ -1,81 +0,0 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:cw_haven/api/structs/account_row.dart';
import 'package:cw_haven/api/wallet.dart';
final accountSizeNative = havenApi
.lookup<NativeFunction<account_size>>('account_size')
.asFunction<SubaddressSize>();
final accountRefreshNative = havenApi
.lookup<NativeFunction<account_refresh>>('account_refresh')
.asFunction<AccountRefresh>();
final accountGetAllNative = havenApi
.lookup<NativeFunction<account_get_all>>('account_get_all')
.asFunction<AccountGetAll>();
final accountAddNewNative = havenApi
.lookup<NativeFunction<account_add_new>>('account_add_row')
.asFunction<AccountAddNew>();
final accountSetLabelNative = havenApi
.lookup<NativeFunction<account_set_label>>('account_set_label_row')
.asFunction<AccountSetLabel>();
bool isUpdating = false;
void refreshAccounts() {
try {
isUpdating = true;
accountRefreshNative();
isUpdating = false;
} catch (e) {
isUpdating = false;
rethrow;
}
}
List<AccountRow> getAllAccount() {
final size = accountSizeNative();
final accountAddressesPointer = accountGetAllNative();
final accountAddresses = accountAddressesPointer.asTypedList(size);
return accountAddresses
.map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
.toList();
}
void addAccountSync({required String label}) {
final labelPointer = label.toNativeUtf8();
accountAddNewNative(labelPointer);
calloc.free(labelPointer);
}
void setLabelForAccountSync({required int accountIndex, required String label}) {
final labelPointer = label.toNativeUtf8();
accountSetLabelNative(accountIndex, labelPointer);
calloc.free(labelPointer);
}
void _addAccount(String label) => addAccountSync(label: label);
void _setLabelForAccount(Map<String, dynamic> args) {
final label = args['label'] as String;
final accountIndex = args['accountIndex'] as int;
setLabelForAccountSync(label: label, accountIndex: accountIndex);
}
Future<void> addAccount({required String label}) async {
_addAccount(label);
await store();
}
Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
_setLabelForAccount({'accountIndex': accountIndex, 'label': label});
await store();
}

View file

@ -1,23 +0,0 @@
import 'dart:ffi';
import 'package:cw_haven/api/convert_utf8_to_string.dart';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:ffi/ffi.dart';
final assetTypesSizeNative = havenApi
.lookup<NativeFunction<account_size>>('asset_types_size')
.asFunction<SubaddressSize>();
final getAssetTypesNative = havenApi
.lookup<NativeFunction<asset_types>>('asset_types')
.asFunction<AssetTypes>();
List<String> getAssetTypes() {
List<String> assetTypes = [];
Pointer<Pointer<Utf8>> assetTypePointers = getAssetTypesNative();
Pointer<Utf8> assetpointer = assetTypePointers.elementAt(0)[0];
String asset = convertUTF8ToString(pointer: assetpointer);
return assetTypes;
}

View file

@ -1,58 +0,0 @@
import 'dart:ffi';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:cw_haven/api/structs/haven_balance_row.dart';
import 'package:cw_haven/api/structs/haven_rate.dart';
import 'asset_types.dart';
List<HavenBalanceRow> getHavenFullBalance({int accountIndex = 0}) {
final size = assetTypesSizeNative();
final balanceAddressesPointer = getHavenFullBalanceNative(accountIndex);
final balanceAddresses = balanceAddressesPointer.asTypedList(size);
return balanceAddresses
.map((addr) => Pointer<HavenBalanceRow>.fromAddress(addr).ref)
.toList();
}
List<HavenBalanceRow> getHavenUnlockedBalance({int accountIndex = 0}) {
final size = assetTypesSizeNative();
final balanceAddressesPointer = getHavenUnlockedBalanceNative(accountIndex);
final balanceAddresses = balanceAddressesPointer.asTypedList(size);
return balanceAddresses
.map((addr) => Pointer<HavenBalanceRow>.fromAddress(addr).ref)
.toList();
}
List<HavenRate> getRate() {
updateRateNative();
final size = sizeOfRateNative();
final ratePointer = getRateNative();
final rate = ratePointer.asTypedList(size);
return rate
.map((addr) => Pointer<HavenRate>.fromAddress(addr).ref)
.toList();
}
final getHavenFullBalanceNative = havenApi
.lookup<NativeFunction<get_full_balance>>('get_full_balance')
.asFunction<GetHavenFullBalance>();
final getHavenUnlockedBalanceNative = havenApi
.lookup<NativeFunction<get_unlocked_balance>>('get_unlocked_balance')
.asFunction<GetHavenUnlockedBalance>();
final getRateNative = havenApi
.lookup<NativeFunction<get_rate>>('get_rate')
.asFunction<GetRate>();
final sizeOfRateNative = havenApi
.lookup<NativeFunction<size_of_rate>>('size_of_rate')
.asFunction<SizeOfRate>();
final updateRateNative = havenApi
.lookup<NativeFunction<update_rate>>('update_rate')
.asFunction<UpdateRate>();

View file

@ -1,8 +0,0 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
String convertUTF8ToString({required Pointer<Utf8> pointer}) {
final str = pointer.toDartString();
calloc.free(pointer);
return str;
}

View file

@ -1,14 +0,0 @@
import 'dart:async';
import 'package:flutter/services.dart';
class CwHaven {
static const MethodChannel _channel =
const MethodChannel('cw_haven');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod<String>('getPlatformVersion') ?? '';
return version;
}
}

View file

@ -1,5 +0,0 @@
class ConnectionToNodeException implements Exception {
ConnectionToNodeException({required this.message});
final String message;
}

View file

@ -1,8 +0,0 @@
class CreationTransactionException implements Exception {
CreationTransactionException({required this.message});
final String message;
@override
String toString() => message;
}

View file

@ -1,10 +0,0 @@
class SetupWalletException implements Exception {
SetupWalletException({required this.message});
final String message;
@override
String toString() {
return message;
}
}

View file

@ -1,8 +0,0 @@
class WalletCreationException implements Exception {
WalletCreationException({required this.message});
final String message;
@override
String toString() => message;
}

View file

@ -1,8 +0,0 @@
class WalletOpeningException implements Exception {
WalletOpeningException({required this.message});
final String message;
@override
String toString() => message;
}

View file

@ -1,10 +0,0 @@
class WalletRestoreFromKeysException implements Exception {
WalletRestoreFromKeysException({required this.message});
final String message;
@override
String toString() {
return message;
}
}

View file

@ -1,5 +0,0 @@
class WalletRestoreFromSeedException implements Exception {
WalletRestoreFromSeedException({required this.message});
final String message;
}

View file

@ -1,6 +0,0 @@
import 'dart:ffi';
import 'dart:io';
final DynamicLibrary havenApi = Platform.isAndroid
? DynamicLibrary.open("libcw_haven.so")
: DynamicLibrary.open("cw_haven.framework/cw_haven");

View file

@ -1,8 +0,0 @@
import 'package:flutter/foundation.dart';
class MoneroOutput {
MoneroOutput({required this.address, required this.amount});
final String address;
final String amount;
}

View file

@ -1,144 +0,0 @@
import 'dart:ffi';
import 'package:cw_haven/api/structs/pending_transaction.dart';
import 'package:cw_haven/api/structs/ut8_box.dart';
import 'package:ffi/ffi.dart';
typedef create_wallet = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Pointer<Utf8>);
typedef restore_wallet_from_seed = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
typedef load_wallet = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
typedef error_string = Pointer<Utf8> Function();
typedef get_filename = Pointer<Utf8> Function();
typedef get_seed = Pointer<Utf8> Function();
typedef get_address = Pointer<Utf8> Function(Int32, Int32);
typedef get_full_balance = Pointer<Int64> Function(Int32);
typedef get_unlocked_balance = Pointer<Int64> Function(Int32);
typedef get_full_balanace = Int64 Function(Int32);
typedef get_unlocked_balanace = Int64 Function(Int32);
typedef get_current_height = Int64 Function();
typedef get_node_height = Int64 Function();
typedef is_connected = Int8 Function();
typedef setup_node = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>?, Pointer<Utf8>?, Int8, Int8, Pointer<Utf8>?, Pointer<Utf8>);
typedef start_refresh = Void Function();
typedef connect_to_node = Int8 Function();
typedef set_refresh_from_block_height = Void Function(Int64);
typedef set_recovering_from_seed = Void Function(Int8);
typedef store_c = Void Function(Pointer<Utf8>);
typedef set_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
typedef set_listener = Void Function();
typedef get_syncing_height = Int64 Function();
typedef is_needed_to_refresh = Int8 Function();
typedef is_new_transaction_exist = Int8 Function();
typedef subaddrress_size = Int32 Function();
typedef subaddrress_refresh = Void Function(Int32);
typedef subaddress_get_all = Pointer<Int64> Function();
typedef subaddress_add_new = Void Function(
Int32 accountIndex, Pointer<Utf8> label);
typedef subaddress_set_label = Void Function(
Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
typedef account_size = Int32 Function();
typedef account_refresh = Void Function();
typedef account_get_all = Pointer<Int64> Function();
typedef account_add_new = Void Function(Pointer<Utf8> label);
typedef account_set_label = Void Function(
Int32 accountIndex, Pointer<Utf8> label);
typedef transactions_refresh = Void Function();
typedef get_tx_key = Pointer<Utf8>? Function(Pointer<Utf8> txId);
typedef transactions_count = Int64 Function();
typedef transactions_get_all = Pointer<Int64> Function();
typedef transaction_create = Int8 Function(
Pointer<Utf8> address,
Pointer<Utf8> assetType,
Pointer<Utf8> paymentId,
Pointer<Utf8> amount,
Int8 priorityRaw,
Int32 subaddrAccount,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef transaction_create_mult_dest = Int8 Function(
Pointer<Pointer<Utf8>> addresses,
Pointer<Utf8> assetType,
Pointer<Utf8> paymentId,
Pointer<Pointer<Utf8>> amounts,
Int32 size,
Int8 priorityRaw,
Int32 subaddrAccount,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef transaction_commit = Int8 Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
typedef secret_view_key = Pointer<Utf8> Function();
typedef public_view_key = Pointer<Utf8> Function();
typedef secret_spend_key = Pointer<Utf8> Function();
typedef public_spend_key = Pointer<Utf8> Function();
typedef close_current_wallet = Void Function();
typedef on_startup = Void Function();
typedef rescan_blockchain = Void Function();
typedef asset_types = Pointer<Pointer<Utf8>> Function();
typedef asset_types_size = Int32 Function();
typedef get_rate = Pointer<Int64> Function();
typedef size_of_rate = Int32 Function();
typedef update_rate = Void Function();
typedef set_trusted_daemon = Void Function(Int8 trusted);
typedef trusted_daemon = Int8 Function();

View file

@ -1,12 +0,0 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class AccountRow extends Struct {
@Int64()
external int id;
external Pointer<Utf8> label;
String getLabel() => label.toDartString();
int getId() => id;
}

View file

@ -1,12 +0,0 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class HavenBalanceRow extends Struct {
@Int64()
external int amount;
external Pointer<Utf8> assetType;
int getAmount() => amount;
String getAssetType() => assetType.toDartString();
}

View file

@ -1,12 +0,0 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class HavenRate extends Struct {
@Int64()
external int rate;
external Pointer<Utf8> assetType;
int getRate() => rate;
String getAssetType() => assetType.toDartString();
}

View file

@ -1,27 +0,0 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class PendingTransactionRaw extends Struct {
@Int64()
external int amount;
@Int64()
external int fee;
external Pointer<Utf8> hash;
String getHash() => hash.toDartString();
}
class PendingTransactionDescription {
PendingTransactionDescription({
required this.amount,
required this.fee,
required this.hash,
required this.pointerAddress});
final int amount;
final int fee;
final String hash;
final int pointerAddress;
}

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