mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-04-21 13:38:15 +00:00
Compare commits
374 commits
Author | SHA1 | Date | |
---|---|---|---|
|
e2014df4df | ||
|
2aedb15489 | ||
|
aa53690f06 | ||
|
89f55c7fec | ||
|
6aa6b8c950 | ||
|
7f69eb8eff | ||
|
f45f8cfa76 | ||
|
7c408a1af6 | ||
|
13d23a42e3 | ||
|
a4de7d34cc | ||
|
27dd2a2134 | ||
|
422c191e65 | ||
|
56bcc23c74 | ||
|
b435838dc3 | ||
|
6534bf62dd | ||
|
29416bdfc6 | ||
|
f43a0ba97d | ||
|
d9acb6728a | ||
|
906c2c3a97 | ||
|
913a4ac7c5 | ||
|
d2e77c9ff0 | ||
|
93212d7970 | ||
|
cfba818f12 | ||
|
ce639c9955 | ||
|
a1b4a35180 | ||
|
86e8c38266 | ||
|
321ae2e7ad | ||
|
fcc2df5e5b | ||
|
5bb7813234 | ||
|
02fec3d581 | ||
|
3251159814 | ||
|
a62b58041a | ||
|
72fa218a98 | ||
|
ec2777b9ff | ||
|
65e6c50a66 | ||
|
6f8c6003d1 | ||
|
dabb2aa1b3 | ||
|
d789ae120b | ||
|
815c16a736 | ||
|
f1014a6c78 | ||
|
3fbc6daba0 | ||
|
15a7a34ece | ||
|
3118968230 | ||
|
37f318a902 | ||
|
42d7275b51 | ||
|
7cf966c443 | ||
|
03f4b2fdea | ||
|
4431d8c689 | ||
|
50163b5d19 | ||
|
78b4e2d6b7 | ||
|
22ff0b1709 | ||
|
e18a254f0c | ||
|
ae0631adeb | ||
|
302ceaaf1f | ||
|
176ed0f89f | ||
|
a503861c0f | ||
|
b32ec57a8d | ||
|
87101c86c2 | ||
|
8c48930feb | ||
|
e4ac7d8569 | ||
|
65782bb711 | ||
|
574d0e82ff | ||
|
fe43785546 | ||
|
f77950de68 | ||
|
e07d878eae | ||
|
8f5d17d026 | ||
|
a40fdfecda | ||
|
6e04f8e34d | ||
|
2298a12afb | ||
|
6361d9f048 | ||
|
ce5d9d43e1 | ||
|
d835b14230 | ||
|
1cddb14bf1 | ||
|
5adfee831e | ||
|
b3e02b64de | ||
|
564c3ba715 | ||
|
441bc8c113 | ||
|
8e703f128c | ||
|
c24935dabf | ||
|
fe2514e97e | ||
|
b190907cae | ||
|
e39c817ec5 | ||
|
6b33aee103 | ||
|
30dedee63f | ||
|
6e725a5bb5 | ||
|
4feb14c7da | ||
|
0f7e44fadd | ||
|
08c5a5fbc7 | ||
|
0d20cb6b3b | ||
|
dd67d2fdbb | ||
|
f7b73620e2 | ||
|
4e26e4c246 | ||
|
c1cd9869c0 | ||
|
448fd0c94d | ||
|
0ed0ef3ed9 | ||
|
f56519ec14 | ||
|
8c6f660ec6 | ||
|
2879e5bc03 | ||
|
a06945b3a2 | ||
|
8b41d0b588 | ||
|
102fab5fae | ||
|
0dad4ad591 | ||
|
2f02d4dc58 | ||
|
e04efc7247 | ||
|
1463ea7972 | ||
|
e1964ea68e | ||
|
c6bff81648 | ||
|
7a3558e7e9 | ||
|
24a20238bc | ||
|
96478de9cc | ||
|
5f9466ca3c | ||
|
34cee82018 | ||
|
2061eba2f2 | ||
|
2edfe0f3cc | ||
|
709eebc1b7 | ||
|
dbc805ed21 | ||
|
7439dbf9fc | ||
|
bf5bfc3d71 | ||
|
60d47f235d | ||
|
48d2ac5e9b | ||
|
3146f4dce9 | ||
|
5ddde67555 | ||
|
fd223ddaea | ||
|
03dcb2babf | ||
|
44f0d0d8df | ||
|
ed65ab5648 | ||
|
29802ddda5 | ||
|
7dd919f795 | ||
|
6539b75f9f | ||
|
05767dea13 | ||
|
9fc6368644 | ||
|
edaaeda838 | ||
|
ae97d3ce24 | ||
|
a576e45199 | ||
|
ad07d7abb9 | ||
|
0d1bfc191f | ||
|
06b0584691 | ||
|
7cdbe581ef | ||
|
116b5747cf | ||
|
63474ac6eb | ||
|
321cf855a7 | ||
|
51b0cc1510 | ||
|
cd9907db5c | ||
|
667f2f504e | ||
|
f1e1bd0dc0 | ||
|
534ee51275 | ||
|
cdffec81df | ||
|
69b3e9b1ab | ||
|
6d291408a3 | ||
|
873fc63045 | ||
|
5a39bb2b64 | ||
|
3ea469bb1f | ||
|
c277cd9641 | ||
|
0623023b3a | ||
|
2e737b5911 | ||
|
5169dfd7fe | ||
|
1c6b84c823 | ||
|
56314e7f24 | ||
|
024086910b | ||
|
8ca4421c2a | ||
|
694910ab18 | ||
|
2dfacd42c5 | ||
|
c4db10c9d3 | ||
|
4589e42ac8 | ||
|
68c7ba6910 | ||
|
176f0ba331 | ||
|
b9ed3ae0a0 | ||
|
452f4a7daa | ||
|
b05f664088 | ||
|
de047339f8 | ||
|
90e421174a | ||
|
75f6e65fd9 | ||
|
1d9b2e39fe | ||
|
6c31e4662d | ||
|
1a3a09a325 | ||
|
ab450684b2 | ||
|
9bd343c987 | ||
|
128dc14ce7 | ||
|
cb11d58c47 | ||
|
1a094d3745 | ||
|
a01dce1c72 | ||
|
38e66bfcb1 | ||
|
0d1bf5895d | ||
|
ad667025ac | ||
|
e7ad498b71 | ||
|
975fe733f0 | ||
|
22f9d4c653 | ||
|
130895a449 | ||
|
2aa548e3e0 | ||
|
4c7cb0c309 | ||
|
b44cde334c | ||
|
516b503f31 | ||
|
1137b50b8a | ||
|
d64c344fd0 | ||
|
4fc2a7acfa | ||
|
ba1ab977d6 | ||
|
0e32e8a408 | ||
|
f97ef50978 | ||
|
4439ad70d2 | ||
|
2028505367 | ||
|
1884bfbaf7 | ||
|
c1ef98833a | ||
|
ae10bef0ee | ||
|
d6aec00b58 | ||
|
744f273862 | ||
|
34ad1d9022 | ||
|
e9aa2d6a30 | ||
|
eeb595e0d9 | ||
|
2e0ac0b2f5 | ||
|
c56038cadf | ||
|
9c64ed6316 | ||
|
120952156f | ||
|
3adddc2368 | ||
|
e749c62ccd | ||
|
cdf2dd8819 | ||
|
4af7243265 | ||
|
2873595e40 | ||
|
71609c34b0 | ||
|
937550cb04 | ||
|
fed7ae91d9 | ||
|
e9252a4d46 | ||
|
ec1b5d7d2b | ||
|
4a59505c30 | ||
|
3f8cf2583c | ||
|
9eb233ec76 | ||
|
cd068eefc7 | ||
|
a74c565f9a | ||
|
465a8b4c96 | ||
|
c3a64b154b | ||
|
64dd830e58 | ||
|
86e3bf0349 | ||
|
840b6f9c99 | ||
|
9f0f94b29b | ||
|
3266e4e055 | ||
|
925b58be50 | ||
|
9e988b8ba5 | ||
|
dbf68f2a68 | ||
|
1ce4bee68c | ||
|
d6abd7d658 | ||
|
3fb18bf2db | ||
|
b548386097 | ||
|
800de8873d | ||
|
cd003ba412 | ||
|
7d047e8d47 | ||
|
31fe9a538b | ||
|
d87af969d6 | ||
|
25c6c7590b | ||
|
8a63c42582 | ||
|
7b603cd7f9 | ||
|
4197ff40f4 | ||
|
d6d4df7822 | ||
|
6cfe9e9c0f | ||
|
f38efd35e9 | ||
|
d8ec93fb30 | ||
|
537e44f1f8 | ||
|
2431d5f300 | ||
|
9a2589b4c3 | ||
|
7511ce2ac3 | ||
|
973d8b3eee | ||
|
6dd7ef183a | ||
|
216719ba56 | ||
|
91de7ddbc0 | ||
|
0ce0350039 | ||
|
db7422a100 | ||
|
9c9a9f8d3e | ||
|
40b0f49f20 | ||
|
3566d75d58 | ||
|
31e785c23f | ||
|
6c42da2add | ||
|
f41a85bd6e | ||
|
ae9a844ed8 | ||
|
4594801cf3 | ||
|
f15d051108 | ||
|
5496d2de96 | ||
|
0d8df43d97 | ||
|
b84c3ab2d3 | ||
|
6494bec72b | ||
|
48d46cd18c | ||
|
f2a654e1e5 | ||
|
1d22eed7c4 | ||
|
44f9886ffd | ||
|
3177fadea6 | ||
|
5452598064 | ||
|
98d77621b2 | ||
|
e95d5a10b6 | ||
|
6ff539e71b | ||
|
3da57bc150 | ||
|
1f0ee995b9 | ||
|
53eb6ac8d1 | ||
|
3d2d0e4e73 | ||
|
0080d25436 | ||
|
9cde0a1f65 | ||
|
a03b0ec2aa | ||
|
016a53f8eb | ||
|
809a5a38e7 | ||
|
d3d6709763 | ||
|
f0070b5aa8 | ||
|
11d1ceb40f | ||
|
699990883c | ||
|
e6b0733044 | ||
|
217bf9e301 | ||
|
07bf622fcd | ||
|
bb2e8580e2 | ||
|
b1eeddced1 | ||
|
c913b05fc9 | ||
|
16b9254761 | ||
|
4109e7ed9f | ||
|
e2f3a1ad79 | ||
|
b4610fb5b0 | ||
|
c13549472d | ||
|
75f3fe42c7 | ||
|
a04ea494a9 | ||
|
fec5f5883f | ||
|
44fbab715a | ||
|
e0d2c8ec74 | ||
|
7d5cb72884 | ||
|
2c86520f37 | ||
|
a779259b06 | ||
|
29e63ca97d | ||
|
7d60793c88 | ||
|
642f0906b8 | ||
|
cdd9e078f8 | ||
|
754f9b45fa | ||
|
4961908c28 | ||
|
05a5d18773 | ||
|
2a605c012f | ||
|
a3d3237e03 | ||
|
4473e3d086 | ||
|
4a5cc3a968 | ||
|
8cc3737dea | ||
|
f942ecd653 | ||
|
9a7ac9b615 | ||
|
98d7ce3a8e | ||
|
3573f70004 | ||
|
412e3fdf07 | ||
|
94757f0f2e | ||
|
53df0ecfb2 | ||
|
8e62c4257b | ||
|
1c73ac2635 | ||
|
98986d74f0 | ||
|
f4b5060c8c | ||
|
8e5284854d | ||
|
0cbc678b08 | ||
|
1740a42020 | ||
|
6cbc37f42c | ||
|
e0051c8af2 | ||
|
57a50a96cd | ||
|
f7b367a3aa | ||
|
21334121c1 | ||
|
f6fe01f6d8 | ||
|
9279295484 | ||
|
51c45d4332 | ||
|
99ea691bef | ||
|
c47bf0b21c | ||
|
2a2c42f23e | ||
|
233029ca21 | ||
|
b0128c867c | ||
|
b9b152a00e | ||
|
9ac0dd809e | ||
|
155395b977 | ||
|
c34938a9be | ||
|
0e0f9803cb | ||
|
87ca5b909d | ||
|
1ec7ee95d2 | ||
|
02dc5c9416 | ||
|
e3d040b9b8 | ||
|
56dcc0ba4a | ||
|
2af6e32392 | ||
|
49ad183ff7 | ||
|
5b324a0fc5 | ||
|
27d319cece | ||
|
9c37f99e9e | ||
|
cec219f3f9 | ||
|
f5489feae7 |
522 changed files with 31908 additions and 12962 deletions
.gitignore.gitmodules
android
asset_sources
default_themes
svg
assets/gif
crypto_plugins
docs
fastlane
Appfile
metadata/android/en-US
changelogs
full_description.txtimages
icon.png
short_description.txtphoneScreenshots
05a1aa12278525211a470eb8a4636ea21eac6172836117bc05b5446c25008abe.png1f346858134354959f6d0c4c7776245b125d92235b3d0190f92c44616dc8a509.png29bb7d3c55248043cdcb1db7528c01b3c8bd329b85e1de1e1cc9467a1885bd26.png337c2f1ca500347ade5d2b42ace7f3d72455acbe8a200995789c8e1c6d1a1c38.png6e64d5cfe73fc22c796f621e9caa35b44799fde6ae444b93f9d1d4eaa656ea82.png990f447807ee10406e8992b6b86653308f97b95e602b7080df0138a3973a971a.png9bf57ffd707362f7780534786ec909a7bf3077c54bacc5e20631edcc3e2435db.png
ios
MoneroWallet.framework
Podfile.lockRunner.xcodeproj/xcshareddata/xcschemes
Runner
WowneroWallet.framework
lib
app_config.dart
db
electrumx_rpc
cached_electrumx_client.dartclient_manager.dartelectrumx_client.dartsubscribable_electrumx_client.dart
exceptions/wallet
main.dartmodels
electrumx_response
exchange
change_now
response_objects
simpleswap
isar
exchange_cache
models
address_label.g.dartblock_explorer.g.dart
ordinal.g.dartstack_theme.dartstack_theme.g.dartblockchain_data
contact_entry.g.dartencrypted_string_value.g.dartethereum
firo_specific
log.g.dartsent_to_address.g.darttransaction_note.g.dartkeys
namecoin_dns
node_model.darttype_adaptors
networking
pages/add_wallet_views
33
.gitignore
vendored
33
.gitignore
vendored
|
@ -20,6 +20,9 @@
|
|||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
#CppWinRT manual install
|
||||
Microsoft.Windows*
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
|
@ -29,6 +32,7 @@
|
|||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
android/app/.cxx
|
||||
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
|
@ -58,8 +62,6 @@ coverage
|
|||
scripts/**/build
|
||||
/lib/external_api_keys.dart
|
||||
|
||||
libcw_monero.dll
|
||||
libcw_wownero.dll
|
||||
libepic_cash_wallet.dll
|
||||
libmobileliblelantus.dll
|
||||
libtor_ffi.dll
|
||||
|
@ -69,6 +71,10 @@ secp256k1.dll
|
|||
/lib/app_config.g.dart
|
||||
/android/app/src/main/app_icon-playstore.png
|
||||
|
||||
# Dart generated files (Freezed, Riverpod, GoRouter etc..)
|
||||
lib/**/*.g.dart
|
||||
lib/**/*.freezed.dart
|
||||
|
||||
## other generated project files
|
||||
|
||||
pubspec.yaml
|
||||
|
@ -101,21 +107,8 @@ pubspec.yaml
|
|||
# FVM Version Cache
|
||||
.fvm/
|
||||
|
||||
android/app/src/main/jniLibs/arm64-v8a/libwownero_wallet2_api_c.so
|
||||
android/app/src/main/jniLibs/arm64-v8a/libmonero_wallet2_api_c.so
|
||||
android/app/src/main/jniLibs/armeabi-v7a/libmonero_wallet2_api_c.so
|
||||
android/app/src/main/jniLibs/armeabi-v7a/libwownero_wallet2_api_c.so
|
||||
android/app/src/main/jniLibs/x86_64/libmonero_wallet2_api_c.so
|
||||
android/app/src/main/jniLibs/x86_64/libwownero_wallet2_api_c.so
|
||||
macos/monero_wallet2_api_c.dylib
|
||||
macos/wownero_wallet2_api_c.dylib
|
||||
/macos/monero_libwallet2_api_c.dylib
|
||||
/macos/wownero_libwallet2_api_c.dylib
|
||||
/ios/monero_libwallet2_api_c.dylib
|
||||
/ios/wownero_libwallet2_api_c.dylib
|
||||
/android/app/src/main/jniLibs/arm64-v8a/libmonero_libwallet2_api_c.so
|
||||
/android/app/src/main/jniLibs/armeabi-v7a/libmonero_libwallet2_api_c.so
|
||||
/android/app/src/main/jniLibs/x86_64/libmonero_libwallet2_api_c.so
|
||||
/android/app/src/main/jniLibs/arm64-v8a/libwownero_libwallet2_api_c.so
|
||||
/android/app/src/main/jniLibs/armeabi-v7a/libwownero_libwallet2_api_c.so
|
||||
/android/app/src/main/jniLibs/x86_64/libwownero_libwallet2_api_c.so
|
||||
scripts/linux/build/libsecret/subprojects/gi-docgen/.meson-subproject-wrap-hash.txt
|
||||
|
||||
crypto_plugins/cs_monero/built_outputs
|
||||
crypto_plugins/cs_monero/build
|
||||
crypto_plugins/*.diff
|
||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,9 +1,6 @@
|
|||
[submodule "crypto_plugins/flutter_libepiccash"]
|
||||
path = crypto_plugins/flutter_libepiccash
|
||||
url = https://github.com/cypherstack/flutter_libepiccash.git
|
||||
[submodule "crypto_plugins/flutter_libmonero"]
|
||||
path = crypto_plugins/flutter_libmonero
|
||||
url = https://github.com/cypherstack/flutter_libmonero.git
|
||||
[submodule "crypto_plugins/flutter_liblelantus"]
|
||||
path = crypto_plugins/flutter_liblelantus
|
||||
url = https://github.com/cypherstack/flutter_liblelantus.git
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '2.0.20'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.3.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
|
@ -18,12 +5,12 @@ allprojects {
|
|||
}
|
||||
}
|
||||
|
||||
rootProject.buildDir = '../build'
|
||||
rootProject.buildDir = "../build"
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
project.evaluationDependsOn(":app")
|
||||
}
|
||||
|
||||
tasks.register("clean", Delete) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.enableR8=true
|
||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.enableJetifier=true
|
|
@ -1,6 +1,5 @@
|
|||
#Fri Jun 23 08:50:38 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
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 localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||
def properties = new Properties()
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
assert localPropertiesFile.exists()
|
||||
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version '8.7.0' apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
asset_sources/svg/campfire/churn.svg
Normal file
3
asset_sources/svg/campfire/churn.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.77444 13.4823C9.60687 13.4092 9.43072 13.3749 9.25027 13.3749H3.75081C2.99076 13.3749 2.37594 13.9897 2.37594 14.7497C2.37594 15.5098 2.99076 16.1246 3.75081 16.1246H5.93126L1.40279 20.6531C0.865736 21.1901 0.865736 22.0602 1.40279 22.5972C1.93985 23.1343 2.80988 23.1343 3.34694 22.5972L7.8754 18.0709V20.2492C7.8754 21.0092 8.49023 21.6241 9.25027 21.6241C10.0103 21.6241 10.6251 21.0092 10.6251 20.2492V14.7497C10.6251 14.5708 10.5887 14.3926 10.5192 14.2247C10.3802 13.8861 10.1139 13.6198 9.77444 13.4823ZM14.2256 10.5177C14.3931 10.5908 14.5693 10.6251 14.7497 10.6251H20.2492C21.0092 10.6251 21.6241 10.0103 21.6241 9.25027C21.6241 8.49023 21.0092 7.8754 20.2492 7.8754H18.0687L22.5972 3.34694C23.1343 2.80988 23.1343 1.93985 22.5972 1.40279C22.0606 0.866166 21.1905 0.865306 20.6531 1.40279L16.1246 5.93341V3.75081C16.1246 2.99076 15.5098 2.37594 14.7497 2.37594C13.9897 2.37594 13.3749 2.99076 13.3749 3.75081V9.25027C13.3749 9.42917 13.4113 9.60739 13.4807 9.7753C13.6198 10.1139 13.8861 10.3802 14.2256 10.5177ZM9.25027 2.37594C8.4898 2.37594 7.8754 2.99076 7.8754 3.75081V5.93126L3.34823 1.40387C2.81117 0.86681 1.94114 0.86681 1.40408 1.40387C0.867025 1.94092 0.867025 2.81096 1.40408 3.34801L5.93341 7.8754H3.75081C2.99076 7.8754 2.37594 8.4898 2.37594 9.25027C2.37594 10.0107 2.99076 10.6251 3.75081 10.6251H9.25027C9.42917 10.6251 9.60739 10.5887 9.7753 10.5192C10.1139 10.3802 10.3802 10.1139 10.5177 9.77444C10.5908 9.60687 10.6251 9.43072 10.6251 9.25027V3.75081C10.6251 2.99076 10.0107 2.37594 9.25027 2.37594ZM18.0709 16.1246H20.2492C21.0092 16.1246 21.6241 15.5098 21.6241 14.7497C21.6241 13.9897 21.0092 13.3749 20.2492 13.3749H14.7497C14.5708 13.3749 14.3926 13.4113 14.2247 13.4806C13.8879 13.6199 13.6198 13.8879 13.4806 14.2247C13.4092 14.3931 13.3749 14.5693 13.3749 14.7497V20.2492C13.3749 21.0092 13.9897 21.6241 14.7497 21.6241C15.5098 21.6241 16.1246 21.0092 16.1246 20.2492V18.0687L20.6531 22.5972C21.1901 23.1343 22.0602 23.1343 22.5972 22.5972C23.1338 22.0606 23.1347 21.1905 22.5972 20.6531L18.0709 16.1246Z" fill="black"/>
|
||||
</svg>
|
After (image error) Size: 2.1 KiB |
3
asset_sources/svg/stack_duo/churn.svg
Normal file
3
asset_sources/svg/stack_duo/churn.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.77444 13.4823C9.60687 13.4092 9.43072 13.3749 9.25027 13.3749H3.75081C2.99076 13.3749 2.37594 13.9897 2.37594 14.7497C2.37594 15.5098 2.99076 16.1246 3.75081 16.1246H5.93126L1.40279 20.6531C0.865736 21.1901 0.865736 22.0602 1.40279 22.5972C1.93985 23.1343 2.80988 23.1343 3.34694 22.5972L7.8754 18.0709V20.2492C7.8754 21.0092 8.49023 21.6241 9.25027 21.6241C10.0103 21.6241 10.6251 21.0092 10.6251 20.2492V14.7497C10.6251 14.5708 10.5887 14.3926 10.5192 14.2247C10.3802 13.8861 10.1139 13.6198 9.77444 13.4823ZM14.2256 10.5177C14.3931 10.5908 14.5693 10.6251 14.7497 10.6251H20.2492C21.0092 10.6251 21.6241 10.0103 21.6241 9.25027C21.6241 8.49023 21.0092 7.8754 20.2492 7.8754H18.0687L22.5972 3.34694C23.1343 2.80988 23.1343 1.93985 22.5972 1.40279C22.0606 0.866166 21.1905 0.865306 20.6531 1.40279L16.1246 5.93341V3.75081C16.1246 2.99076 15.5098 2.37594 14.7497 2.37594C13.9897 2.37594 13.3749 2.99076 13.3749 3.75081V9.25027C13.3749 9.42917 13.4113 9.60739 13.4807 9.7753C13.6198 10.1139 13.8861 10.3802 14.2256 10.5177ZM9.25027 2.37594C8.4898 2.37594 7.8754 2.99076 7.8754 3.75081V5.93126L3.34823 1.40387C2.81117 0.86681 1.94114 0.86681 1.40408 1.40387C0.867025 1.94092 0.867025 2.81096 1.40408 3.34801L5.93341 7.8754H3.75081C2.99076 7.8754 2.37594 8.4898 2.37594 9.25027C2.37594 10.0107 2.99076 10.6251 3.75081 10.6251H9.25027C9.42917 10.6251 9.60739 10.5887 9.7753 10.5192C10.1139 10.3802 10.3802 10.1139 10.5177 9.77444C10.5908 9.60687 10.6251 9.43072 10.6251 9.25027V3.75081C10.6251 2.99076 10.0107 2.37594 9.25027 2.37594ZM18.0709 16.1246H20.2492C21.0092 16.1246 21.6241 15.5098 21.6241 14.7497C21.6241 13.9897 21.0092 13.3749 20.2492 13.3749H14.7497C14.5708 13.3749 14.3926 13.4113 14.2247 13.4806C13.8879 13.6199 13.6198 13.8879 13.4806 14.2247C13.4092 14.3931 13.3749 14.5693 13.3749 14.7497V20.2492C13.3749 21.0092 13.9897 21.6241 14.7497 21.6241C15.5098 21.6241 16.1246 21.0092 16.1246 20.2492V18.0687L20.6531 22.5972C21.1901 23.1343 22.0602 23.1343 22.5972 22.5972C23.1338 22.0606 23.1347 21.1905 22.5972 20.6531L18.0709 16.1246Z" fill="black"/>
|
||||
</svg>
|
After (image error) Size: 2.1 KiB |
3
asset_sources/svg/stack_wallet/churn.svg
Normal file
3
asset_sources/svg/stack_wallet/churn.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.77444 13.4823C9.60687 13.4092 9.43072 13.3749 9.25027 13.3749H3.75081C2.99076 13.3749 2.37594 13.9897 2.37594 14.7497C2.37594 15.5098 2.99076 16.1246 3.75081 16.1246H5.93126L1.40279 20.6531C0.865736 21.1901 0.865736 22.0602 1.40279 22.5972C1.93985 23.1343 2.80988 23.1343 3.34694 22.5972L7.8754 18.0709V20.2492C7.8754 21.0092 8.49023 21.6241 9.25027 21.6241C10.0103 21.6241 10.6251 21.0092 10.6251 20.2492V14.7497C10.6251 14.5708 10.5887 14.3926 10.5192 14.2247C10.3802 13.8861 10.1139 13.6198 9.77444 13.4823ZM14.2256 10.5177C14.3931 10.5908 14.5693 10.6251 14.7497 10.6251H20.2492C21.0092 10.6251 21.6241 10.0103 21.6241 9.25027C21.6241 8.49023 21.0092 7.8754 20.2492 7.8754H18.0687L22.5972 3.34694C23.1343 2.80988 23.1343 1.93985 22.5972 1.40279C22.0606 0.866166 21.1905 0.865306 20.6531 1.40279L16.1246 5.93341V3.75081C16.1246 2.99076 15.5098 2.37594 14.7497 2.37594C13.9897 2.37594 13.3749 2.99076 13.3749 3.75081V9.25027C13.3749 9.42917 13.4113 9.60739 13.4807 9.7753C13.6198 10.1139 13.8861 10.3802 14.2256 10.5177ZM9.25027 2.37594C8.4898 2.37594 7.8754 2.99076 7.8754 3.75081V5.93126L3.34823 1.40387C2.81117 0.86681 1.94114 0.86681 1.40408 1.40387C0.867025 1.94092 0.867025 2.81096 1.40408 3.34801L5.93341 7.8754H3.75081C2.99076 7.8754 2.37594 8.4898 2.37594 9.25027C2.37594 10.0107 2.99076 10.6251 3.75081 10.6251H9.25027C9.42917 10.6251 9.60739 10.5887 9.7753 10.5192C10.1139 10.3802 10.3802 10.1139 10.5177 9.77444C10.5908 9.60687 10.6251 9.43072 10.6251 9.25027V3.75081C10.6251 2.99076 10.0107 2.37594 9.25027 2.37594ZM18.0709 16.1246H20.2492C21.0092 16.1246 21.6241 15.5098 21.6241 14.7497C21.6241 13.9897 21.0092 13.3749 20.2492 13.3749H14.7497C14.5708 13.3749 14.3926 13.4113 14.2247 13.4806C13.8879 13.6199 13.6198 13.8879 13.4806 14.2247C13.4092 14.3931 13.3749 14.5693 13.3749 14.7497V20.2492C13.3749 21.0092 13.9897 21.6241 14.7497 21.6241C15.5098 21.6241 16.1246 21.0092 16.1246 20.2492V18.0687L20.6531 22.5972C21.1901 23.1343 22.0602 23.1343 22.5972 22.5972C23.1338 22.0606 23.1347 21.1905 22.5972 20.6531L18.0709 16.1246Z" fill="black"/>
|
||||
</svg>
|
After (image error) Size: 2.1 KiB |
BIN
assets/gif/monero-chan-dance.gif
Normal file
BIN
assets/gif/monero-chan-dance.gif
Normal file
Binary file not shown.
After ![]() (image error) Size: 2.2 MiB |
|
@ -1 +1 @@
|
|||
Subproject commit 46a7da857d4113eb3998567b18ac0b33a470f4fd
|
||||
Subproject commit 25e6cb3a3e7bee04e425af6beccb47e8d0708fdb
|
|
@ -1 +1 @@
|
|||
Subproject commit f8746dbef5c5ad5ed2dad12f615723d087083e9c
|
||||
Subproject commit 7b325030bce46a423aa46497d1a608b7a8a58976
|
|
@ -1 +0,0 @@
|
|||
Subproject commit c0b8994009d29bc7fd2f0f2edbb004c39bf93951
|
|
@ -1 +1 @@
|
|||
Subproject commit 2a74a97fb0f0e22a5280b22c010b710cdeec33bb
|
||||
Subproject commit 6f1310eccd336fb3c8dc00b61e39a3f0f3a2b59a
|
|
@ -13,12 +13,12 @@ Here you will find instructions on how to install the necessary tools for buildi
|
|||
The following instructions are for building and running on a Linux host. Alternatively, see the [Mac](#mac-host) and/or [Windows](#windows-host) section. This entire section (except for the Android Studio section) needs to be completed in WSL if building on a Windows host.
|
||||
|
||||
### Flutter
|
||||
Install Flutter 3.22.1 by [following their guide](https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk). You can also clone https://github.com/flutter/flutter, check out the `3.22.1` tag, and add its `flutter/bin` folder to your PATH as in
|
||||
Install Flutter 3.29.2 by [following their guide](https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk). You can also clone https://github.com/flutter/flutter, check out the `3.29.2` tag, and add its `flutter/bin` folder to your PATH as in
|
||||
```sh
|
||||
FLUTTER_DIR="$HOME/development/flutter"
|
||||
git clone https://github.com/flutter/flutter.git "$FLUTTER_DIR"
|
||||
cd "$FLUTTER_DIR"
|
||||
git checkout 3.22.1
|
||||
git checkout 3.29.2
|
||||
echo 'export PATH="$PATH:'"$FLUTTER_DIR"'/bin"' >> "$HOME/.profile"
|
||||
source "$HOME/.profile"
|
||||
flutter precache
|
||||
|
@ -38,7 +38,7 @@ Use `Tools > SDK Manager` to install:
|
|||
- `SDK Tools > Android SDK command line tools`
|
||||
- `SDK Tools > CMake`
|
||||
and for Android builds,
|
||||
- `SDK Tools > Android SDK (API 30)`
|
||||
- `SDK Tools > Android SDK (API 35)`
|
||||
- `SDK Tools > NDK`
|
||||
|
||||
Then in `File > Settings > Plugins`, install the **Flutter** and **Dart** plugins and restart the IDE. In `File > Settings > Languages & Frameworks > Flutter > Editor`, enable auto format on save to match the project's code style. If you have problems with the Dart SDK, make sure to run `flutter` in a terminal to download it (use `source ~/.bashrc` to update your environment variables if you're still using the same terminal from which you ran `setup.sh`). Run `flutter doctor` to install any missing dependencies and review and agree to any license agreements.
|
||||
|
@ -53,16 +53,28 @@ sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-
|
|||
### Build dependencies
|
||||
Install basic dependencies
|
||||
```
|
||||
sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm python3-distutils g++ gcc gperf libopencv-dev
|
||||
sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python3 libtool libtinfo6 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm g++ gcc gperf libopencv-dev python3-typogrify xsltproc valac gobject-introspection meson
|
||||
```
|
||||
|
||||
Install [Rust](https://www.rust-lang.org/tools/install) with command:
|
||||
For Ubuntu 20.04,
|
||||
```
|
||||
sudo apt-get install valac
|
||||
pip3 install --upgrade meson==0.64.1 markdown==3.4.1 markupsafe==2.1.1 jinja2==3.1.2 pygments==2.13.0 toml==0.10.2 typogrify==2.0.7 tomli==2.0.1
|
||||
```
|
||||
|
||||
For Ubuntu 24.04,
|
||||
```
|
||||
sudo apt install pipx libgcrypt20-dev libglib2.0-dev libsecret-1-dev
|
||||
pipx install meson==0.64.1 markdown==3.4.1 markupsafe==2.1.1 jinja2==3.1.2 pygments==2.13.0 toml==0.10.2 typogrify==2.0.7 tomli==2.0.1
|
||||
```
|
||||
|
||||
Install [Rust](https://www.rust-lang.org/tools/install) via [rustup.rs](https://rustup.rs), the required Rust toolchains, and `cargo-ndk` with command:
|
||||
```
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source ~/.bashrc
|
||||
rustup install 1.67.1 1.72.0 1.73.0
|
||||
rustup default 1.67.1
|
||||
cargo install cargo-ndk --version 2.12.7 --locked
|
||||
source ~/.bashrc
|
||||
rustup install 1.85.1 1.81.0
|
||||
rustup default 1.85.1
|
||||
cargo install cargo-ndk
|
||||
```
|
||||
|
||||
Android specific dependencies:
|
||||
|
@ -77,6 +89,7 @@ sudo apt-get install clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev
|
|||
pip3 install --upgrade meson==0.64.1 markdown==3.4.1 markupsafe==2.1.1 jinja2==3.1.2 pygments==2.13.0 toml==0.10.2 typogrify==2.0.7 tomli==2.0.1
|
||||
```
|
||||
|
||||
### Clone the repository and initialize submodules
|
||||
After installing the prerequisites listed above, download the code and init the submodules
|
||||
```
|
||||
git clone https://github.com/cypherstack/stack_wallet.git
|
||||
|
@ -92,17 +105,15 @@ cd scripts/linux
|
|||
cd ../..
|
||||
```
|
||||
|
||||
### Build coinlib
|
||||
Coinlib's native secp256k1 library must be built prior to running Stack Wallet. It can be built from within the root `stack_wallet` folder on a...
|
||||
- Linux host for Linux targets: `dart run coinlib:build_linux`, or
|
||||
### Build secp256k1
|
||||
Coinlib requires a secp256k1 library to be built prior to running Stack Wallet. It can be built from within the root `stack_wallet` folder on a...
|
||||
- Linux host for Linux targets: `dart run coinlib:build_linux` (requires [Docker](https://docs.docker.com/engine/install/ubuntu/) or [`podman`](https://podman.io/docs/installation))
|
||||
- Linux host for Windows targets: `dart run coinlib:build_windows_crosscompile`
|
||||
- Windows host: `dart run coinlib:build_windows`
|
||||
- WSL2 host: `dart run coinlib:build_wsl`
|
||||
- macOS host: `dart run coinlib:build_macos`
|
||||
|
||||
To build coinlib on Linux, you will need `docker` (see [installation instructions](https://docs.docker.com/engine/install/ubuntu/)) or [`podman`](https://podman.io/docs/installation) (`sudo apt-get -y install podman`)
|
||||
|
||||
For Windows targets, you can use a `secp256k1.dll` produced by any of the three middle options if the first attempt doesn't succeed.
|
||||
or by using `scripts/linux/build_secp256k1.sh` or `scripts/windows/build_secp256k1.bat`.
|
||||
|
||||
### Run prebuild script
|
||||
|
||||
|
@ -117,7 +128,7 @@ or manually by creating the files referenced in that script with the specified c
|
|||
|
||||
### Build plugins
|
||||
#### Build script: `build_app.sh`
|
||||
The `build_app.sh` script is use to build applications Stack Wallet. View the script's help message with `./build_app.sh -h` for more information on its usage.
|
||||
The `build_app.sh` script is used to build the Stack Wallet and its family of applications. View the script's help message with `./build_app.sh -h` for more information on its usage.
|
||||
|
||||
Options:
|
||||
|
||||
|
@ -145,24 +156,17 @@ cd scripts
|
|||
./build_app.sh -a stack_wallet -p linux
|
||||
```
|
||||
|
||||
##### Remove system packages (may be needed for building flutter_libmonero)
|
||||
[`flutter_libmonero`](https://github.com/cypherstack/flutter_libmonero) may have issues building due to conflicts with system packages: if so, follow this section.
|
||||
|
||||
Remove pre-installed system libraries for the following packages built by cryptography plugins in the crypto_plugins folder: `boost iconv libjson-dev libsecret openssl sodium unbound zmq`. You can use
|
||||
```
|
||||
sudo apt list --installed | grep boost
|
||||
```
|
||||
for example to find which pre-installed packages you may need to remove with `sudo apt remove`. Be careful, as some packages (especially boost) are linked to GNOME (GUI) packages: when in doubt, remove `-dev` packages first like with
|
||||
```
|
||||
sudo apt-get remove '^libboost.*-dev.*'
|
||||
```
|
||||
<!-- TODO: configure compiler to prefer built over system libraries. Should already use them? -->
|
||||
|
||||
#### Building plugins and configure for Windows
|
||||
Install dependencies like MXE:
|
||||
```
|
||||
cd scripts
|
||||
cd scripts/windows
|
||||
./deps.sh
|
||||
./build_app.sh -a stack_wallet -p windows
|
||||
```
|
||||
|
||||
and use `scripts/build_app.sh` to build plugins:
|
||||
```
|
||||
cd ..
|
||||
./build_app.sh -a stack_wallet -p windows -v 2.1.0 -b 210
|
||||
```
|
||||
|
||||
### Running
|
||||
|
@ -205,13 +209,13 @@ brew install brotli cairo coreutils gdbm gettext glib gmp libevent libidn2 libng
|
|||
```
|
||||
<!-- TODO: determine which of the above list are not needed at all. -->
|
||||
|
||||
Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install toolchains 1.67.1 and 1.72.0 and `cbindgen` and `cargo-lipo` too. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s):
|
||||
Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install toolchains 1.81.0 and 1.85.1 and `cbindgen` and `cargo-lipo` too. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s):
|
||||
```
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source ~/.bashrc
|
||||
rustup install 1.67.1 1.72.0 1.73.0
|
||||
rustup default 1.67.1
|
||||
cargo install cargo-ndk --version 2.12.7 --locked
|
||||
rustup install 1.85.1 1.81.0
|
||||
rustup default 1.85.1
|
||||
cargo install cargo-ndk
|
||||
cargo install cbindgen cargo-lipo
|
||||
rustup target add aarch64-apple-ios aarch64-apple-darwin
|
||||
```
|
||||
|
@ -219,7 +223,7 @@ rustup target add aarch64-apple-ios aarch64-apple-darwin
|
|||
Optionally download [Android Studio](https://developer.android.com/studio) as an IDE and activate its Dart and Flutter plugins. VS Code may work as an alternative, but this is not recommended.
|
||||
|
||||
### Flutter
|
||||
Install [Flutter](https://docs.flutter.dev/get-started/install) 3.22.1 on your Mac host by following [these instructions](https://docs.flutter.dev/get-started/install/macos). Run `flutter doctor` in a terminal to confirm its installation.
|
||||
Install [Flutter](https://docs.flutter.dev/get-started/install) 3.29.2 on your Mac host by following [these instructions](https://docs.flutter.dev/get-started/install/macos). Run `flutter doctor` in a terminal to confirm its installation.
|
||||
|
||||
### Build plugins and configure
|
||||
#### Building plugins for iOS
|
||||
|
@ -272,35 +276,27 @@ Install the following libraries:
|
|||
sudo apt-get install libgtk2.0-dev
|
||||
```
|
||||
|
||||
You will also need to install MXE on the WSL2 Ubuntu 20.04 host and can do so by running `stack_wallet/scripts/windows/deps.sh`:
|
||||
```
|
||||
./stack_wallet/scripts/windows/deps.sh
|
||||
```
|
||||
|
||||
The WSL2 host may optionally be navigated to the `stack_wallet` repository on the Windows host in order to build the plugins in-place and skip the next section in which you copy the `dll`s from WSL2 to Windows. Then build windows `dll` libraries by running the following script on the WSL2 Ubuntu 20.04 host:
|
||||
|
||||
- `stack_wallet/scripts/windows/build_all.sh`
|
||||
|
||||
Copy the resulting `dll`s to their respective positions on the Windows host:
|
||||
If the DLLs were built on the WSL filesystem instead of on Windows, copy the resulting `dll`s to their respective positions on the Windows host:
|
||||
|
||||
- `stack_wallet/crypto_plugins/flutter_libepiccash/scripts/windows/build/libepic_cash_wallet.dll`
|
||||
- `stack_wallet/crypto_plugins/flutter_liblelantus/scripts/windows/build/libmobileliblelantus.dll`
|
||||
<!--
|
||||
- `stack_wallet/crypto_plugins/flutter_libmonero/scripts/windows/build/libcw_monero.dll`
|
||||
- `stack_wallet/crypto_plugins/flutter_libmonero/scripts/windows/build/libcw_wownero.dll`
|
||||
-->
|
||||
|
||||
<!-- TODO: script the copying or installation of libraries from WSL2 to the parent Windows host -->
|
||||
|
||||
Frostdart will be built by the Windows host later.
|
||||
|
||||
### Install Flutter on Windows host
|
||||
Install Flutter 3.22.1 on your Windows host (not in WSL2) by [following their guide](https://docs.flutter.dev/get-started/install/windows/desktop?tab=download#install-the-flutter-sdk) or by cloning https://github.com/flutter/flutter, checking out the `3.22.1` tag, and adding its `flutter/bin` folder to your PATH as in
|
||||
Install Flutter 3.29.2 on your Windows host (not in WSL2) by [following their guide](https://docs.flutter.dev/get-started/install/windows/desktop?tab=download#install-the-flutter-sdk) or by cloning https://github.com/flutter/flutter, checking out the `3.29.2` tag, and adding its `flutter/bin` folder to your PATH as in
|
||||
```bat
|
||||
@echo off
|
||||
set "FLUTTER_DIR=%USERPROFILE%\development\flutter"
|
||||
git clone https://github.com/flutter/flutter.git "%FLUTTER_DIR%"
|
||||
cd /d "%FLUTTER_DIR%"
|
||||
git checkout 3.22.1
|
||||
git checkout 3.29.2
|
||||
setx PATH "%PATH%;%FLUTTER_DIR%\bin"
|
||||
echo Flutter setup completed. Please restart your command prompt.
|
||||
```
|
||||
|
@ -310,9 +306,9 @@ Run `flutter doctor` in PowerShell to confirm its installation.
|
|||
### Rust
|
||||
Install [Rust](https://www.rust-lang.org/tools/install) on the Windows host (not in WSL2). Download the installer from [rustup.rs](https://rustup.rs), make sure it works on the commandline (you may need to open a new terminal), and install the following versions:
|
||||
```
|
||||
rustup install 1.67.1 1.72.0 1.73.0
|
||||
rustup default 1.67.1
|
||||
cargo install cargo-ndk --version 2.12.7 --locked
|
||||
rustup install 1.85.1 1.81.0
|
||||
rustup default 1.85.1
|
||||
cargo install cargo-ndk
|
||||
```
|
||||
|
||||
### Windows SDK and Developer Mode
|
||||
|
|
1
fastlane/Appfile
Normal file
1
fastlane/Appfile
Normal file
|
@ -0,0 +1 @@
|
|||
package_name("com.cypherstack.stackwallet")
|
11
fastlane/metadata/android/en-US/full_description.txt
Normal file
11
fastlane/metadata/android/en-US/full_description.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
Stack Wallet is a fully open source cryptocurrency wallet. With an easy to use user interface and quick and speedy transactions, this wallet is ideal for anyone no matter how much they know about the cryptocurrency space. The app is actively maintained to provide new user friendly features.
|
||||
|
||||
Highlights include:
|
||||
- 10 Different cryptocurrencies
|
||||
- All private keys and seeds stay on device and are never shared.
|
||||
- Easy backup and restore feature to save all the information that's important to you.
|
||||
- Trading cryptocurrencies through our partners.
|
||||
- Custom address book
|
||||
- Favorite wallets with fast syncing
|
||||
- Custom Nodes.
|
||||
- Open source software.
|
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 26 KiB |
Binary file not shown.
After ![]() (image error) Size: 62 KiB |
Binary file not shown.
After ![]() (image error) Size: 57 KiB |
Binary file not shown.
After ![]() (image error) Size: 46 KiB |
Binary file not shown.
After ![]() (image error) Size: 43 KiB |
Binary file not shown.
After ![]() (image error) Size: 65 KiB |
Binary file not shown.
After ![]() (image error) Size: 54 KiB |
Binary file not shown.
After ![]() (image error) Size: 46 KiB |
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
|||
An open source, non-custodial cryptocurrency wallet.
|
1
ios/MoneroWallet.framework/.gitignore
vendored
1
ios/MoneroWallet.framework/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
MoneroWallet
|
|
@ -1,57 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>23E224</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>MoneroWallet</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.cypherstack.MoneroWallet</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>MoneroWallet</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>???</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>iPhoneOS</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string>21E210</string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>iphoneos</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>17.4</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>21E210</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>iphoneos17.4</string>
|
||||
<key>DTXcode</key>
|
||||
<string>1530</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>15E204a</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>16.0</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -3,12 +3,14 @@ PODS:
|
|||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
- SwiftProtobuf
|
||||
- coinlib_flutter (0.3.2):
|
||||
- coinlib_flutter (0.5.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- ReachabilitySwift
|
||||
- cs_monero_flutter_libs_ios (0.0.1):
|
||||
- Flutter
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- devicelocale (0.0.1):
|
||||
|
@ -50,8 +52,6 @@ PODS:
|
|||
- Flutter (1.0.0)
|
||||
- flutter_libepiccash (0.0.1):
|
||||
- Flutter
|
||||
- flutter_libmonero (0.0.1):
|
||||
- Flutter
|
||||
- flutter_libsparkmobile (0.0.1):
|
||||
- Flutter
|
||||
- flutter_local_notifications (0.0.1):
|
||||
|
@ -67,15 +67,16 @@ PODS:
|
|||
- Flutter
|
||||
- lelantus (0.0.1):
|
||||
- Flutter
|
||||
- local_auth (0.0.1):
|
||||
- local_auth_darwin (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- MTBBarcodeScanner (5.0.11)
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- permission_handler_apple (9.1.1):
|
||||
- permission_handler_apple (9.3.0):
|
||||
- Flutter
|
||||
- ReachabilitySwift (5.0.0)
|
||||
- SDWebImage (5.13.2):
|
||||
|
@ -83,14 +84,14 @@ PODS:
|
|||
- SDWebImage/Core (5.13.2)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- sqlite3 (3.46.0):
|
||||
- sqlite3/common (= 3.46.0)
|
||||
- sqlite3/common (3.46.0)
|
||||
- sqlite3/fts5 (3.46.0):
|
||||
- "sqlite3 (3.46.0+1)":
|
||||
- "sqlite3/common (= 3.46.0+1)"
|
||||
- "sqlite3/common (3.46.0+1)"
|
||||
- "sqlite3/fts5 (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3/perf-threadsafe (3.46.0):
|
||||
- "sqlite3/perf-threadsafe (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3/rtree (3.46.0):
|
||||
- "sqlite3/rtree (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
|
@ -106,19 +107,21 @@ PODS:
|
|||
- Flutter
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- wakelock (0.0.1):
|
||||
- wakelock_plus (0.0.1):
|
||||
- Flutter
|
||||
- xelis_flutter (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`)
|
||||
- coinlib_flutter (from `.symlinks/plugins/coinlib_flutter/darwin`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- cs_monero_flutter_libs_ios (from `.symlinks/plugins/cs_monero_flutter_libs_ios/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_libepiccash (from `.symlinks/plugins/flutter_libepiccash/ios`)
|
||||
- flutter_libmonero (from `.symlinks/plugins/flutter_libmonero/ios`)
|
||||
- flutter_libsparkmobile (from `.symlinks/plugins/flutter_libsparkmobile/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
|
@ -127,7 +130,7 @@ DEPENDENCIES:
|
|||
- integration_test (from `.symlinks/plugins/integration_test/ios`)
|
||||
- isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`)
|
||||
- lelantus (from `.symlinks/plugins/lelantus/ios`)
|
||||
- local_auth (from `.symlinks/plugins/local_auth/ios`)
|
||||
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
|
@ -136,7 +139,8 @@ DEPENDENCIES:
|
|||
- stack_wallet_backup (from `.symlinks/plugins/stack_wallet_backup/ios`)
|
||||
- tor_ffi_plugin (from `.symlinks/plugins/tor_ffi_plugin/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock (from `.symlinks/plugins/wakelock/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
- xelis_flutter (from `.symlinks/plugins/xelis_flutter/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
|
@ -156,6 +160,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/coinlib_flutter/darwin"
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
cs_monero_flutter_libs_ios:
|
||||
:path: ".symlinks/plugins/cs_monero_flutter_libs_ios/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
devicelocale:
|
||||
|
@ -166,8 +172,6 @@ EXTERNAL SOURCES:
|
|||
:path: Flutter
|
||||
flutter_libepiccash:
|
||||
:path: ".symlinks/plugins/flutter_libepiccash/ios"
|
||||
flutter_libmonero:
|
||||
:path: ".symlinks/plugins/flutter_libmonero/ios"
|
||||
flutter_libsparkmobile:
|
||||
:path: ".symlinks/plugins/flutter_libsparkmobile/ios"
|
||||
flutter_local_notifications:
|
||||
|
@ -184,8 +188,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/isar_flutter_libs/ios"
|
||||
lelantus:
|
||||
:path: ".symlinks/plugins/lelantus/ios"
|
||||
local_auth:
|
||||
:path: ".symlinks/plugins/local_auth/ios"
|
||||
local_auth_darwin:
|
||||
:path: ".symlinks/plugins/local_auth_darwin/darwin"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
|
@ -202,46 +206,48 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/tor_ffi_plugin/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
wakelock:
|
||||
:path: ".symlinks/plugins/wakelock/ios"
|
||||
wakelock_plus:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
xelis_flutter:
|
||||
:path: ".symlinks/plugins/xelis_flutter/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
|
||||
coinlib_flutter: 6abec900d67762a6e7ccfd567a3cd3ae00bbee35
|
||||
coinlib_flutter: 9275e8255ef67d3da33beb6e117d09ced4f46eb5
|
||||
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
||||
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
|
||||
devicelocale: b22617f40038496deffba44747101255cee005b0
|
||||
cs_monero_flutter_libs_ios: fd353631682247f72a36493ff060d4328d6f720d
|
||||
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
|
||||
devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
|
||||
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
|
||||
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_libepiccash: 36241aa7d3126f6521529985ccb3dc5eaf7bb317
|
||||
flutter_libmonero: da68a616b73dd0374a8419c684fa6b6df2c44ffe
|
||||
flutter_libsparkmobile: 6373955cc3327a926d17059e7405dde2fb12f99f
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
|
||||
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
|
||||
frostdart: 4c72b69ccac2f13ede744107db046a125acce597
|
||||
integration_test: 13825b8a9334a850581300559b8839134b124670
|
||||
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
|
||||
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
||||
isar_flutter_libs: fdf730ca925d05687f36d7f1d355e482529ed097
|
||||
lelantus: 417f0221260013dfc052cae9cf4b741b6479edba
|
||||
local_auth: 1740f55d7af0a2e2a8684ce225fe79d8931e808c
|
||||
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
|
||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
|
||||
share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
|
||||
sqlite3: 154b084339ede06960a5b3c8160066adc9176b7d
|
||||
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
|
||||
sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630
|
||||
sqlite3_flutter_libs: 0d611efdf6d1c9297d5ab03dab21b75aeebdae31
|
||||
stack_wallet_backup: 5b8563aba5d8ffbf2ce1944331ff7294a0ec7c03
|
||||
SwiftProtobuf: 6ef3f0e422ef90d6605ca20b21a94f6c1324d6b3
|
||||
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
|
||||
tor_ffi_plugin: d80e291b649379c8176e1be739e49be007d4ef93
|
||||
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||
|
||||
PODFILE CHECKSUM: 57c8aed26fba39d3ec9424816221f294a07c58eb
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
COCOAPODS: 1.16.2
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import UIKit
|
||||
import Flutter
|
||||
|
||||
@UIApplicationMain
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
|
|
1
ios/WowneroWallet.framework/.gitignore
vendored
1
ios/WowneroWallet.framework/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
WowneroWallet
|
|
@ -1,57 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>23E224</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>WowneroWallet</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.cypherstack.WowneroWallet</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>WowneroWallet</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>???</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>iPhoneOS</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string>21E210</string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>iphoneos</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>17.4</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>21E210</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>iphoneos17.4</string>
|
||||
<key>DTXcode</key>
|
||||
<string>1530</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>15E204a</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>16.0</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -27,6 +27,8 @@ abstract class AppConfig {
|
|||
|
||||
static List<CryptoCurrency> get coins => _supportedCoins;
|
||||
|
||||
static ({String from, String to}) get swapDefaults => _swapDefaults;
|
||||
|
||||
static bool get isSingleCoinApp => coins.length == 1;
|
||||
|
||||
static CryptoCurrency? getCryptoCurrencyFor(String coinIdentifier) {
|
||||
|
|
|
@ -29,6 +29,8 @@ import '../utilities/constants.dart';
|
|||
import '../utilities/flutter_secure_storage_interface.dart';
|
||||
import '../utilities/logger.dart';
|
||||
import '../utilities/prefs.dart';
|
||||
import '../utilities/stack_file_system.dart';
|
||||
import '../utilities/util.dart';
|
||||
import '../wallets/crypto_currency/crypto_currency.dart';
|
||||
import 'hive/db.dart';
|
||||
import 'isar/main_db.dart';
|
||||
|
@ -43,10 +45,7 @@ class DbVersionMigrator with WalletDB {
|
|||
// safe to skip to v11 for campfire
|
||||
fromVersion = 11;
|
||||
}
|
||||
Logging.instance.log(
|
||||
"Running migrate fromVersion $fromVersion",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
Logging.instance.i("Running migrate fromVersion $fromVersion");
|
||||
switch (fromVersion) {
|
||||
case 0:
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
|
@ -77,6 +76,8 @@ class DbVersionMigrator with WalletDB {
|
|||
name: e.name,
|
||||
id: e.id,
|
||||
useSSL: e.useSSL,
|
||||
torEnabled: e.torEnabled,
|
||||
clearnetEnabled: e.clearnetEnabled,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
@ -88,6 +89,8 @@ class DbVersionMigrator with WalletDB {
|
|||
name: node.name,
|
||||
id: node.id,
|
||||
useSSL: node.useSSL,
|
||||
torEnabled: node.torEnabled,
|
||||
clearnetEnabled: node.clearnetEnabled,
|
||||
),
|
||||
prefs: prefs,
|
||||
failovers: failovers,
|
||||
|
@ -96,12 +99,13 @@ class DbVersionMigrator with WalletDB {
|
|||
|
||||
try {
|
||||
latestSetId = await client.getLelantusLatestCoinId();
|
||||
} catch (e) {
|
||||
} catch (e, s) {
|
||||
// default to 2 for now
|
||||
latestSetId = 2;
|
||||
Logging.instance.log(
|
||||
Logging.instance.w(
|
||||
"Failed to fetch latest coin id during firo db migrate: $e \nUsing a default value of 2",
|
||||
level: LogLevel.Warning,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +144,6 @@ class DbVersionMigrator with WalletDB {
|
|||
),
|
||||
});
|
||||
}
|
||||
Logger.print("newcoins $coins", normalLength: false);
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: walletInfo.walletId,
|
||||
key: '_lelantus_coins',
|
||||
|
@ -439,6 +442,20 @@ class DbVersionMigrator with WalletDB {
|
|||
// try to continue migrating
|
||||
return await migrate(13, secureStore: secureStore);
|
||||
|
||||
case 13:
|
||||
// migrate
|
||||
await _v13(secureStore);
|
||||
|
||||
// update version
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: DB.boxNameDBInfo,
|
||||
key: "hive_data_version",
|
||||
value: 14,
|
||||
);
|
||||
|
||||
// try to continue migrating
|
||||
return await migrate(14, secureStore: secureStore);
|
||||
|
||||
default:
|
||||
// finally return
|
||||
return;
|
||||
|
@ -730,4 +747,31 @@ class DbVersionMigrator with WalletDB {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _v13(SecureStorageInterface secureStore) async {
|
||||
if (!(Util.isArmLinux || Util.isTestEnv)) {
|
||||
// open logs db
|
||||
final isar = await Isar.open(
|
||||
[isar_models.LogSchema],
|
||||
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
||||
inspector: false,
|
||||
maxSizeMiB: 512,
|
||||
);
|
||||
|
||||
// fetch all logs
|
||||
final allLogs = await isar.logs.where().findAll();
|
||||
|
||||
// migrate to simple file based logs. Date/time may be out of order
|
||||
for (final log in allLogs) {
|
||||
Logging.instance.log(
|
||||
log.logLevel.getLoggerLevel(),
|
||||
"MIGRATED LOG::=> ${log.message}",
|
||||
time: DateTime.fromMillisecondsSinceEpoch(log.timestampInMillisUTC),
|
||||
);
|
||||
}
|
||||
|
||||
// finally delete logs db
|
||||
await isar.close(deleteFromDisk: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:cw_core/wallet_info.dart' as xmr;
|
||||
import 'package:compat/compat.dart' as lib_monero_compat;
|
||||
import 'package:hive/hive.dart' show Box;
|
||||
import 'package:hive/src/hive_impl.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
|
@ -71,7 +71,7 @@ class DB {
|
|||
Box<Trade>? _boxTradesV2;
|
||||
Box<String>? _boxTradeNotes;
|
||||
Box<String>? _boxFavoriteWallets;
|
||||
Box<xmr.WalletInfo>? _walletInfoSource;
|
||||
Box<lib_monero_compat.WalletInfo>? _walletInfoSource;
|
||||
Box<dynamic>? _boxPrefs;
|
||||
Box<TradeWalletLookup>? _boxTradeLookup;
|
||||
Box<dynamic>? _boxDBInfo;
|
||||
|
@ -85,7 +85,8 @@ class DB {
|
|||
final Map<String, Box<dynamic>> _getSparkUsedCoinsTagsCacheBoxes = {};
|
||||
|
||||
// exposed for monero
|
||||
Box<xmr.WalletInfo> get moneroWalletInfoBox => _walletInfoSource!;
|
||||
Box<lib_monero_compat.WalletInfo> get moneroWalletInfoBox =>
|
||||
_walletInfoSource!;
|
||||
|
||||
// mutex for stack backup
|
||||
final mutex = Mutex();
|
||||
|
@ -147,8 +148,8 @@ class DB {
|
|||
_boxTradesV2 = await hive.openBox<Trade>(boxNameTradesV2);
|
||||
_boxTradeNotes = await hive.openBox<String>(boxNameTradeNotes);
|
||||
_boxTradeLookup = await hive.openBox<TradeWalletLookup>(boxNameTradeLookup);
|
||||
_walletInfoSource =
|
||||
await hive.openBox<xmr.WalletInfo>(xmr.WalletInfo.boxName);
|
||||
_walletInfoSource = await hive.openBox<lib_monero_compat.WalletInfo>(
|
||||
lib_monero_compat.WalletInfo.boxName);
|
||||
_boxFavoriteWallets = await hive.openBox<String>(boxNameFavoriteWallets);
|
||||
|
||||
await Future.wait([
|
||||
|
@ -165,9 +166,10 @@ class DB {
|
|||
AppConfig.getCryptoCurrencyFor(jsonObject["coin"] as String);
|
||||
return false;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
Logging.instance.e(
|
||||
"Error, ${jsonObject["coin"]} does not exist, $name wallet cannot be loaded",
|
||||
level: LogLevel.Error,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
@ -342,7 +344,7 @@ class DB {
|
|||
await DB.instance.deleteBoxFromDisk(boxName: "theme");
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Error);
|
||||
Logging.instance.e("$e $s", error: e, stackTrace: s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@ import 'dart:async';
|
|||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_libsparkmobile/flutter_libsparkmobile.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:sqlite3/sqlite3.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../electrumx_rpc/electrumx_client.dart';
|
||||
import '../../models/electrumx_response/spark_models.dart';
|
||||
import '../../utilities/extensions/extensions.dart';
|
||||
import '../../utilities/logger.dart';
|
||||
import '../../utilities/stack_file_system.dart';
|
||||
|
@ -19,18 +19,8 @@ part 'firo_cache_reader.dart';
|
|||
part 'firo_cache_worker.dart';
|
||||
part 'firo_cache_writer.dart';
|
||||
|
||||
/// Temporary debugging log function for this file
|
||||
void _debugLog(Object? object) {
|
||||
if (kDebugMode) {
|
||||
Logging.instance.log(
|
||||
object,
|
||||
level: LogLevel.Debug,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _FiroCache {
|
||||
static const int _setCacheVersion = 1;
|
||||
static const int _setCacheVersion = 2;
|
||||
static const int _tagsCacheVersion = 2;
|
||||
|
||||
static final networks = [
|
||||
|
@ -115,7 +105,8 @@ abstract class _FiroCache {
|
|||
VACUUM;
|
||||
""",
|
||||
);
|
||||
_debugLog(
|
||||
|
||||
Logging.instance.d(
|
||||
"_deleteAllCache() "
|
||||
"duration = ${DateTime.now().difference(start)}",
|
||||
);
|
||||
|
@ -134,7 +125,7 @@ abstract class _FiroCache {
|
|||
blockHash TEXT NOT NULL,
|
||||
setHash TEXT NOT NULL,
|
||||
groupId INTEGER NOT NULL,
|
||||
timestampUTC INTEGER NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
UNIQUE (blockHash, setHash, groupId)
|
||||
);
|
||||
|
||||
|
@ -143,7 +134,8 @@ abstract class _FiroCache {
|
|||
serialized TEXT NOT NULL,
|
||||
txHash TEXT NOT NULL,
|
||||
context TEXT NOT NULL,
|
||||
UNIQUE(serialized, txHash, context)
|
||||
groupId INTEGER NOT NULL,
|
||||
UNIQUE(serialized, txHash, context, groupId)
|
||||
);
|
||||
|
||||
CREATE TABLE SparkSetCoins (
|
||||
|
|
|
@ -6,6 +6,8 @@ typedef LTagPair = ({String tag, String txid});
|
|||
/// background isolate and [FiroCacheCoordinator] should manage that isolate
|
||||
abstract class FiroCacheCoordinator {
|
||||
static final Map<CryptoCurrencyNetwork, _FiroCacheWorker> _workers = {};
|
||||
static final Map<CryptoCurrencyNetwork, Mutex> _tagLocks = {};
|
||||
static final Map<CryptoCurrencyNetwork, Mutex> _setLocks = {};
|
||||
|
||||
static bool _init = false;
|
||||
static Future<void> init() async {
|
||||
|
@ -15,6 +17,8 @@ abstract class FiroCacheCoordinator {
|
|||
_init = true;
|
||||
await _FiroCache.init();
|
||||
for (final network in _FiroCache.networks) {
|
||||
_tagLocks[network] = Mutex();
|
||||
_setLocks[network] = Mutex();
|
||||
_workers[network] = await _FiroCacheWorker.spawn(network);
|
||||
}
|
||||
}
|
||||
|
@ -31,11 +35,17 @@ abstract class FiroCacheCoordinator {
|
|||
final usedTagsCacheFile = File(
|
||||
"${dir.path}/${_FiroCache.sparkUsedTagsCacheFileName(network)}",
|
||||
);
|
||||
final int bytes =
|
||||
((await setCacheFile.exists()) ? await setCacheFile.length() : 0) +
|
||||
((await usedTagsCacheFile.exists())
|
||||
? await usedTagsCacheFile.length()
|
||||
: 0);
|
||||
|
||||
final setSize =
|
||||
(await setCacheFile.exists()) ? await setCacheFile.length() : 0;
|
||||
final tagsSize = (await usedTagsCacheFile.exists())
|
||||
? await usedTagsCacheFile.length()
|
||||
: 0;
|
||||
|
||||
Logging.instance.d("Spark cache used tags size: $tagsSize");
|
||||
Logging.instance.d("Spark cache anon set size: $setSize");
|
||||
|
||||
final int bytes = tagsSize + setSize;
|
||||
|
||||
if (bytes < 1024) {
|
||||
return '$bytes B';
|
||||
|
@ -55,43 +65,93 @@ abstract class FiroCacheCoordinator {
|
|||
ElectrumXClient client,
|
||||
CryptoCurrencyNetwork network,
|
||||
) async {
|
||||
final count = await FiroCacheCoordinator.getUsedCoinTagsCount(network);
|
||||
final unhashedTags = await client.getSparkUnhashedUsedCoinsTagsWithTxHashes(
|
||||
startNumber: count,
|
||||
);
|
||||
if (unhashedTags.isNotEmpty) {
|
||||
await _workers[network]!.runTask(
|
||||
FCTask(
|
||||
func: FCFuncName._updateSparkUsedTagsWith,
|
||||
data: unhashedTags,
|
||||
),
|
||||
await _tagLocks[network]!.protect(() async {
|
||||
final count = await FiroCacheCoordinator.getUsedCoinTagsCount(network);
|
||||
final unhashedTags =
|
||||
await client.getSparkUnhashedUsedCoinsTagsWithTxHashes(
|
||||
startNumber: count,
|
||||
);
|
||||
}
|
||||
if (unhashedTags.isNotEmpty) {
|
||||
await _workers[network]!.runTask(
|
||||
FCTask(
|
||||
func: FCFuncName._updateSparkUsedTagsWith,
|
||||
data: unhashedTags,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static Future<void> runFetchAndUpdateSparkAnonSetCacheForGroupId(
|
||||
int groupId,
|
||||
ElectrumXClient client,
|
||||
CryptoCurrencyNetwork network,
|
||||
void Function(int countFetched, int totalCount)? progressUpdated,
|
||||
) async {
|
||||
final blockhashResult =
|
||||
await FiroCacheCoordinator.getLatestSetInfoForGroupId(
|
||||
groupId,
|
||||
network,
|
||||
);
|
||||
final blockHash = blockhashResult?.blockHash ?? "";
|
||||
await _setLocks[network]!.protect(() async {
|
||||
const sectorSize =
|
||||
1500; // chosen as a somewhat decent value. Could be changed in the future if wanted/needed
|
||||
final prevMeta = await FiroCacheCoordinator.getLatestSetInfoForGroupId(
|
||||
groupId,
|
||||
network,
|
||||
);
|
||||
|
||||
final json = await client.getSparkAnonymitySet(
|
||||
coinGroupId: groupId.toString(),
|
||||
startBlockHash: blockHash.toHexReversedFromBase64,
|
||||
);
|
||||
final prevSize = prevMeta?.size ?? 0;
|
||||
|
||||
await _workers[network]!.runTask(
|
||||
FCTask(
|
||||
func: FCFuncName._updateSparkAnonSetCoinsWith,
|
||||
data: (groupId, json),
|
||||
),
|
||||
);
|
||||
final meta = await client.getSparkAnonymitySetMeta(
|
||||
coinGroupId: groupId,
|
||||
);
|
||||
|
||||
progressUpdated?.call(prevSize, meta.size);
|
||||
|
||||
if (prevMeta?.blockHash == meta.blockHash) {
|
||||
Logging.instance.d("prevMeta?.blockHash == meta.blockHash");
|
||||
return;
|
||||
}
|
||||
|
||||
final numberOfCoinsToFetch = meta.size - prevSize;
|
||||
|
||||
final fullSectorCount = numberOfCoinsToFetch ~/ sectorSize;
|
||||
final remainder = numberOfCoinsToFetch % sectorSize;
|
||||
|
||||
final List<dynamic> coins = [];
|
||||
|
||||
for (int i = 0; i < fullSectorCount; i++) {
|
||||
final start = (i * sectorSize);
|
||||
final data = await client.getSparkAnonymitySetBySector(
|
||||
coinGroupId: groupId,
|
||||
latestBlock: meta.blockHash,
|
||||
startIndex: start,
|
||||
endIndex: start + sectorSize,
|
||||
);
|
||||
progressUpdated?.call(start + sectorSize, numberOfCoinsToFetch);
|
||||
|
||||
coins.addAll(data);
|
||||
}
|
||||
|
||||
if (remainder > 0) {
|
||||
final data = await client.getSparkAnonymitySetBySector(
|
||||
coinGroupId: groupId,
|
||||
latestBlock: meta.blockHash,
|
||||
startIndex: numberOfCoinsToFetch - remainder,
|
||||
endIndex: numberOfCoinsToFetch,
|
||||
);
|
||||
progressUpdated?.call(numberOfCoinsToFetch, numberOfCoinsToFetch);
|
||||
|
||||
coins.addAll(data);
|
||||
}
|
||||
|
||||
final result = coins
|
||||
.map((e) => RawSparkCoin.fromRPCResponse(e as List, groupId))
|
||||
.toList();
|
||||
|
||||
await _workers[network]!.runTask(
|
||||
FCTask(
|
||||
func: FCFuncName._updateSparkAnonSetCoinsWith,
|
||||
data: (meta, result),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
|
@ -165,28 +225,29 @@ abstract class FiroCacheCoordinator {
|
|||
);
|
||||
}
|
||||
|
||||
static Future<
|
||||
List<
|
||||
({
|
||||
String serialized,
|
||||
String txHash,
|
||||
String context,
|
||||
})>> getSetCoinsForGroupId(
|
||||
static Future<List<RawSparkCoin>> getSetCoinsForGroupId(
|
||||
int groupId, {
|
||||
int? newerThanTimeStamp,
|
||||
String? afterBlockHash,
|
||||
required CryptoCurrencyNetwork network,
|
||||
}) async {
|
||||
final resultSet = await _Reader._getSetCoinsForGroupId(
|
||||
groupId,
|
||||
db: _FiroCache.setCacheDB(network),
|
||||
newerThanTimeStamp: newerThanTimeStamp,
|
||||
);
|
||||
final resultSet = afterBlockHash == null
|
||||
? await _Reader._getSetCoinsForGroupId(
|
||||
groupId,
|
||||
db: _FiroCache.setCacheDB(network),
|
||||
)
|
||||
: await _Reader._getSetCoinsForGroupIdAndBlockHash(
|
||||
groupId,
|
||||
afterBlockHash,
|
||||
db: _FiroCache.setCacheDB(network),
|
||||
);
|
||||
|
||||
return resultSet
|
||||
.map(
|
||||
(row) => (
|
||||
(row) => RawSparkCoin(
|
||||
serialized: row["serialized"] as String,
|
||||
txHash: row["txHash"] as String,
|
||||
context: row["context"] as String,
|
||||
groupId: groupId,
|
||||
),
|
||||
)
|
||||
.toList()
|
||||
|
@ -194,12 +255,7 @@ abstract class FiroCacheCoordinator {
|
|||
.toList();
|
||||
}
|
||||
|
||||
static Future<
|
||||
({
|
||||
String blockHash,
|
||||
String setHash,
|
||||
int timestampUTC,
|
||||
})?> getLatestSetInfoForGroupId(
|
||||
static Future<SparkAnonymitySetMeta?> getLatestSetInfoForGroupId(
|
||||
int groupId,
|
||||
CryptoCurrencyNetwork network,
|
||||
) async {
|
||||
|
@ -212,10 +268,11 @@ abstract class FiroCacheCoordinator {
|
|||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
return SparkAnonymitySetMeta(
|
||||
coinGroupId: groupId,
|
||||
blockHash: result.first["blockHash"] as String,
|
||||
setHash: result.first["setHash"] as String,
|
||||
timestampUTC: result.first["timestampUTC"] as int,
|
||||
size: result.first["size"] as int,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,21 +8,15 @@ abstract class _Reader {
|
|||
static Future<ResultSet> _getSetCoinsForGroupId(
|
||||
int groupId, {
|
||||
required Database db,
|
||||
int? newerThanTimeStamp,
|
||||
}) async {
|
||||
String query = """
|
||||
SELECT sc.serialized, sc.txHash, sc.context
|
||||
final query = """
|
||||
SELECT sc.serialized, sc.txHash, sc.context, sc.groupId
|
||||
FROM SparkSet AS ss
|
||||
JOIN SparkSetCoins AS ssc ON ss.id = ssc.setId
|
||||
JOIN SparkCoin AS sc ON ssc.coinId = sc.id
|
||||
WHERE ss.groupId = $groupId
|
||||
WHERE ss.groupId = $groupId;
|
||||
""";
|
||||
|
||||
if (newerThanTimeStamp != null) {
|
||||
query += " AND ss.timestampUTC"
|
||||
" > $newerThanTimeStamp";
|
||||
}
|
||||
|
||||
return db.select("$query;");
|
||||
}
|
||||
|
||||
|
@ -31,16 +25,45 @@ abstract class _Reader {
|
|||
required Database db,
|
||||
}) async {
|
||||
final query = """
|
||||
SELECT ss.blockHash, ss.setHash, ss.timestampUTC
|
||||
SELECT ss.blockHash, ss.setHash, ss.size
|
||||
FROM SparkSet ss
|
||||
WHERE ss.groupId = $groupId
|
||||
ORDER BY ss.timestampUTC DESC
|
||||
ORDER BY ss.size DESC
|
||||
LIMIT 1;
|
||||
""";
|
||||
|
||||
return db.select("$query;");
|
||||
}
|
||||
|
||||
static Future<ResultSet> _getSetCoinsForGroupIdAndBlockHash(
|
||||
int groupId,
|
||||
String blockHash, {
|
||||
required Database db,
|
||||
}) async {
|
||||
const query = """
|
||||
WITH TargetBlock AS (
|
||||
SELECT id
|
||||
FROM SparkSet
|
||||
WHERE blockHash = ?
|
||||
),
|
||||
TargetSets AS (
|
||||
SELECT id AS setId
|
||||
FROM SparkSet
|
||||
WHERE groupId = ? AND id > (SELECT id FROM TargetBlock)
|
||||
)
|
||||
SELECT
|
||||
SparkCoin.serialized,
|
||||
SparkCoin.txHash,
|
||||
SparkCoin.context,
|
||||
SparkCoin.groupId
|
||||
FROM SparkSetCoins
|
||||
JOIN SparkCoin ON SparkSetCoins.coinId = SparkCoin.id
|
||||
WHERE SparkSetCoins.setId IN (SELECT setId FROM TargetSets);
|
||||
""";
|
||||
|
||||
return db.select("$query;", [blockHash, groupId]);
|
||||
}
|
||||
|
||||
static Future<bool> _checkSetInfoForGroupIdExists(
|
||||
int groupId, {
|
||||
required Database db,
|
||||
|
|
|
@ -48,7 +48,11 @@ class _FiroCacheWorker {
|
|||
try {
|
||||
await Isolate.spawn(
|
||||
_startWorkerIsolate,
|
||||
(initPort.sendPort, setCacheFilePath, usedTagsCacheFilePath),
|
||||
(
|
||||
initPort.sendPort,
|
||||
setCacheFilePath,
|
||||
usedTagsCacheFilePath,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
initPort.close();
|
||||
|
@ -90,7 +94,8 @@ class _FiroCacheWorker {
|
|||
final FCResult result;
|
||||
switch (task.func) {
|
||||
case FCFuncName._updateSparkAnonSetCoinsWith:
|
||||
final data = task.data as (int, Map<String, dynamic>);
|
||||
final data =
|
||||
task.data as (SparkAnonymitySetMeta, List<RawSparkCoin>);
|
||||
result = _updateSparkAnonSetCoinsWith(
|
||||
setCacheDb,
|
||||
data.$2,
|
||||
|
|
|
@ -19,8 +19,8 @@ FCResult _updateSparkUsedTagsWith(
|
|||
) {
|
||||
// hash the tags here since this function is called in a background isolate
|
||||
final hashedTags = LibSpark.hashTags(
|
||||
base64Tags: tags.map((e) => e[0] as String),
|
||||
);
|
||||
base64Tags: tags.map((e) => e[0] as String).toSet(),
|
||||
).toList();
|
||||
|
||||
if (hashedTags.isEmpty) {
|
||||
// nothing to add, return early
|
||||
|
@ -52,29 +52,13 @@ FCResult _updateSparkUsedTagsWith(
|
|||
// ================== write to spark anon set cache ==========================
|
||||
|
||||
/// update the sqlite cache
|
||||
/// Expected json format:
|
||||
/// {
|
||||
/// "blockHash": "someBlockHash",
|
||||
/// "setHash": "someSetHash",
|
||||
/// "coins": [
|
||||
/// ["serliazed1", "hash1", "context1"],
|
||||
/// ["serliazed2", "hash2", "context2"],
|
||||
/// ...
|
||||
/// ["serliazed3", "hash3", "context3"],
|
||||
/// ["serliazed4", "hash4", "context4"],
|
||||
/// ],
|
||||
/// }
|
||||
///
|
||||
/// returns true if successful, otherwise false
|
||||
FCResult _updateSparkAnonSetCoinsWith(
|
||||
Database db,
|
||||
Map<String, dynamic> json,
|
||||
int groupId,
|
||||
final List<RawSparkCoin> coinsRaw,
|
||||
SparkAnonymitySetMeta meta,
|
||||
) {
|
||||
final blockHash = json["blockHash"] as String;
|
||||
final setHash = json["setHash"] as String;
|
||||
final coinsRaw = json["coins"] as List;
|
||||
|
||||
if (coinsRaw.isEmpty) {
|
||||
// no coins to actually insert
|
||||
return FCResult(success: true);
|
||||
|
@ -87,9 +71,9 @@ FCResult _updateSparkAnonSetCoinsWith(
|
|||
WHERE blockHash = ? AND setHash = ? AND groupId = ?;
|
||||
""",
|
||||
[
|
||||
blockHash,
|
||||
setHash,
|
||||
groupId,
|
||||
meta.blockHash,
|
||||
meta.setHash,
|
||||
meta.coinGroupId,
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -98,59 +82,28 @@ FCResult _updateSparkAnonSetCoinsWith(
|
|||
return FCResult(success: true);
|
||||
}
|
||||
|
||||
final coins = coinsRaw
|
||||
.map(
|
||||
(e) => [
|
||||
e[0] as String,
|
||||
e[1] as String,
|
||||
e[2] as String,
|
||||
],
|
||||
)
|
||||
.toList()
|
||||
.reversed;
|
||||
|
||||
final timestamp = DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000;
|
||||
final coins = coinsRaw.reversed;
|
||||
|
||||
db.execute("BEGIN;");
|
||||
try {
|
||||
db.execute(
|
||||
"""
|
||||
INSERT INTO SparkSet (blockHash, setHash, groupId, timestampUTC)
|
||||
INSERT INTO SparkSet (blockHash, setHash, groupId, size)
|
||||
VALUES (?, ?, ?, ?);
|
||||
""",
|
||||
[blockHash, setHash, groupId, timestamp],
|
||||
[meta.blockHash, meta.setHash, meta.coinGroupId, meta.size],
|
||||
);
|
||||
final setId = db.lastInsertRowId;
|
||||
|
||||
for (final coin in coins) {
|
||||
int coinId;
|
||||
try {
|
||||
// try to insert and get row id
|
||||
db.execute(
|
||||
"""
|
||||
INSERT INTO SparkCoin (serialized, txHash, context)
|
||||
VALUES (?, ?, ?);
|
||||
db.execute(
|
||||
"""
|
||||
INSERT INTO SparkCoin (serialized, txHash, context, groupId)
|
||||
VALUES (?, ?, ?, ?);
|
||||
""",
|
||||
coin,
|
||||
);
|
||||
coinId = db.lastInsertRowId;
|
||||
} on SqliteException catch (e) {
|
||||
// if there already is a matching coin in the db
|
||||
// just grab its row id
|
||||
if (e.extendedResultCode == 2067) {
|
||||
final result = db.select(
|
||||
"""
|
||||
SELECT id
|
||||
FROM SparkCoin
|
||||
WHERE serialized = ? AND txHash = ? AND context = ?;
|
||||
""",
|
||||
coin,
|
||||
);
|
||||
coinId = result.first["id"] as int;
|
||||
} else {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
[coin.serialized, coin.txHash, coin.context, coin.groupId],
|
||||
);
|
||||
final coinId = db.lastInsertRowId;
|
||||
|
||||
// finally add the row id to the newly added set
|
||||
db.execute(
|
||||
|
|
|
@ -100,17 +100,17 @@ class CachedElectrumXClient {
|
|||
}
|
||||
// save set to db
|
||||
await box.put(groupId, set);
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Updated current anonymity set for ${cryptoCurrency.identifier} with group ID $groupId",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
}
|
||||
|
||||
return set;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"Failed to process CachedElectrumX.getAnonymitySet(): $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
Logging.instance.e(
|
||||
"Failed to process CachedElectrumX.getAnonymitySet(): ",
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
|
@ -155,16 +155,17 @@ class CachedElectrumXClient {
|
|||
await box.put(txHash, result);
|
||||
}
|
||||
|
||||
// Logging.instance.log("using fetched result", level: LogLevel.Info);
|
||||
// Logging.instance.log("using fetched result");
|
||||
return result;
|
||||
} else {
|
||||
// Logging.instance.log("using cached result", level: LogLevel.Info);
|
||||
// Logging.instance.log("using cached result");
|
||||
return Map<String, dynamic>.from(cachedTx);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"Failed to process CachedElectrumX.getTransaction(): $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
Logging.instance.e(
|
||||
"Failed to process CachedElectrumX.getTransaction(): ",
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
|
@ -212,9 +213,10 @@ class CachedElectrumXClient {
|
|||
|
||||
return resultingList;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"Failed to process CachedElectrumX.getUsedCoinSerials(): $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
Logging.instance.e(
|
||||
"Failed to process CachedElectrumX.getUsedCoinSerials(): ",
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:electrum_adapter/electrum_adapter.dart';
|
||||
|
||||
import '../utilities/logger.dart';
|
||||
import '../utilities/prefs.dart';
|
||||
import '../utilities/tor_plain_net_option_enum.dart';
|
||||
import '../wallets/crypto_currency/crypto_currency.dart';
|
||||
|
||||
class ClientManager {
|
||||
|
@ -8,6 +12,7 @@ class ClientManager {
|
|||
static final ClientManager sharedInstance = ClientManager._();
|
||||
|
||||
final Map<String, ElectrumClient> _map = {};
|
||||
final Map<String, TorPlainNetworkOption> _mapNet = {};
|
||||
final Map<String, int> _heights = {};
|
||||
final Map<String, StreamSubscription<BlockHeader>> _subscriptions = {};
|
||||
final Map<String, Completer<int>> _heightCompleters = {};
|
||||
|
@ -22,28 +27,54 @@ class ClientManager {
|
|||
|
||||
ElectrumClient? getClient({
|
||||
required CryptoCurrency cryptoCurrency,
|
||||
}) =>
|
||||
_map[_keyHelper(cryptoCurrency)];
|
||||
required TorPlainNetworkOption netType,
|
||||
}) {
|
||||
final _key = _keyHelper(cryptoCurrency);
|
||||
|
||||
void addClient(
|
||||
if (netType == _mapNet[_key]) {
|
||||
return _map[_key];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addClient(
|
||||
ElectrumClient client, {
|
||||
required CryptoCurrency cryptoCurrency,
|
||||
}) {
|
||||
required TorPlainNetworkOption netType,
|
||||
}) async {
|
||||
final key = _keyHelper(cryptoCurrency);
|
||||
if (_map[key] != null) {
|
||||
throw Exception("ElectrumX Client for $key already exists.");
|
||||
if (_mapNet[key] == netType) {
|
||||
throw Exception(
|
||||
"ElectrumX Client for $key and $netType already exists.",
|
||||
);
|
||||
}
|
||||
|
||||
await remove(cryptoCurrency: cryptoCurrency);
|
||||
|
||||
_map[key] = client;
|
||||
_mapNet[key] = netType;
|
||||
} else {
|
||||
_map[key] = client;
|
||||
_mapNet[key] = netType;
|
||||
}
|
||||
|
||||
_heightCompleters[key] = Completer<int>();
|
||||
_subscriptions[key] = client.subscribeHeaders().listen((event) {
|
||||
_heights[key] = event.height;
|
||||
_subscriptions[key] = client.subscribeHeaders().listen(
|
||||
(event) {
|
||||
_heights[key] = event.height;
|
||||
|
||||
if (!_heightCompleters[key]!.isCompleted) {
|
||||
_heightCompleters[key]!.complete(event.height);
|
||||
}
|
||||
});
|
||||
if (!_heightCompleters[key]!.isCompleted) {
|
||||
_heightCompleters[key]!.complete(event.height);
|
||||
}
|
||||
},
|
||||
onError: (Object err, StackTrace s) => Logging.instance.e(
|
||||
"ClientManager listen",
|
||||
error: err,
|
||||
stackTrace: s,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> getChainHeightFor(CryptoCurrency cryptoCurrency) async {
|
||||
|
@ -60,10 +91,24 @@ class ClientManager {
|
|||
);
|
||||
}
|
||||
|
||||
if (Prefs.instance.useTor) {
|
||||
if (_mapNet[key]! == TorPlainNetworkOption.clear) {
|
||||
throw Exception(
|
||||
"Non-TOR only client for $key found.",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (_mapNet[key]! == TorPlainNetworkOption.tor) {
|
||||
throw Exception(
|
||||
"TOR only client for $key found.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return _heights[key] ?? await _heightCompleters[key]!.future;
|
||||
}
|
||||
|
||||
Future<ElectrumClient?> remove({
|
||||
Future<(ElectrumClient?, TorPlainNetworkOption?)> remove({
|
||||
required CryptoCurrency cryptoCurrency,
|
||||
}) async {
|
||||
final key = _keyHelper(cryptoCurrency);
|
||||
|
@ -72,7 +117,7 @@ class ClientManager {
|
|||
_heights.remove(key);
|
||||
_heightCompleters.remove(key);
|
||||
|
||||
return _map.remove(key);
|
||||
return (_map.remove(key), _mapNet.remove(key));
|
||||
}
|
||||
|
||||
Future<void> closeAll() async {
|
||||
|
@ -91,6 +136,7 @@ class ClientManager {
|
|||
_heightCompleters.clear();
|
||||
_heights.clear();
|
||||
_subscriptions.clear();
|
||||
_mapNet.clear();
|
||||
_map.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import 'package:mutex/mutex.dart';
|
|||
import 'package:stream_channel/stream_channel.dart';
|
||||
|
||||
import '../exceptions/electrumx/no_such_transaction.dart';
|
||||
import '../models/electrumx_response/spark_models.dart';
|
||||
import '../services/event_bus/events/global/tor_connection_status_changed_event.dart';
|
||||
import '../services/event_bus/events/global/tor_status_changed_event.dart';
|
||||
import '../services/event_bus/global_event_bus.dart';
|
||||
|
@ -29,19 +30,17 @@ import '../utilities/amount/amount.dart';
|
|||
import '../utilities/extensions/impl/string.dart';
|
||||
import '../utilities/logger.dart';
|
||||
import '../utilities/prefs.dart';
|
||||
import '../utilities/tor_plain_net_option_enum.dart';
|
||||
import '../wallets/crypto_currency/crypto_currency.dart';
|
||||
import '../wallets/crypto_currency/interfaces/electrumx_currency_interface.dart';
|
||||
import 'client_manager.dart';
|
||||
|
||||
typedef SparkMempoolData = ({
|
||||
String txid,
|
||||
List<String> serialContext,
|
||||
List<String> lTags,
|
||||
List<String> coins,
|
||||
});
|
||||
|
||||
class WifiOnlyException implements Exception {}
|
||||
|
||||
class TorOnlyException implements Exception {}
|
||||
|
||||
class ClearnetOnlyException implements Exception {}
|
||||
|
||||
class ElectrumXNode {
|
||||
ElectrumXNode({
|
||||
required this.address,
|
||||
|
@ -49,12 +48,16 @@ class ElectrumXNode {
|
|||
required this.name,
|
||||
required this.id,
|
||||
required this.useSSL,
|
||||
required this.torEnabled,
|
||||
required this.clearnetEnabled,
|
||||
});
|
||||
final String address;
|
||||
final int port;
|
||||
final String name;
|
||||
final String id;
|
||||
final bool useSSL;
|
||||
final bool torEnabled;
|
||||
final bool clearnetEnabled;
|
||||
|
||||
factory ElectrumXNode.from(ElectrumXNode node) {
|
||||
return ElectrumXNode(
|
||||
|
@ -63,6 +66,8 @@ class ElectrumXNode {
|
|||
name: node.name,
|
||||
id: node.id,
|
||||
useSSL: node.useSSL,
|
||||
torEnabled: node.torEnabled,
|
||||
clearnetEnabled: node.clearnetEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -74,6 +79,7 @@ class ElectrumXNode {
|
|||
|
||||
class ElectrumXClient {
|
||||
final CryptoCurrency cryptoCurrency;
|
||||
final TorPlainNetworkOption netType;
|
||||
|
||||
String get host => _host;
|
||||
late String _host;
|
||||
|
@ -90,12 +96,13 @@ class ElectrumXClient {
|
|||
ElectrumClient? getElectrumAdapter() =>
|
||||
ClientManager.sharedInstance.getClient(
|
||||
cryptoCurrency: cryptoCurrency,
|
||||
netType: netType,
|
||||
);
|
||||
|
||||
late Prefs _prefs;
|
||||
late TorService _torService;
|
||||
|
||||
List<ElectrumXNode>? failovers;
|
||||
late final List<ElectrumXNode> _failovers;
|
||||
int currentFailoverIndex = -1;
|
||||
|
||||
final Duration connectionTimeoutForSpecialCaseJsonRPCClients;
|
||||
|
@ -119,6 +126,7 @@ class ElectrumXClient {
|
|||
required int port,
|
||||
required bool useSSL,
|
||||
required Prefs prefs,
|
||||
required this.netType,
|
||||
required List<ElectrumXNode> failovers,
|
||||
required this.cryptoCurrency,
|
||||
this.connectionTimeoutForSpecialCaseJsonRPCClients =
|
||||
|
@ -131,6 +139,7 @@ class ElectrumXClient {
|
|||
_host = host;
|
||||
_port = port;
|
||||
_useSSL = useSSL;
|
||||
_failovers = failovers;
|
||||
|
||||
final bus = globalEventBusForTesting ?? GlobalEventBus.instance;
|
||||
|
||||
|
@ -168,6 +177,7 @@ class ElectrumXClient {
|
|||
_electrumAdapterChannel = null;
|
||||
await (await ClientManager.sharedInstance
|
||||
.remove(cryptoCurrency: cryptoCurrency))
|
||||
.$1
|
||||
?.close();
|
||||
|
||||
// Also close any chain height services that are currently open.
|
||||
|
@ -193,6 +203,10 @@ class ElectrumXClient {
|
|||
failovers: failovers,
|
||||
globalEventBusForTesting: globalEventBusForTesting,
|
||||
cryptoCurrency: cryptoCurrency,
|
||||
netType: TorPlainNetworkOption.fromNodeData(
|
||||
node.torEnabled,
|
||||
node.clearnetEnabled,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -219,10 +233,9 @@ class ElectrumXClient {
|
|||
if (!_prefs.torKillSwitch) {
|
||||
// Then we'll just proceed and connect to ElectrumX through
|
||||
// clearnet at the bottom of this function.
|
||||
Logging.instance.log(
|
||||
Logging.instance.w(
|
||||
"Tor preference set but Tor is not enabled, killswitch not set,"
|
||||
" connecting to Electrum adapter through clearnet",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
} else {
|
||||
// ... But if the killswitch is set, then we throw an exception.
|
||||
|
@ -236,6 +249,18 @@ class ElectrumXClient {
|
|||
// Get the proxy info from the TorService.
|
||||
proxyInfo = _torService.getProxyInfo();
|
||||
}
|
||||
|
||||
if (netType == TorPlainNetworkOption.clear) {
|
||||
_electrumAdapterChannel = null;
|
||||
await ClientManager.sharedInstance
|
||||
.remove(cryptoCurrency: cryptoCurrency);
|
||||
}
|
||||
} else {
|
||||
if (netType == TorPlainNetworkOption.tor) {
|
||||
_electrumAdapterChannel = null;
|
||||
await ClientManager.sharedInstance
|
||||
.remove(cryptoCurrency: cryptoCurrency);
|
||||
}
|
||||
}
|
||||
|
||||
// If the current ElectrumAdapterClient is closed, create a new one.
|
||||
|
@ -253,9 +278,11 @@ class ElectrumXClient {
|
|||
usePort = port;
|
||||
useUseSSL = useSSL;
|
||||
} else {
|
||||
useHost = failovers![currentFailoverIndex].address;
|
||||
usePort = failovers![currentFailoverIndex].port;
|
||||
useUseSSL = failovers![currentFailoverIndex].useSSL;
|
||||
_electrumAdapterChannel = null;
|
||||
await ClientManager.sharedInstance.remove(cryptoCurrency: cryptoCurrency);
|
||||
useHost = _failovers[currentFailoverIndex].address;
|
||||
usePort = _failovers[currentFailoverIndex].port;
|
||||
useUseSSL = _failovers[currentFailoverIndex].useSSL;
|
||||
}
|
||||
|
||||
_electrumAdapterChannel ??= await electrum_adapter.connect(
|
||||
|
@ -288,9 +315,10 @@ class ElectrumXClient {
|
|||
);
|
||||
}
|
||||
|
||||
ClientManager.sharedInstance.addClient(
|
||||
await ClientManager.sharedInstance.addClient(
|
||||
newClient,
|
||||
cryptoCurrency: cryptoCurrency,
|
||||
netType: netType,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -352,6 +380,10 @@ class ElectrumXClient {
|
|||
return response;
|
||||
} on WifiOnlyException {
|
||||
rethrow;
|
||||
} on ClearnetOnlyException {
|
||||
rethrow;
|
||||
} on TorOnlyException {
|
||||
rethrow;
|
||||
} on SocketException {
|
||||
// likely timed out so then retry
|
||||
if (retries > 0) {
|
||||
|
@ -365,8 +397,17 @@ class ElectrumXClient {
|
|||
} else {
|
||||
rethrow;
|
||||
}
|
||||
} catch (e) {
|
||||
if (failovers != null && currentFailoverIndex < failovers!.length - 1) {
|
||||
} catch (e, s) {
|
||||
final errorMessage = e.toString();
|
||||
Logging.instance.w(
|
||||
"$host $e",
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
if (errorMessage.contains("JSON-RPC error")) {
|
||||
currentFailoverIndex = _failovers.length;
|
||||
}
|
||||
if (currentFailoverIndex < _failovers.length - 1) {
|
||||
currentFailoverIndex++;
|
||||
return request(
|
||||
command: command,
|
||||
|
@ -442,6 +483,10 @@ class ElectrumXClient {
|
|||
return response;
|
||||
} on WifiOnlyException {
|
||||
rethrow;
|
||||
} on ClearnetOnlyException {
|
||||
rethrow;
|
||||
} on TorOnlyException {
|
||||
rethrow;
|
||||
} on SocketException {
|
||||
// likely timed out so then retry
|
||||
if (retries > 0) {
|
||||
|
@ -455,7 +500,7 @@ class ElectrumXClient {
|
|||
rethrow;
|
||||
}
|
||||
} catch (e) {
|
||||
if (failovers != null && currentFailoverIndex < failovers!.length - 1) {
|
||||
if (currentFailoverIndex < _failovers.length - 1) {
|
||||
currentFailoverIndex++;
|
||||
return batchRequest(
|
||||
command: command,
|
||||
|
@ -488,9 +533,16 @@ class ElectrumXClient {
|
|||
return await request(
|
||||
requestID: requestID,
|
||||
command: 'server.ping',
|
||||
requestTimeout: const Duration(seconds: 2),
|
||||
requestTimeout: const Duration(seconds: 30),
|
||||
retries: retryCount,
|
||||
).timeout(const Duration(seconds: 2)) as bool;
|
||||
).timeout(
|
||||
const Duration(seconds: 30),
|
||||
onTimeout: () {
|
||||
Logging.instance.d(
|
||||
"ElectrumxClient.ping timed out with retryCount=$retryCount, host=$_host",
|
||||
);
|
||||
},
|
||||
) as bool;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
|
@ -512,10 +564,7 @@ class ElectrumXClient {
|
|||
command: 'blockchain.headers.subscribe',
|
||||
);
|
||||
if (response == null) {
|
||||
Logging.instance.log(
|
||||
"getBlockHeadTip returned null response",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
Logging.instance.e("getBlockHeadTip returned null response");
|
||||
throw 'getBlockHeadTip returned null response';
|
||||
}
|
||||
return Map<String, dynamic>.from(response as Map);
|
||||
|
@ -706,14 +755,15 @@ class ElectrumXClient {
|
|||
try {
|
||||
final data = List<Map<String, dynamic>>.from(response[i] as List);
|
||||
result.add(data);
|
||||
} catch (e) {
|
||||
} catch (e, s) {
|
||||
// to ensure we keep same length of responses as requests/args
|
||||
// add empty list on error
|
||||
result.add([]);
|
||||
|
||||
Logging.instance.log(
|
||||
Logging.instance.e(
|
||||
"getBatchUTXOs failed to parse response=${response[i]}: $e",
|
||||
level: LogLevel.Error,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -776,15 +826,13 @@ class ElectrumXClient {
|
|||
bool verbose = true,
|
||||
String? requestID,
|
||||
}) async {
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"attempting to fetch blockchain.transaction.get...",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
await checkElectrumAdapter();
|
||||
final dynamic response = await getElectrumAdapter()!.getTransaction(txHash);
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Fetching blockchain.transaction.get finished",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
if (!verbose) {
|
||||
|
@ -813,17 +861,15 @@ class ElectrumXClient {
|
|||
String blockhash = "",
|
||||
String? requestID,
|
||||
}) async {
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"attempting to fetch lelantus.getanonymityset...",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
await checkElectrumAdapter();
|
||||
final Map<String, dynamic> response =
|
||||
await (getElectrumAdapter() as FiroElectrumClient)
|
||||
.getLelantusAnonymitySet(groupId: groupId, blockHash: blockhash);
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Fetching lelantus.getanonymityset finished",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
@ -836,16 +882,14 @@ class ElectrumXClient {
|
|||
dynamic mints,
|
||||
String? requestID,
|
||||
}) async {
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"attempting to fetch lelantus.getmintmetadata...",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
await checkElectrumAdapter();
|
||||
final dynamic response = await (getElectrumAdapter() as FiroElectrumClient)
|
||||
.getLelantusMintData(mints: mints);
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Fetching lelantus.getmintmetadata finished",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
@ -856,9 +900,8 @@ class ElectrumXClient {
|
|||
String? requestID,
|
||||
required int startNumber,
|
||||
}) async {
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"attempting to fetch lelantus.getusedcoinserials...",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
await checkElectrumAdapter();
|
||||
|
||||
|
@ -869,9 +912,8 @@ class ElectrumXClient {
|
|||
response = await (getElectrumAdapter() as FiroElectrumClient)
|
||||
.getLelantusUsedCoinSerials(startNumber: startNumber);
|
||||
// TODO add 2 minute timeout.
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Fetching lelantus.getusedcoinserials finished",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
retryCount--;
|
||||
|
@ -884,16 +926,14 @@ class ElectrumXClient {
|
|||
///
|
||||
/// ex: 1
|
||||
Future<int> getLelantusLatestCoinId({String? requestID}) async {
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"attempting to fetch lelantus.getlatestcoinid...",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
await checkElectrumAdapter();
|
||||
final int response =
|
||||
await (getElectrumAdapter() as FiroElectrumClient).getLatestCoinId();
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Fetching lelantus.getlatestcoinid finished",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
@ -927,12 +967,11 @@ class ElectrumXClient {
|
|||
coinGroupId: coinGroupId,
|
||||
startBlockHash: startBlockHash,
|
||||
);
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Finished ElectrumXClient.getSparkAnonymitySet(coinGroupId"
|
||||
"=$coinGroupId, startBlockHash=$startBlockHash). "
|
||||
"coins.length: ${(response["coins"] as List?)?.length}"
|
||||
"Duration=${DateTime.now().difference(start)}",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return response;
|
||||
} catch (e) {
|
||||
|
@ -970,7 +1009,7 @@ class ElectrumXClient {
|
|||
// );
|
||||
//
|
||||
// return tags;
|
||||
// } catch (e) {
|
||||
// } catch (e, s) {
|
||||
// Logging.instance.log(e, level: LogLevel.Error);
|
||||
// rethrow;
|
||||
// }
|
||||
|
@ -986,29 +1025,30 @@ class ElectrumXClient {
|
|||
/// "b476ed2b374bb081ea51d111f68f0136252521214e213d119b8dc67b92f5a390",
|
||||
/// ]
|
||||
/// }
|
||||
Future<List<Map<String, dynamic>>> getSparkMintMetaData({
|
||||
String? requestID,
|
||||
required List<String> sparkCoinHashes,
|
||||
}) async {
|
||||
try {
|
||||
Logging.instance.log(
|
||||
"attempting to fetch spark.getsparkmintmetadata...",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
await checkElectrumAdapter();
|
||||
final List<dynamic> response =
|
||||
await (getElectrumAdapter() as FiroElectrumClient)
|
||||
.getSparkMintMetaData(sparkCoinHashes: sparkCoinHashes);
|
||||
Logging.instance.log(
|
||||
"Fetching spark.getsparkmintmetadata finished",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return List<Map<String, dynamic>>.from(response);
|
||||
} catch (e) {
|
||||
Logging.instance.log(e, level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
/// NOT USED?
|
||||
// Future<List<Map<String, dynamic>>> getSparkMintMetaData({
|
||||
// String? requestID,
|
||||
// required List<String> sparkCoinHashes,
|
||||
// }) async {
|
||||
// try {
|
||||
// Logging.instance.log(
|
||||
// "attempting to fetch spark.getsparkmintmetadata...",
|
||||
// level: LogLevel.Info,
|
||||
// );
|
||||
// await checkElectrumAdapter();
|
||||
// final List<dynamic> response =
|
||||
// await (getElectrumAdapter() as FiroElectrumClient)
|
||||
// .getSparkMintMetaData(sparkCoinHashes: sparkCoinHashes);
|
||||
// Logging.instance.log(
|
||||
// "Fetching spark.getsparkmintmetadata finished",
|
||||
// level: LogLevel.Info,
|
||||
// );
|
||||
// return List<Map<String, dynamic>>.from(response);
|
||||
// } catch (e, s) {
|
||||
// Logging.instance.log(e, level: LogLevel.Error);
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Returns the latest Spark set id
|
||||
///
|
||||
|
@ -1017,20 +1057,22 @@ class ElectrumXClient {
|
|||
String? requestID,
|
||||
}) async {
|
||||
try {
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"attempting to fetch spark.getsparklatestcoinid...",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
await checkElectrumAdapter();
|
||||
final int response = await (getElectrumAdapter() as FiroElectrumClient)
|
||||
.getSparkLatestCoinId();
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Fetching spark.getsparklatestcoinid finished",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return response;
|
||||
} catch (e) {
|
||||
Logging.instance.log(e, level: LogLevel.Error);
|
||||
} catch (e, s) {
|
||||
Logging.instance.e(
|
||||
e,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -1050,15 +1092,18 @@ class ElectrumXClient {
|
|||
.map((e) => e.toHexReversedFromBase64)
|
||||
.toSet();
|
||||
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Finished ElectrumXClient.getMempoolTxids(). "
|
||||
"Duration=${DateTime.now().difference(start)}",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
return txids;
|
||||
} catch (e) {
|
||||
Logging.instance.log(e, level: LogLevel.Error);
|
||||
} catch (e, s) {
|
||||
Logging.instance.e(
|
||||
e,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -1084,7 +1129,7 @@ class ElectrumXClient {
|
|||
final List<SparkMempoolData> result = [];
|
||||
for (final entry in map.entries) {
|
||||
result.add(
|
||||
(
|
||||
SparkMempoolData(
|
||||
txid: entry.key,
|
||||
serialContext:
|
||||
List<String>.from(entry.value["serial_context"] as List),
|
||||
|
@ -1095,15 +1140,14 @@ class ElectrumXClient {
|
|||
);
|
||||
}
|
||||
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Finished ElectrumXClient.getMempoolSparkData(txids: $txids). "
|
||||
"Duration=${DateTime.now().difference(start)}",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
return result;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Error);
|
||||
Logging.instance.e("$e\n$s", error: e, stackTrace: s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -1127,19 +1171,119 @@ class ElectrumXClient {
|
|||
final map = Map<String, dynamic>.from(response as Map);
|
||||
final tags = List<List<dynamic>>.from(map["tagsandtxids"] as List);
|
||||
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Finished ElectrumXClient.getSparkUnhashedUsedCoinsTagsWithTxHashes("
|
||||
"startNumber=$startNumber). # of tags fetched=${tags.length}, "
|
||||
"Duration=${DateTime.now().difference(start)}",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
return tags;
|
||||
} catch (e) {
|
||||
Logging.instance.log(e, level: LogLevel.Error);
|
||||
} catch (e, s) {
|
||||
Logging.instance.e(
|
||||
e,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
// ======== New Paginated Endpoints ==========================================
|
||||
|
||||
Future<SparkAnonymitySetMeta> getSparkAnonymitySetMeta({
|
||||
String? requestID,
|
||||
required int coinGroupId,
|
||||
}) async {
|
||||
try {
|
||||
const command = "spark.getsparkanonymitysetmeta";
|
||||
Logging.instance.d(
|
||||
"[${getElectrumAdapter()?.host}] => attempting to fetch $command...",
|
||||
);
|
||||
|
||||
final start = DateTime.now();
|
||||
final response = await request(
|
||||
requestID: requestID,
|
||||
command: command,
|
||||
args: [
|
||||
"$coinGroupId",
|
||||
],
|
||||
);
|
||||
|
||||
final map = Map<String, dynamic>.from(response as Map);
|
||||
|
||||
final result = SparkAnonymitySetMeta(
|
||||
coinGroupId: coinGroupId,
|
||||
blockHash: map["blockHash"] as String,
|
||||
setHash: map["setHash"] as String,
|
||||
size: map["size"] as int,
|
||||
);
|
||||
|
||||
Logging.instance.d(
|
||||
"Finished ElectrumXClient.getSparkAnonymitySetMeta("
|
||||
"requestID=$requestID, "
|
||||
"coinGroupId=$coinGroupId"
|
||||
"). Set meta=$result, "
|
||||
"Duration=${DateTime.now().difference(start)}",
|
||||
);
|
||||
|
||||
return result;
|
||||
} catch (e, s) {
|
||||
Logging.instance.e(
|
||||
e,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<dynamic>> getSparkAnonymitySetBySector({
|
||||
String? requestID,
|
||||
required int coinGroupId,
|
||||
required String latestBlock,
|
||||
required int startIndex, // inclusive
|
||||
required int endIndex, // exclusive
|
||||
}) async {
|
||||
try {
|
||||
const command =
|
||||
"spark.getsparkanonymitysetsector"; // TODO verify this will be correct
|
||||
final start = DateTime.now();
|
||||
final response = await request(
|
||||
requestID: requestID,
|
||||
command: command,
|
||||
args: [
|
||||
"$coinGroupId",
|
||||
latestBlock,
|
||||
"$startIndex",
|
||||
"$endIndex",
|
||||
],
|
||||
);
|
||||
|
||||
final map = Map<String, dynamic>.from(response as Map);
|
||||
|
||||
final result = map["coins"] as List;
|
||||
|
||||
Logging.instance.d(
|
||||
"Finished ElectrumXClient.getSparkAnonymitySetBySector("
|
||||
"requestID=$requestID, "
|
||||
"coinGroupId=$coinGroupId, "
|
||||
"latestBlock=$latestBlock, "
|
||||
"startIndex=$startIndex, "
|
||||
"endIndex=$endIndex"
|
||||
"). # of coins=${result.length}, "
|
||||
"Duration=${DateTime.now().difference(start)}",
|
||||
);
|
||||
|
||||
return result;
|
||||
} catch (e, s) {
|
||||
Logging.instance.e(
|
||||
e,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
Future<bool> isMasterNodeCollateral({
|
||||
|
@ -1158,16 +1302,19 @@ class ElectrumXClient {
|
|||
],
|
||||
);
|
||||
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"Finished ElectrumXClient.isMasterNodeCollateral, "
|
||||
"response: $response, "
|
||||
"Duration=${DateTime.now().difference(start)}",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
return response as bool;
|
||||
} catch (e) {
|
||||
Logging.instance.log(e, level: LogLevel.Error);
|
||||
} catch (e, s) {
|
||||
Logging.instance.e(
|
||||
e,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -1226,7 +1373,7 @@ class ElectrumXClient {
|
|||
} catch (e, s) {
|
||||
final String msg = "Error parsing fee rate. Response: $response"
|
||||
"\nResult: $response\nError: $e\nStack trace: $s";
|
||||
Logging.instance.log(msg, level: LogLevel.Fatal);
|
||||
Logging.instance.e(msg, error: e, stackTrace: s);
|
||||
throw Exception(msg);
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -503,7 +503,7 @@
|
|||
// _responseHandler(response);
|
||||
// } catch (e, s) {
|
||||
// Logging.instance
|
||||
// .log("JsonRPC jsonDecode: $e\n$s", level: LogLevel.Error);
|
||||
// .log("JsonRPC jsonDecode", error: e, stackTrace: s,);
|
||||
// rethrow;
|
||||
// } finally {
|
||||
// _responseData = [];
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
class NodeTorMismatchConfigException implements Exception {
|
||||
final String message;
|
||||
|
||||
NodeTorMismatchConfigException({required this.message});
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
416
lib/main.dart
416
lib/main.dart
|
@ -13,22 +13,21 @@ import 'dart:io';
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:coinlib_flutter/coinlib_flutter.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:compat/compat.dart' as lib_monero_compat;
|
||||
import 'package:cs_monero/cs_monero.dart' as lib_monero;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_libmonero/monero/monero.dart';
|
||||
import 'package:flutter_libmonero/wownero/wownero.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:window_size/window_size.dart';
|
||||
import 'package:xelis_flutter/src/api/api.dart' as xelis_api;
|
||||
import 'package:xelis_flutter/src/api/logger.dart' as xelis_logging;
|
||||
import 'package:xelis_flutter/src/frb_generated.dart' as xelis_rust;
|
||||
|
||||
import 'app_config.dart';
|
||||
import 'db/db_version_migration.dart';
|
||||
|
@ -39,7 +38,6 @@ import 'db/sqlite/firo_cache.dart';
|
|||
import 'models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'models/exchange/change_now/exchange_transaction_status.dart';
|
||||
import 'models/exchange/response_objects/trade.dart';
|
||||
import 'models/isar/models/isar_models.dart';
|
||||
import 'models/models.dart';
|
||||
import 'models/node_model.dart';
|
||||
import 'models/notification_model.dart';
|
||||
|
@ -60,8 +58,6 @@ import 'providers/global/base_currencies_provider.dart';
|
|||
import 'providers/global/trades_service_provider.dart';
|
||||
import 'providers/providers.dart';
|
||||
import 'route_generator.dart';
|
||||
// import 'package:stackwallet/services/buy/buy_data_loading_service.dart';
|
||||
import 'services/debug_service.dart';
|
||||
import 'services/exchange/exchange_data_loading_service.dart';
|
||||
import 'services/locale_service.dart';
|
||||
import 'services/node_service.dart';
|
||||
|
@ -79,27 +75,53 @@ import 'utilities/prefs.dart';
|
|||
import 'utilities/stack_file_system.dart';
|
||||
import 'utilities/util.dart';
|
||||
import 'wallets/isar/providers/all_wallets_info_provider.dart';
|
||||
import 'wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
||||
import 'widgets/crypto_notifications.dart';
|
||||
|
||||
final openedFromSWBFileStringStateProvider =
|
||||
StateProvider<String?>((ref) => null);
|
||||
final openedFromSWBFileStringStateProvider = StateProvider<String?>(
|
||||
(ref) => null,
|
||||
);
|
||||
|
||||
void startListeningToRustLogs() {
|
||||
xelis_api.createLogStream().listen(
|
||||
(logEntry) {
|
||||
final Level level;
|
||||
switch (logEntry.level) {
|
||||
case xelis_logging.Level.error:
|
||||
level = Level.error;
|
||||
case xelis_logging.Level.warn:
|
||||
level = Level.warning;
|
||||
case xelis_logging.Level.info:
|
||||
level = Level.info;
|
||||
case xelis_logging.Level.debug:
|
||||
level = Level.debug;
|
||||
case xelis_logging.Level.trace:
|
||||
level = Level.trace;
|
||||
}
|
||||
|
||||
Logging.instance.log(
|
||||
level,
|
||||
"[Xelis Rust Log] ${logEntry.tag}: ${logEntry.msg}",
|
||||
);
|
||||
},
|
||||
onError: (dynamic e) {
|
||||
Logging.instance.e("Error receiving Xelis Rust logs: $e");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// main() is the entry point to the app. It initializes Hive (local database),
|
||||
// runs the MyApp widget and checks for new users, caching the value in the
|
||||
// miscellaneous box for later use
|
||||
void main(List<String> args) async {
|
||||
// talker.info('initializing Rust lib ...');
|
||||
await xelis_rust.RustLib.init();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
if (Util.isDesktop && args.length == 2 && args.first == "-d") {
|
||||
StackFileSystem.setDesktopOverrideDir(args.last);
|
||||
}
|
||||
|
||||
// Tell flutter_libmonero how to get access to the application dir
|
||||
FS.setApplicationRootDirectoryFunction(
|
||||
StackFileSystem.applicationRootDirectory,
|
||||
);
|
||||
// TODO set any other external libs file paths (bad external lib design workaround)
|
||||
|
||||
final loadCoinlibFuture = loadCoinlib();
|
||||
|
||||
GoogleFonts.config.allowRuntimeFetching = false;
|
||||
|
@ -121,26 +143,11 @@ void main(List<String> args) async {
|
|||
if (screenHeight != null) {
|
||||
// starting to height be 3/4 screen height or 900, whichever is smaller
|
||||
final height = min<double>(screenHeight * 0.75, 900);
|
||||
setWindowFrame(
|
||||
Rect.fromLTWH(0, 0, 1220, height),
|
||||
);
|
||||
setWindowFrame(Rect.fromLTWH(0, 0, 1220, height));
|
||||
}
|
||||
}
|
||||
|
||||
// FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||
if (!(Logging.isArmLinux || Logging.isTestEnv)) {
|
||||
final isar = await Isar.open(
|
||||
[LogSchema],
|
||||
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
||||
inspector: false,
|
||||
maxSizeMiB: 512,
|
||||
);
|
||||
await Logging.instance.init(isar);
|
||||
await DebugService.instance.init(isar);
|
||||
|
||||
// clear out all info logs on startup. No need to await and block
|
||||
unawaited(DebugService.instance.deleteLogsOlderThan());
|
||||
}
|
||||
|
||||
// Registering Transaction Model Adapters
|
||||
DB.instance.hive.registerAdapter(TransactionDataAdapter());
|
||||
|
@ -172,15 +179,15 @@ void main(List<String> args) async {
|
|||
// node model adapter
|
||||
DB.instance.hive.registerAdapter(NodeModelAdapter());
|
||||
|
||||
DB.instance.hive.registerAdapter(NodeAdapter());
|
||||
|
||||
if (!DB.instance.hive.isAdapterRegistered(WalletInfoAdapter().typeId)) {
|
||||
DB.instance.hive.registerAdapter(WalletInfoAdapter());
|
||||
if (!DB.instance.hive.isAdapterRegistered(
|
||||
lib_monero_compat.WalletInfoAdapter().typeId,
|
||||
)) {
|
||||
DB.instance.hive.registerAdapter(lib_monero_compat.WalletInfoAdapter());
|
||||
}
|
||||
|
||||
DB.instance.hive.registerAdapter(WalletTypeAdapter());
|
||||
DB.instance.hive.registerAdapter(lib_monero_compat.WalletTypeAdapter());
|
||||
|
||||
DB.instance.hive.registerAdapter(UnspentCoinsInfoAdapter());
|
||||
lib_monero.Logging.useLogger = kDebugMode;
|
||||
|
||||
DB.instance.hive.init(
|
||||
(await StackFileSystem.applicationHiveDirectory()).path,
|
||||
|
@ -190,6 +197,17 @@ void main(List<String> args) async {
|
|||
await DB.instance.hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await Prefs.instance.init();
|
||||
|
||||
await Logging.instance.initialize(
|
||||
(await StackFileSystem.applicationLogsDirectory(Prefs.instance)).path,
|
||||
level: Prefs.instance.logLevel,
|
||||
);
|
||||
|
||||
await xelis_api.setUpRustLogger();
|
||||
startListeningToRustLogs();
|
||||
|
||||
// setup lib spark logging
|
||||
initSparkLogging(Prefs.instance.logLevel);
|
||||
|
||||
if (AppConfig.appName == "Campfire" &&
|
||||
!Util.isDesktop &&
|
||||
!CampfireMigration.didRun) {
|
||||
|
@ -213,10 +231,12 @@ void main(List<String> args) async {
|
|||
|
||||
// Desktop migrate handled elsewhere (currently desktop_login_view.dart)
|
||||
if (!Util.isDesktop) {
|
||||
final int dbVersion = DB.instance.get<dynamic>(
|
||||
boxName: DB.boxNameDBInfo,
|
||||
key: "hive_data_version",
|
||||
) as int? ??
|
||||
final int dbVersion =
|
||||
DB.instance.get<dynamic>(
|
||||
boxName: DB.boxNameDBInfo,
|
||||
key: "hive_data_version",
|
||||
)
|
||||
as int? ??
|
||||
0;
|
||||
if (dbVersion < Constants.currentDataVersion) {
|
||||
try {
|
||||
|
@ -228,18 +248,15 @@ void main(List<String> args) async {
|
|||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"Cannot migrate mobile database\n$e $s",
|
||||
level: LogLevel.Error,
|
||||
printFullLength: true,
|
||||
Logging.instance.w(
|
||||
"Cannot migrate mobile database",
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monero.onStartup();
|
||||
wownero.onStartup();
|
||||
|
||||
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||
// overlays: [SystemUiOverlay.bottom]);
|
||||
unawaited(NotificationApi.init());
|
||||
|
@ -254,22 +271,25 @@ void main(List<String> args) async {
|
|||
|
||||
// verify current user preference theme and revert to default
|
||||
// if problems are found to prevent app being unusable
|
||||
if (!(await ThemeService.instance
|
||||
.verifyInstalled(themeId: Prefs.instance.themeId))) {
|
||||
if (!(await ThemeService.instance.verifyInstalled(
|
||||
themeId: Prefs.instance.themeId,
|
||||
))) {
|
||||
Prefs.instance.themeId = "light";
|
||||
}
|
||||
|
||||
// verify current user preference light brightness theme and revert to default
|
||||
// if problems are found to prevent app being unusable
|
||||
if (!(await ThemeService.instance
|
||||
.verifyInstalled(themeId: Prefs.instance.systemBrightnessLightThemeId))) {
|
||||
if (!(await ThemeService.instance.verifyInstalled(
|
||||
themeId: Prefs.instance.systemBrightnessLightThemeId,
|
||||
))) {
|
||||
Prefs.instance.systemBrightnessLightThemeId = "light";
|
||||
}
|
||||
|
||||
// verify current user preference dark brightness theme and revert to default
|
||||
// if problems are found to prevent app being unusable
|
||||
if (!(await ThemeService.instance
|
||||
.verifyInstalled(themeId: Prefs.instance.systemBrightnessDarkThemeId))) {
|
||||
if (!(await ThemeService.instance.verifyInstalled(
|
||||
themeId: Prefs.instance.systemBrightnessDarkThemeId,
|
||||
))) {
|
||||
Prefs.instance.systemBrightnessDarkThemeId = "dark";
|
||||
}
|
||||
|
||||
|
@ -285,18 +305,14 @@ class MyApp extends StatelessWidget {
|
|||
final localeService = LocaleService();
|
||||
localeService.loadLocale();
|
||||
|
||||
return const KeyboardDismisser(
|
||||
child: MaterialAppWithTheme(),
|
||||
);
|
||||
return const KeyboardDismisser(child: MaterialAppWithTheme());
|
||||
}
|
||||
}
|
||||
|
||||
// Sidenote: MaterialAppWithTheme and InitView are only separated for clarity. No other reason.
|
||||
|
||||
class MaterialAppWithTheme extends ConsumerStatefulWidget {
|
||||
const MaterialAppWithTheme({
|
||||
super.key,
|
||||
});
|
||||
const MaterialAppWithTheme({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<MaterialAppWithTheme> createState() =>
|
||||
|
@ -370,7 +386,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
prefs: ref.read(prefsChangeNotifierProvider),
|
||||
);
|
||||
ref.read(priceAnd24hChangeNotifierProvider).start(true);
|
||||
await ref.read(pWallets).load(
|
||||
await ref
|
||||
.read(pWallets)
|
||||
.load(
|
||||
ref.read(prefsChangeNotifierProvider),
|
||||
ref.read(mainDBProvider),
|
||||
);
|
||||
|
@ -400,7 +418,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled) {
|
||||
switch (ref.read(prefsChangeNotifierProvider).backupFrequencyType) {
|
||||
case BackupFrequencyType.everyTenMinutes:
|
||||
ref.read(autoSWBServiceProvider).startPeriodicBackupTimer(
|
||||
ref
|
||||
.read(autoSWBServiceProvider)
|
||||
.startPeriodicBackupTimer(
|
||||
duration: const Duration(minutes: 10),
|
||||
);
|
||||
break;
|
||||
|
@ -418,7 +438,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
// .userID; // Just reading the ref should set it if it's not already set
|
||||
// We shouldn't need to do this, instead only generating an ID when (or if) the userID is looked up when creating a quote
|
||||
} catch (e, s) {
|
||||
Logger.print("$e $s", normalLength: false);
|
||||
Logging.instance.e("load failure", error: e, stackTrace: s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,9 +453,10 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
ref.read(prefsChangeNotifierProvider).systemBrightnessDarkThemeId;
|
||||
break;
|
||||
case Brightness.light:
|
||||
themeId = ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.systemBrightnessLightThemeId;
|
||||
themeId =
|
||||
ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.systemBrightnessLightThemeId;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -454,9 +475,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
ref.read(applicationThemesDirectoryPathProvider.notifier).state =
|
||||
StackFileSystem.themesDir!.path;
|
||||
|
||||
ref.read(themeProvider.state).state = ref.read(pThemeService).getTheme(
|
||||
themeId: themeId,
|
||||
)!;
|
||||
ref.read(themeProvider.state).state =
|
||||
ref.read(pThemeService).getTheme(themeId: themeId)!;
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
// fetch open file if it exists
|
||||
|
@ -484,18 +504,17 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
ref.read(prefsChangeNotifierProvider).systemBrightnessDarkThemeId;
|
||||
break;
|
||||
case Brightness.light:
|
||||
themeId = ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.systemBrightnessLightThemeId;
|
||||
themeId =
|
||||
ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.systemBrightnessLightThemeId;
|
||||
break;
|
||||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (ref.read(prefsChangeNotifierProvider).enableSystemBrightness) {
|
||||
ref.read(themeProvider.state).state =
|
||||
ref.read(pThemeService).getTheme(
|
||||
themeId: themeId,
|
||||
)!;
|
||||
ref.read(pThemeService).getTheme(themeId: themeId)!;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -574,15 +593,14 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
/// should only be called on android currently
|
||||
Future<void> getOpenFile() async {
|
||||
// update provider with new file content state
|
||||
ref.read(openedFromSWBFileStringStateProvider.state).state =
|
||||
await platform.invokeMethod("getOpenFile");
|
||||
ref.read(openedFromSWBFileStringStateProvider.state).state = await platform
|
||||
.invokeMethod("getOpenFile");
|
||||
|
||||
// call reset to clear cached value
|
||||
await resetOpenPath();
|
||||
|
||||
Logging.instance.log(
|
||||
Logging.instance.d(
|
||||
"This is the .swb content from intent: ${ref.read(openedFromSWBFileStringStateProvider.state).state}",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -593,9 +611,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
|
||||
Future<void> goToRestoreSWB(String encrypted) async {
|
||||
if (!ref.read(prefsChangeNotifierProvider).hasPin) {
|
||||
await Navigator.of(navigatorKey.currentContext!)
|
||||
.pushNamed(CreatePinView.routeName, arguments: true)
|
||||
.then((value) {
|
||||
await Navigator.of(
|
||||
navigatorKey.currentContext!,
|
||||
).pushNamed(CreatePinView.routeName, arguments: true).then((value) {
|
||||
if (value is! bool || value == false) {
|
||||
Navigator.of(navigatorKey.currentContext!).pushNamed(
|
||||
RestoreFromEncryptedStringView.routeName,
|
||||
|
@ -609,16 +627,17 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
navigatorKey.currentContext!,
|
||||
RouteGenerator.getRoute(
|
||||
shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
|
||||
builder: (_) => LockscreenView(
|
||||
showBackButton: true,
|
||||
routeOnSuccess: RestoreFromEncryptedStringView.routeName,
|
||||
routeOnSuccessArguments: encrypted,
|
||||
biometricsCancelButtonString: "CANCEL",
|
||||
biometricsLocalizedReason:
|
||||
"Authenticate to restore ${AppConfig.appName} backup",
|
||||
biometricsAuthenticationTitle:
|
||||
"Restore ${AppConfig.prefix} backup",
|
||||
),
|
||||
builder:
|
||||
(_) => LockscreenView(
|
||||
showBackButton: true,
|
||||
routeOnSuccess: RestoreFromEncryptedStringView.routeName,
|
||||
routeOnSuccessArguments: encrypted,
|
||||
biometricsCancelButtonString: "CANCEL",
|
||||
biometricsLocalizedReason:
|
||||
"Authenticate to restore ${AppConfig.appName} backup",
|
||||
biometricsAuthenticationTitle:
|
||||
"Restore ${AppConfig.prefix} backup",
|
||||
),
|
||||
settings: const RouteSettings(name: "/swbrestorelockscreen"),
|
||||
),
|
||||
),
|
||||
|
@ -628,10 +647,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
|
||||
InputBorder _buildOutlineInputBorder(Color color) {
|
||||
return OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
width: 1,
|
||||
color: color,
|
||||
),
|
||||
borderSide: BorderSide(width: 1, color: color),
|
||||
borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius),
|
||||
);
|
||||
}
|
||||
|
@ -669,9 +685,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
),
|
||||
// splashFactory: NoSplash.splashFactory,
|
||||
splashColor: Colors.transparent,
|
||||
buttonTheme: ButtonThemeData(
|
||||
splashColor: colorScheme.splash,
|
||||
),
|
||||
buttonTheme: ButtonThemeData(splashColor: colorScheme.splash),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
// splashFactory: NoSplash.splashFactory,
|
||||
|
@ -679,8 +693,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
minimumSize: MaterialStateProperty.all<Size>(const Size(46, 46)),
|
||||
// textStyle: MaterialStateProperty.all<TextStyle>(
|
||||
// STextStyles.button(context)),
|
||||
foregroundColor:
|
||||
MaterialStateProperty.all(colorScheme.buttonTextSecondary),
|
||||
foregroundColor: MaterialStateProperty.all(
|
||||
colorScheme.buttonTextSecondary,
|
||||
),
|
||||
backgroundColor: MaterialStateProperty.all<Color>(
|
||||
colorScheme.buttonBackSecondary,
|
||||
),
|
||||
|
@ -697,25 +712,22 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
checkboxTheme: CheckboxThemeData(
|
||||
splashRadius: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(Constants.size.checkboxBorderRadius),
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.checkboxBorderRadius,
|
||||
),
|
||||
),
|
||||
checkColor: MaterialStateColor.resolveWith(
|
||||
(state) {
|
||||
if (state.contains(MaterialState.selected)) {
|
||||
return colorScheme.checkboxIconChecked;
|
||||
}
|
||||
checkColor: MaterialStateColor.resolveWith((state) {
|
||||
if (state.contains(MaterialState.selected)) {
|
||||
return colorScheme.checkboxIconChecked;
|
||||
}
|
||||
return colorScheme.checkboxBGChecked;
|
||||
}),
|
||||
fillColor: MaterialStateColor.resolveWith((states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return colorScheme.checkboxBGChecked;
|
||||
},
|
||||
),
|
||||
fillColor: MaterialStateColor.resolveWith(
|
||||
(states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return colorScheme.checkboxBGChecked;
|
||||
}
|
||||
return colorScheme.checkboxBorderEmpty;
|
||||
},
|
||||
),
|
||||
}
|
||||
return colorScheme.checkboxBorderEmpty;
|
||||
}),
|
||||
),
|
||||
appBarTheme: AppBarTheme(
|
||||
centerTitle: false,
|
||||
|
@ -733,91 +745,101 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
),
|
||||
// labelStyle: STextStyles.fieldLabel(context),
|
||||
// hintStyle: STextStyles.fieldLabel(context),
|
||||
enabledBorder:
|
||||
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
|
||||
focusedBorder:
|
||||
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
|
||||
enabledBorder: _buildOutlineInputBorder(
|
||||
colorScheme.textFieldDefaultBG,
|
||||
),
|
||||
focusedBorder: _buildOutlineInputBorder(
|
||||
colorScheme.textFieldDefaultBG,
|
||||
),
|
||||
errorBorder: _buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
|
||||
disabledBorder:
|
||||
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
|
||||
focusedErrorBorder:
|
||||
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
|
||||
disabledBorder: _buildOutlineInputBorder(
|
||||
colorScheme.textFieldDefaultBG,
|
||||
),
|
||||
focusedErrorBorder: _buildOutlineInputBorder(
|
||||
colorScheme.textFieldDefaultBG,
|
||||
),
|
||||
),
|
||||
),
|
||||
home: CryptoNotifications(
|
||||
child: Util.isDesktop
|
||||
? FutureBuilder(
|
||||
future: loadShared(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (_desktopHasPassword) {
|
||||
String? startupWalletId;
|
||||
if (ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.gotoWalletOnStartup) {
|
||||
startupWalletId = ref
|
||||
child:
|
||||
Util.isDesktop
|
||||
? FutureBuilder(
|
||||
future: loadShared(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (_desktopHasPassword) {
|
||||
String? startupWalletId;
|
||||
if (ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.startupWalletId;
|
||||
}
|
||||
.gotoWalletOnStartup) {
|
||||
startupWalletId =
|
||||
ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.startupWalletId;
|
||||
}
|
||||
|
||||
return DesktopLoginView(
|
||||
startupWalletId: startupWalletId,
|
||||
load: load,
|
||||
);
|
||||
} else {
|
||||
return const IntroView();
|
||||
}
|
||||
} else {
|
||||
return const LoadingView();
|
||||
}
|
||||
},
|
||||
)
|
||||
: FutureBuilder(
|
||||
future: load(),
|
||||
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
// FlutterNativeSplash.remove();
|
||||
if (ref.read(pAllWalletsInfo).isNotEmpty ||
|
||||
ref.read(prefsChangeNotifierProvider).hasPin) {
|
||||
// return HomeView();
|
||||
|
||||
String? startupWalletId;
|
||||
if (ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.gotoWalletOnStartup) {
|
||||
startupWalletId = ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.startupWalletId;
|
||||
}
|
||||
|
||||
return LockscreenView(
|
||||
isInitialAppLogin: true,
|
||||
routeOnSuccess: HomeView.routeName,
|
||||
routeOnSuccessArguments: startupWalletId,
|
||||
biometricsAuthenticationTitle:
|
||||
"Unlock ${AppConfig.prefix}",
|
||||
biometricsLocalizedReason:
|
||||
"Unlock your ${AppConfig.appName} using biometrics",
|
||||
biometricsCancelButtonString: "Cancel",
|
||||
);
|
||||
} else {
|
||||
if (AppConfig.appName == "Campfire" &&
|
||||
!CampfireMigration.didRun &&
|
||||
CampfireMigration.hasOldWallets) {
|
||||
return const CampfireMigrateView();
|
||||
return DesktopLoginView(
|
||||
startupWalletId: startupWalletId,
|
||||
load: load,
|
||||
);
|
||||
} else {
|
||||
return const IntroView();
|
||||
}
|
||||
} else {
|
||||
return const LoadingView();
|
||||
}
|
||||
} else {
|
||||
// CURRENTLY DISABLED as cannot be animated
|
||||
// technically not needed as FlutterNativeSplash will overlay
|
||||
// anything returned here until the future completes but
|
||||
// FutureBuilder requires you to return something
|
||||
return const LoadingView();
|
||||
}
|
||||
},
|
||||
),
|
||||
},
|
||||
)
|
||||
: FutureBuilder(
|
||||
future: load(),
|
||||
builder: (
|
||||
BuildContext context,
|
||||
AsyncSnapshot<void> snapshot,
|
||||
) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
// FlutterNativeSplash.remove();
|
||||
if (ref.read(pAllWalletsInfo).isNotEmpty ||
|
||||
ref.read(prefsChangeNotifierProvider).hasPin) {
|
||||
// return HomeView();
|
||||
|
||||
String? startupWalletId;
|
||||
if (ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.gotoWalletOnStartup) {
|
||||
startupWalletId =
|
||||
ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.startupWalletId;
|
||||
}
|
||||
|
||||
return LockscreenView(
|
||||
isInitialAppLogin: true,
|
||||
routeOnSuccess: HomeView.routeName,
|
||||
routeOnSuccessArguments: startupWalletId,
|
||||
biometricsAuthenticationTitle:
|
||||
"Unlock ${AppConfig.prefix}",
|
||||
biometricsLocalizedReason:
|
||||
"Unlock your ${AppConfig.appName} using biometrics",
|
||||
biometricsCancelButtonString: "Cancel",
|
||||
);
|
||||
} else {
|
||||
if (AppConfig.appName == "Campfire" &&
|
||||
!CampfireMigration.didRun &&
|
||||
CampfireMigration.hasOldWallets) {
|
||||
return const CampfireMigrateView();
|
||||
} else {
|
||||
return const IntroView();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CURRENTLY DISABLED as cannot be animated
|
||||
// technically not needed as FlutterNativeSplash will overlay
|
||||
// anything returned here until the future completes but
|
||||
// FutureBuilder requires you to return something
|
||||
return const LoadingView();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
98
lib/models/electrumx_response/spark_models.dart
Normal file
98
lib/models/electrumx_response/spark_models.dart
Normal file
|
@ -0,0 +1,98 @@
|
|||
class SparkMempoolData {
|
||||
final String txid;
|
||||
final List<String> serialContext;
|
||||
final List<String> lTags;
|
||||
final List<String> coins;
|
||||
|
||||
SparkMempoolData({
|
||||
required this.txid,
|
||||
required this.serialContext,
|
||||
required this.lTags,
|
||||
required this.coins,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "SparkMempoolData{"
|
||||
"txid: $txid, "
|
||||
"serialContext: $serialContext, "
|
||||
"lTags: $lTags, "
|
||||
"coins: $coins"
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
||||
class SparkAnonymitySetMeta {
|
||||
final int coinGroupId;
|
||||
final String blockHash;
|
||||
final String setHash;
|
||||
final int size;
|
||||
|
||||
SparkAnonymitySetMeta({
|
||||
required this.coinGroupId,
|
||||
required this.blockHash,
|
||||
required this.setHash,
|
||||
required this.size,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "SparkAnonymitySetMeta{"
|
||||
"coinGroupId: $coinGroupId, "
|
||||
"blockHash: $blockHash, "
|
||||
"setHash: $setHash, "
|
||||
"size: $size"
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
||||
class RawSparkCoin {
|
||||
final String serialized;
|
||||
final String txHash;
|
||||
final String context;
|
||||
final int groupId;
|
||||
|
||||
RawSparkCoin({
|
||||
required this.serialized,
|
||||
required this.txHash,
|
||||
required this.context,
|
||||
required this.groupId,
|
||||
});
|
||||
|
||||
static RawSparkCoin fromRPCResponse(List<dynamic> data, int groupId) {
|
||||
try {
|
||||
if (data.length != 3) throw Exception();
|
||||
return RawSparkCoin(
|
||||
serialized: data[0] as String,
|
||||
txHash: data[1] as String,
|
||||
context: data[2] as String,
|
||||
groupId: groupId,
|
||||
);
|
||||
} catch (_) {
|
||||
throw Exception("Invalid coin data: $data");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! RawSparkCoin) return false;
|
||||
return serialized == other.serialized &&
|
||||
txHash == other.txHash &&
|
||||
groupId == other.groupId &&
|
||||
context == other.context;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(serialized, txHash, context);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "SparkAnonymitySetMeta{"
|
||||
"serialized: $serialized, "
|
||||
"txHash: $txHash, "
|
||||
"context: $context, "
|
||||
"groupId: $groupId"
|
||||
"}";
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
|
||||
import '../../../utilities/logger.dart';
|
||||
|
||||
enum CNEstimateType { direct, reverse }
|
||||
|
@ -112,8 +113,11 @@ class CNExchangeEstimate {
|
|||
toAmount: Decimal.parse(json["toAmount"].toString()),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("Failed to parse: $json \n$e\n$s", level: LogLevel.Fatal);
|
||||
Logging.instance.e(
|
||||
"Failed to parse: $json",
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,8 +57,11 @@ class EstimatedExchangeAmount {
|
|||
networkFee: Decimal.tryParse(json["networkFee"].toString()),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("Failed to parse: $json \n$e\n$s", level: LogLevel.Fatal);
|
||||
Logging.instance.e(
|
||||
"Failed to parse: $json",
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ class ExchangeTransactionStatus {
|
|||
});
|
||||
|
||||
factory ExchangeTransactionStatus.fromJson(Map<String, dynamic> json) {
|
||||
Logging.instance.log(json, printFullLength: true, level: LogLevel.Info);
|
||||
Logging.instance.d(json, stackTrace: StackTrace.current);
|
||||
try {
|
||||
return ExchangeTransactionStatus(
|
||||
status: changeNowTransactionStatusFromStringIgnoreCase(
|
||||
|
@ -228,7 +228,7 @@ class ExchangeTransactionStatus {
|
|||
payload: json["payload"] as Object?,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
|
||||
Logging.instance.f("", error: e, stackTrace: s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
|
||||
import '../../../utilities/logger.dart';
|
||||
|
||||
class Estimate {
|
||||
|
@ -18,6 +19,7 @@ class Estimate {
|
|||
final String? warningMessage;
|
||||
final String? rateId;
|
||||
final String exchangeProvider;
|
||||
final String? exchangeProviderLogo;
|
||||
final String? kycRating;
|
||||
|
||||
Estimate({
|
||||
|
@ -27,6 +29,7 @@ class Estimate {
|
|||
this.warningMessage,
|
||||
this.rateId,
|
||||
required this.exchangeProvider,
|
||||
this.exchangeProviderLogo,
|
||||
this.kycRating,
|
||||
});
|
||||
|
||||
|
@ -46,7 +49,11 @@ class Estimate {
|
|||
kycRating: kycRating,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Estimate.fromMap(): $e\n$s", level: LogLevel.Error);
|
||||
Logging.instance.e(
|
||||
"Estimate.fromMap()",
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
|
||||
import '../../../utilities/logger.dart';
|
||||
|
||||
class FixedRateMarket {
|
||||
|
@ -53,10 +54,7 @@ class FixedRateMarket {
|
|||
minerFee: Decimal.tryParse(json["minerFee"].toString()),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"FixedRateMarket.fromMap(): $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
Logging.instance.e("FixedRateMarket.fromMap(): ", error: e, stackTrace: s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,10 +59,7 @@ class SPCurrency {
|
|||
warningsTo: json["warnings_to"] as List<dynamic>,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"SPCurrency.fromJson failed to parse: $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
Logging.instance.e("SPCurrency.fromJson failed to parse: ", error: e, stackTrace: s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'currency.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetCurrencyCollection on Isar {
|
||||
IsarCollection<Currency> get currencies => this.collection();
|
||||
|
@ -135,7 +135,7 @@ const CurrencySchema = CollectionSchema(
|
|||
getId: _currencyGetId,
|
||||
getLinks: _currencyGetLinks,
|
||||
attach: _currencyAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _currencyEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'pair.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetPairCollection on Isar {
|
||||
IsarCollection<Pair> get pairs => this.collection();
|
||||
|
@ -92,7 +92,7 @@ const PairSchema = CollectionSchema(
|
|||
getId: _pairGetId,
|
||||
getLinks: _pairGetLinks,
|
||||
attach: _pairAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _pairEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'address_label.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetAddressLabelCollection on Isar {
|
||||
IsarCollection<AddressLabel> get addressLabels => this.collection();
|
||||
|
@ -81,7 +81,7 @@ const AddressLabelSchema = CollectionSchema(
|
|||
getId: _addressLabelGetId,
|
||||
getLinks: _addressLabelGetLinks,
|
||||
attach: _addressLabelAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _addressLabelEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'block_explorer.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetTransactionBlockExplorerCollection on Isar {
|
||||
IsarCollection<TransactionBlockExplorer> get transactionBlockExplorers =>
|
||||
|
@ -54,7 +54,7 @@ const TransactionBlockExplorerSchema = CollectionSchema(
|
|||
getId: _transactionBlockExplorerGetId,
|
||||
getLinks: _transactionBlockExplorerGetLinks,
|
||||
attach: _transactionBlockExplorerAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _transactionBlockExplorerEstimateSize(
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
import '../../../../exceptions/address/address_exception.dart';
|
||||
import 'crypto_currency_address.dart';
|
||||
import 'transaction.dart';
|
||||
|
@ -27,6 +28,7 @@ class Address extends CryptoCurrencyAddress {
|
|||
required this.derivationPath,
|
||||
required this.type,
|
||||
required this.subType,
|
||||
this.zSafeFrost,
|
||||
this.otherData,
|
||||
});
|
||||
|
||||
|
@ -55,6 +57,8 @@ class Address extends CryptoCurrencyAddress {
|
|||
|
||||
final transactions = IsarLinks<Transaction>();
|
||||
|
||||
late final bool? zSafeFrost;
|
||||
|
||||
int derivationChain() {
|
||||
if (subType == AddressSubType.receiving) {
|
||||
return 0; // 0 for receiving (external)
|
||||
|
@ -80,6 +84,7 @@ class Address extends CryptoCurrencyAddress {
|
|||
AddressType? type,
|
||||
AddressSubType? subType,
|
||||
DerivationPath? derivationPath,
|
||||
bool? zSafeFrost,
|
||||
String? otherData,
|
||||
}) {
|
||||
return Address(
|
||||
|
@ -90,6 +95,7 @@ class Address extends CryptoCurrencyAddress {
|
|||
type: type ?? this.type,
|
||||
subType: subType ?? this.subType,
|
||||
derivationPath: derivationPath ?? this.derivationPath,
|
||||
zSafeFrost: zSafeFrost ?? this.zSafeFrost,
|
||||
otherData: otherData ?? this.otherData,
|
||||
);
|
||||
}
|
||||
|
@ -105,6 +111,7 @@ class Address extends CryptoCurrencyAddress {
|
|||
"subType: ${subType.name}, "
|
||||
"transactionsLength: ${transactions.length} "
|
||||
"derivationPath: $derivationPath, "
|
||||
"zSafeFrost: $zSafeFrost, "
|
||||
"otherData: $otherData, "
|
||||
"}";
|
||||
|
||||
|
@ -117,6 +124,7 @@ class Address extends CryptoCurrencyAddress {
|
|||
"type": type.name,
|
||||
"subType": subType.name,
|
||||
"derivationPath": derivationPath?.value,
|
||||
"zSafeFrost": zSafeFrost,
|
||||
"otherData": otherData,
|
||||
};
|
||||
return jsonEncode(result);
|
||||
|
@ -143,6 +151,7 @@ class Address extends CryptoCurrencyAddress {
|
|||
derivationPath: derivationPath,
|
||||
type: AddressType.values.byName(json["type"] as String),
|
||||
subType: AddressSubType.values.byName(json["subType"] as String),
|
||||
zSafeFrost: json["zSafeFrost"] as bool?,
|
||||
otherData: json["otherData"] as String?,
|
||||
);
|
||||
}
|
||||
|
@ -165,7 +174,9 @@ enum AddressType {
|
|||
tezos,
|
||||
frostMS,
|
||||
p2tr,
|
||||
solana;
|
||||
solana,
|
||||
cardanoShelley,
|
||||
xelis;
|
||||
|
||||
String get readableName {
|
||||
switch (this) {
|
||||
|
@ -201,6 +212,10 @@ enum AddressType {
|
|||
return "Solana";
|
||||
case AddressType.p2tr:
|
||||
return "P2TR (taproot)";
|
||||
case AddressType.cardanoShelley:
|
||||
return "Cardano Shelley";
|
||||
case AddressType.xelis:
|
||||
return "Xelis";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'address.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetAddressCollection on Isar {
|
||||
IsarCollection<Address> get addresses => this.collection();
|
||||
|
@ -59,6 +59,11 @@ const AddressSchema = CollectionSchema(
|
|||
id: 7,
|
||||
name: r'walletId',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'zSafeFrost': PropertySchema(
|
||||
id: 8,
|
||||
name: r'zSafeFrost',
|
||||
type: IsarType.bool,
|
||||
)
|
||||
},
|
||||
estimateSize: _addressEstimateSize,
|
||||
|
@ -124,7 +129,7 @@ const AddressSchema = CollectionSchema(
|
|||
getId: _addressGetId,
|
||||
getLinks: _addressGetLinks,
|
||||
attach: _addressAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _addressEstimateSize(
|
||||
|
@ -172,6 +177,7 @@ void _addressSerialize(
|
|||
writer.writeByte(offsets[5], object.type.index);
|
||||
writer.writeString(offsets[6], object.value);
|
||||
writer.writeString(offsets[7], object.walletId);
|
||||
writer.writeBool(offsets[8], object.zSafeFrost);
|
||||
}
|
||||
|
||||
Address _addressDeserialize(
|
||||
|
@ -195,6 +201,7 @@ Address _addressDeserialize(
|
|||
AddressType.p2pkh,
|
||||
value: reader.readString(offsets[6]),
|
||||
walletId: reader.readString(offsets[7]),
|
||||
zSafeFrost: reader.readBoolOrNull(offsets[8]),
|
||||
);
|
||||
object.id = id;
|
||||
return object;
|
||||
|
@ -229,6 +236,8 @@ P _addressDeserializeProp<P>(
|
|||
return (reader.readString(offset)) as P;
|
||||
case 7:
|
||||
return (reader.readString(offset)) as P;
|
||||
case 8:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
|
@ -269,6 +278,8 @@ const _AddresstypeEnumValueMap = {
|
|||
'frostMS': 13,
|
||||
'p2tr': 14,
|
||||
'solana': 15,
|
||||
'cardanoShelley': 16,
|
||||
'xelis': 17,
|
||||
};
|
||||
const _AddresstypeValueEnumMap = {
|
||||
0: AddressType.p2pkh,
|
||||
|
@ -287,6 +298,8 @@ const _AddresstypeValueEnumMap = {
|
|||
13: AddressType.frostMS,
|
||||
14: AddressType.p2tr,
|
||||
15: AddressType.solana,
|
||||
16: AddressType.cardanoShelley,
|
||||
17: AddressType.xelis,
|
||||
};
|
||||
|
||||
Id _addressGetId(Address object) {
|
||||
|
@ -1474,6 +1487,32 @@ extension AddressQueryFilter
|
|||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, Address, QAfterFilterCondition> zSafeFrostIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'zSafeFrost',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, Address, QAfterFilterCondition> zSafeFrostIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'zSafeFrost',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, Address, QAfterFilterCondition> zSafeFrostEqualTo(
|
||||
bool? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'zSafeFrost',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension AddressQueryObject
|
||||
|
@ -1621,6 +1660,18 @@ extension AddressQuerySortBy on QueryBuilder<Address, Address, QSortBy> {
|
|||
return query.addSortBy(r'walletId', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, Address, QAfterSortBy> sortByZSafeFrost() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'zSafeFrost', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, Address, QAfterSortBy> sortByZSafeFrostDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'zSafeFrost', Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension AddressQuerySortThenBy
|
||||
|
@ -1708,6 +1759,18 @@ extension AddressQuerySortThenBy
|
|||
return query.addSortBy(r'walletId', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, Address, QAfterSortBy> thenByZSafeFrost() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'zSafeFrost', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, Address, QAfterSortBy> thenByZSafeFrostDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'zSafeFrost', Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension AddressQueryWhereDistinct
|
||||
|
@ -1756,6 +1819,12 @@ extension AddressQueryWhereDistinct
|
|||
return query.addDistinctBy(r'walletId', caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, Address, QDistinct> distinctByZSafeFrost() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'zSafeFrost');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension AddressQueryProperty
|
||||
|
@ -1814,6 +1883,12 @@ extension AddressQueryProperty
|
|||
return query.addPropertyName(r'walletId');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Address, bool?, QQueryOperations> zSafeFrostProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'zSafeFrost');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
|
@ -1821,7 +1896,7 @@ extension AddressQueryProperty
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const DerivationPathSchema = Schema(
|
||||
name: r'DerivationPath',
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'input.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const InputSchema = Schema(
|
||||
name: r'Input',
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'output.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const OutputSchema = Schema(
|
||||
name: r'Output',
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'transaction.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetTransactionCollection on Isar {
|
||||
IsarCollection<Transaction> get transactions => this.collection();
|
||||
|
@ -171,7 +171,7 @@ const TransactionSchema = CollectionSchema(
|
|||
getId: _transactionGetId,
|
||||
getLinks: _transactionGetLinks,
|
||||
attach: _transactionAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _transactionEstimateSize(
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:isar/isar.dart';
|
||||
|
@ -76,12 +77,43 @@ class UTXO {
|
|||
int getConfirmations(int currentChainHeight) {
|
||||
if (blockTime == null || blockHash == null) return 0;
|
||||
if (blockHeight == null || blockHeight! <= 0) return 0;
|
||||
return max(0, currentChainHeight - (blockHeight! - 1));
|
||||
return _isMonero()
|
||||
? max(0, currentChainHeight - (blockHeight!))
|
||||
: max(0, currentChainHeight - (blockHeight! - 1));
|
||||
}
|
||||
|
||||
bool isConfirmed(int currentChainHeight, int minimumConfirms) {
|
||||
bool isConfirmed(
|
||||
int currentChainHeight,
|
||||
int minimumConfirms,
|
||||
int minimumCoinbaseConfirms, {
|
||||
int? overrideMinConfirms, // added to handle namecoin name op outputs
|
||||
}) {
|
||||
final confirmations = getConfirmations(currentChainHeight);
|
||||
return confirmations >= minimumConfirms;
|
||||
|
||||
if (overrideMinConfirms != null) {
|
||||
return confirmations >= overrideMinConfirms;
|
||||
}
|
||||
return confirmations >=
|
||||
(isCoinbase ? minimumCoinbaseConfirms : minimumConfirms);
|
||||
}
|
||||
|
||||
// fuzzy
|
||||
bool _isMonero() {
|
||||
return keyImage != null;
|
||||
}
|
||||
|
||||
@ignore
|
||||
String? get keyImage {
|
||||
if (otherData == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final map = jsonDecode(otherData!) as Map;
|
||||
return map[UTXOOtherDataKeys.keyImage] as String;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
UTXO copyWith({
|
||||
|
@ -149,3 +181,9 @@ class UTXO {
|
|||
@ignore
|
||||
int get hashCode => Object.hashAll([walletId, txid, vout]);
|
||||
}
|
||||
|
||||
abstract final class UTXOOtherDataKeys {
|
||||
static const keyImage = "keyImage";
|
||||
static const spent = "spent";
|
||||
static const nameOpData = "nameOpData";
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'utxo.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetUTXOCollection on Isar {
|
||||
IsarCollection<UTXO> get utxos => this.collection();
|
||||
|
@ -149,7 +149,7 @@ const UTXOSchema = CollectionSchema(
|
|||
getId: _uTXOGetId,
|
||||
getLinks: _uTXOGetLinks,
|
||||
attach: _uTXOAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _uTXOEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'input_v2.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const OutpointV2Schema = Schema(
|
||||
name: r'OutpointV2',
|
||||
|
@ -330,7 +330,7 @@ extension OutpointV2QueryObject
|
|||
on QueryBuilder<OutpointV2, OutpointV2, QFilterCondition> {}
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const InputV2Schema = Schema(
|
||||
name: r'InputV2',
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'output_v2.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const OutputV2Schema = Schema(
|
||||
name: r'OutputV2',
|
||||
|
|
|
@ -109,12 +109,19 @@ class TransactionV2 {
|
|||
|
||||
int getConfirmations(int currentChainHeight) {
|
||||
if (height == null || height! <= 0) return 0;
|
||||
return max(0, currentChainHeight - (height! - 1));
|
||||
return _isMonero()
|
||||
? max(0, currentChainHeight - (height!))
|
||||
: max(0, currentChainHeight - (height! - 1));
|
||||
}
|
||||
|
||||
bool isConfirmed(int currentChainHeight, int minimumConfirms) {
|
||||
bool isConfirmed(
|
||||
int currentChainHeight,
|
||||
int minimumConfirms,
|
||||
int minimumCoinbaseConfirms,
|
||||
) {
|
||||
final confirmations = getConfirmations(currentChainHeight);
|
||||
return confirmations >= minimumConfirms;
|
||||
return confirmations >=
|
||||
(isCoinbase() ? minimumCoinbaseConfirms : minimumConfirms);
|
||||
}
|
||||
|
||||
Amount getFee({required int fractionDigits}) {
|
||||
|
@ -124,6 +131,10 @@ class TransactionV2 {
|
|||
return fee;
|
||||
}
|
||||
|
||||
if (isCoinbase()) {
|
||||
return Amount.zeroWith(fractionDigits: fractionDigits);
|
||||
}
|
||||
|
||||
final inSum =
|
||||
inputs.map((e) => e.value).reduce((value, element) => value += element);
|
||||
final outSum = outputs
|
||||
|
@ -134,6 +145,14 @@ class TransactionV2 {
|
|||
}
|
||||
|
||||
Amount getAmountReceivedInThisWallet({required int fractionDigits}) {
|
||||
if (_isMonero()) {
|
||||
if (type == TransactionType.incoming) {
|
||||
return _getMoneroAmount()!;
|
||||
} else {
|
||||
return Amount.zeroWith(fractionDigits: fractionDigits);
|
||||
}
|
||||
}
|
||||
|
||||
final outSum = outputs
|
||||
.where((e) => e.walletOwns)
|
||||
.fold(BigInt.zero, (p, e) => p + e.value);
|
||||
|
@ -151,6 +170,14 @@ class TransactionV2 {
|
|||
}
|
||||
|
||||
Amount getAmountSentFromThisWallet({required int fractionDigits}) {
|
||||
if (_isMonero()) {
|
||||
if (type == TransactionType.outgoing) {
|
||||
return _getMoneroAmount()!;
|
||||
} else {
|
||||
return Amount.zeroWith(fractionDigits: fractionDigits);
|
||||
}
|
||||
}
|
||||
|
||||
final inSum = inputs
|
||||
.where((e) => e.walletOwns)
|
||||
.fold(BigInt.zero, (p, e) => p + e.value);
|
||||
|
@ -191,18 +218,37 @@ class TransactionV2 {
|
|||
}
|
||||
}
|
||||
|
||||
Amount? _getMoneroAmount() {
|
||||
try {
|
||||
return Amount.fromSerializedJsonString(
|
||||
_getFromOtherData(key: TxV2OdKeys.moneroAmount) as String,
|
||||
);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
bool _isMonero() {
|
||||
final value = _getFromOtherData(key: TxV2OdKeys.isMoneroTransaction);
|
||||
return value is bool ? value : false;
|
||||
}
|
||||
|
||||
String statusLabel({
|
||||
required int currentChainHeight,
|
||||
required int minConfirms,
|
||||
required int minCoinbaseConfirms,
|
||||
}) {
|
||||
String prettyConfirms() =>
|
||||
"(${getConfirmations(currentChainHeight)}/$minConfirms)";
|
||||
String prettyConfirms() => "("
|
||||
"${getConfirmations(currentChainHeight)}"
|
||||
"/"
|
||||
"${(isCoinbase() ? minCoinbaseConfirms : minConfirms)}"
|
||||
")";
|
||||
|
||||
if (subType == TransactionSubType.cashFusion ||
|
||||
subType == TransactionSubType.mint ||
|
||||
(subType == TransactionSubType.sparkMint &&
|
||||
type == TransactionType.sentToSelf)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Anonymized";
|
||||
} else {
|
||||
return "Anonymizing ${prettyConfirms()}";
|
||||
|
@ -217,7 +263,7 @@ class TransactionV2 {
|
|||
if (isCancelled) {
|
||||
return "Cancelled";
|
||||
} else if (type == TransactionType.incoming) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Received";
|
||||
} else {
|
||||
if (numberOfMessages == 1) {
|
||||
|
@ -229,7 +275,7 @@ class TransactionV2 {
|
|||
}
|
||||
}
|
||||
} else if (type == TransactionType.outgoing) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Sent (confirmed)";
|
||||
} else {
|
||||
if (numberOfMessages == 1) {
|
||||
|
@ -247,19 +293,19 @@ class TransactionV2 {
|
|||
// if (_transaction.isMinting) {
|
||||
// return "Minting";
|
||||
// } else
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Received";
|
||||
} else {
|
||||
return "Receiving ${prettyConfirms()}";
|
||||
}
|
||||
} else if (type == TransactionType.outgoing) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Sent";
|
||||
} else {
|
||||
return "Sending ${prettyConfirms()}";
|
||||
}
|
||||
} else if (type == TransactionType.sentToSelf) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Sent to self";
|
||||
} else {
|
||||
return "Sent to self ${prettyConfirms()}";
|
||||
|
@ -277,6 +323,9 @@ class TransactionV2 {
|
|||
return map[key];
|
||||
}
|
||||
|
||||
bool isCoinbase() =>
|
||||
type == TransactionType.incoming && inputs.any((e) => e.coinbase != null);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TransactionV2(\n'
|
||||
|
@ -307,4 +356,7 @@ abstract final class TxV2OdKeys {
|
|||
static const contractAddress = "contractAddress";
|
||||
static const nonce = "nonce";
|
||||
static const overrideFee = "overrideFee";
|
||||
static const moneroAmount = "moneroAmount";
|
||||
static const moneroAccountIndex = "moneroAccountIndex";
|
||||
static const isMoneroTransaction = "isMoneroTransaction";
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'transaction_v2.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetTransactionV2Collection on Isar {
|
||||
IsarCollection<TransactionV2> get transactionV2s => this.collection();
|
||||
|
@ -177,7 +177,7 @@ const TransactionV2Schema = CollectionSchema(
|
|||
getId: _transactionV2GetId,
|
||||
getLinks: _transactionV2GetLinks,
|
||||
attach: _transactionV2Attach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _transactionV2EstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'contact_entry.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetContactEntryCollection on Isar {
|
||||
IsarCollection<ContactEntry> get contactEntrys => this.collection();
|
||||
|
@ -69,7 +69,7 @@ const ContactEntrySchema = CollectionSchema(
|
|||
getId: _contactEntryGetId,
|
||||
getLinks: _contactEntryGetLinks,
|
||||
attach: _contactEntryAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _contactEntryEstimateSize(
|
||||
|
@ -1142,7 +1142,7 @@ extension ContactEntryQueryProperty
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const ContactAddressEntrySchema = Schema(
|
||||
name: r'ContactAddressEntry',
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'encrypted_string_value.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetEncryptedStringValueCollection on Isar {
|
||||
IsarCollection<EncryptedStringValue> get encryptedStringValues =>
|
||||
|
@ -54,7 +54,7 @@ const EncryptedStringValueSchema = CollectionSchema(
|
|||
getId: _encryptedStringValueGetId,
|
||||
getLinks: _encryptedStringValueGetLinks,
|
||||
attach: _encryptedStringValueAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _encryptedStringValueEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'eth_contract.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetEthContractCollection on Isar {
|
||||
IsarCollection<EthContract> get ethContracts => this.collection();
|
||||
|
@ -74,7 +74,7 @@ const EthContractSchema = CollectionSchema(
|
|||
getId: _ethContractGetId,
|
||||
getLinks: _ethContractGetLinks,
|
||||
attach: _ethContractAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _ethContractEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'lelantus_coin.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetLelantusCoinCollection on Isar {
|
||||
IsarCollection<LelantusCoin> get lelantusCoins => this.collection();
|
||||
|
@ -101,7 +101,7 @@ const LelantusCoinSchema = CollectionSchema(
|
|||
getId: _lelantusCoinGetId,
|
||||
getLinks: _lelantusCoinGetLinks,
|
||||
attach: _lelantusCoinAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _lelantusCoinEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'log.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetLogCollection on Isar {
|
||||
IsarCollection<Log> get logs => this.collection();
|
||||
|
@ -59,7 +59,7 @@ const LogSchema = CollectionSchema(
|
|||
getId: _logGetId,
|
||||
getLinks: _logGetLinks,
|
||||
attach: _logAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _logEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'sent_to_address.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetSentToAddressCollection on Isar {
|
||||
IsarCollection<SentToAddress> get sentToAddress => this.collection();
|
||||
|
@ -81,7 +81,7 @@ const SentToAddressSchema = CollectionSchema(
|
|||
getId: _sentToAddressGetId,
|
||||
getLinks: _sentToAddressGetLinks,
|
||||
attach: _sentToAddressAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _sentToAddressEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'transaction_note.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetTransactionNoteCollection on Isar {
|
||||
IsarCollection<TransactionNote> get transactionNotes => this.collection();
|
||||
|
@ -76,7 +76,7 @@ const TransactionNoteSchema = CollectionSchema(
|
|||
getId: _transactionNoteGetId,
|
||||
getLinks: _transactionNoteGetLinks,
|
||||
attach: _transactionNoteAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _transactionNoteEstimateSize(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'ordinal.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetOrdinalCollection on Isar {
|
||||
IsarCollection<Ordinal> get ordinals => this.collection();
|
||||
|
@ -83,7 +83,7 @@ const OrdinalSchema = CollectionSchema(
|
|||
getId: _ordinalGetId,
|
||||
getLinks: _ordinalGetLinks,
|
||||
attach: _ordinalAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _ordinalEstimateSize(
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
import '../../app_config.dart';
|
||||
import '../../utilities/extensions/impl/box_shadow.dart';
|
||||
import '../../utilities/extensions/impl/gradient.dart';
|
||||
|
@ -1884,10 +1885,7 @@ class StackTheme {
|
|||
(map[mainNetId] as String).toBigIntFromHex.toInt(),
|
||||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"Color not found in theme for $mainNetId",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
Logging.instance.w("Color not found in theme for $mainNetId");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'stack_theme.dart';
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetStackThemeCollection on Isar {
|
||||
IsarCollection<StackTheme> get stackThemes => this.collection();
|
||||
|
@ -860,7 +860,7 @@ const StackThemeSchema = CollectionSchema(
|
|||
getId: _stackThemeGetId,
|
||||
getLinks: _stackThemeGetLinks,
|
||||
attach: _stackThemeAttach,
|
||||
version: '3.0.5',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _stackThemeEstimateSize(
|
||||
|
@ -18012,7 +18012,7 @@ extension StackThemeQueryProperty
|
|||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const ThemeAssetsSchema = Schema(
|
||||
name: r'ThemeAssets',
|
||||
|
@ -25833,7 +25833,7 @@ extension ThemeAssetsQueryObject
|
|||
on QueryBuilder<ThemeAssets, ThemeAssets, QFilterCondition> {}
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const ThemeAssetsV2Schema = Schema(
|
||||
name: r'ThemeAssetsV2',
|
||||
|
@ -29441,7 +29441,7 @@ extension ThemeAssetsV2QueryObject
|
|||
on QueryBuilder<ThemeAssetsV2, ThemeAssetsV2, QFilterCondition> {}
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
const ThemeAssetsV3Schema = Schema(
|
||||
name: r'ThemeAssetsV3',
|
||||
|
|
164
lib/models/keys/view_only_wallet_data.dart
Normal file
164
lib/models/keys/view_only_wallet_data.dart
Normal file
|
@ -0,0 +1,164 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import '../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
|
||||
import 'key_data_interface.dart';
|
||||
|
||||
// do not remove or change the order of these enum values
|
||||
enum ViewOnlyWalletType {
|
||||
cryptonote,
|
||||
addressOnly,
|
||||
xPub;
|
||||
}
|
||||
|
||||
sealed class ViewOnlyWalletData with KeyDataInterface {
|
||||
@override
|
||||
final String walletId;
|
||||
|
||||
ViewOnlyWalletType get type;
|
||||
|
||||
ViewOnlyWalletData({
|
||||
required this.walletId,
|
||||
});
|
||||
|
||||
static ViewOnlyWalletData fromJsonEncodedString(
|
||||
String jsonEncodedString, {
|
||||
required String walletId,
|
||||
}) {
|
||||
final map = jsonDecode(jsonEncodedString) as Map;
|
||||
final json = Map<String, dynamic>.from(map);
|
||||
final type = ViewOnlyWalletType.values[json["type"] as int];
|
||||
|
||||
switch (type) {
|
||||
case ViewOnlyWalletType.cryptonote:
|
||||
return CryptonoteViewOnlyWalletData.fromJsonEncodedString(
|
||||
jsonEncodedString,
|
||||
walletId: walletId,
|
||||
);
|
||||
|
||||
case ViewOnlyWalletType.addressOnly:
|
||||
return AddressViewOnlyWalletData.fromJsonEncodedString(
|
||||
jsonEncodedString,
|
||||
walletId: walletId,
|
||||
);
|
||||
|
||||
case ViewOnlyWalletType.xPub:
|
||||
return ExtendedKeysViewOnlyWalletData.fromJsonEncodedString(
|
||||
jsonEncodedString,
|
||||
walletId: walletId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String toJsonEncodedString();
|
||||
}
|
||||
|
||||
class CryptonoteViewOnlyWalletData extends ViewOnlyWalletData {
|
||||
@override
|
||||
final type = ViewOnlyWalletType.cryptonote;
|
||||
|
||||
final String address;
|
||||
final String privateViewKey;
|
||||
|
||||
CryptonoteViewOnlyWalletData({
|
||||
required super.walletId,
|
||||
required this.address,
|
||||
required this.privateViewKey,
|
||||
});
|
||||
|
||||
static CryptonoteViewOnlyWalletData fromJsonEncodedString(
|
||||
String jsonEncodedString, {
|
||||
required String walletId,
|
||||
}) {
|
||||
final map = jsonDecode(jsonEncodedString) as Map;
|
||||
final json = Map<String, dynamic>.from(map);
|
||||
|
||||
return CryptonoteViewOnlyWalletData(
|
||||
walletId: walletId,
|
||||
address: json["address"] as String,
|
||||
privateViewKey: json["privateViewKey"] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toJsonEncodedString() => jsonEncode({
|
||||
"type": type.index,
|
||||
"address": address,
|
||||
"privateViewKey": privateViewKey,
|
||||
});
|
||||
}
|
||||
|
||||
class AddressViewOnlyWalletData extends ViewOnlyWalletData {
|
||||
@override
|
||||
final type = ViewOnlyWalletType.addressOnly;
|
||||
|
||||
final String address;
|
||||
|
||||
AddressViewOnlyWalletData({
|
||||
required super.walletId,
|
||||
required this.address,
|
||||
});
|
||||
|
||||
static AddressViewOnlyWalletData fromJsonEncodedString(
|
||||
String jsonEncodedString, {
|
||||
required String walletId,
|
||||
}) {
|
||||
final map = jsonDecode(jsonEncodedString) as Map;
|
||||
final json = Map<String, dynamic>.from(map);
|
||||
|
||||
return AddressViewOnlyWalletData(
|
||||
walletId: walletId,
|
||||
address: json["address"] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toJsonEncodedString() => jsonEncode({
|
||||
"type": type.index,
|
||||
"address": address,
|
||||
});
|
||||
}
|
||||
|
||||
class ExtendedKeysViewOnlyWalletData extends ViewOnlyWalletData {
|
||||
@override
|
||||
final type = ViewOnlyWalletType.xPub;
|
||||
|
||||
final List<XPub> xPubs;
|
||||
|
||||
ExtendedKeysViewOnlyWalletData({
|
||||
required super.walletId,
|
||||
required List<XPub> xPubs,
|
||||
}) : xPubs = List.unmodifiable(xPubs);
|
||||
|
||||
static ExtendedKeysViewOnlyWalletData fromJsonEncodedString(
|
||||
String jsonEncodedString, {
|
||||
required String walletId,
|
||||
}) {
|
||||
final map = jsonDecode(jsonEncodedString) as Map;
|
||||
final json = Map<String, dynamic>.from(map);
|
||||
|
||||
return ExtendedKeysViewOnlyWalletData(
|
||||
walletId: walletId,
|
||||
xPubs: List<Map<String, dynamic>>.from((json["xPubs"] as List))
|
||||
.map(
|
||||
(e) => XPub(
|
||||
path: e["path"] as String,
|
||||
encoded: e["encoded"] as String,
|
||||
),
|
||||
)
|
||||
.toList(growable: false),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toJsonEncodedString() => jsonEncode({
|
||||
"type": type.index,
|
||||
"xPubs": [
|
||||
...xPubs.map(
|
||||
(e) => {
|
||||
"path": e.path,
|
||||
"encoded": e.encoded,
|
||||
},
|
||||
),
|
||||
],
|
||||
});
|
||||
}
|
25
lib/models/namecoin_dns/dns_a_record_address_type.dart
Normal file
25
lib/models/namecoin_dns/dns_a_record_address_type.dart
Normal file
|
@ -0,0 +1,25 @@
|
|||
enum DNSAddressType {
|
||||
IPv4,
|
||||
IPv6,
|
||||
Tor,
|
||||
Freenet,
|
||||
I2P,
|
||||
ZeroNet;
|
||||
|
||||
String get key {
|
||||
switch (this) {
|
||||
case DNSAddressType.IPv4:
|
||||
return "ip";
|
||||
case DNSAddressType.IPv6:
|
||||
return "ip6";
|
||||
case DNSAddressType.Tor:
|
||||
return "_tor";
|
||||
case DNSAddressType.Freenet:
|
||||
return "freenet";
|
||||
case DNSAddressType.I2P:
|
||||
return "i2p";
|
||||
case DNSAddressType.ZeroNet:
|
||||
return "zeronet";
|
||||
}
|
||||
}
|
||||
}
|
129
lib/models/namecoin_dns/dns_record.dart
Normal file
129
lib/models/namecoin_dns/dns_record.dart
Normal file
|
@ -0,0 +1,129 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:namecoin/namecoin.dart';
|
||||
|
||||
import '../../utilities/extensions/extensions.dart';
|
||||
import 'dns_record_type.dart';
|
||||
|
||||
@Immutable()
|
||||
abstract class DNSRecordBase {
|
||||
final String name;
|
||||
|
||||
DNSRecordBase({required this.name});
|
||||
|
||||
String getValueString();
|
||||
}
|
||||
|
||||
@Immutable()
|
||||
final class RawDNSRecord extends DNSRecordBase {
|
||||
final String value;
|
||||
|
||||
RawDNSRecord({required super.name, required this.value});
|
||||
|
||||
@override
|
||||
String getValueString() => value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "RawDNSRecord(name: $name, value: $value)";
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable()
|
||||
final class DNSRecord extends DNSRecordBase {
|
||||
final DNSRecordType type;
|
||||
final Map<String, dynamic> data;
|
||||
|
||||
DNSRecord({
|
||||
required super.name,
|
||||
required this.type,
|
||||
required this.data,
|
||||
});
|
||||
|
||||
@override
|
||||
String getValueString() {
|
||||
// TODO error handling
|
||||
dynamic value = data;
|
||||
while (value is Map) {
|
||||
value = value[value.keys.first];
|
||||
}
|
||||
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
DNSRecord copyWith({
|
||||
DNSRecordType? type,
|
||||
Map<String, dynamic>? data,
|
||||
}) {
|
||||
return DNSRecord(
|
||||
type: type ?? this.type,
|
||||
data: data ?? this.data,
|
||||
name: name,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "DNSRecord(name: $name, type: $type, data: $data)";
|
||||
}
|
||||
|
||||
static String merge(List<DNSRecord> records) {
|
||||
final Map<String, dynamic> result = {};
|
||||
|
||||
for (final record in records) {
|
||||
switch (record.type) {
|
||||
case DNSRecordType.CNAME:
|
||||
if (result[record.data.keys.first] != null) {
|
||||
throw Exception("CNAME record already exists");
|
||||
}
|
||||
_deepMerge(result, record.data);
|
||||
break;
|
||||
|
||||
case DNSRecordType.TLS:
|
||||
case DNSRecordType.NS:
|
||||
case DNSRecordType.DS:
|
||||
case DNSRecordType.SRV:
|
||||
case DNSRecordType.SSH:
|
||||
case DNSRecordType.TXT:
|
||||
case DNSRecordType.IMPORT:
|
||||
case DNSRecordType.A:
|
||||
_deepMerge(result, record.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final string = jsonEncode(result);
|
||||
if (string.toUint8ListFromUtf8.length > valueMaxLength) {
|
||||
throw Exception(
|
||||
"Value length (${string.toUint8ListFromUtf8.length}) exceeds maximum"
|
||||
" allowed ($valueMaxLength)",
|
||||
);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
void _deepMerge(Map<String, dynamic> base, Map<String, dynamic> updates) {
|
||||
updates.forEach((key, value) {
|
||||
if (value is Map<String, dynamic> && base[key] is Map<String, dynamic>) {
|
||||
_deepMerge(base[key] as Map<String, dynamic>, value);
|
||||
} else if (value is List && base[key] is List) {
|
||||
(base[key] as List).addAll(value);
|
||||
} else {
|
||||
if (base[key] != null) {
|
||||
throw Exception(
|
||||
"Attempted to overwrite value: ${base[key]} where key=$key",
|
||||
);
|
||||
}
|
||||
if (value is Map) {
|
||||
base[key] = Map<String, dynamic>.from(value);
|
||||
} else if (value is List) {
|
||||
base[key] = List<dynamic>.from(value);
|
||||
} else {
|
||||
base[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
68
lib/models/namecoin_dns/dns_record_type.dart
Normal file
68
lib/models/namecoin_dns/dns_record_type.dart
Normal file
|
@ -0,0 +1,68 @@
|
|||
enum DNSRecordType {
|
||||
A,
|
||||
CNAME,
|
||||
NS,
|
||||
DS,
|
||||
TLS,
|
||||
SRV,
|
||||
TXT,
|
||||
IMPORT,
|
||||
SSH;
|
||||
|
||||
String get info {
|
||||
switch (this) {
|
||||
case DNSRecordType.A:
|
||||
return "An A record maps your domain to an address (IPv4, IPv6, Tor,"
|
||||
" Freenet, I2P, or ZeroNet).";
|
||||
case DNSRecordType.CNAME:
|
||||
return "A CNAME record redirects your domain to another domain,"
|
||||
" essentially acting as an alias.";
|
||||
case DNSRecordType.NS:
|
||||
return "An NS record specifies the nameservers that are authoritative"
|
||||
" for your domain.";
|
||||
case DNSRecordType.DS:
|
||||
return "A DS record holds information about DNSSEC (DNS Security "
|
||||
"Extensions) for your domain, helping with verification and "
|
||||
"integrity.";
|
||||
case DNSRecordType.TLS:
|
||||
return "A TLS record is used for specifying details about how to "
|
||||
"establish secure connections (like TLS certificates) for your"
|
||||
" domain.";
|
||||
case DNSRecordType.SRV:
|
||||
return "An SRV record specifies the location of servers for specific"
|
||||
" services, such as SIP, XMPP, or Minecraft servers.";
|
||||
case DNSRecordType.TXT:
|
||||
return "A TXT record allows you to add arbitrary text to your domain's"
|
||||
" DNS record, often used for verification (e.g., SPF, DKIM).";
|
||||
case DNSRecordType.IMPORT:
|
||||
return "An IMPORT record is used to bring in DNS records from an"
|
||||
" external source into your domain's configuration.";
|
||||
case DNSRecordType.SSH:
|
||||
return "An SSH record provides information related to SSH public keys"
|
||||
" for securely connecting to your domain's services.";
|
||||
}
|
||||
}
|
||||
|
||||
String? get key {
|
||||
switch (this) {
|
||||
case DNSRecordType.A:
|
||||
return null;
|
||||
case DNSRecordType.CNAME:
|
||||
return "alias";
|
||||
case DNSRecordType.NS:
|
||||
return "ns";
|
||||
case DNSRecordType.DS:
|
||||
return "ds";
|
||||
case DNSRecordType.TLS:
|
||||
return "tls";
|
||||
case DNSRecordType.SRV:
|
||||
return "srv";
|
||||
case DNSRecordType.TXT:
|
||||
return "txt";
|
||||
case DNSRecordType.IMPORT:
|
||||
return "import";
|
||||
case DNSRecordType.SSH:
|
||||
return "sshfp";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
import '../utilities/default_nodes.dart';
|
||||
import '../utilities/flutter_secure_storage_interface.dart';
|
||||
|
||||
|
@ -38,6 +39,10 @@ class NodeModel {
|
|||
final bool isDown;
|
||||
// @HiveField(10)
|
||||
final bool? trusted;
|
||||
// @HiveField(11)
|
||||
final bool torEnabled;
|
||||
// @HiveField(12)
|
||||
final bool clearnetEnabled;
|
||||
|
||||
NodeModel({
|
||||
required this.host,
|
||||
|
@ -49,6 +54,8 @@ class NodeModel {
|
|||
required this.coinName,
|
||||
required this.isFailover,
|
||||
required this.isDown,
|
||||
required this.torEnabled,
|
||||
required this.clearnetEnabled,
|
||||
this.loginName,
|
||||
this.trusted,
|
||||
});
|
||||
|
@ -58,12 +65,14 @@ class NodeModel {
|
|||
int? port,
|
||||
String? name,
|
||||
bool? useSSL,
|
||||
String? loginName,
|
||||
required String? loginName,
|
||||
bool? enabled,
|
||||
String? coinName,
|
||||
bool? isFailover,
|
||||
bool? isDown,
|
||||
bool? trusted,
|
||||
required bool? trusted,
|
||||
bool? torEnabled,
|
||||
bool? clearnetEnabled,
|
||||
}) {
|
||||
return NodeModel(
|
||||
host: host ?? this.host,
|
||||
|
@ -71,12 +80,14 @@ class NodeModel {
|
|||
name: name ?? this.name,
|
||||
id: id,
|
||||
useSSL: useSSL ?? this.useSSL,
|
||||
loginName: loginName ?? this.loginName,
|
||||
loginName: loginName,
|
||||
enabled: enabled ?? this.enabled,
|
||||
coinName: coinName ?? this.coinName,
|
||||
isFailover: isFailover ?? this.isFailover,
|
||||
isDown: isDown ?? this.isDown,
|
||||
trusted: trusted ?? this.trusted,
|
||||
trusted: trusted,
|
||||
torEnabled: torEnabled ?? this.torEnabled,
|
||||
clearnetEnabled: clearnetEnabled ?? this.clearnetEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -98,6 +109,8 @@ class NodeModel {
|
|||
map['isFailover'] = isFailover;
|
||||
map['isDown'] = isDown;
|
||||
map['trusted'] = trusted;
|
||||
map['torEnabled'] = torEnabled;
|
||||
map['clearEnabled'] = clearnetEnabled;
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,13 +28,15 @@ class NodeModelAdapter extends TypeAdapter<NodeModel> {
|
|||
isFailover: fields[8] as bool,
|
||||
isDown: fields[9] as bool,
|
||||
trusted: fields[10] as bool?,
|
||||
torEnabled: fields[11] as bool? ?? true,
|
||||
clearnetEnabled: fields[12] as bool? ?? true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, NodeModel obj) {
|
||||
writer
|
||||
..writeByte(11)
|
||||
..writeByte(13)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
|
@ -56,7 +58,11 @@ class NodeModelAdapter extends TypeAdapter<NodeModel> {
|
|||
..writeByte(9)
|
||||
..write(obj.isDown)
|
||||
..writeByte(10)
|
||||
..write(obj.trusted);
|
||||
..write(obj.trusted)
|
||||
..writeByte(11)
|
||||
..write(obj.torEnabled)
|
||||
..writeByte(12)
|
||||
..write(obj.clearnetEnabled);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:socks5_proxy/socks_client.dart';
|
||||
|
||||
import '../utilities/logger.dart';
|
||||
|
||||
// WIP wrapper layer
|
||||
|
@ -52,10 +53,7 @@ class HTTP {
|
|||
response.statusCode,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"HTTP.get() rethrew: $e\n$s",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
Logging.instance.w("HTTP.get() rethrew: ", error: e, stackTrace: s);
|
||||
rethrow;
|
||||
} finally {
|
||||
httpClient.close(force: true);
|
||||
|
@ -98,10 +96,7 @@ class HTTP {
|
|||
response.statusCode,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"HTTP.post() rethrew: $e\n$s",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
Logging.instance.w("HTTP.post() rethrew: ", error: e, stackTrace: s);
|
||||
rethrow;
|
||||
} finally {
|
||||
httpClient.close(force: true);
|
||||
|
@ -118,6 +113,11 @@ class HTTP {
|
|||
onDone: () => completer.complete(
|
||||
Uint8List.fromList(bytes),
|
||||
),
|
||||
onError: (Object err, StackTrace s) => Logging.instance.e(
|
||||
"Http wrapper layer listen",
|
||||
error: err,
|
||||
stackTrace: s,
|
||||
),
|
||||
);
|
||||
return completer.future;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
@ -69,6 +68,7 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
|
|||
...AppConfig.coins.where((e) => e.network == CryptoCurrencyNetwork.main),
|
||||
];
|
||||
final List<AddWalletListEntity> coinEntities = [];
|
||||
final List<AddWalletListEntity> coinTestnetEntities = [];
|
||||
final List<EthTokenEntity> tokenEntities = [];
|
||||
|
||||
final bool isDesktop = Util.isDesktop;
|
||||
|
@ -130,16 +130,11 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
|
|||
void initState() {
|
||||
_searchFieldController = TextEditingController();
|
||||
_searchFocusNode = FocusNode();
|
||||
// _coinsTestnet.remove(Coin.firoTestNet);
|
||||
|
||||
if (Util.isDesktop && !kDebugMode) {
|
||||
_coins.removeWhere((e) => e is BitcoinFrost);
|
||||
}
|
||||
|
||||
coinEntities.addAll(_coins.map((e) => CoinEntity(e)));
|
||||
|
||||
if (ref.read(prefsChangeNotifierProvider).showTestNetCoins) {
|
||||
coinEntities.addAll(_coinsTestnet.map((e) => CoinEntity(e)));
|
||||
coinTestnetEntities.addAll(_coinsTestnet.map((e) => CoinEntity(e)));
|
||||
}
|
||||
|
||||
if (AppConfig.coins.whereType<Ethereum>().isNotEmpty) {
|
||||
|
@ -158,7 +153,12 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
|
|||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.refresh(addWalletSelectedEntityStateProvider);
|
||||
if (mounted) {
|
||||
ref.refresh(addWalletSelectedEntityStateProvider);
|
||||
if (isDesktop) {
|
||||
_searchFocusNode.requestFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
super.initState();
|
||||
|
@ -286,6 +286,14 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
|
|||
initialState: ExpandableState.expanded,
|
||||
animationDurationMultiplier: 0.5,
|
||||
),
|
||||
if (coinTestnetEntities.isNotEmpty)
|
||||
ExpandingSubListItem(
|
||||
title: "Testnet",
|
||||
entities:
|
||||
filter(_searchTerm, coinTestnetEntities),
|
||||
initialState: ExpandableState.expanded,
|
||||
animationDurationMultiplier: 0.5,
|
||||
),
|
||||
if (tokenEntities.isNotEmpty)
|
||||
ExpandingSubListItem(
|
||||
title: "Tokens",
|
||||
|
@ -419,6 +427,13 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
|
|||
entities: filter(_searchTerm, coinEntities),
|
||||
initialState: ExpandableState.expanded,
|
||||
),
|
||||
if (coinTestnetEntities.isNotEmpty)
|
||||
ExpandingSubListItem(
|
||||
title: "Testnet",
|
||||
entities:
|
||||
filter(_searchTerm, coinTestnetEntities),
|
||||
initialState: ExpandableState.expanded,
|
||||
),
|
||||
if (tokenEntities.isNotEmpty)
|
||||
ExpandingSubListItem(
|
||||
title: "Tokens",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../../../frost_route_generator.dart';
|
||||
import '../../../../wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||
import '../../../../../providers/frost_wallet/frost_wallet_providers.dart';
|
||||
import '../../../../../services/frost.dart';
|
||||
import '../../../../../utilities/logger.dart';
|
||||
|
@ -15,6 +15,7 @@ import '../../../../../widgets/dialogs/frost/frost_error_dialog.dart';
|
|||
import '../../../../../widgets/frost_step_user_steps.dart';
|
||||
import '../../../../../widgets/stack_dialog.dart';
|
||||
import '../../../../../widgets/textfields/frost_step_field.dart';
|
||||
import '../../../../wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||
|
||||
class FrostCreateStep2 extends ConsumerStatefulWidget {
|
||||
const FrostCreateStep2({
|
||||
|
@ -177,10 +178,7 @@ class _FrostCreateStep2State extends ConsumerState<FrostCreateStep2> {
|
|||
.routeName,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"$e\n$s",
|
||||
level: LogLevel.Fatal,
|
||||
);
|
||||
Logging.instance.f("$e\n$s", error: e, stackTrace: s,);
|
||||
if (context.mounted) {
|
||||
return await showDialog<void>(
|
||||
context: context,
|
||||
|
|
|
@ -178,10 +178,7 @@ class _FrostCreateStep3State extends ConsumerState<FrostCreateStep3> {
|
|||
.routeName,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"$e\n$s",
|
||||
level: LogLevel.Fatal,
|
||||
);
|
||||
Logging.instance.f("$e\n$s", error: e, stackTrace: s,);
|
||||
|
||||
if (context.mounted) {
|
||||
return await showDialog<void>(
|
||||
|
|
|
@ -219,10 +219,7 @@ class _FrostCreateStep5State extends ConsumerState<FrostCreateStep5> {
|
|||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"$e\n$s",
|
||||
level: LogLevel.Fatal,
|
||||
);
|
||||
Logging.instance.f("$e\n$s", error: e, stackTrace: s,);
|
||||
|
||||
// pop progress dialog
|
||||
if (context.mounted && !progressPopped) {
|
||||
|
|
|
@ -81,10 +81,7 @@ class _FrostReshareStep1aState extends ConsumerState<FrostReshareStep1a> {
|
|||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"$e\n$s",
|
||||
level: LogLevel.Fatal,
|
||||
);
|
||||
Logging.instance.f("$e\n$s", error: e, stackTrace: s,);
|
||||
|
||||
if (mounted) {
|
||||
await showDialog<void>(
|
||||
|
|
|
@ -117,10 +117,7 @@ class _FrostReshareStep1bState extends ConsumerState<FrostReshareStep1b> {
|
|||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"$e\n$s",
|
||||
level: LogLevel.Fatal,
|
||||
);
|
||||
Logging.instance.f("$e\n$s", error: e, stackTrace: s,);
|
||||
|
||||
if (mounted) {
|
||||
await showDialog<void>(
|
||||
|
|
|
@ -204,10 +204,7 @@ class _FrostReshareStep1cState extends ConsumerState<FrostReshareStep1c> {
|
|||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"$e\n$s",
|
||||
level: LogLevel.Fatal,
|
||||
);
|
||||
Logging.instance.f("$e\n$s", error: e, stackTrace: s,);
|
||||
|
||||
if (context.mounted) {
|
||||
await showDialog<void>(
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue