Merge branch 'dev'
9
.gitignore
vendored
@@ -12,11 +12,11 @@ src/ui_*.h
|
|||||||
*.autosave
|
*.autosave
|
||||||
src/precompiled.h.cpp
|
src/precompiled.h.cpp
|
||||||
.qmake.stash
|
.qmake.stash
|
||||||
silentdragon
|
silentdragonlite
|
||||||
silentdragon.app
|
silentdragonlite.app
|
||||||
silentdragon-lite-mingw*
|
silentdragon-lite-mingw*
|
||||||
silentdragon-lite.vcxproj*
|
silentdragon-lite.vcxproj*
|
||||||
silentdragon.vcxproj*
|
silentdragonlite.vcxproj*
|
||||||
silentdragon-lite.sln
|
silentdragon-lite.sln
|
||||||
silentdragon-lite.pro.user
|
silentdragon-lite.pro.user
|
||||||
/Makefile
|
/Makefile
|
||||||
@@ -37,3 +37,6 @@ IDEWorkspaceChecks.plist
|
|||||||
*.sln
|
*.sln
|
||||||
node_modules
|
node_modules
|
||||||
silentdragonlite.pro.user.4.10-pre1
|
silentdragonlite.pro.user.4.10-pre1
|
||||||
|
silentdragonlite
|
||||||
|
silentdragonlite_plugin_import.cpp
|
||||||
|
silentdragonlite_resource.rc
|
||||||
|
|||||||
27
README.md
@@ -1,24 +1,31 @@
|
|||||||
# SilentDragonLite
|
# SilentDragonLite
|
||||||
|
|
||||||
SilentDragonLite is a GUI wallet for the [Hush](https://myhush.org) cryptocoin, which does not require you to download the full blockchain!
|
SilentDragonLite is a lightwallet for HUSH ($HUSH) runs on Linux and Windows which does not require you to download the full blockchain. This is experimental software under active development!
|
||||||
|
|
||||||
|
## PRIVACY NOTICE
|
||||||
|
|
||||||
|
SilentDragonLite contacts a few different external websites to get various bits of data. * coingecko.com for price data API * explorer.myhush.org for explorer links * dexstats.info for address utilities, hush-lightwallet.de to get Data.
|
||||||
|
|
||||||
|
This means your IP address is known to these servers. Enable Tor setting in SilentDragon to prevent this, or better yet, use TAILS: https://tails.boum.org/
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Go to the releases page and grab the latest installers or binary. https://github.com/MyHush/SilentDragonLite/releases
|
||||||
|
|
||||||
## Compiling from source
|
## Compiling from source
|
||||||
|
* SilentDragonLite is written in C++ 14, and can be compiled with g++/clang++/visual c++.
|
||||||
* silentdragon is written in C++ 14, and can be compiled with g++/clang++/visual c++.
|
|
||||||
* It also depends on Qt5, which you can get from [here](https://www.qt.io/download).
|
* It also depends on Qt5, which you can get from [here](https://www.qt.io/download).
|
||||||
* You'll need Rust v1.37 +
|
* You'll need Rust v1.37 +
|
||||||
|
|
||||||
### Building on Linux
|
## Building on Linux
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/MyHush/SilenDragonLite
|
git clone https://github.com/MyHush/SilenDragonLite.git
|
||||||
cd SilentDragonLite
|
cd silentdragonlite
|
||||||
qmake silentdragon-lite.pro CONFIG+=debug
|
/path/to/qt5/bin/qmake silentdragon-lite.pro CONFIG+=debug
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
```
|
|
||||||
And to run the binary:
|
|
||||||
|
|
||||||
```
|
|
||||||
./silentdragonlite
|
./silentdragonlite
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
6
lib/Cargo.lock
generated
@@ -1051,7 +1051,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=89ee34ba526d9d45a72787b07af9407bd96a337c)",
|
"silentdragonlitelib 0.1.0 (git+https://github.com/MyHush/silentdragonlite-cli?rev=099ad194dac6ee51474b3637d357aca0665a8181)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1467,7 +1467,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "silentdragonlitelib"
|
name = "silentdragonlitelib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/DenioD/silentdragonlite-cli?rev=89ee34ba526d9d45a72787b07af9407bd96a337c#89ee34ba526d9d45a72787b07af9407bd96a337c"
|
source = "git+https://github.com/MyHush/silentdragonlite-cli?rev=099ad194dac6ee51474b3637d357aca0665a8181#099ad194dac6ee51474b3637d357aca0665a8181"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bellman 0.1.0 (git+https://github.com/DenioD/librustzcash.git?rev=caaee693c47c2ee9ecd1e1546b8fe3c714f342bc)",
|
"bellman 0.1.0 (git+https://github.com/DenioD/librustzcash.git?rev=caaee693c47c2ee9ecd1e1546b8fe3c714f342bc)",
|
||||||
@@ -2481,7 +2481,7 @@ dependencies = [
|
|||||||
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
|
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
|
||||||
"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
|
"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
|
||||||
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||||
"checksum silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=89ee34ba526d9d45a72787b07af9407bd96a337c)" = "<none>"
|
"checksum silentdragonlitelib 0.1.0 (git+https://github.com/MyHush/silentdragonlite-cli?rev=099ad194dac6ee51474b3637d357aca0665a8181)" = "<none>"
|
||||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
|
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
|
||||||
"checksum sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585232e78a4fc18133eef9946d3080befdf68b906c51b621531c37e91787fa2b"
|
"checksum sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585232e78a4fc18133eef9946d3080befdf68b906c51b621531c37e91787fa2b"
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ crate-type = ["staticlib"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.58"
|
libc = "0.2.58"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
silentdragonlitelib = { git = "https://github.com/DenioD/silentdragonlite-cli", rev = "89ee34ba526d9d45a72787b07af9407bd96a337c" }
|
silentdragonlitelib = { git = "https://github.com/MyHush/silentdragonlite-cli", rev = "099ad194dac6ee51474b3637d357aca0665a8181" }
|
||||||
|
|||||||
10
lib/Makefile
@@ -1,24 +1,28 @@
|
|||||||
ifeq ($(shell uname),Darwin)
|
ifeq ($(shell uname),Darwin)
|
||||||
EXT := dylib
|
EXT := dylib
|
||||||
|
CFLAGS := "-mmacosx-version-min=10.11"
|
||||||
else
|
else
|
||||||
EXT := a
|
EXT := a
|
||||||
|
CFLAGS := ""
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
PWD := $(shell pwd)
|
||||||
|
|
||||||
all: release
|
all: release
|
||||||
|
|
||||||
winrelease: target/x86_64-pc-windows-gnu/release/silentdragonlite.lib
|
winrelease: target/x86_64-pc-windows-gnu/release/silentdragonlite.lib
|
||||||
|
|
||||||
target/x86_64-pc-windows-gnu/release/silentdragonlite.lib: src/lib.rs Cargo.toml
|
target/x86_64-pc-windows-gnu/release/silentdragonlite.lib: src/lib.rs Cargo.toml
|
||||||
cargo build --lib --release --target x86_64-pc-windows-gnu
|
SODIUM_LIB_DIR="$(PWD)/libsodium-mingw/" cargo build --lib --release --target x86_64-pc-windows-gnu
|
||||||
|
|
||||||
release: target/release/silentdragonlite.$(EXT)
|
release: target/release/silentdragonlite.$(EXT)
|
||||||
debug: target/debug/silentdragonlite.$(EXT)
|
debug: target/debug/silentdragonlite.$(EXT)
|
||||||
|
|
||||||
target/release/silentdragonlite.$(EXT): src/lib.rs Cargo.toml
|
target/release/silentdragonlite.$(EXT): src/lib.rs Cargo.toml
|
||||||
cargo build --lib --release
|
LIBS="" CFLAGS=$(CFLAGS) cargo build --lib --release
|
||||||
|
|
||||||
target/debug/silentdragonlite.$(EXT): src/lib.rs Cargo.toml
|
target/debug/silentdragonlite.$(EXT): src/lib.rs Cargo.toml
|
||||||
cargo build --lib
|
LIBS="" CFLAGS=$(CFLAGS) cargo build --lib
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf target
|
rm -rf target
|
||||||
BIN
lib/libsodium-mingw/libsodium.a
Normal file
@@ -105,14 +105,6 @@ pub extern fn litelib_initialize_new_from_phrase(dangerous: bool, server: *const
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let seed = match lightclient.do_seed_phrase() {
|
|
||||||
Ok(s) => s.dump(),
|
|
||||||
Err(e) => {
|
|
||||||
let e_str = CString::new(format!("Error: {}", e)).unwrap();
|
|
||||||
return e_str.into_raw();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient)));
|
LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient)));
|
||||||
|
|
||||||
let c_str = CString::new("OK").unwrap();
|
let c_str = CString::new("OK").unwrap();
|
||||||
|
|||||||
122
res/logo.svg
@@ -14,12 +14,25 @@
|
|||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"
|
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"
|
||||||
id="svg947"
|
id="svg947"
|
||||||
sodipodi:docname="logo2.svg"
|
sodipodi:docname="logo.svg"
|
||||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
|
inkscape:version="0.92.4 (f8dce91, 2019-08-02)"><metadata
|
||||||
id="metadata953"><rdf:RDF><cc:Work
|
id="metadata953"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||||
id="defs951" /><sodipodi:namedview
|
id="defs951">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</defs><sodipodi:namedview
|
||||||
pagecolor="#ffffff"
|
pagecolor="#ffffff"
|
||||||
bordercolor="#666666"
|
bordercolor="#666666"
|
||||||
borderopacity="1"
|
borderopacity="1"
|
||||||
@@ -28,107 +41,92 @@
|
|||||||
guidetolerance="10"
|
guidetolerance="10"
|
||||||
inkscape:pageopacity="0"
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:window-width="2493"
|
inkscape:window-width="3440"
|
||||||
inkscape:window-height="1385"
|
inkscape:window-height="1385"
|
||||||
id="namedview949"
|
id="namedview949"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
inkscape:zoom="1.204"
|
inkscape:zoom="1.204"
|
||||||
inkscape:cx="69.774919"
|
inkscape:cx="-65.607141"
|
||||||
inkscape:cy="327.00515"
|
inkscape:cy="327.00515"
|
||||||
inkscape:window-x="67"
|
inkscape:window-x="0"
|
||||||
inkscape:window-y="27"
|
inkscape:window-y="27"
|
||||||
inkscape:window-maximized="1"
|
inkscape:window-maximized="1"
|
||||||
inkscape:current-layer="svg947"
|
inkscape:current-layer="svg947"
|
||||||
units="in" />
|
units="in" />
|
||||||
<g
|
<g
|
||||||
id="Layer1"
|
id="g906"
|
||||||
transform="matrix(0.36813642,0,0,0.36813642,312.34626,301.46667)">
|
transform="matrix(8.0134463,-0.61542838,0.57707593,7.5140325,-224.79791,-183.45367)">
|
||||||
<g
|
|
||||||
transform="matrix(21.7676,-1.67174,1.56756,20.411,-1459.09,-1317.23)"
|
|
||||||
id="g906">
|
|
||||||
<path
|
<path
|
||||||
d="m 101.667,55.665 c 0,-4.644 -3.536,-8.415 -7.891,-8.415 H 34.391 c -4.355,0 -7.891,3.771 -7.891,8.415 v 32.67 c 0,4.644 3.536,8.415 7.891,8.415 h 59.385 c 4.355,0 7.891,-3.771 7.891,-8.415 z"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#403c3c;stroke:#676767;stroke-width:1.55999994px"
|
|
||||||
id="path904"
|
id="path904"
|
||||||
inkscape:connector-curvature="0" />
|
style="fill:#403c3c;stroke:#676767;stroke-width:1.55999994px"
|
||||||
</g>
|
d="m 101.667,55.665 c 0,-4.644 -3.536,-8.415 -7.891,-8.415 H 34.391 c -4.355,0 -7.891,3.771 -7.891,8.415 v 32.67 c 0,4.644 3.536,8.415 7.891,8.415 h 59.385 c 4.355,0 7.891,-3.771 7.891,-8.415 z" />
|
||||||
<g
|
</g><g
|
||||||
transform="matrix(10.4324,-0.762793,0.788494,10.7839,-910.913,-519.817)"
|
id="g910"
|
||||||
id="g910">
|
transform="matrix(3.8405464,-0.28081188,0.29027336,3.9699463,-22.993991,110.1031)">
|
||||||
<rect
|
<rect
|
||||||
x="30.333"
|
id="rect908"
|
||||||
y="15.958"
|
|
||||||
width="123.333"
|
|
||||||
height="10.333"
|
|
||||||
style="fill:#989898"
|
style="fill:#989898"
|
||||||
id="rect908" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(10.4426,-0.607527,0.590589,10.1515,-857.477,-497.419)"
|
|
||||||
id="g914">
|
|
||||||
<rect
|
|
||||||
x="30.333"
|
|
||||||
y="15.958"
|
|
||||||
width="123.333"
|
|
||||||
height="10.333"
|
height="10.333"
|
||||||
|
width="123.333"
|
||||||
|
y="15.958"
|
||||||
|
x="30.333" />
|
||||||
|
</g><g
|
||||||
|
id="g914"
|
||||||
|
transform="matrix(3.8443014,-0.22365281,0.21741732,3.7371369,-3.322253,118.34862)">
|
||||||
|
<rect
|
||||||
|
id="rect912"
|
||||||
style="fill:#d4d4d4"
|
style="fill:#d4d4d4"
|
||||||
id="rect912" />
|
height="10.333"
|
||||||
</g>
|
width="123.333"
|
||||||
<g
|
y="15.958"
|
||||||
transform="matrix(22.5859,0,0,20.3805,-1392.73,-1333.51)"
|
x="30.333" />
|
||||||
id="g918">
|
</g><g
|
||||||
|
id="g918"
|
||||||
|
transform="matrix(8.3146924,0,0,7.5028043,-200.36838,-189.44693)"
|
||||||
|
style="fill:#e5e5e5;fill-opacity:1">
|
||||||
<path
|
<path
|
||||||
d="m 101.667,55.665 c 0,-4.644 -3.403,-8.415 -7.594,-8.415 h -59.98 c -4.191,0 -7.593,3.771 -7.593,8.415 v 32.67 c 0,4.644 3.402,8.415 7.593,8.415 h 59.98 c 4.191,0 7.594,-3.771 7.594,-8.415 z"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#545454;stroke:#676767;stroke-width:1.54999995px"
|
|
||||||
id="path916"
|
id="path916"
|
||||||
inkscape:connector-curvature="0" />
|
style="fill:#e5e5e5;stroke:#676767;stroke-width:1.54999995px;fill-opacity:1"
|
||||||
</g>
|
d="m 101.667,55.665 c 0,-4.644 -3.403,-8.415 -7.594,-8.415 h -59.98 c -4.191,0 -7.593,3.771 -7.593,8.415 v 32.67 c 0,4.644 3.402,8.415 7.593,8.415 h 59.98 c 4.191,0 7.594,-3.771 7.594,-8.415 z" />
|
||||||
|
</g><g
|
||||||
|
transform="matrix(0.13492995,0,0,0.13731406,123.30027,138.8355)"
|
||||||
<g
|
|
||||||
transform="matrix(22.0427,0,0,22.0427,-1356.84,-1529.77)"
|
|
||||||
id="g940">
|
|
||||||
<g
|
|
||||||
transform="matrix(0.0166278,0,0,0.0169216,38.2584,49.3588)"
|
|
||||||
id="g930">
|
id="g930">
|
||||||
<path
|
<path
|
||||||
d="m 408.79,544.347 c -4.781,393.34 11.42,829.733 222.972,1280.253 233.27,496.77 562.438,768.91 880.738,902.9 400.43,-203.47 700.25,-512.61 875.74,-926.93 C 2565.08,1390.14 2623.25,986.361 2613.93,546.64 2401.04,668.826 2190.35,711.166 1980.91,665.398 1800.1,625.888 1619.67,480.693 1504.39,342.5 1342.48,544.925 1094.45,674.584 905.24,674.128 603.662,673.4 408.79,544.347 408.79,544.347 Z"
|
d="m 408.79,544.347 c -4.781,393.34 11.42,829.733 222.972,1280.253 233.27,496.77 562.438,768.91 880.738,902.9 400.43,-203.47 700.25,-512.61 875.74,-926.93 C 2565.08,1390.14 2623.25,986.361 2613.93,546.64 2401.04,668.826 2190.35,711.166 1980.91,665.398 1800.1,625.888 1619.67,480.693 1504.39,342.5 1342.48,544.925 1094.45,674.584 905.24,674.128 603.662,673.4 408.79,544.347 408.79,544.347 Z"
|
||||||
style="fill:#535050;stroke:#231f20;stroke-width:113.56999969px;stroke-linecap:butt;stroke-miterlimit:1.41420996"
|
style="fill:#535050;stroke:#231f20;stroke-width:113.56999969px;stroke-linecap:butt;stroke-miterlimit:1.41420996"
|
||||||
id="path928"
|
id="path928"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
</g>
|
</g><g
|
||||||
<g
|
transform="matrix(0.12668053,0,0,0.13183216,134.79779,148.99931)"
|
||||||
transform="matrix(0.0156112,0,0,0.01624605,39.675272,50.611315)"
|
id="g934"
|
||||||
id="g934">
|
style="fill:#52ffff;fill-opacity:1">
|
||||||
<path
|
<path
|
||||||
d="m 395.114,579.927 c -4.781,393.341 25.096,794.153 236.648,1244.673 233.27,496.77 562.438,768.91 880.738,902.9 400.43,-203.47 677.91,-509.43 866.26,-919.86 157.91,-344.09 267.28,-776.03 257.97,-1215.749 -212.9,122.186 -446.38,119.275 -655.82,73.507 C 1800.1,625.888 1626.34,498.787 1511.05,360.594 1349.14,563.019 1067.1,686.858 877.887,686.402 576.309,685.674 395.114,579.927 395.114,579.927 Z"
|
d="m 395.114,579.927 c -4.781,393.341 25.096,794.153 236.648,1244.673 233.27,496.77 562.438,768.91 880.738,902.9 400.43,-203.47 677.91,-509.43 866.26,-919.86 157.91,-344.09 267.28,-776.03 257.97,-1215.749 -212.9,122.186 -446.38,119.275 -655.82,73.507 C 1800.1,625.888 1626.34,498.787 1511.05,360.594 1349.14,563.019 1067.1,686.858 877.887,686.402 576.309,685.674 395.114,579.927 395.114,579.927 Z"
|
||||||
style="fill:#f4b728"
|
style="fill:#52ffff;fill-opacity:1"
|
||||||
id="path932"
|
id="path932"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
</g>
|
</g><g
|
||||||
<g
|
transform="matrix(0.70076537,0,0,0.70076537,168.89283,194.4473)"
|
||||||
transform="matrix(0.0863573,0,0,0.0863573,43.8769,56.212)"
|
|
||||||
id="g938">
|
id="g938">
|
||||||
<path
|
<path
|
||||||
d="M 305.776,155.342 V 120.964 H 244.28 V 83.228 h -37.768 v 37.736 h -61.496 v 45.532 h 95.333 l -77.956,107.298 -17.377,22.075 v 34.377 h 61.496 v 37.616 h 4.529 v 0.153 h 28.709 v -0.153 h 4.53 v -37.616 h 61.496 V 284.714 H 210.443 L 288.4,177.416 Z"
|
d="M 305.776,155.342 V 120.964 H 244.28 V 83.228 h -37.768 v 37.736 h -61.496 v 45.532 h 95.333 l -77.956,107.298 -17.377,22.075 v 34.377 h 61.496 v 37.616 h 4.529 v 0.153 h 28.709 v -0.153 h 4.53 v -37.616 h 61.496 V 284.714 H 210.443 L 288.4,177.416 Z"
|
||||||
style="fill:#231f20;fill-rule:nonzero"
|
style="fill:#231f20;fill-rule:nonzero"
|
||||||
id="path936"
|
id="path936"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
</g>
|
</g><g
|
||||||
</g>
|
|
||||||
|
|
||||||
</g><g
|
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
inkscape:label="Belt"
|
inkscape:label="Belt"
|
||||||
style="display:inline"
|
style="display:inline"
|
||||||
transform="translate(0,547.00007)"><g
|
transform="translate(0,547.00007)"><g
|
||||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"
|
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;fill:#52504f;fill-opacity:1"
|
||||||
transform="matrix(3.6074755,0,0,3.1676851,24.481313,-551.22181)"
|
transform="matrix(3.6074755,0,0,3.1676851,24.481313,-551.22181)"
|
||||||
id="g922">
|
id="g922">
|
||||||
<path
|
<path
|
||||||
d="m 174.197,108.212 c 0,-3.207 -2.286,-5.81 -5.101,-5.81 h -31.213 c -2.816,0 -5.102,2.603 -5.102,5.81 v 13.64 c 0,3.206 2.286,5.809 5.102,5.809 h 31.213 c 2.815,0 5.101,-2.603 5.101,-5.809 z"
|
d="m 174.197,108.212 c 0,-3.207 -2.286,-5.81 -5.101,-5.81 h -31.213 c -2.816,0 -5.102,2.603 -5.102,5.81 v 13.64 c 0,3.206 2.286,5.809 5.102,5.809 h 31.213 c 2.815,0 5.101,-2.603 5.101,-5.809 z"
|
||||||
style="fill:#545454;stroke:#676767;stroke-width:5.17999983px"
|
style="fill:#52504f;stroke:#676767;stroke-width:5.17999983px;fill-opacity:1"
|
||||||
id="path920"
|
id="path920"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
</g><g
|
</g><g
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
145
res/logo2.svg
@@ -1,145 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="7in"
|
|
||||||
height="7in"
|
|
||||||
viewBox="0 0 672.00001 672.00003"
|
|
||||||
version="1.1"
|
|
||||||
xml:space="preserve"
|
|
||||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"
|
|
||||||
id="svg947"
|
|
||||||
sodipodi:docname="logo2.svg"
|
|
||||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
|
|
||||||
id="metadata953"><rdf:RDF><cc:Work
|
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
|
||||||
id="defs951" /><sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="2493"
|
|
||||||
inkscape:window-height="1385"
|
|
||||||
id="namedview949"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="1.204"
|
|
||||||
inkscape:cx="69.774919"
|
|
||||||
inkscape:cy="327.00515"
|
|
||||||
inkscape:window-x="67"
|
|
||||||
inkscape:window-y="27"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg947"
|
|
||||||
units="in" />
|
|
||||||
<g
|
|
||||||
id="Layer1"
|
|
||||||
transform="matrix(0.36813642,0,0,0.36813642,312.34626,301.46667)">
|
|
||||||
<g
|
|
||||||
transform="matrix(21.7676,-1.67174,1.56756,20.411,-1459.09,-1317.23)"
|
|
||||||
id="g906">
|
|
||||||
<path
|
|
||||||
d="m 101.667,55.665 c 0,-4.644 -3.536,-8.415 -7.891,-8.415 H 34.391 c -4.355,0 -7.891,3.771 -7.891,8.415 v 32.67 c 0,4.644 3.536,8.415 7.891,8.415 h 59.385 c 4.355,0 7.891,-3.771 7.891,-8.415 z"
|
|
||||||
style="fill:#403c3c;stroke:#676767;stroke-width:1.55999994px"
|
|
||||||
id="path904"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(10.4324,-0.762793,0.788494,10.7839,-910.913,-519.817)"
|
|
||||||
id="g910">
|
|
||||||
<rect
|
|
||||||
x="30.333"
|
|
||||||
y="15.958"
|
|
||||||
width="123.333"
|
|
||||||
height="10.333"
|
|
||||||
style="fill:#989898"
|
|
||||||
id="rect908" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(10.4426,-0.607527,0.590589,10.1515,-857.477,-497.419)"
|
|
||||||
id="g914">
|
|
||||||
<rect
|
|
||||||
x="30.333"
|
|
||||||
y="15.958"
|
|
||||||
width="123.333"
|
|
||||||
height="10.333"
|
|
||||||
style="fill:#d4d4d4"
|
|
||||||
id="rect912" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(22.5859,0,0,20.3805,-1392.73,-1333.51)"
|
|
||||||
id="g918">
|
|
||||||
<path
|
|
||||||
d="m 101.667,55.665 c 0,-4.644 -3.403,-8.415 -7.594,-8.415 h -59.98 c -4.191,0 -7.593,3.771 -7.593,8.415 v 32.67 c 0,4.644 3.402,8.415 7.593,8.415 h 59.98 c 4.191,0 7.594,-3.771 7.594,-8.415 z"
|
|
||||||
style="fill:#545454;stroke:#676767;stroke-width:1.54999995px"
|
|
||||||
id="path916"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
|
|
||||||
|
|
||||||
<g
|
|
||||||
transform="matrix(22.0427,0,0,22.0427,-1356.84,-1529.77)"
|
|
||||||
id="g940">
|
|
||||||
<g
|
|
||||||
transform="matrix(0.0166278,0,0,0.0169216,38.2584,49.3588)"
|
|
||||||
id="g930">
|
|
||||||
<path
|
|
||||||
d="m 408.79,544.347 c -4.781,393.34 11.42,829.733 222.972,1280.253 233.27,496.77 562.438,768.91 880.738,902.9 400.43,-203.47 700.25,-512.61 875.74,-926.93 C 2565.08,1390.14 2623.25,986.361 2613.93,546.64 2401.04,668.826 2190.35,711.166 1980.91,665.398 1800.1,625.888 1619.67,480.693 1504.39,342.5 1342.48,544.925 1094.45,674.584 905.24,674.128 603.662,673.4 408.79,544.347 408.79,544.347 Z"
|
|
||||||
style="fill:#535050;stroke:#231f20;stroke-width:113.56999969px;stroke-linecap:butt;stroke-miterlimit:1.41420996"
|
|
||||||
id="path928"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(0.0156112,0,0,0.01624605,39.675272,50.611315)"
|
|
||||||
id="g934">
|
|
||||||
<path
|
|
||||||
d="m 395.114,579.927 c -4.781,393.341 25.096,794.153 236.648,1244.673 233.27,496.77 562.438,768.91 880.738,902.9 400.43,-203.47 677.91,-509.43 866.26,-919.86 157.91,-344.09 267.28,-776.03 257.97,-1215.749 -212.9,122.186 -446.38,119.275 -655.82,73.507 C 1800.1,625.888 1626.34,498.787 1511.05,360.594 1349.14,563.019 1067.1,686.858 877.887,686.402 576.309,685.674 395.114,579.927 395.114,579.927 Z"
|
|
||||||
style="fill:#f4b728"
|
|
||||||
id="path932"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(0.0863573,0,0,0.0863573,43.8769,56.212)"
|
|
||||||
id="g938">
|
|
||||||
<path
|
|
||||||
d="M 305.776,155.342 V 120.964 H 244.28 V 83.228 h -37.768 v 37.736 h -61.496 v 45.532 h 95.333 l -77.956,107.298 -17.377,22.075 v 34.377 h 61.496 v 37.616 h 4.529 v 0.153 h 28.709 v -0.153 h 4.53 v -37.616 h 61.496 V 284.714 H 210.443 L 288.4,177.416 Z"
|
|
||||||
style="fill:#231f20;fill-rule:nonzero"
|
|
||||||
id="path936"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
</g><g
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
inkscape:label="Belt"
|
|
||||||
style="display:inline"
|
|
||||||
transform="translate(0,547.00007)"><g
|
|
||||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"
|
|
||||||
transform="matrix(3.6074755,0,0,3.1676851,24.481313,-551.22181)"
|
|
||||||
id="g922">
|
|
||||||
<path
|
|
||||||
d="m 174.197,108.212 c 0,-3.207 -2.286,-5.81 -5.101,-5.81 h -31.213 c -2.816,0 -5.102,2.603 -5.102,5.81 v 13.64 c 0,3.206 2.286,5.809 5.102,5.809 h 31.213 c 2.815,0 5.101,-2.603 5.101,-5.809 z"
|
|
||||||
style="fill:#545454;stroke:#676767;stroke-width:5.17999983px"
|
|
||||||
id="path920"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g><g
|
|
||||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"
|
|
||||||
transform="matrix(4.2945691,0,0,4.3255294,-62.20745,-679.73088)"
|
|
||||||
id="g926">
|
|
||||||
<circle
|
|
||||||
cx="140.291"
|
|
||||||
cy="113.78"
|
|
||||||
r="5.006"
|
|
||||||
style="fill:#ffffff"
|
|
||||||
id="circle924" />
|
|
||||||
</g></g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 451 KiB After Width: | Height: | Size: 451 KiB |
@@ -13,7 +13,7 @@ PRECOMPILED_HEADER = src/precompiled.h
|
|||||||
QT += widgets
|
QT += widgets
|
||||||
QT += websockets
|
QT += websockets
|
||||||
|
|
||||||
TARGET = silentdragonlite
|
TARGET = Silentdragonlite
|
||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
|
||||||
@@ -60,7 +60,8 @@ SOURCES += \
|
|||||||
src/viewalladdresses.cpp \
|
src/viewalladdresses.cpp \
|
||||||
src/datamodel.cpp \
|
src/datamodel.cpp \
|
||||||
src/controller.cpp \
|
src/controller.cpp \
|
||||||
src/liteinterface.cpp
|
src/liteinterface.cpp \
|
||||||
|
src/camount.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/firsttimewizard.h \
|
src/firsttimewizard.h \
|
||||||
@@ -88,9 +89,11 @@ HEADERS += \
|
|||||||
src/datamodel.h \
|
src/datamodel.h \
|
||||||
src/controller.h \
|
src/controller.h \
|
||||||
src/liteinterface.h \
|
src/liteinterface.h \
|
||||||
|
src/camount.h \
|
||||||
lib/silentdragonlitelib.h
|
lib/silentdragonlitelib.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
|
src/encryption.ui \
|
||||||
src/mainwindow.ui \
|
src/mainwindow.ui \
|
||||||
src/migration.ui \
|
src/migration.ui \
|
||||||
src/newseed.ui \
|
src/newseed.ui \
|
||||||
@@ -145,6 +148,8 @@ else:win32: librust.target = $$PWD/lib/target/x86_64-pc-windows-gnu/release/s
|
|||||||
unix: librust.commands = $(MAKE) -C $$PWD/lib
|
unix: librust.commands = $(MAKE) -C $$PWD/lib
|
||||||
else:win32: librust.commands = $(MAKE) -C $$PWD/lib winrelease
|
else:win32: librust.commands = $(MAKE) -C $$PWD/lib winrelease
|
||||||
|
|
||||||
|
librust.depends = lib/Cargo.toml lib/src/lib.rs
|
||||||
|
|
||||||
librustclean.commands = "rm -rf $$PWD/lib/target"
|
librustclean.commands = "rm -rf $$PWD/lib/target"
|
||||||
distclean.depends += librustclean
|
distclean.depends += librustclean
|
||||||
|
|
||||||
|
|||||||
BIN
silentdragonlite
27
src/about.ui
@@ -17,7 +17,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string notr="true">silentdragon FullNode</string>
|
<string notr="true">SilentDragon Lite</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>463</width>
|
<width>463</width>
|
||||||
<height>517</height>
|
<height>534</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
@@ -51,17 +51,18 @@
|
|||||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
p, li { white-space: pre-wrap; }
|
p, li { white-space: pre-wrap; }
|
||||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.1pt; font-weight:400; font-style:normal;">
|
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">Copyright (c) 2018 Aditya Kulkarni. (MIT License)</span></p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2018-2019 DenioD (MIT License)</p>
|
||||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;"><br /></p>
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">Special thanks to:</span></p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Special thanks to:</p>
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">JSON for Modern C++ : </span><a href="https://nlohmann.github.io/json/"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://nlohmann.github.io/json/</span></a></p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Aditya Kulkarni for the awesome open source code</p>
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">QR Code generator library Nayuki : </span><a href="https://www.nayuki.io/page/qr-code-generator-library"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://www.nayuki.io/page/qr-code-ge…</span></a></p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">JSON for Modern C++ : <a href="https://nlohmann.github.io/json/"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;">https://nlohmann.github.io/json/</span></a></p>
|
||||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">Made with QT : </span><a href="https://www.qt.io/"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://www.qt.io/</span></a></p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">QR Code generator library Nayuki : <a href="https://www.nayuki.io/page/qr-code-generator-library"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;">https://www.nayuki.io/page/qr-code-ge…</span></a></p>
|
||||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">LICENSE:</span></p>
|
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Made with QT : <a href="https://www.qt.io/"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;">https://www.qt.io/</span></a></p>
|
||||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</span></p>
|
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LICENSE:</p>
|
||||||
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Ubuntu'; font-size:11pt;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</li>
|
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>
|
||||||
<li style=" font-family:'Ubuntu'; font-size:11pt;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Software is provided &quot;as is&quot;, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.</li></ul></body></html></string>
|
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</li>
|
||||||
|
<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Software is provided &quot;as is&quot;, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.</li></ul></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
|||||||
@@ -24,16 +24,16 @@ void AddressCombo::setCurrentText(const QString& text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressCombo::addItem(const QString& text, double bal) {
|
void AddressCombo::addItem(const QString& text, CAmount bal) {
|
||||||
QString txt = AddressBook::addLabelToAddress(text);
|
QString txt = AddressBook::addLabelToAddress(text);
|
||||||
if (bal > 0)
|
if (bal.toqint64() > 0)
|
||||||
txt = txt % "(" % Settings::gethushDisplayFormat(bal) % ")";
|
txt = txt % "(" % bal.toDecimalhushString() % ")";
|
||||||
|
|
||||||
QComboBox::addItem(txt);
|
QComboBox::addItem(txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressCombo::insertItem(int index, const QString& text, double bal) {
|
void AddressCombo::insertItem(int index, const QString& text, CAmount bal) {
|
||||||
QString txt = AddressBook::addLabelToAddress(text) %
|
QString txt = AddressBook::addLabelToAddress(text) %
|
||||||
"(" % Settings::gethushDisplayFormat(bal) % ")";
|
"(" % bal.toDecimalhushString() % ")";
|
||||||
QComboBox::insertItem(index, txt);
|
QComboBox::insertItem(index, txt);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef ADDRESSCOMBO_H
|
#ifndef ADDRESSCOMBO_H
|
||||||
#define ADDRESSCOMBO_H
|
#define ADDRESSCOMBO_H
|
||||||
|
|
||||||
|
#include "camount.h"
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
class AddressCombo : public QComboBox
|
class AddressCombo : public QComboBox
|
||||||
@@ -12,8 +13,8 @@ public:
|
|||||||
QString itemText(int i);
|
QString itemText(int i);
|
||||||
QString currentText();
|
QString currentText();
|
||||||
|
|
||||||
void addItem(const QString& itemText, double bal);
|
void addItem(const QString& itemText, CAmount bal);
|
||||||
void insertItem(int index, const QString& text, double bal = 0.0);
|
void insertItem(int index, const QString& text, CAmount bal = CAmount::fromqint64(0));
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setCurrentText(const QString& itemText);
|
void setCurrentText(const QString& itemText);
|
||||||
|
|||||||
@@ -1,32 +1,45 @@
|
|||||||
#include "balancestablemodel.h"
|
#include "balancestablemodel.h"
|
||||||
#include "addressbook.h"
|
#include "addressbook.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "camount.h"
|
||||||
|
|
||||||
BalancesTableModel::BalancesTableModel(QObject *parent)
|
BalancesTableModel::BalancesTableModel(QObject *parent)
|
||||||
: QAbstractTableModel(parent) {
|
: QAbstractTableModel(parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BalancesTableModel::setNewData(const QMap<QString, double> balances,
|
void BalancesTableModel::setNewData(const QList<QString> zaddrs, const QList<QString> taddrs,
|
||||||
const QList<UnspentOutput> outputs)
|
const QMap<QString, CAmount> balances, const QList<UnspentOutput> outputs)
|
||||||
{
|
{
|
||||||
loading = false;
|
loading = false;
|
||||||
|
|
||||||
int currentRows = rowCount(QModelIndex());
|
int currentRows = rowCount(QModelIndex());
|
||||||
// Copy over the utxos for our use
|
// Copy over the utxos for our use
|
||||||
delete utxos;
|
delete unspentOutputs;
|
||||||
utxos = new QList<UnspentOutput>();
|
unspentOutputs = new QList<UnspentOutput>();
|
||||||
|
|
||||||
// This is a QList deep copy.
|
// This is a QList deep copy.
|
||||||
*utxos = outputs;
|
*unspentOutputs = outputs;
|
||||||
|
|
||||||
// Process the address balances into a list
|
// Process the address balances into a list
|
||||||
delete modeldata;
|
delete modeldata;
|
||||||
modeldata = new QList<std::tuple<QString, double>>();
|
modeldata = new QList<std::tuple<QString, CAmount>>();
|
||||||
std::for_each(balances.keyBegin(), balances.keyEnd(), [=] (auto keyIt) {
|
std::for_each(balances.keyBegin(), balances.keyEnd(), [=] (auto keyIt) {
|
||||||
if (balances.value(keyIt) > 0)
|
modeldata->push_back(std::make_tuple(keyIt, balances.value(keyIt)));
|
||||||
modeldata->push_back(std::make_tuple(keyIt, balances.value(keyIt)));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add all addresses that have no balances as well
|
||||||
|
for (auto zaddr: zaddrs) {
|
||||||
|
if (!balances.contains(zaddr)) {
|
||||||
|
modeldata->push_back(std::make_tuple(zaddr, CAmount::fromqint64(0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto taddr: taddrs) {
|
||||||
|
if (!balances.contains(taddr)) {
|
||||||
|
modeldata->push_back(std::make_tuple(taddr, CAmount::fromqint64(0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// And then update the data
|
// And then update the data
|
||||||
dataChanged(index(0, 0), index(modeldata->size()-1, columnCount(index(0,0))-1));
|
dataChanged(index(0, 0), index(modeldata->size()-1, columnCount(index(0,0))-1));
|
||||||
|
|
||||||
@@ -37,7 +50,7 @@ void BalancesTableModel::setNewData(const QMap<QString, double> balances,
|
|||||||
|
|
||||||
BalancesTableModel::~BalancesTableModel() {
|
BalancesTableModel::~BalancesTableModel() {
|
||||||
delete modeldata;
|
delete modeldata;
|
||||||
delete utxos;
|
delete unspentOutputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BalancesTableModel::rowCount(const QModelIndex&) const
|
int BalancesTableModel::rowCount(const QModelIndex&) const
|
||||||
@@ -70,8 +83,9 @@ QVariant BalancesTableModel::data(const QModelIndex &index, int role) const
|
|||||||
if (role == Qt::ForegroundRole) {
|
if (role == Qt::ForegroundRole) {
|
||||||
// If any of the UTXOs for this address has zero confirmations, paint it in red
|
// If any of the UTXOs for this address has zero confirmations, paint it in red
|
||||||
const auto& addr = std::get<0>(modeldata->at(index.row()));
|
const auto& addr = std::get<0>(modeldata->at(index.row()));
|
||||||
for (auto utxo : *utxos) {
|
for (auto unconfirmedOutput : *unspentOutputs) {
|
||||||
if (utxo.address == addr && !utxo.spendable) {
|
if (unconfirmedOutput.address == addr &&
|
||||||
|
(!unconfirmedOutput.spendable || unconfirmedOutput.pending)) {
|
||||||
QBrush b;
|
QBrush b;
|
||||||
b.setColor(Qt::red);
|
b.setColor(Qt::red);
|
||||||
return b;
|
return b;
|
||||||
@@ -87,14 +101,14 @@ QVariant BalancesTableModel::data(const QModelIndex &index, int role) const
|
|||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case 0: return AddressBook::addLabelToAddress(std::get<0>(modeldata->at(index.row())));
|
case 0: return AddressBook::addLabelToAddress(std::get<0>(modeldata->at(index.row())));
|
||||||
case 1: return Settings::gethushDisplayFormat(std::get<1>(modeldata->at(index.row())));
|
case 1: return std::get<1>(modeldata->at(index.row())).toDecimalhushString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(role == Qt::ToolTipRole) {
|
if(role == Qt::ToolTipRole) {
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case 0: return AddressBook::addLabelToAddress(std::get<0>(modeldata->at(index.row())));
|
case 0: return AddressBook::addLabelToAddress(std::get<0>(modeldata->at(index.row())));
|
||||||
case 1: return Settings::getUSDFormat(std::get<1>(modeldata->at(index.row())));
|
case 1: return std::get<1>(modeldata->at(index.row())).toDecimalhushString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
#include "datamodel.h"
|
#include "datamodel.h"
|
||||||
|
#include "camount.h"
|
||||||
|
|
||||||
|
|
||||||
class BalancesTableModel : public QAbstractTableModel
|
class BalancesTableModel : public QAbstractTableModel
|
||||||
@@ -11,7 +12,7 @@ public:
|
|||||||
BalancesTableModel(QObject* parent);
|
BalancesTableModel(QObject* parent);
|
||||||
~BalancesTableModel();
|
~BalancesTableModel();
|
||||||
|
|
||||||
void setNewData(const QMap<QString, double> balances, const QList<UnspentOutput> outputs);
|
void setNewData(const QList<QString> zaddrs, const QList<QString> taddrs, const QMap<QString, CAmount> balances, const QList<UnspentOutput> outputs);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const;
|
int rowCount(const QModelIndex &parent) const;
|
||||||
int columnCount(const QModelIndex &parent) const;
|
int columnCount(const QModelIndex &parent) const;
|
||||||
@@ -19,8 +20,8 @@ public:
|
|||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<std::tuple<QString, double>>* modeldata = nullptr;
|
QList<std::tuple<QString, CAmount>>* modeldata = nullptr;
|
||||||
QList<UnspentOutput>* utxos = nullptr;
|
QList<UnspentOutput>* unspentOutputs = nullptr;
|
||||||
|
|
||||||
bool loading = true;
|
bool loading = true;
|
||||||
};
|
};
|
||||||
|
|||||||
64
src/camount.cpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#include "camount.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
const int NUMPLACES = 8;
|
||||||
|
const qint64 COIN = 100000000;
|
||||||
|
|
||||||
|
double CAmount::toDecimalDouble() const {
|
||||||
|
return static_cast<double>(this->amount) / COIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CAmount::toDecimalString() const {
|
||||||
|
if (amount < 0) {
|
||||||
|
CAmount negative(-1 * this->amount);
|
||||||
|
return "-" + negative.toDecimalString();
|
||||||
|
}
|
||||||
|
|
||||||
|
int wholePart = amount / COIN;
|
||||||
|
int decimalPart = amount % COIN;
|
||||||
|
|
||||||
|
QString r = QString::number(wholePart);
|
||||||
|
if (decimalPart > 0) {
|
||||||
|
QString decimalPartStr = QString::number(decimalPart);
|
||||||
|
r = r + "." + decimalPartStr.rightJustified(NUMPLACES, '0');
|
||||||
|
|
||||||
|
// Trim tailing 0s
|
||||||
|
while (r.right(1) == "0") {
|
||||||
|
r = r.left(r.length() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CAmount::toDecimalUSDString() const {
|
||||||
|
double dblAmount = static_cast<double>(this->amount) / COIN;
|
||||||
|
double price = Settings::getInstance()->getZECPrice();
|
||||||
|
|
||||||
|
return "$" + QLocale(QLocale::English).toString(dblAmount*price, 'f', 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CAmount::toDecimalhushString() const {
|
||||||
|
return this->toDecimalString() % " " % Settings::getTokenName();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CAmount::toDecimalhushUSDString() const {
|
||||||
|
auto usdString = this->toDecimalUSDString();
|
||||||
|
if (!usdString.isEmpty())
|
||||||
|
return this->toDecimalhushString() % " (" % usdString % ")";
|
||||||
|
else
|
||||||
|
return this->toDecimalhushString();
|
||||||
|
}
|
||||||
|
|
||||||
|
CAmount CAmount::fromDecimalString(QString decimalString) {
|
||||||
|
auto amtParts = decimalString.split(".");
|
||||||
|
qint64 r = amtParts[0].toULongLong() * COIN;
|
||||||
|
if (amtParts.length() == 2) {
|
||||||
|
auto trailingZeros = QString("0").repeated(NUMPLACES - amtParts[1].length());
|
||||||
|
r += QString(amtParts[1] + trailingZeros).toULongLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
return CAmount(r);
|
||||||
|
}
|
||||||
55
src/camount.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef CAMOUNT_H
|
||||||
|
#define CAMOUNT_H
|
||||||
|
|
||||||
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
class CAmount {
|
||||||
|
private:
|
||||||
|
CAmount(qint64 amount) {
|
||||||
|
this->amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 amount;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static CAmount fromDecimalString(QString decimalString);
|
||||||
|
static CAmount fromqint64(qint64 a) {
|
||||||
|
return CAmount(a);
|
||||||
|
}
|
||||||
|
static CAmount fromDouble(double d) {
|
||||||
|
return CAmount::fromDecimalString(QString::number(d, 'f', 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
CAmount() : amount(0) {};
|
||||||
|
CAmount(const CAmount&) = default;
|
||||||
|
~CAmount() = default;
|
||||||
|
|
||||||
|
double toDecimalDouble() const;
|
||||||
|
QString toDecimalString() const;
|
||||||
|
QString toDecimalUSDString() const;
|
||||||
|
QString toDecimalhushString() const;
|
||||||
|
QString toDecimalhushUSDString() const;
|
||||||
|
qint64 toqint64() const { return amount; };
|
||||||
|
|
||||||
|
CAmount operator+ (const CAmount& other) const {
|
||||||
|
return CAmount(this->amount + other.amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAmount operator- (const CAmount& other) const {
|
||||||
|
return CAmount(this->amount - other.amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator< (const CAmount& other) const {
|
||||||
|
return this->amount < other.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator< (const qint64& other) const {
|
||||||
|
return this->amount < other;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator> (const CAmount& other) const {
|
||||||
|
return this->amount > other.amount;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CAMOUNT_H
|
||||||
@@ -6,33 +6,14 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>538</width>
|
<width>626</width>
|
||||||
<height>458</height>
|
<height>713</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Confirm Transaction</string>
|
<string>Confirm Transaction</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>From</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="sendFrom">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true"/>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="sendToAddrs">
|
<widget class="QGroupBox" name="sendToAddrs">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@@ -174,19 +155,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="nopeersWarning">
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">color: red;</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>hushd doesn't seem to have any peers. You might not be connected to the internet, so this transaction might not work.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="syncingWarning">
|
<widget class="QLabel" name="syncingWarning">
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
@@ -200,19 +168,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="warningLabel">
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">color: red;</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>You are using a custom fee. Since fees are transparent, you are giving up some privacy. Please use this only if you know what you are doing!</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line">
|
<widget class="Line" name="line">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|||||||
@@ -43,20 +43,20 @@ void ConnectionLoader::doAutoConnect() {
|
|||||||
|
|
||||||
auto config = std::shared_ptr<ConnectionConfig>(new ConnectionConfig());
|
auto config = std::shared_ptr<ConnectionConfig>(new ConnectionConfig());
|
||||||
config->dangerous = true;
|
config->dangerous = true;
|
||||||
config->server = QString("https://hush-lightwallet.de:439");
|
config->server = Settings::getInstance()->getSettings().server;
|
||||||
|
|
||||||
// Initialize the library
|
// Initialize the library
|
||||||
main->logger->write(QObject::tr("Attempting to initialize"));
|
main->logger->write(QObject::tr("Attempting to initialize library with ") + config->server);
|
||||||
|
|
||||||
// Check to see if there's an existing wallet
|
// Check to see if there's an existing wallet
|
||||||
if (litelib_wallet_exists(Settings::getChainName().toStdString().c_str())) {
|
if (litelib_wallet_exists(Settings::getChainName().toStdString().c_str())) {
|
||||||
main->logger->write(QObject::tr("Using existing wallet."));
|
main->logger->write(QObject::tr("Using existing wallet."));
|
||||||
char* resp = litelib_initialize_existing(config->dangerous, config->server.toStdString().c_str());
|
char* resp = litelib_initialize_existing(config->dangerous, config->server.toStdString().c_str());
|
||||||
QString response = litelib_process_response(resp);
|
QString response = litelib_process_response(resp);
|
||||||
|
|
||||||
if (response.toUpper().trimmed() != "OK") {
|
if (response.toUpper().trimmed() != "OK") {
|
||||||
showError(response);
|
showError(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
main->logger->write(QObject::tr("Create/restore wallet."));
|
main->logger->write(QObject::tr("Create/restore wallet."));
|
||||||
@@ -65,9 +65,10 @@ void ConnectionLoader::doAutoConnect() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto connection = makeConnection(config);
|
auto connection = makeConnection(config);
|
||||||
|
auto me = this;
|
||||||
|
|
||||||
// After the lib is initialized, try to do get info
|
// After the lib is initialized, try to do get info
|
||||||
connection->doRPC("info", "", [=](auto reply) {
|
connection->doRPC("info", "", [=](auto) {
|
||||||
// If success, set the connection
|
// If success, set the connection
|
||||||
main->logger->write("Connection is online.");
|
main->logger->write("Connection is online.");
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ void ConnectionLoader::doAutoConnect() {
|
|||||||
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) {
|
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) {
|
||||||
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
|
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
|
||||||
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
|
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
|
||||||
showInformation("Synced " + QString::number(synced) + " / " + QString::number(total));
|
me->showInformation("Synced " + QString::number(synced) + " / " + QString::number(total));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[=](QString err) {
|
[=](QString err) {
|
||||||
@@ -173,15 +174,11 @@ void Executor::run() {
|
|||||||
|
|
||||||
QString reply = litelib_process_response(resp);
|
QString reply = litelib_process_response(resp);
|
||||||
|
|
||||||
qDebug() << "Reply=" << reply;
|
//qDebug() << "RPC Reply=" << reply;
|
||||||
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
|
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
|
||||||
if (parsed.is_discarded() || parsed.is_null()) {
|
if (parsed.is_discarded() || parsed.is_null()) {
|
||||||
emit handleError(reply);
|
emit handleError(reply);
|
||||||
} else {
|
} else {
|
||||||
const bool isGuiThread =
|
|
||||||
QThread::currentThread() == QCoreApplication::instance()->thread();
|
|
||||||
qDebug() << "executing RPC: isGUI=" << isGuiThread;
|
|
||||||
|
|
||||||
emit responseReady(parsed);
|
emit responseReady(parsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,7 +213,7 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Doing RPC: " << cmd;
|
//qDebug() << "Doing RPC: " << cmd;
|
||||||
|
|
||||||
// Create a runner.
|
// Create a runner.
|
||||||
auto runner = new Executor(cmd, args);
|
auto runner = new Executor(cmd, args);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "addressbook.h"
|
#include "addressbook.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "camount.h"
|
||||||
#include "websockets.h"
|
#include "websockets.h"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
@@ -28,7 +29,7 @@ Controller::Controller(MainWindow* main) {
|
|||||||
priceTimer = new QTimer(main);
|
priceTimer = new QTimer(main);
|
||||||
QObject::connect(priceTimer, &QTimer::timeout, [=]() {
|
QObject::connect(priceTimer, &QTimer::timeout, [=]() {
|
||||||
if (Settings::getInstance()->getAllowFetchPrices())
|
if (Settings::getInstance()->getAllowFetchPrices())
|
||||||
refreshhushPrice();
|
refreshZECPrice();
|
||||||
});
|
});
|
||||||
priceTimer->start(Settings::priceRefreshSpeed); // Every hour
|
priceTimer->start(Settings::priceRefreshSpeed); // Every hour
|
||||||
|
|
||||||
@@ -64,16 +65,11 @@ void Controller::setConnection(Connection* c) {
|
|||||||
|
|
||||||
this->zrpc->setConnection(c);
|
this->zrpc->setConnection(c);
|
||||||
|
|
||||||
ui->statusBar->showMessage("Connectet with https://hush-lightwallet.de");
|
ui->statusBar->showMessage("");
|
||||||
|
|
||||||
// See if we need to remove the reindex/rescan flags from the hush.conf file
|
// If we're allowed to get the Hush Price, get the prices
|
||||||
auto hushConfLocation = Settings::getInstance()->gethushdConfLocation();
|
|
||||||
Settings::removeFromhushConf(hushConfLocation, "rescan");
|
|
||||||
Settings::removeFromhushConf(hushConfLocation, "reindex");
|
|
||||||
|
|
||||||
// If we're allowed to get the hush Price, get the prices
|
|
||||||
if (Settings::getInstance()->getAllowFetchPrices())
|
if (Settings::getInstance()->getAllowFetchPrices())
|
||||||
refreshhushPrice();
|
refreshZECPrice();
|
||||||
|
|
||||||
// If we're allowed to check for updates, check for a new release
|
// If we're allowed to check for updates, check for a new release
|
||||||
if (Settings::getInstance()->getCheckForUpdates())
|
if (Settings::getInstance()->getCheckForUpdates())
|
||||||
@@ -96,18 +92,12 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx) {
|
|||||||
// Construct the JSON params
|
// Construct the JSON params
|
||||||
json rec = json::object();
|
json rec = json::object();
|
||||||
rec["address"] = toAddr.addr.toStdString();
|
rec["address"] = toAddr.addr.toStdString();
|
||||||
rec["amount"] = toAddr.amount * 100000000;
|
rec["amount"] = toAddr.amount.toqint64();
|
||||||
if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.trimmed().isEmpty())
|
if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.trimmed().isEmpty())
|
||||||
rec["memo"] = toAddr.memo.toStdString();
|
rec["memo"] = toAddr.memo.toStdString();
|
||||||
|
|
||||||
allRecepients.push_back(rec);
|
allRecepients.push_back(rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Add fees if custom fees are allowed.
|
|
||||||
// if (Settings::getInstance()->getAllowCustomFees()) {
|
|
||||||
// params.push_back(1); // minconf
|
|
||||||
// params.push_back(tx.fee);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -120,9 +110,10 @@ void Controller::noConnection() {
|
|||||||
main->ui->statusBar->showMessage(QObject::tr("No Connection"), 1000);
|
main->ui->statusBar->showMessage(QObject::tr("No Connection"), 1000);
|
||||||
|
|
||||||
// Clear balances table.
|
// Clear balances table.
|
||||||
QMap<QString, double> emptyBalances;
|
QMap<QString, CAmount> emptyBalances;
|
||||||
QList<UnspentOutput> emptyOutputs;
|
QList<UnspentOutput> emptyOutputs;
|
||||||
balancesTableModel->setNewData(emptyBalances, emptyOutputs);
|
QList<QString> emptyAddresses;
|
||||||
|
balancesTableModel->setNewData(emptyAddresses, emptyAddresses, emptyBalances, emptyOutputs);
|
||||||
|
|
||||||
// Clear Transactions table.
|
// Clear Transactions table.
|
||||||
QList<TransactionItem> emptyTxs;
|
QList<TransactionItem> emptyTxs;
|
||||||
@@ -136,9 +127,6 @@ void Controller::noConnection() {
|
|||||||
ui->balSheilded->setToolTip("");
|
ui->balSheilded->setToolTip("");
|
||||||
ui->balTransparent->setToolTip("");
|
ui->balTransparent->setToolTip("");
|
||||||
ui->balTotal->setToolTip("");
|
ui->balTotal->setToolTip("");
|
||||||
|
|
||||||
// Clear send tab from address
|
|
||||||
ui->inputsCombo->clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will refresh all the balance data from hushd
|
/// This will refresh all the balance data from hushd
|
||||||
@@ -156,8 +144,6 @@ void Controller::getInfoThenRefresh(bool force) {
|
|||||||
static bool prevCallSucceeded = false;
|
static bool prevCallSucceeded = false;
|
||||||
|
|
||||||
zrpc->fetchInfo([=] (const json& reply) {
|
zrpc->fetchInfo([=] (const json& reply) {
|
||||||
qDebug() << "Info updated";
|
|
||||||
|
|
||||||
prevCallSucceeded = true;
|
prevCallSucceeded = true;
|
||||||
|
|
||||||
// Testnet?
|
// Testnet?
|
||||||
@@ -171,18 +157,21 @@ void Controller::getInfoThenRefresh(bool force) {
|
|||||||
if (!Settings::getInstance()->isTestnet())
|
if (!Settings::getInstance()->isTestnet())
|
||||||
main->disableRecurring();
|
main->disableRecurring();
|
||||||
|
|
||||||
static int lastBlock = 0;
|
|
||||||
int curBlock = reply["latest_block_height"].get<json::number_integer_t>();
|
int curBlock = reply["latest_block_height"].get<json::number_integer_t>();
|
||||||
|
bool doUpdate = force || (model->getLatestBlock() != curBlock);
|
||||||
model->setLatestBlock(curBlock);
|
model->setLatestBlock(curBlock);
|
||||||
ui->blockHeight->setText(QString::number(curBlock));
|
ui->blockHeight->setText(QString::number(curBlock));
|
||||||
|
|
||||||
// Connected, so display checkmark.
|
// Connected, so display checkmark.
|
||||||
|
auto tooltip = Settings::getInstance()->getSettings().server + "\n" + QString::fromStdString(reply.dump());
|
||||||
QIcon i(":/icons/res/connected.gif");
|
QIcon i(":/icons/res/connected.gif");
|
||||||
main->statusLabel->setText( "connected" "(" + QString::number(curBlock) + ")");
|
main->statusLabel->setText(chainName + "(" + QString::number(curBlock) + ")");
|
||||||
main->statusLabel->setText(" HUSH/USD=$" + QString::number( (double) Settings::getInstance()->gethushPrice() ));
|
main->statusLabel->setText(" HUSH/USD=$" + QString::number( (double) Settings::getInstance()->getZECPrice() ));
|
||||||
|
main->statusLabel->setToolTip(tooltip);
|
||||||
main->statusIcon->setPixmap(i.pixmap(16, 16));
|
main->statusIcon->setPixmap(i.pixmap(16, 16));
|
||||||
|
main->statusIcon->setToolTip(tooltip);
|
||||||
|
|
||||||
//int version = reply["version"].get<json::string_t>();
|
//int version = reply["version"].get<json::string_t>();
|
||||||
int version = 1;
|
int version = 1;
|
||||||
Settings::getInstance()->sethushdVersion(version);
|
Settings::getInstance()->sethushdVersion(version);
|
||||||
ui->Version->setText(QString::fromStdString(reply["version"].get<json::string_t>()));
|
ui->Version->setText(QString::fromStdString(reply["version"].get<json::string_t>()));
|
||||||
@@ -194,10 +183,16 @@ void Controller::getInfoThenRefresh(bool force) {
|
|||||||
// See if recurring payments needs anything
|
// See if recurring payments needs anything
|
||||||
Recurring::getInstance()->processPending(main);
|
Recurring::getInstance()->processPending(main);
|
||||||
|
|
||||||
if ( force || (curBlock != lastBlock) ) {
|
// Check if the wallet is locked/encrypted
|
||||||
// Something changed, so refresh everything.
|
zrpc->fetchWalletEncryptionStatus([=] (const json& reply) {
|
||||||
lastBlock = curBlock;
|
bool isEncrypted = reply["encrypted"].get<json::boolean_t>();
|
||||||
|
bool isLocked = reply["locked"].get<json::boolean_t>();
|
||||||
|
|
||||||
|
model->setEncryptionStatus(isEncrypted, isLocked);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( doUpdate ) {
|
||||||
|
// Something changed, so refresh everything.
|
||||||
refreshBalances();
|
refreshBalances();
|
||||||
refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans()
|
refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans()
|
||||||
refreshTransactions();
|
refreshTransactions();
|
||||||
@@ -255,71 +250,105 @@ void Controller::updateUI(bool anyUnconfirmed) {
|
|||||||
ui->unconfirmedWarning->setVisible(anyUnconfirmed);
|
ui->unconfirmedWarning->setVisible(anyUnconfirmed);
|
||||||
|
|
||||||
// Update balances model data, which will update the table too
|
// Update balances model data, which will update the table too
|
||||||
balancesTableModel->setNewData(model->getAllBalances(), model->getUTXOs());
|
balancesTableModel->setNewData(model->getAllZAddresses(), model->getAllTAddresses(), model->getAllBalances(), model->getUTXOs());
|
||||||
|
|
||||||
// Update from address
|
|
||||||
main->updateFromCombo();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to process reply of the listunspent and z_listunspent API calls, used below.
|
// Function to process reply of the listunspent and z_listunspent API calls, used below.
|
||||||
bool Controller::processUnspent(const json& reply, QMap<QString, double>* balancesMap, QList<UnspentOutput>* newUtxos) {
|
void Controller::processUnspent(const json& reply, QMap<QString, CAmount>* balancesMap, QList<UnspentOutput>* unspentOutputs) {
|
||||||
bool anyUnconfirmed = false;
|
|
||||||
|
|
||||||
auto processFn = [=](const json& array) {
|
auto processFn = [=](const json& array) {
|
||||||
for (auto& it : array) {
|
for (auto& it : array) {
|
||||||
QString qsAddr = QString::fromStdString(it["address"]);
|
QString qsAddr = QString::fromStdString(it["address"]);
|
||||||
int block = it["created_in_block"].get<json::number_unsigned_t>();
|
int block = it["created_in_block"].get<json::number_unsigned_t>();
|
||||||
QString txid = QString::fromStdString(it["created_in_txid"]);
|
QString txid = QString::fromStdString(it["created_in_txid"]);
|
||||||
QString amount = Settings::getDecimalString(it["value"].get<json::number_float_t>());
|
CAmount amount = CAmount::fromqint64(it["value"].get<json::number_unsigned_t>());
|
||||||
|
|
||||||
newUtxos->push_back(UnspentOutput{ qsAddr, txid, amount, block, true });
|
bool spendable = it["unconfirmed_spent"].is_null() && it["spent"].is_null(); // TODO: Wait for 4 confirmations
|
||||||
|
bool pending = !it["unconfirmed_spent"].is_null();
|
||||||
|
|
||||||
(*balancesMap)[qsAddr] = ((*balancesMap)[qsAddr] + (it["value"].get<json::number_float_t>()) /100000000);
|
unspentOutputs->push_back(UnspentOutput{ qsAddr, txid, amount, block, spendable, pending });
|
||||||
|
if (spendable) {
|
||||||
|
(*balancesMap)[qsAddr] = (*balancesMap)[qsAddr] +
|
||||||
|
CAmount::fromqint64(it["value"].get<json::number_unsigned_t>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
processFn(reply["unspent_notes"].get<json::array_t>());
|
processFn(reply["unspent_notes"].get<json::array_t>());
|
||||||
processFn(reply["utxos"].get<json::array_t>());
|
processFn(reply["utxos"].get<json::array_t>());
|
||||||
|
processFn(reply["pending_notes"].get<json::array_t>());
|
||||||
return anyUnconfirmed;
|
processFn(reply["pending_utxos"].get<json::array_t>());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Controller::updateUIBalances() {
|
||||||
|
CAmount balT = getModel()->getBalT();
|
||||||
|
CAmount balZ = getModel()->getBalZ();
|
||||||
|
CAmount balVerified = getModel()->getBalVerified();
|
||||||
|
|
||||||
|
// Reduce the BalanceZ by the pending outgoing amount. We're adding
|
||||||
|
// here because totalPending is already negative for outgoing txns.
|
||||||
|
balZ = balZ + getModel()->getTotalPending();
|
||||||
|
|
||||||
|
CAmount balTotal = balT + balZ;
|
||||||
|
CAmount balAvailable = balT + balVerified;
|
||||||
|
|
||||||
|
// Balances table
|
||||||
|
ui->balSheilded ->setText(balZ.toDecimalhushString());
|
||||||
|
ui->balVerified ->setText(balVerified.toDecimalhushString());
|
||||||
|
ui->balTransparent->setText(balT.toDecimalhushString());
|
||||||
|
ui->balTotal ->setText(balTotal.toDecimalhushString());
|
||||||
|
|
||||||
|
ui->balSheilded ->setToolTip(balZ.toDecimalUSDString());
|
||||||
|
ui->balVerified ->setToolTip(balVerified.toDecimalUSDString());
|
||||||
|
ui->balTransparent->setToolTip(balT.toDecimalUSDString());
|
||||||
|
ui->balTotal ->setToolTip(balTotal.toDecimalUSDString());
|
||||||
|
|
||||||
|
// Send tab
|
||||||
|
ui->txtAvailablehush->setText(balAvailable.toDecimalhushString());
|
||||||
|
ui->txtAvailableUSD->setText(balAvailable.toDecimalUSDString());
|
||||||
|
}
|
||||||
|
|
||||||
void Controller::refreshBalances() {
|
void Controller::refreshBalances() {
|
||||||
if (!zrpc->haveConnection())
|
if (!zrpc->haveConnection())
|
||||||
return noConnection();
|
return noConnection();
|
||||||
|
|
||||||
// 1. Get the Balances
|
// 1. Get the Balances
|
||||||
zrpc->fetchBalance([=] (json reply) {
|
zrpc->fetchBalance([=] (json reply) {
|
||||||
auto balT = reply["tbalance"].get<json::number_float_t>();
|
CAmount balT = CAmount::fromqint64(reply["tbalance"].get<json::number_unsigned_t>());
|
||||||
auto balZ = reply["zbalance"].get<json::number_float_t>();
|
CAmount balZ = CAmount::fromqint64(reply["zbalance"].get<json::number_unsigned_t>());
|
||||||
auto balTotal = balT + balZ;
|
CAmount balVerified = CAmount::fromqint64(reply["verified_zbalance"].get<json::number_unsigned_t>());
|
||||||
|
|
||||||
|
model->setBalT(balT);
|
||||||
|
model->setBalZ(balZ);
|
||||||
|
model->setBalVerified(balVerified);
|
||||||
|
|
||||||
|
// This is for the websockets
|
||||||
AppDataModel::getInstance()->setBalances(balT, balZ);
|
AppDataModel::getInstance()->setBalances(balT, balZ);
|
||||||
|
|
||||||
ui->balSheilded ->setText(Settings::gethushDisplayFormat(balZ /100000000));
|
// This is for the datamodel
|
||||||
ui->balTransparent->setText(Settings::gethushDisplayFormat(balT /100000000));
|
CAmount balAvailable = balT + balVerified;
|
||||||
ui->balTotal ->setText(Settings::gethushDisplayFormat(balTotal /100000000));
|
model->setAvailableBalance(balAvailable);
|
||||||
|
|
||||||
|
|
||||||
ui->balSheilded ->setToolTip(Settings::gethushDisplayFormat(balZ /100000000));
|
|
||||||
ui->balTransparent->setToolTip(Settings::gethushDisplayFormat(balT /100000000));
|
|
||||||
ui->balTotal ->setToolTip(Settings::gethushDisplayFormat(balTotal /100000000));
|
|
||||||
|
|
||||||
|
|
||||||
|
updateUIBalances();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Get the UTXOs
|
// 2. Get the UTXOs
|
||||||
// First, create a new UTXO list. It will be replacing the existing list when everything is processed.
|
// First, create a new UTXO list. It will be replacing the existing list when everything is processed.
|
||||||
auto newUtxos = new QList<UnspentOutput>();
|
auto newUnspentOutputs = new QList<UnspentOutput>();
|
||||||
auto newBalances = new QMap<QString, double>();
|
auto newBalances = new QMap<QString, CAmount>();
|
||||||
|
|
||||||
// Call the Transparent and Z unspent APIs serially and then, once they're done, update the UI
|
// Call the Transparent and Z unspent APIs serially and then, once they're done, update the UI
|
||||||
zrpc->fetchUnspent([=] (json reply) {
|
zrpc->fetchUnspent([=] (json reply) {
|
||||||
auto anyUnconfirmed = processUnspent(reply, newBalances, newUtxos);
|
processUnspent(reply, newBalances, newUnspentOutputs);
|
||||||
|
|
||||||
// Swap out the balances and UTXOs
|
// Swap out the balances and UTXOs
|
||||||
model->replaceBalances(newBalances);
|
model->replaceBalances(newBalances);
|
||||||
model->replaceUTXOs(newUtxos);
|
model->replaceUTXOs(newUnspentOutputs);
|
||||||
|
|
||||||
|
// Find if any output is not spendable or is pending
|
||||||
|
bool anyUnconfirmed = std::find_if(newUnspentOutputs->constBegin(), newUnspentOutputs->constEnd(),
|
||||||
|
[=](const UnspentOutput& u) -> bool {
|
||||||
|
return !u.spendable || u.pending;
|
||||||
|
}) != newUnspentOutputs->constEnd();
|
||||||
|
|
||||||
updateUI(anyUnconfirmed);
|
updateUI(anyUnconfirmed);
|
||||||
|
|
||||||
@@ -336,15 +365,27 @@ void Controller::refreshTransactions() {
|
|||||||
|
|
||||||
for (auto& it : reply.get<json::array_t>()) {
|
for (auto& it : reply.get<json::array_t>()) {
|
||||||
QString address;
|
QString address;
|
||||||
quint64 total_amount;
|
CAmount total_amount;
|
||||||
QList<TransactionItemDetail> items;
|
QList<TransactionItemDetail> items;
|
||||||
|
|
||||||
|
long confirmations;
|
||||||
|
if (it.find("unconfirmed") != it.end() && it["unconfirmed"].get<json::boolean_t>()) {
|
||||||
|
confirmations = 0;
|
||||||
|
} else {
|
||||||
|
confirmations = model->getLatestBlock() - it["block_height"].get<json::number_integer_t>() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto txid = QString::fromStdString(it["txid"]);
|
||||||
|
auto datetime = it["datetime"].get<json::number_integer_t>();
|
||||||
|
|
||||||
// First, check if there's outgoing metadata
|
// First, check if there's outgoing metadata
|
||||||
if (!it["outgoing_metadata"].is_null()) {
|
if (!it["outgoing_metadata"].is_null()) {
|
||||||
|
|
||||||
for (auto o: it["outgoing_metadata"].get<json::array_t>()) {
|
for (auto o: it["outgoing_metadata"].get<json::array_t>()) {
|
||||||
QString address = QString::fromStdString(o["address"]);
|
QString address = QString::fromStdString(o["address"]);
|
||||||
double amount = -1 * o ["value"].get<json::number_float_t>() /100000000; // Sent items are -ve
|
|
||||||
|
// Sent items are -ve
|
||||||
|
CAmount amount = CAmount::fromqint64(-1 * o["value"].get<json::number_unsigned_t>());
|
||||||
|
|
||||||
// Check for Memos
|
// Check for Memos
|
||||||
|
|
||||||
@@ -355,42 +396,40 @@ void Controller::refreshTransactions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
items.push_back(TransactionItemDetail{address, amount, memo});
|
items.push_back(TransactionItemDetail{address, amount, memo});
|
||||||
total_amount += amount;
|
total_amount = total_amount + amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items.length() == 1) {
|
{
|
||||||
address = items[0].address;
|
// Concat all the addresses
|
||||||
} else {
|
QList<QString> addresses;
|
||||||
address = "(Multiple)";
|
for (auto item : items) {
|
||||||
|
addresses.push_back(item.address);
|
||||||
|
}
|
||||||
|
address = addresses.join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
txdata.push_back(TransactionItem{
|
txdata.push_back(TransactionItem{
|
||||||
"Sent",
|
"Sent", datetime, address, txid,confirmations, items
|
||||||
it["datetime"].get<json::number_unsigned_t>(),
|
|
||||||
address,
|
|
||||||
QString::fromStdString(it["txid"]),
|
|
||||||
model->getLatestBlock() - it["block_height"].get<json::number_unsigned_t>(),
|
|
||||||
items
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Incoming Transaction
|
// Incoming Transaction
|
||||||
address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"]));
|
address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"]));
|
||||||
model->markAddressUsed(address);
|
model->markAddressUsed(address);
|
||||||
|
|
||||||
|
QString memo;
|
||||||
|
if (!it["memo"].is_null()) {
|
||||||
|
memo = QString::fromStdString(it["memo"]);
|
||||||
|
}
|
||||||
|
|
||||||
items.push_back(TransactionItemDetail{
|
items.push_back(TransactionItemDetail{
|
||||||
address,
|
address,
|
||||||
it["amount"].get<json::number_float_t>() /100000000,
|
CAmount::fromqint64(it["amount"].get<json::number_integer_t>()),
|
||||||
""
|
memo
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
TransactionItem tx{
|
TransactionItem tx{
|
||||||
"Receive",
|
"Receive", datetime, address, txid,confirmations, items
|
||||||
it["datetime"].get<json::number_unsigned_t>(),
|
|
||||||
address,
|
|
||||||
QString::fromStdString(it["txid"]),
|
|
||||||
model->getLatestBlock() - it["block_height"].get<json::number_unsigned_t>(),
|
|
||||||
items
|
|
||||||
};
|
};
|
||||||
|
|
||||||
txdata.push_back(tx);
|
txdata.push_back(tx);
|
||||||
@@ -398,11 +437,63 @@ void Controller::refreshTransactions() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate the total unspent amount that's pending. This will need to be
|
||||||
|
// shown in the UI so the user can keep track of pending funds
|
||||||
|
CAmount totalPending;
|
||||||
|
for (auto txitem : txdata) {
|
||||||
|
if (txitem.confirmations == 0) {
|
||||||
|
for (auto item: txitem.items) {
|
||||||
|
totalPending = totalPending + item.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getModel()->setTotalPending(totalPending);
|
||||||
|
|
||||||
|
// Update UI Balance
|
||||||
|
updateUIBalances();
|
||||||
|
|
||||||
// Update model data, which updates the table view
|
// Update model data, which updates the table view
|
||||||
transactionsTableModel->replaceData(txdata);
|
transactionsTableModel->replaceData(txdata);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the wallet is encrpyted and locked, we need to unlock it
|
||||||
|
void Controller::unlockIfEncrypted(std::function<void(void)> cb, std::function<void(void)> error) {
|
||||||
|
auto encStatus = getModel()->getEncryptionStatus();
|
||||||
|
if (encStatus.first && encStatus.second) {
|
||||||
|
// Wallet is encrypted and locked. Ask for the password and unlock.
|
||||||
|
QString password = QInputDialog::getText(main, main->tr("Wallet Password"),
|
||||||
|
main->tr("Your wallet is encrypted.\nPlease enter your wallet password"), QLineEdit::Password);
|
||||||
|
|
||||||
|
if (password.isEmpty()) {
|
||||||
|
QMessageBox::critical(main, main->tr("Wallet Decryption Failed"),
|
||||||
|
main->tr("Please enter a valid password"),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
zrpc->unlockWallet(password, [=](json reply) {
|
||||||
|
if (isJsonResultSuccess(reply)) {
|
||||||
|
cb();
|
||||||
|
|
||||||
|
// Refresh the wallet so the encryption status is now in sync.
|
||||||
|
refresh(true);
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(main, main->tr("Wallet Decryption Failed"),
|
||||||
|
QString::fromStdString(reply["error"].get<json::string_t>()),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Not locked, so just call the function
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a transaction with the standard UI. i.e., standard status bar message and standard error
|
* Execute a transaction with the standard UI. i.e., standard status bar message and standard error
|
||||||
* handling
|
* handling
|
||||||
@@ -428,21 +519,25 @@ void Controller::executeStandardUITransaction(Tx tx) {
|
|||||||
void Controller::executeTransaction(Tx tx,
|
void Controller::executeTransaction(Tx tx,
|
||||||
const std::function<void(QString txid)> submitted,
|
const std::function<void(QString txid)> submitted,
|
||||||
const std::function<void(QString txid, QString errStr)> error) {
|
const std::function<void(QString txid, QString errStr)> error) {
|
||||||
// First, create the json params
|
unlockIfEncrypted([=] () {
|
||||||
json params = json::array();
|
// First, create the json params
|
||||||
fillTxJsonParams(params, tx);
|
json params = json::array();
|
||||||
std::cout << std::setw(2) << params << std::endl;
|
fillTxJsonParams(params, tx);
|
||||||
|
std::cout << std::setw(2) << params << std::endl;
|
||||||
|
|
||||||
zrpc->sendTransaction(QString::fromStdString(params.dump()), [=](const json& reply) {
|
zrpc->sendTransaction(QString::fromStdString(params.dump()), [=](const json& reply) {
|
||||||
if (reply.find("txid") == reply.end()) {
|
if (reply.find("txid") == reply.end()) {
|
||||||
error("", "Couldn't understand Response: " + QString::fromStdString(reply.dump()));
|
error("", "Couldn't understand Response: " + QString::fromStdString(reply.dump()));
|
||||||
}
|
} else {
|
||||||
|
QString txid = QString::fromStdString(reply["txid"].get<json::string_t>());
|
||||||
QString txid = QString::fromStdString(reply["txid"].get<json::string_t>());
|
submitted(txid);
|
||||||
submitted(txid);
|
}
|
||||||
},
|
},
|
||||||
[=](QString errStr) {
|
[=](QString errStr) {
|
||||||
error("", errStr);
|
error("", errStr);
|
||||||
|
});
|
||||||
|
}, [=]() {
|
||||||
|
error("", main->tr("Failed to unlock wallet"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +546,7 @@ void Controller::checkForUpdate(bool silent) {
|
|||||||
if (!zrpc->haveConnection())
|
if (!zrpc->haveConnection())
|
||||||
return noConnection();
|
return noConnection();
|
||||||
|
|
||||||
QUrl cmcURL("https://api.github.com/repos/MyHush/SilentDragonLite/releases");
|
QUrl cmcURL("https://api.github.com/repos/DenioD/SilentDragonLite/releases");
|
||||||
|
|
||||||
QNetworkRequest req;
|
QNetworkRequest req;
|
||||||
req.setUrl(cmcURL);
|
req.setUrl(cmcURL);
|
||||||
@@ -499,7 +594,7 @@ void Controller::checkForUpdate(bool silent) {
|
|||||||
.arg(currentVersion.toString()),
|
.arg(currentVersion.toString()),
|
||||||
QMessageBox::Yes, QMessageBox::Cancel);
|
QMessageBox::Yes, QMessageBox::Cancel);
|
||||||
if (ans == QMessageBox::Yes) {
|
if (ans == QMessageBox::Yes) {
|
||||||
QDesktopServices::openUrl(QUrl("https://github.com/MyHush/SilentDragonLite/releases"));
|
QDesktopServices::openUrl(QUrl("https://github.com/DenioD/SilentDragonLite/releases"));
|
||||||
} else {
|
} else {
|
||||||
// If the user selects cancel, don't bother them again for this version
|
// If the user selects cancel, don't bother them again for this version
|
||||||
s.setValue("update/lastversion", maxVersion.toString());
|
s.setValue("update/lastversion", maxVersion.toString());
|
||||||
@@ -521,7 +616,7 @@ void Controller::checkForUpdate(bool silent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the hush->USD price from coinmarketcap using their API
|
// Get the hush->USD price from coinmarketcap using their API
|
||||||
void Controller::refreshhushPrice() {
|
void Controller::refreshZECPrice() {
|
||||||
if (!zrpc->haveConnection())
|
if (!zrpc->haveConnection())
|
||||||
return noConnection();
|
return noConnection();
|
||||||
|
|
||||||
@@ -546,7 +641,7 @@ void Controller::refreshhushPrice() {
|
|||||||
} else {
|
} else {
|
||||||
qDebug() << reply->errorString();
|
qDebug() << reply->errorString();
|
||||||
}
|
}
|
||||||
Settings::getInstance()->sethushPrice(0);
|
Settings::getInstance()->setZECPrice(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,7 +650,7 @@ void Controller::refreshhushPrice() {
|
|||||||
auto all = reply->readAll();
|
auto all = reply->readAll();
|
||||||
auto parsed = json::parse(all, nullptr, false);
|
auto parsed = json::parse(all, nullptr, false);
|
||||||
if (parsed.is_discarded()) {
|
if (parsed.is_discarded()) {
|
||||||
Settings::getInstance()->sethushPrice(0);
|
Settings::getInstance()->setZECPrice(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,7 +664,7 @@ void Controller::refreshhushPrice() {
|
|||||||
// TODO: support BTC/EUR prices as well
|
// TODO: support BTC/EUR prices as well
|
||||||
//QString price = QString::fromStdString(hush["usd"].get<json::string_t>());
|
//QString price = QString::fromStdString(hush["usd"].get<json::string_t>());
|
||||||
qDebug() << "HUSH = $" << QString::number((double)hush["usd"]);
|
qDebug() << "HUSH = $" << QString::number((double)hush["usd"]);
|
||||||
Settings::getInstance()->sethushPrice( hush["usd"] );
|
Settings::getInstance()->setZECPrice( hush["usd"] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
@@ -578,7 +673,7 @@ void Controller::refreshhushPrice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If nothing, then set the price to 0;
|
// If nothing, then set the price to 0;
|
||||||
Settings::getInstance()->sethushPrice(0);
|
Settings::getInstance()->setZECPrice(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
#include "camount.h"
|
||||||
#include "datamodel.h"
|
#include "datamodel.h"
|
||||||
#include "balancestablemodel.h"
|
#include "balancestablemodel.h"
|
||||||
#include "txtablemodel.h"
|
#include "txtablemodel.h"
|
||||||
@@ -21,15 +22,6 @@ struct WatchedTx {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct MigrationStatus {
|
|
||||||
bool available; // Whether the underlying hushd supports migration?
|
|
||||||
bool enabled;
|
|
||||||
QString saplingAddress;
|
|
||||||
double unmigrated;
|
|
||||||
double migrated;
|
|
||||||
QList<QString> txids;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Controller
|
class Controller
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -44,8 +36,7 @@ public:
|
|||||||
void refreshAddresses();
|
void refreshAddresses();
|
||||||
|
|
||||||
void checkForUpdate(bool silent = true);
|
void checkForUpdate(bool silent = true);
|
||||||
void refreshhushPrice();
|
void refreshZECPrice();
|
||||||
//void getZboardTopics(std::function<void(QMap<QString, QString>)> cb);
|
|
||||||
|
|
||||||
void executeStandardUITransaction(Tx tx);
|
void executeStandardUITransaction(Tx tx);
|
||||||
|
|
||||||
@@ -61,11 +52,52 @@ public:
|
|||||||
void noConnection();
|
void noConnection();
|
||||||
bool isEmbedded() { return ehushd != nullptr; }
|
bool isEmbedded() { return ehushd != nullptr; }
|
||||||
|
|
||||||
void createNewZaddr(bool sapling, const std::function<void(json)>& cb) { zrpc->createNewZaddr(sapling, cb); }
|
void encryptWallet(QString password, const std::function<void(json)>& cb) {
|
||||||
void createNewTaddr(const std::function<void(json)>& cb) { zrpc->createNewTaddr(cb); }
|
zrpc->encryptWallet(password, cb);
|
||||||
|
}
|
||||||
|
|
||||||
void fetchPrivKey(QString addr, const std::function<void(json)>& cb) { zrpc->fetchPrivKey(addr, cb); }
|
void removeWalletEncryption(QString password, const std::function<void(json)>& cb) {
|
||||||
void fetchAllPrivKeys(const std::function<void(json)> cb) { zrpc->fetchAllPrivKeys(cb); }
|
zrpc->removeWalletEncryption(password, cb); }
|
||||||
|
|
||||||
|
void saveWallet(const std::function<void(json)>& cb) { zrpc->saveWallet(cb); }
|
||||||
|
|
||||||
|
void createNewZaddr(bool sapling, const std::function<void(json)>& cb) {
|
||||||
|
unlockIfEncrypted([=] () {
|
||||||
|
zrpc->createNewZaddr(sapling, cb);
|
||||||
|
}, [=](){});
|
||||||
|
}
|
||||||
|
void createNewTaddr(const std::function<void(json)>& cb) {
|
||||||
|
unlockIfEncrypted([=] () {
|
||||||
|
zrpc->createNewTaddr(cb);
|
||||||
|
}, [=](){});
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchPrivKey(QString addr, const std::function<void(json)>& cb) {
|
||||||
|
unlockIfEncrypted([=] () {
|
||||||
|
zrpc->fetchPrivKey(addr, cb);
|
||||||
|
},
|
||||||
|
[=]() {
|
||||||
|
cb({ {"error", "Failed to unlock wallet"} });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchAllPrivKeys(const std::function<void(json)> cb) {
|
||||||
|
unlockIfEncrypted([=] () {
|
||||||
|
zrpc->fetchAllPrivKeys(cb);
|
||||||
|
},
|
||||||
|
[=]() {
|
||||||
|
cb({ {"error", "Failed to unlock wallet"} });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchSeed(const std::function<void(json)> cb) {
|
||||||
|
unlockIfEncrypted([=] () {
|
||||||
|
zrpc->fetchSeed(cb);
|
||||||
|
},
|
||||||
|
[=]() {
|
||||||
|
cb({ {"error", "Failed to unlock wallet"} });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// void importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb) { zrpc->importZPrivKey(addr, rescan, cb); }
|
// void importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb) { zrpc->importZPrivKey(addr, rescan, cb); }
|
||||||
// void importTPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb) { zrpc->importTPrivKey(addr, rescan, cb); }
|
// void importTPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb) { zrpc->importTPrivKey(addr, rescan, cb); }
|
||||||
@@ -78,10 +110,13 @@ private:
|
|||||||
|
|
||||||
void refreshTransactions();
|
void refreshTransactions();
|
||||||
|
|
||||||
bool processUnspent (const json& reply, QMap<QString, double>* newBalances, QList<UnspentOutput>* newUtxos);
|
void processUnspent (const json& reply, QMap<QString, CAmount>* newBalances, QList<UnspentOutput>* newUnspentOutputs);
|
||||||
void updateUI (bool anyUnconfirmed);
|
void updateUI (bool anyUnconfirmed);
|
||||||
|
void updateUIBalances ();
|
||||||
|
|
||||||
void getInfoThenRefresh(bool force);
|
void getInfoThenRefresh (bool force);
|
||||||
|
|
||||||
|
void unlockIfEncrypted (std::function<void(void)> cb, std::function<void(void)> error);
|
||||||
|
|
||||||
QProcess* ehushd = nullptr;
|
QProcess* ehushd = nullptr;
|
||||||
|
|
||||||
@@ -89,7 +124,7 @@ private:
|
|||||||
BalancesTableModel* balancesTableModel = nullptr;
|
BalancesTableModel* balancesTableModel = nullptr;
|
||||||
|
|
||||||
DataModel* model;
|
DataModel* model;
|
||||||
LiteInterface* zrpc;
|
LiteInterface* zrpc;
|
||||||
|
|
||||||
QTimer* timer;
|
QTimer* timer;
|
||||||
QTimer* txTimer;
|
QTimer* txTimer;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ DataModel::DataModel() {
|
|||||||
QWriteLocker locker(lock);
|
QWriteLocker locker(lock);
|
||||||
|
|
||||||
utxos = new QList<UnspentOutput>();
|
utxos = new QList<UnspentOutput>();
|
||||||
balances = new QMap<QString, double>();
|
balances = new QMap<QString, CAmount>();
|
||||||
usedAddresses = new QMap<QString, bool>();
|
usedAddresses = new QMap<QString, bool>();
|
||||||
zaddresses = new QList<QString>();
|
zaddresses = new QList<QString>();
|
||||||
taddresses = new QList<QString>();
|
taddresses = new QList<QString>();
|
||||||
@@ -24,6 +24,7 @@ DataModel::~DataModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DataModel::setLatestBlock(int blockHeight) {
|
void DataModel::setLatestBlock(int blockHeight) {
|
||||||
|
QReadLocker locker(lock);
|
||||||
this->latestBlock = blockHeight;
|
this->latestBlock = blockHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ void DataModel::replaceTaddresses(QList<QString>* newT) {
|
|||||||
taddresses = newT;
|
taddresses = newT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataModel::replaceBalances(QMap<QString, double>* newBalances) {
|
void DataModel::replaceBalances(QMap<QString, CAmount>* newBalances) {
|
||||||
QWriteLocker locker(lock);
|
QWriteLocker locker(lock);
|
||||||
Q_ASSERT(newBalances);
|
Q_ASSERT(newBalances);
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
#ifndef DATAMODEL_H
|
#ifndef DATAMODEL_H
|
||||||
#define DATAMODEL_H
|
#define DATAMODEL_H
|
||||||
|
|
||||||
|
#include "camount.h"
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
|
||||||
struct UnspentOutput {
|
struct UnspentOutput {
|
||||||
QString address;
|
QString address;
|
||||||
QString txid;
|
QString txid;
|
||||||
QString amount;
|
CAmount amount;
|
||||||
int blockCreated;
|
int blockCreated;
|
||||||
bool spendable;
|
bool spendable;
|
||||||
|
bool pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -18,34 +20,60 @@ class DataModel {
|
|||||||
public:
|
public:
|
||||||
void replaceZaddresses(QList<QString>* newZ);
|
void replaceZaddresses(QList<QString>* newZ);
|
||||||
void replaceTaddresses(QList<QString>* newZ);
|
void replaceTaddresses(QList<QString>* newZ);
|
||||||
void replaceBalances(QMap<QString, double>* newBalances);
|
void replaceBalances(QMap<QString, CAmount>* newBalances);
|
||||||
void replaceUTXOs(QList<UnspentOutput>* utxos);
|
void replaceUTXOs(QList<UnspentOutput>* utxos);
|
||||||
|
|
||||||
void markAddressUsed(QString address);
|
void markAddressUsed(QString address);
|
||||||
|
|
||||||
void setLatestBlock(int blockHeight);
|
void setLatestBlock(int blockHeight);
|
||||||
int getLatestBlock() { return this->latestBlock; }
|
int getLatestBlock() { QReadLocker locker(lock); return this->latestBlock; }
|
||||||
|
|
||||||
|
void setEncryptionStatus(bool encrypted, bool locked) { this->isEncrypted = encrypted; this->isLocked = locked; }
|
||||||
|
QPair<bool, bool> getEncryptionStatus() { return qMakePair(this->isEncrypted, this->isLocked); }
|
||||||
|
|
||||||
const QList<QString> getAllZAddresses() { QReadLocker locker(lock); return *zaddresses; }
|
const QList<QString> getAllZAddresses() { QReadLocker locker(lock); return *zaddresses; }
|
||||||
const QList<QString> getAllTAddresses() { QReadLocker locker(lock); return *taddresses; }
|
const QList<QString> getAllTAddresses() { QReadLocker locker(lock); return *taddresses; }
|
||||||
const QList<UnspentOutput> getUTXOs() { QReadLocker locker(lock); return *utxos; }
|
const QList<UnspentOutput> getUTXOs() { QReadLocker locker(lock); return *utxos; }
|
||||||
const QMap<QString, double> getAllBalances() { QReadLocker locker(lock); return *balances; }
|
const QMap<QString, CAmount> getAllBalances() { QReadLocker locker(lock); return *balances; }
|
||||||
const QMap<QString, bool> getUsedAddresses() { QReadLocker locker(lock); return *usedAddresses; }
|
const QMap<QString, bool> getUsedAddresses() { QReadLocker locker(lock); return *usedAddresses; }
|
||||||
|
|
||||||
|
CAmount getAvailableBalance() { QReadLocker locker(lock); return availableBalance; }
|
||||||
|
void setAvailableBalance(CAmount a) { QReadLocker locker(lock); this->availableBalance = a; }
|
||||||
|
|
||||||
|
CAmount getBalT() { QReadLocker locker(lock); return balT; }
|
||||||
|
void setBalT(CAmount a) { QReadLocker locker(lock); this->balT = a; }
|
||||||
|
|
||||||
|
CAmount getBalZ() { QReadLocker locker(lock); return balZ; }
|
||||||
|
void setBalZ(CAmount a) { QReadLocker locker(lock); this->balZ = a; }
|
||||||
|
|
||||||
|
CAmount getBalVerified() { QReadLocker locker(lock); return balVerified; }
|
||||||
|
void setBalVerified(CAmount a) { QReadLocker locker(lock); this->balVerified = a; }
|
||||||
|
|
||||||
|
CAmount getTotalPending() { QReadLocker locker(lock); return totalPending; }
|
||||||
|
void setTotalPending(CAmount a) { QReadLocker locker(lock); this->totalPending = a; }
|
||||||
|
|
||||||
DataModel();
|
DataModel();
|
||||||
~DataModel();
|
~DataModel();
|
||||||
private:
|
private:
|
||||||
int latestBlock;
|
int latestBlock;
|
||||||
|
|
||||||
|
bool isEncrypted = false;
|
||||||
|
bool isLocked = false;
|
||||||
|
|
||||||
QList<UnspentOutput>* utxos = nullptr;
|
QList<UnspentOutput>* utxos = nullptr;
|
||||||
QMap<QString, double>* balances = nullptr;
|
QMap<QString, CAmount>* balances = nullptr;
|
||||||
QMap<QString, bool>* usedAddresses = nullptr;
|
QMap<QString, bool>* usedAddresses = nullptr;
|
||||||
QList<QString>* zaddresses = nullptr;
|
QList<QString>* zaddresses = nullptr;
|
||||||
QList<QString>* taddresses = nullptr;
|
QList<QString>* taddresses = nullptr;
|
||||||
|
|
||||||
QReadWriteLock* lock;
|
CAmount availableBalance;
|
||||||
|
CAmount totalPending; // Outgoing pending is -ve
|
||||||
|
|
||||||
|
CAmount balT;
|
||||||
|
CAmount balZ;
|
||||||
|
CAmount balVerified;
|
||||||
|
|
||||||
|
QReadWriteLock* lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DATAMODEL_H
|
#endif // DATAMODEL_H
|
||||||
165
src/encryption.ui
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>encryptionDialog</class>
|
||||||
|
<widget class="QDialog" name="encryptionDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Encrypt Your Wallet</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Encryption Password:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Confirm Password:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QLineEdit" name="txtConfirmPassword">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="lblPasswordMatch">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: red;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Passwords don't match</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLineEdit" name="txtPassword">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0" colspan="2">
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>WARNING: If you forget your password, the only way to recover the wallet is from the seed phrase.</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
<property name="centerButtons">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>txtPassword</tabstop>
|
||||||
|
<tabstop>txtConfirmPassword</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>encryptionDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>encryptionDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
@@ -39,7 +39,7 @@ void LiteInterface::createNewZaddr(bool, const std::function<void(json)>& cb) {
|
|||||||
if (conn == nullptr)
|
if (conn == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
conn->doRPCWithDefaultErrorHandling("new", "zs1", cb);
|
conn->doRPCWithDefaultErrorHandling("new", "zs", cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LiteInterface::createNewTaddr(const std::function<void(json)>& cb) {
|
void LiteInterface::createNewTaddr(const std::function<void(json)>& cb) {
|
||||||
@@ -56,6 +56,13 @@ void LiteInterface::fetchPrivKey(QString addr, const std::function<void(json)>&
|
|||||||
conn->doRPCWithDefaultErrorHandling("export", addr, cb);
|
conn->doRPCWithDefaultErrorHandling("export", addr, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LiteInterface::fetchSeed(const std::function<void(json)>& cb) {
|
||||||
|
if (conn == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
conn->doRPCWithDefaultErrorHandling("seed", "", cb);
|
||||||
|
}
|
||||||
|
|
||||||
void LiteInterface::fetchBalance(const std::function<void(json)>& cb) {
|
void LiteInterface::fetchBalance(const std::function<void(json)>& cb) {
|
||||||
if (conn == nullptr)
|
if (conn == nullptr)
|
||||||
return;
|
return;
|
||||||
@@ -77,6 +84,36 @@ void LiteInterface::saveWallet(const std::function<void(json)>& cb) {
|
|||||||
conn->doRPCWithDefaultErrorHandling("save", "", cb);
|
conn->doRPCWithDefaultErrorHandling("save", "", cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LiteInterface::unlockWallet(QString password, const std::function<void(json)>& cb) {
|
||||||
|
if (conn == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
conn->doRPCWithDefaultErrorHandling("unlock", password, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteInterface::fetchWalletEncryptionStatus(const std::function<void(json)>& cb) {
|
||||||
|
if (conn == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
conn->doRPCWithDefaultErrorHandling("encryptionstatus", "", cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteInterface::encryptWallet(QString password, const std::function<void(json)>& cb) {
|
||||||
|
if (conn == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
conn->doRPCWithDefaultErrorHandling("encrypt", password, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LiteInterface::removeWalletEncryption(QString password, const std::function<void(json)>& cb) {
|
||||||
|
if (conn == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
conn->doRPCWithDefaultErrorHandling("decrypt", password, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LiteInterface::sendTransaction(QString params, const std::function<void(json)>& cb,
|
void LiteInterface::sendTransaction(QString params, const std::function<void(json)>& cb,
|
||||||
const std::function<void(QString)>& err) {
|
const std::function<void(QString)>& err) {
|
||||||
if (conn == nullptr)
|
if (conn == nullptr)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
#include "camount.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
@@ -11,7 +12,7 @@ using json = nlohmann::json;
|
|||||||
// into a struct with address, amount, memo
|
// into a struct with address, amount, memo
|
||||||
struct TransactionItemDetail {
|
struct TransactionItemDetail {
|
||||||
QString address;
|
QString address;
|
||||||
double amount;
|
CAmount amount;
|
||||||
QString memo;
|
QString memo;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,9 +53,15 @@ public:
|
|||||||
|
|
||||||
void fetchPrivKey(QString addr, const std::function<void(json)>& cb);
|
void fetchPrivKey(QString addr, const std::function<void(json)>& cb);
|
||||||
void fetchAllPrivKeys(const std::function<void(json)>);
|
void fetchAllPrivKeys(const std::function<void(json)>);
|
||||||
|
void fetchSeed(const std::function<void(json)>&);
|
||||||
|
|
||||||
void saveWallet(const std::function<void(json)>& cb);
|
void saveWallet(const std::function<void(json)>& cb);
|
||||||
|
|
||||||
|
void fetchWalletEncryptionStatus(const std::function<void(json)>& cb);
|
||||||
|
void encryptWallet(QString password, const std::function<void(json)>& cb);
|
||||||
|
void unlockWallet(QString password, const std::function<void(json)>& cb);
|
||||||
|
void removeWalletEncryption(QString password, const std::function<void(json)>& cb);
|
||||||
|
|
||||||
//void importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
|
//void importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
|
||||||
//void importTPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
|
//void importTPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
|
||||||
|
|
||||||
|
|||||||
10
src/main.cpp
@@ -150,9 +150,8 @@ public:
|
|||||||
parser.setApplicationDescription("Shielded desktop light wallet for hush");
|
parser.setApplicationDescription("Shielded desktop light wallet for hush");
|
||||||
parser.addHelpOption();
|
parser.addHelpOption();
|
||||||
|
|
||||||
|
|
||||||
// Positional argument will specify a hush payment URI
|
// Positional argument will specify a hush payment URI
|
||||||
parser.addPositionalArgument("HUSHURI", "An optional hush URI to pay");
|
parser.addPositionalArgument("hushURI", "An optional hush URI to pay");
|
||||||
|
|
||||||
parser.process(a);
|
parser.process(a);
|
||||||
|
|
||||||
@@ -165,7 +164,7 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QCoreApplication::setOrganizationName("myhush.org");
|
QCoreApplication::setOrganizationName("Hush");
|
||||||
QCoreApplication::setApplicationName("SilentDragonLite");
|
QCoreApplication::setApplicationName("SilentDragonLite");
|
||||||
|
|
||||||
QString locale = QLocale::system().name();
|
QString locale = QLocale::system().name();
|
||||||
@@ -173,7 +172,7 @@ public:
|
|||||||
qDebug() << "Loading locale " << locale;
|
qDebug() << "Loading locale " << locale;
|
||||||
|
|
||||||
QTranslator translator;
|
QTranslator translator;
|
||||||
translator.load(QString(":/translations/res/zec_qt_wallet_") + locale);
|
translator.load(QString(":/translations/res/hush_qt_wallet_") + locale);
|
||||||
a.installTranslator(&translator);
|
a.installTranslator(&translator);
|
||||||
|
|
||||||
QIcon icon(":/icons/res/icon.ico");
|
QIcon icon(":/icons/res/icon.ico");
|
||||||
@@ -204,8 +203,9 @@ public:
|
|||||||
|
|
||||||
Settings::getInstance()->setUseEmbedded(false);
|
Settings::getInstance()->setUseEmbedded(false);
|
||||||
|
|
||||||
|
|
||||||
w = new MainWindow();
|
w = new MainWindow();
|
||||||
w->setWindowTitle("SilentDragonLite v" + QString(APP_VERSION));
|
w->setWindowTitle("SilentDragon Lite v" + QString(APP_VERSION));
|
||||||
|
|
||||||
// If there was a payment URI on the command line, pay it
|
// If there was a payment URI on the command line, pay it
|
||||||
if (parser.positionalArguments().length() > 0) {
|
if (parser.positionalArguments().length() > 0) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "addressbook.h"
|
#include "addressbook.h"
|
||||||
#include "viewalladdresses.h"
|
#include "viewalladdresses.h"
|
||||||
|
#include "ui_encryption.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "ui_mobileappconnector.h"
|
#include "ui_mobileappconnector.h"
|
||||||
#include "ui_addressbook.h"
|
#include "ui_addressbook.h"
|
||||||
@@ -22,8 +23,6 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
ui(new Ui::MainWindow)
|
ui(new Ui::MainWindow)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// Include css
|
// Include css
|
||||||
QString theme_name;
|
QString theme_name;
|
||||||
try
|
try
|
||||||
@@ -37,9 +36,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
|
|
||||||
this->slot_change_theme(theme_name);
|
this->slot_change_theme(theme_name);
|
||||||
|
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
logger = new Logger(this, QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite-cli-wallet.log"));
|
logger = new Logger(this, QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite-wallet.log"));
|
||||||
|
|
||||||
// Status Bar
|
// Status Bar
|
||||||
setupStatusBar();
|
setupStatusBar();
|
||||||
@@ -59,7 +57,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
|
|
||||||
// File a bug
|
// File a bug
|
||||||
QObject::connect(ui->actionFile_a_bug, &QAction::triggered, [=]() {
|
QObject::connect(ui->actionFile_a_bug, &QAction::triggered, [=]() {
|
||||||
QDesktopServices::openUrl(QUrl("https://github.com/MyHush/silentdragonlite/issues/new"));
|
QDesktopServices::openUrl(QUrl("https://github.com/DenioD/SilentDragonLite/issues/new"));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up check for updates action
|
// Set up check for updates action
|
||||||
@@ -83,11 +81,20 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
payhushURI();
|
payhushURI();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Wallet encryption
|
||||||
|
QObject::connect(ui->actionEncrypt_Wallet, &QAction::triggered, [=]() {
|
||||||
|
encryptWallet();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(ui->actionRemove_Wallet_Encryption, &QAction::triggered, [=]() {
|
||||||
|
removeWalletEncryption();
|
||||||
|
});
|
||||||
|
|
||||||
// Export All Private Keys
|
// Export All Private Keys
|
||||||
QObject::connect(ui->actionExport_All_Private_Keys, &QAction::triggered, this, &MainWindow::exportAllKeys);
|
QObject::connect(ui->actionExport_All_Private_Keys, &QAction::triggered, this, &MainWindow::exportAllKeys);
|
||||||
|
|
||||||
// Backup wallet.dat
|
// Backup wallet.dat
|
||||||
QObject::connect(ui->actionBackup_wallet_dat, &QAction::triggered, this, &MainWindow::backupWalletDat);
|
QObject::connect(ui->actionExport_Seed, &QAction::triggered, this, &MainWindow::exportSeed);
|
||||||
|
|
||||||
// Export transactions
|
// Export transactions
|
||||||
QObject::connect(ui->actionExport_transactions, &QAction::triggered, this, &MainWindow::exportTransactions);
|
QObject::connect(ui->actionExport_transactions, &QAction::triggered, this, &MainWindow::exportTransactions);
|
||||||
@@ -179,13 +186,19 @@ void MainWindow::restoreSavedStates() {
|
|||||||
QSettings s;
|
QSettings s;
|
||||||
restoreGeometry(s.value("geometry").toByteArray());
|
restoreGeometry(s.value("geometry").toByteArray());
|
||||||
|
|
||||||
ui->balancesTable->horizontalHeader()->restoreState(s.value("baltablegeometry").toByteArray());
|
auto balance_geom = s.value("baltablegeom");
|
||||||
ui->transactionsTable->horizontalHeader()->restoreState(s.value("tratablegeometry").toByteArray());
|
if (balance_geom == QVariant()) {
|
||||||
|
ui->balancesTable->setColumnWidth(0, 500);
|
||||||
|
} else {
|
||||||
|
ui->balancesTable->horizontalHeader()->restoreState(balance_geom.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
// Explicitly set the tx table resize headers, since some previous values may have made them
|
auto tx_geom = s.value("tratablegeom");
|
||||||
// non-expandable.
|
if (tx_geom == QVariant()) {
|
||||||
ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive);
|
ui->transactionsTable->setColumnWidth(1, 500);
|
||||||
ui->transactionsTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Interactive);
|
} else {
|
||||||
|
ui->transactionsTable->horizontalHeader()->restoreState(tx_geom.toByteArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::doClose() {
|
void MainWindow::doClose() {
|
||||||
@@ -196,8 +209,8 @@ void MainWindow::closeEvent(QCloseEvent* event) {
|
|||||||
QSettings s;
|
QSettings s;
|
||||||
|
|
||||||
s.setValue("geometry", saveGeometry());
|
s.setValue("geometry", saveGeometry());
|
||||||
s.setValue("baltablegeometry", ui->balancesTable->horizontalHeader()->saveState());
|
s.setValue("baltablegeom", ui->balancesTable->horizontalHeader()->saveState());
|
||||||
s.setValue("tratablegeometry", ui->transactionsTable->horizontalHeader()->saveState());
|
s.setValue("tratablegeom", ui->transactionsTable->horizontalHeader()->saveState());
|
||||||
|
|
||||||
s.sync();
|
s.sync();
|
||||||
|
|
||||||
@@ -209,6 +222,128 @@ void MainWindow::closeEvent(QCloseEvent* event) {
|
|||||||
QMainWindow::closeEvent(event);
|
QMainWindow::closeEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::encryptWallet() {
|
||||||
|
// Check if wallet is already encrypted
|
||||||
|
auto encStatus = rpc->getModel()->getEncryptionStatus();
|
||||||
|
if (encStatus.first) {
|
||||||
|
QMessageBox::information(this, tr("Wallet is already encrypted"),
|
||||||
|
tr("Your wallet is already encrypted with a password.\nPlease use 'Remove Wallet Encryption' if you want to remove the wallet encryption."),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog d(this);
|
||||||
|
Ui_encryptionDialog ed;
|
||||||
|
ed.setupUi(&d);
|
||||||
|
|
||||||
|
// Handle edits on the password box
|
||||||
|
auto fnPasswordEdited = [=](const QString&) {
|
||||||
|
// Enable the OK button if the passwords match.
|
||||||
|
if (!ed.txtPassword->text().isEmpty() &&
|
||||||
|
ed.txtPassword->text() == ed.txtConfirmPassword->text()) {
|
||||||
|
ed.lblPasswordMatch->setText("");
|
||||||
|
ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
|
||||||
|
} else {
|
||||||
|
ed.lblPasswordMatch->setText(tr("Passwords don't match"));
|
||||||
|
ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(ed.txtConfirmPassword, &QLineEdit::textChanged, fnPasswordEdited);
|
||||||
|
QObject::connect(ed.txtPassword, &QLineEdit::textChanged, fnPasswordEdited);
|
||||||
|
|
||||||
|
ed.txtPassword->setText("");
|
||||||
|
ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||||
|
|
||||||
|
auto fnShowError = [=](QString title, const json& res) {
|
||||||
|
QMessageBox::critical(this, title,
|
||||||
|
tr("Error was:\n") + QString::fromStdString(res.dump()),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (d.exec() == QDialog::Accepted) {
|
||||||
|
rpc->encryptWallet(ed.txtPassword->text(), [=](json res) {
|
||||||
|
if (isJsonResultSuccess(res)) {
|
||||||
|
// Save the wallet
|
||||||
|
rpc->saveWallet([=] (json reply) {
|
||||||
|
if (isJsonResultSuccess(reply)) {
|
||||||
|
QMessageBox::information(this, tr("Wallet Encrypted"),
|
||||||
|
tr("Your wallet was successfully encrypted! The password will be needed to send funds or export private keys."),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
fnShowError(tr("Wallet Encryption Failed"), reply);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// And then refresh the UI
|
||||||
|
rpc->refresh(true);
|
||||||
|
} else {
|
||||||
|
fnShowError(tr("Wallet Encryption Failed"), res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::removeWalletEncryption() {
|
||||||
|
// Check if wallet is already encrypted
|
||||||
|
auto encStatus = rpc->getModel()->getEncryptionStatus();
|
||||||
|
if (!encStatus.first) {
|
||||||
|
QMessageBox::information(this, tr("Wallet is not encrypted"),
|
||||||
|
tr("Your wallet is not encrypted with a password."),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
QString password = QInputDialog::getText(this, tr("Wallet Password"),
|
||||||
|
tr("Please enter your wallet password"), QLineEdit::Password, "", &ok);
|
||||||
|
|
||||||
|
// If cancel was pressed, just return
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.isEmpty()) {
|
||||||
|
QMessageBox::critical(this, tr("Wallet Decryption Failed"),
|
||||||
|
tr("Please enter a password to decrypt your wallet!"),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc->removeWalletEncryption(password, [=] (json res) {
|
||||||
|
if (isJsonResultSuccess(res)) {
|
||||||
|
// Save the wallet
|
||||||
|
rpc->saveWallet([=] (json reply) {
|
||||||
|
if(isJsonResultSuccess(reply)) {
|
||||||
|
QMessageBox::information(this, tr("Wallet Encryption Removed"),
|
||||||
|
tr("Your wallet was successfully decrypted! You will no longer need a password to send funds or export private keys."),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(this, tr("Wallet Decryption Failed"),
|
||||||
|
QString::fromStdString(reply["error"].get<json::string_t>()),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// And then refresh the UI
|
||||||
|
rpc->refresh(true);
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(this, tr("Wallet Decryption Failed"),
|
||||||
|
QString::fromStdString(res["error"].get<json::string_t>()),
|
||||||
|
QMessageBox::Ok
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::setupStatusBar() {
|
void MainWindow::setupStatusBar() {
|
||||||
// Status Bar
|
// Status Bar
|
||||||
loadingLabel = new QLabel();
|
loadingLabel = new QLabel();
|
||||||
@@ -259,11 +394,6 @@ void MainWindow::setupSettingsModal() {
|
|||||||
settings.setupUi(&settingsDialog);
|
settings.setupUi(&settingsDialog);
|
||||||
Settings::saveRestore(&settingsDialog);
|
Settings::saveRestore(&settingsDialog);
|
||||||
|
|
||||||
// Setup save sent check box
|
|
||||||
QObject::connect(settings.chkSaveTxs, &QCheckBox::stateChanged, [=](auto checked) {
|
|
||||||
Settings::getInstance()->setSaveZtxs(checked);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Setup theme combo
|
// Setup theme combo
|
||||||
int theme_index = settings.comboBoxTheme->findText(Settings::getInstance()->get_theme_name(), Qt::MatchExactly);
|
int theme_index = settings.comboBoxTheme->findText(Settings::getInstance()->get_theme_name(), Qt::MatchExactly);
|
||||||
settings.comboBoxTheme->setCurrentIndex(theme_index);
|
settings.comboBoxTheme->setCurrentIndex(theme_index);
|
||||||
@@ -274,55 +404,15 @@ void MainWindow::setupSettingsModal() {
|
|||||||
QMessageBox::information(this, tr("Restart"), tr("Please restart Silentdragonlite to have the theme apply"), QMessageBox::Ok);
|
QMessageBox::information(this, tr("Restart"), tr("Please restart Silentdragonlite to have the theme apply"), QMessageBox::Ok);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save sent transactions
|
|
||||||
settings.chkSaveTxs->setChecked(Settings::getInstance()->getSaveZtxs());
|
|
||||||
|
|
||||||
// Custom fees
|
|
||||||
settings.chkCustomFees->setChecked(Settings::getInstance()->getAllowCustomFees());
|
|
||||||
|
|
||||||
// Auto shielding
|
|
||||||
settings.chkAutoShield->setChecked(Settings::getInstance()->getAutoShield());
|
|
||||||
|
|
||||||
// Check for updates
|
// Check for updates
|
||||||
settings.chkCheckUpdates->setChecked(Settings::getInstance()->getCheckForUpdates());
|
settings.chkCheckUpdates->setChecked(Settings::getInstance()->getCheckForUpdates());
|
||||||
|
|
||||||
// Fetch prices
|
// Fetch prices
|
||||||
settings.chkFetchPrices->setChecked(Settings::getInstance()->getAllowFetchPrices());
|
settings.chkFetchPrices->setChecked(Settings::getInstance()->getAllowFetchPrices());
|
||||||
|
|
||||||
// Use Tor
|
|
||||||
bool isUsingTor = false;
|
|
||||||
if (rpc->getConnection() != nullptr) {
|
|
||||||
isUsingTor = !rpc->getConnection()->config->proxy.isEmpty();
|
|
||||||
}
|
|
||||||
settings.chkTor->setChecked(isUsingTor);
|
|
||||||
|
|
||||||
// Connection Settings
|
|
||||||
QIntValidator validator(0, 65535);
|
|
||||||
settings.port->setValidator(&validator);
|
|
||||||
|
|
||||||
// If values are coming from hush.conf, then disable all the fields
|
|
||||||
auto hushConfLocation = Settings::getInstance()->gethushdConfLocation();
|
|
||||||
if (!hushConfLocation.isEmpty()) {
|
|
||||||
settings.confMsg->setText("Settings are being read from \n" + hushConfLocation);
|
|
||||||
settings.hostname->setEnabled(false);
|
|
||||||
settings.port->setEnabled(false);
|
|
||||||
settings.rpcuser->setEnabled(false);
|
|
||||||
settings.rpcpassword->setEnabled(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
settings.confMsg->setText("No local HUSH3.conf found. Please configure connection manually.");
|
|
||||||
settings.hostname->setEnabled(true);
|
|
||||||
settings.port->setEnabled(true);
|
|
||||||
settings.rpcuser->setEnabled(true);
|
|
||||||
settings.rpcpassword->setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load current values into the dialog
|
// Load current values into the dialog
|
||||||
auto conf = Settings::getInstance()->getSettings();
|
auto conf = Settings::getInstance()->getSettings();
|
||||||
settings.hostname->setText(conf.host);
|
settings.txtServer->setText(conf.server);
|
||||||
settings.port->setText(conf.port);
|
|
||||||
settings.rpcuser->setText(conf.rpcuser);
|
|
||||||
settings.rpcpassword->setText(conf.rpcpassword);
|
|
||||||
|
|
||||||
// Connection tab by default
|
// Connection tab by default
|
||||||
settings.tabWidget->setCurrentIndex(0);
|
settings.tabWidget->setCurrentIndex(0);
|
||||||
@@ -331,78 +421,25 @@ void MainWindow::setupSettingsModal() {
|
|||||||
if (!rpc->isEmbedded()) {
|
if (!rpc->isEmbedded()) {
|
||||||
settings.chkRescan->setEnabled(false);
|
settings.chkRescan->setEnabled(false);
|
||||||
settings.chkRescan->setToolTip(tr("You're using an external hushd. Please restart hushd with -rescan"));
|
settings.chkRescan->setToolTip(tr("You're using an external hushd. Please restart hushd with -rescan"));
|
||||||
|
|
||||||
settings.chkReindex->setEnabled(false);
|
|
||||||
settings.chkReindex->setToolTip(tr("You're using an external hushd. Please restart hushd with -reindex"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsDialog.exec() == QDialog::Accepted) {
|
if (settingsDialog.exec() == QDialog::Accepted) {
|
||||||
// Custom fees
|
|
||||||
bool customFees = settings.chkCustomFees->isChecked();
|
|
||||||
Settings::getInstance()->setAllowCustomFees(customFees);
|
|
||||||
ui->minerFeeAmt->setReadOnly(!customFees);
|
|
||||||
if (!customFees)
|
|
||||||
ui->minerFeeAmt->setText(Settings::getDecimalString(Settings::getMinerFee()));
|
|
||||||
|
|
||||||
// Auto shield
|
|
||||||
Settings::getInstance()->setAutoShield(settings.chkAutoShield->isChecked());
|
|
||||||
|
|
||||||
// Check for updates
|
// Check for updates
|
||||||
Settings::getInstance()->setCheckForUpdates(settings.chkCheckUpdates->isChecked());
|
Settings::getInstance()->setCheckForUpdates(settings.chkCheckUpdates->isChecked());
|
||||||
|
|
||||||
// Allow fetching prices
|
// Allow fetching prices
|
||||||
Settings::getInstance()->setAllowFetchPrices(settings.chkFetchPrices->isChecked());
|
Settings::getInstance()->setAllowFetchPrices(settings.chkFetchPrices->isChecked());
|
||||||
|
|
||||||
if (!isUsingTor && settings.chkTor->isChecked()) {
|
// Save the server
|
||||||
// If "use tor" was previously unchecked and now checked
|
Settings::getInstance()->saveSettings(settings.txtServer->text().trimmed());
|
||||||
Settings::addTohushConf(hushConfLocation, "proxy=127.0.0.1:9050");
|
|
||||||
rpc->getConnection()->config->proxy = "proxy=127.0.0.1:9050";
|
|
||||||
|
|
||||||
QMessageBox::information(this, tr("Enable Tor"),
|
if (false /* connection needs reloading?*/) {
|
||||||
tr("Connection over Tor has been enabled. To use this feature, you need to restart Silentdragonlite."),
|
|
||||||
QMessageBox::Ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUsingTor && !settings.chkTor->isChecked()) {
|
|
||||||
// If "use tor" was previously checked and now is unchecked
|
|
||||||
Settings::removeFromhushConf(hushConfLocation, "proxy");
|
|
||||||
rpc->getConnection()->config->proxy.clear();
|
|
||||||
|
|
||||||
QMessageBox::information(this, tr("Disable Tor"),
|
|
||||||
tr("Connection over Tor has been disabled. To fully disconnect from Tor, you need to restart silentdragon."),
|
|
||||||
QMessageBox::Ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hushConfLocation.isEmpty()) {
|
|
||||||
// Save settings
|
// Save settings
|
||||||
Settings::getInstance()->saveSettings(
|
Settings::getInstance()->saveSettings(settings.txtServer->text());
|
||||||
settings.hostname->text(),
|
|
||||||
settings.port->text(),
|
|
||||||
settings.rpcuser->text(),
|
|
||||||
settings.rpcpassword->text());
|
|
||||||
|
|
||||||
auto cl = new ConnectionLoader(this, rpc);
|
auto cl = new ConnectionLoader(this, rpc);
|
||||||
cl->loadConnection();
|
cl->loadConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if rescan or reindex have been enabled
|
|
||||||
bool showRestartInfo = false;
|
|
||||||
if (settings.chkRescan->isChecked()) {
|
|
||||||
Settings::addTohushConf(hushConfLocation, "rescan=1");
|
|
||||||
showRestartInfo = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings.chkReindex->isChecked()) {
|
|
||||||
Settings::addTohushConf(hushConfLocation, "reindex=1");
|
|
||||||
showRestartInfo = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showRestartInfo) {
|
|
||||||
auto desc = tr("silentdragon needs to restart to rescan/reindex. silentdragon will now close, please restart silentdragon to continue");
|
|
||||||
|
|
||||||
QMessageBox::information(this, tr("Restart silentdragon"), desc, QMessageBox::Ok);
|
|
||||||
QTimer::singleShot(1, [=]() { this->close(); });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -541,13 +578,9 @@ void MainWindow::payhushURI(QString uri, QString myAddr) {
|
|||||||
// Now, set the fields on the send tab
|
// Now, set the fields on the send tab
|
||||||
clearSendForm();
|
clearSendForm();
|
||||||
|
|
||||||
if (!myAddr.isEmpty()) {
|
|
||||||
ui->inputsCombo->setCurrentText(myAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->Address1->setText(paymentInfo.addr);
|
ui->Address1->setText(paymentInfo.addr);
|
||||||
ui->Address1->setCursorPosition(0);
|
ui->Address1->setCursorPosition(0);
|
||||||
ui->Amount1->setText(Settings::getDecimalString(paymentInfo.amt.toDouble()));
|
ui->Amount1->setText(paymentInfo.amt);
|
||||||
ui->MemoTxt1->setText(paymentInfo.memo);
|
ui->MemoTxt1->setText(paymentInfo.memo);
|
||||||
|
|
||||||
// And switch to the send tab.
|
// And switch to the send tab.
|
||||||
@@ -627,97 +660,110 @@ void MainWindow::exportTransactions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backup the wallet.dat file. This is kind of a hack, since it has to read from the filesystem rather than an RPC call
|
* Export the seed phrase.
|
||||||
* This might fail for various reasons - Remote hushd, non-standard locations, custom params passed to hushd, many others
|
|
||||||
*/
|
*/
|
||||||
void MainWindow::backupWalletDat() {
|
void MainWindow::exportSeed() {
|
||||||
if (!rpc->getConnection())
|
if (!rpc->getConnection())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
rpc->fetchSeed([=](json reply) {
|
||||||
|
if (isJsonError(reply)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog d(this);
|
||||||
|
Ui_PrivKey pui;
|
||||||
|
pui.setupUi(&d);
|
||||||
|
|
||||||
|
// Make the window big by default
|
||||||
|
auto ps = this->geometry();
|
||||||
|
QMargins margin = QMargins() + 50;
|
||||||
|
d.setGeometry(ps.marginsRemoved(margin));
|
||||||
|
|
||||||
|
Settings::saveRestore(&d);
|
||||||
|
|
||||||
|
pui.privKeyTxt->setReadOnly(true);
|
||||||
|
pui.privKeyTxt->setLineWrapMode(QPlainTextEdit::LineWrapMode::NoWrap);
|
||||||
|
pui.privKeyTxt->setPlainText(QString::fromStdString(reply.dump()));
|
||||||
|
|
||||||
|
pui.helpLbl->setText(tr("This is your wallet seed. Please back it up carefully and safely."));
|
||||||
|
|
||||||
|
// Wire up save button
|
||||||
|
QObject::connect(pui.buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, [=] () {
|
||||||
|
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
|
||||||
|
"Hush-seed.txt");
|
||||||
|
QFile file(fileName);
|
||||||
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
|
QMessageBox::information(this, tr("Unable to open file"), file.errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QTextStream out(&file);
|
||||||
|
out << pui.privKeyTxt->toPlainText();
|
||||||
|
});
|
||||||
|
|
||||||
|
pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true);
|
||||||
|
|
||||||
|
d.exec();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// QDir hushdir(rpc->getConnection()->config->hushDir);
|
|
||||||
// QString backupDefaultName = "hush-wallet-backup-" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".dat";
|
|
||||||
|
|
||||||
// if (Settings::getInstance()->isTestnet()) {
|
|
||||||
// hushdir.cd("testnet3");
|
|
||||||
// backupDefaultName = "testnet-" + backupDefaultName;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// QFile wallet(hushdir.filePath("wallet.dat"));
|
|
||||||
// if (!wallet.exists()) {
|
|
||||||
// QMessageBox::critical(this, tr("No wallet.dat"), tr("Couldn't find the wallet.dat on this computer") + "\n" +
|
|
||||||
// tr("You need to back it up from the machine hushd is running on"), QMessageBox::Ok);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// QUrl backupName = QFileDialog::getSaveFileUrl(this, tr("Backup wallet.dat"), backupDefaultName, "Data file (*.dat)");
|
|
||||||
// if (backupName.isEmpty())
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// if (!wallet.copy(backupName.toLocalFile())) {
|
|
||||||
// QMessageBox::critical(this, tr("Couldn't backup"), tr("Couldn't backup the wallet.dat file.") +
|
|
||||||
// tr("You need to back it up manually."), QMessageBox::Ok);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::exportAllKeys() {
|
void MainWindow::exportAllKeys() {
|
||||||
exportKeys("");
|
exportKeys("");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::exportKeys(QString addr) {
|
void MainWindow::exportKeys(QString addr) {
|
||||||
|
if (!rpc->getConnection())
|
||||||
|
return;
|
||||||
|
|
||||||
bool allKeys = addr.isEmpty() ? true : false;
|
bool allKeys = addr.isEmpty() ? true : false;
|
||||||
|
|
||||||
QDialog d(this);
|
auto fnUpdateUIWithKeys = [=](json reply) {
|
||||||
Ui_PrivKey pui;
|
if (isJsonError(reply)) {
|
||||||
pui.setupUi(&d);
|
|
||||||
|
|
||||||
// Make the window big by default
|
|
||||||
auto ps = this->geometry();
|
|
||||||
QMargins margin = QMargins() + 50;
|
|
||||||
d.setGeometry(ps.marginsRemoved(margin));
|
|
||||||
|
|
||||||
Settings::saveRestore(&d);
|
|
||||||
|
|
||||||
pui.privKeyTxt->setPlainText(tr("Loading..."));
|
|
||||||
pui.privKeyTxt->setReadOnly(true);
|
|
||||||
pui.privKeyTxt->setLineWrapMode(QPlainTextEdit::LineWrapMode::NoWrap);
|
|
||||||
|
|
||||||
if (allKeys)
|
|
||||||
pui.helpLbl->setText(tr("These are all the private keys for all the addresses in your wallet"));
|
|
||||||
else
|
|
||||||
pui.helpLbl->setText(tr("Private key for ") + addr);
|
|
||||||
|
|
||||||
// Disable the save button until it finishes loading
|
|
||||||
pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
|
|
||||||
pui.buttonBox->button(QDialogButtonBox::Ok)->setVisible(false);
|
|
||||||
|
|
||||||
// Wire up save button
|
|
||||||
QObject::connect(pui.buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, [=] () {
|
|
||||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
|
|
||||||
allKeys ? "hush-all-privatekeys.txt" : "hush-privatekey.txt");
|
|
||||||
QFile file(fileName);
|
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
|
||||||
QMessageBox::information(this, tr("Unable to open file"), file.errorString());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QTextStream out(&file);
|
|
||||||
out << pui.privKeyTxt->toPlainText();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Call the API
|
|
||||||
auto isDialogAlive = std::make_shared<bool>(true);
|
|
||||||
|
|
||||||
auto fnUpdateUIWithKeys = [=](json reply) {
|
|
||||||
// Check to see if we are still showing.
|
|
||||||
if (! *(isDialogAlive.get()) ) return;
|
|
||||||
|
|
||||||
if (reply.is_discarded() || !reply.is_array()) {
|
if (reply.is_discarded() || !reply.is_array()) {
|
||||||
pui.privKeyTxt->setPlainText(tr("Error loading private keys"));
|
QMessageBox::critical(this, tr("Error getting private keys"),
|
||||||
pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
|
tr("Error loading private keys: ") + QString::fromStdString(reply.dump()),
|
||||||
|
QMessageBox::Ok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDialog d(this);
|
||||||
|
Ui_PrivKey pui;
|
||||||
|
pui.setupUi(&d);
|
||||||
|
|
||||||
|
// Make the window big by default
|
||||||
|
auto ps = this->geometry();
|
||||||
|
QMargins margin = QMargins() + 50;
|
||||||
|
d.setGeometry(ps.marginsRemoved(margin));
|
||||||
|
|
||||||
|
Settings::saveRestore(&d);
|
||||||
|
|
||||||
|
pui.privKeyTxt->setReadOnly(true);
|
||||||
|
pui.privKeyTxt->setLineWrapMode(QPlainTextEdit::LineWrapMode::NoWrap);
|
||||||
|
|
||||||
|
if (allKeys)
|
||||||
|
pui.helpLbl->setText(tr("These are all the private keys for all the addresses in your wallet"));
|
||||||
|
else
|
||||||
|
pui.helpLbl->setText(tr("Private key for ") + addr);
|
||||||
|
|
||||||
|
|
||||||
|
// Wire up save button
|
||||||
|
QObject::connect(pui.buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, [=] () {
|
||||||
|
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
|
||||||
|
allKeys ? "Hush-all-privatekeys.txt" : "Hush-privatekey.txt");
|
||||||
|
QFile file(fileName);
|
||||||
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
|
QMessageBox::information(this, tr("Unable to open file"), file.errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QTextStream out(&file);
|
||||||
|
out << pui.privKeyTxt->toPlainText();
|
||||||
|
});
|
||||||
|
|
||||||
QString allKeysTxt;
|
QString allKeysTxt;
|
||||||
for (auto i : reply.get<json::array_t>()) {
|
for (auto i : reply.get<json::array_t>()) {
|
||||||
allKeysTxt = allKeysTxt % QString::fromStdString(i["private_key"]) % " # addr=" % QString::fromStdString(i["address"]) % "\n";
|
allKeysTxt = allKeysTxt % QString::fromStdString(i["private_key"]) % " # addr=" % QString::fromStdString(i["address"]) % "\n";
|
||||||
@@ -725,6 +771,8 @@ void MainWindow::exportKeys(QString addr) {
|
|||||||
|
|
||||||
pui.privKeyTxt->setPlainText(allKeysTxt);
|
pui.privKeyTxt->setPlainText(allKeysTxt);
|
||||||
pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true);
|
pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true);
|
||||||
|
|
||||||
|
d.exec();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (allKeys) {
|
if (allKeys) {
|
||||||
@@ -733,9 +781,6 @@ void MainWindow::exportKeys(QString addr) {
|
|||||||
else {
|
else {
|
||||||
rpc->fetchPrivKey(addr, fnUpdateUIWithKeys);
|
rpc->fetchPrivKey(addr, fnUpdateUIWithKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
d.exec();
|
|
||||||
*isDialogAlive = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setupBalancesTab() {
|
void MainWindow::setupBalancesTab() {
|
||||||
@@ -743,40 +788,6 @@ void MainWindow::setupBalancesTab() {
|
|||||||
ui->lblSyncWarning->setVisible(false);
|
ui->lblSyncWarning->setVisible(false);
|
||||||
ui->lblSyncWarningReceive->setVisible(false);
|
ui->lblSyncWarningReceive->setVisible(false);
|
||||||
|
|
||||||
// Double click on balances table
|
|
||||||
auto fnDoSendFrom = [=](const QString& addr, const QString& to = QString(), bool sendMax = false) {
|
|
||||||
// Find the inputs combo
|
|
||||||
for (int i = 0; i < ui->inputsCombo->count(); i++) {
|
|
||||||
auto inputComboAddress = ui->inputsCombo->itemText(i);
|
|
||||||
if (inputComboAddress.startsWith(addr)) {
|
|
||||||
ui->inputsCombo->setCurrentIndex(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's a to address, add that as well
|
|
||||||
if (!to.isEmpty()) {
|
|
||||||
// Remember to clear any existing address fields, because we are creating a new transaction.
|
|
||||||
this->clearSendForm();
|
|
||||||
ui->Address1->setText(to);
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if max button has to be checked
|
|
||||||
if (sendMax) {
|
|
||||||
ui->Max1->setChecked(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// And switch to the send tab.
|
|
||||||
ui->tabWidget->setCurrentIndex(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Double click opens up memo if one exists
|
|
||||||
QObject::connect(ui->balancesTable, &QTableView::doubleClicked, [=](auto index) {
|
|
||||||
index = index.sibling(index.row(), 0);
|
|
||||||
auto addr = AddressBook::addressFromAddressLabel(ui->balancesTable->model()->data(index).toString());
|
|
||||||
|
|
||||||
fnDoSendFrom(addr);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Setup context menu on balances tab
|
// Setup context menu on balances tab
|
||||||
ui->balancesTable->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->balancesTable->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
@@ -800,18 +811,8 @@ void MainWindow::setupBalancesTab() {
|
|||||||
this->exportKeys(addr);
|
this->exportKeys(addr);
|
||||||
});
|
});
|
||||||
|
|
||||||
menu.addAction("Send from " % addr.left(40) % (addr.size() > 40 ? "..." : ""), [=]() {
|
|
||||||
fnDoSendFrom(addr);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (Settings::isTAddress(addr)) {
|
if (Settings::isTAddress(addr)) {
|
||||||
auto defaultSapling = rpc->getDefaultSaplingAddress();
|
|
||||||
if (!defaultSapling.isEmpty()) {
|
|
||||||
menu.addAction(tr("Shield balance to Sapling"), [=] () {
|
|
||||||
fnDoSendFrom(addr, defaultSapling, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.addAction(tr("View on block explorer"), [=] () {
|
menu.addAction(tr("View on block explorer"), [=] () {
|
||||||
Settings::openAddressInExplorer(addr);
|
Settings::openAddressInExplorer(addr);
|
||||||
});
|
});
|
||||||
@@ -1092,7 +1093,7 @@ void MainWindow::setupReceiveTab() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->rcvLabel->setText(label);
|
ui->rcvLabel->setText(label);
|
||||||
ui->rcvBal->setText(Settings::gethushUSDDisplayFormat(rpc->getModel()->getAllBalances().value(addr)));
|
ui->rcvBal->setText(rpc->getModel()->getAllBalances().value(addr).toDecimalhushUSDString());
|
||||||
ui->txtReceive->setPlainText(addr);
|
ui->txtReceive->setPlainText(addr);
|
||||||
ui->qrcodeDisplay->setQrcodeString(addr);
|
ui->qrcodeDisplay->setQrcodeString(addr);
|
||||||
if (rpc->getModel()->getUsedAddresses().value(addr, false)) {
|
if (rpc->getModel()->getUsedAddresses().value(addr, false)) {
|
||||||
@@ -1183,7 +1184,7 @@ void MainWindow::updateTAddrCombo(bool checked) {
|
|||||||
// If the address is in the address book, add it.
|
// If the address is in the address book, add it.
|
||||||
if (labels.contains(taddr) && !addrs.contains(taddr)) {
|
if (labels.contains(taddr) && !addrs.contains(taddr)) {
|
||||||
addrs.insert(taddr);
|
addrs.insert(taddr);
|
||||||
ui->listReceiveAddresses->addItem(taddr, 0);
|
ui->listReceiveAddresses->addItem(taddr, CAmount::fromqint64(0));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1194,7 +1195,7 @@ void MainWindow::updateTAddrCombo(bool checked) {
|
|||||||
if (!addrs.contains(addr)) {
|
if (!addrs.contains(addr)) {
|
||||||
addrs.insert(addr);
|
addrs.insert(addr);
|
||||||
// Balance is zero since it has not been previously added
|
// Balance is zero since it has not been previously added
|
||||||
ui->listReceiveAddresses->addItem(addr, 0);
|
ui->listReceiveAddresses->addItem(addr, CAmount::fromqint64(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1211,7 +1212,7 @@ void MainWindow::updateTAddrCombo(bool checked) {
|
|||||||
// 5. Add a last, disabled item if there are remaining items
|
// 5. Add a last, disabled item if there are remaining items
|
||||||
if (allTaddrs.size() > addrs.size()) {
|
if (allTaddrs.size() > addrs.size()) {
|
||||||
auto num = QString::number(allTaddrs.size() - addrs.size());
|
auto num = QString::number(allTaddrs.size() - addrs.size());
|
||||||
ui->listReceiveAddresses->addItem("-- " + num + " more --", 0);
|
ui->listReceiveAddresses->addItem("-- " + num + " more --", CAmount::fromqint64(0));
|
||||||
|
|
||||||
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(ui->listReceiveAddresses->model());
|
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(ui->listReceiveAddresses->model());
|
||||||
QStandardItem* item = model->findItems("--", Qt::MatchStartsWith)[0];
|
QStandardItem* item = model->findItems("--", Qt::MatchStartsWith)[0];
|
||||||
@@ -1230,9 +1231,6 @@ void MainWindow::updateLabels() {
|
|||||||
addZAddrsToComboList(ui->rdioZSAddr->isChecked())(true);
|
addZAddrsToComboList(ui->rdioZSAddr->isChecked())(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the Send Tab
|
|
||||||
updateFromCombo();
|
|
||||||
|
|
||||||
// Update the autocomplete
|
// Update the autocomplete
|
||||||
updateLabelsAutoComplete();
|
updateLabelsAutoComplete();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ using json = nlohmann::json;
|
|||||||
// Struct used to hold destination info when sending a Tx.
|
// Struct used to hold destination info when sending a Tx.
|
||||||
struct ToFields {
|
struct ToFields {
|
||||||
QString addr;
|
QString addr;
|
||||||
double amount;
|
CAmount amount;
|
||||||
QString memo;
|
QString memo;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ struct ToFields {
|
|||||||
struct Tx {
|
struct Tx {
|
||||||
QString fromAddr;
|
QString fromAddr;
|
||||||
QList<ToFields> toAddrs;
|
QList<ToFields> toAddrs;
|
||||||
double fee;
|
CAmount fee;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@@ -47,7 +47,6 @@ public:
|
|||||||
QRegExpValidator* getAmountValidator() { return amtValidator; }
|
QRegExpValidator* getAmountValidator() { return amtValidator; }
|
||||||
|
|
||||||
QString doSendTxValidations(Tx tx);
|
QString doSendTxValidations(Tx tx);
|
||||||
void setDefaultPayFrom();
|
|
||||||
|
|
||||||
void replaceWormholeClient(WormholeClient* newClient);
|
void replaceWormholeClient(WormholeClient* newClient);
|
||||||
bool isWebsocketListening();
|
bool isWebsocketListening();
|
||||||
@@ -59,7 +58,6 @@ public:
|
|||||||
|
|
||||||
void updateLabels();
|
void updateLabels();
|
||||||
void updateTAddrCombo(bool checked);
|
void updateTAddrCombo(bool checked);
|
||||||
void updateFromCombo();
|
|
||||||
|
|
||||||
// Disable recurring on mainnet
|
// Disable recurring on mainnet
|
||||||
void disableRecurring();
|
void disableRecurring();
|
||||||
@@ -98,9 +96,11 @@ private:
|
|||||||
Tx createTxFromSendPage();
|
Tx createTxFromSendPage();
|
||||||
bool confirmTx(Tx tx, RecurringPaymentInfo* rpi);
|
bool confirmTx(Tx tx, RecurringPaymentInfo* rpi);
|
||||||
|
|
||||||
|
void encryptWallet();
|
||||||
|
void removeWalletEncryption();
|
||||||
|
|
||||||
void cancelButton();
|
void cancelButton();
|
||||||
void sendButton();
|
void sendButton();
|
||||||
void inputComboTextChanged(int index);
|
|
||||||
void addAddressSection();
|
void addAddressSection();
|
||||||
void maxAmountChecked(int checked);
|
void maxAmountChecked(int checked);
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ private:
|
|||||||
void importPrivKey();
|
void importPrivKey();
|
||||||
void exportAllKeys();
|
void exportAllKeys();
|
||||||
void exportKeys(QString addr = "");
|
void exportKeys(QString addr = "");
|
||||||
void backupWalletDat();
|
void exportSeed();
|
||||||
void exportTransactions();
|
void exportTransactions();
|
||||||
|
|
||||||
void doImport(QList<QString>* keys);
|
void doImport(QList<QString>* keys);
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>968</width>
|
<width>1274</width>
|
||||||
<height>616</height>
|
<height>779</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>4</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="tab">
|
<widget class="QWidget" name="tab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
@@ -75,6 +75,37 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_17">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_15">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Notarized</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="balVerified">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
@@ -148,26 +179,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="lblSyncWarning">
|
<widget class="QLabel" name="lblSyncWarning">
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">color:red;</string>
|
<string notr="true">color:red;</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Your node is still syncing, balances may not be updated</string>
|
<string>Your node is still syncing, balances may not be updated.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@@ -186,10 +204,26 @@
|
|||||||
<string notr="true">color: red;</string>
|
<string notr="true">color: red;</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Some transactions are not yet confirmed</string>
|
<string>Some transactions are not yet confirmed. Balances may change.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@@ -262,65 +296,64 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>From</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="flat">
|
<property name="flat">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
<spacer name="horizontalSpacer_6">
|
||||||
<item>
|
<property name="orientation">
|
||||||
<widget class="AddressCombo" name="inputsCombo"/>
|
<enum>Qt::Horizontal</enum>
|
||||||
</item>
|
</property>
|
||||||
</layout>
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
<widget class="QLabel" name="label_5">
|
||||||
<item>
|
<property name="font">
|
||||||
<widget class="QLabel" name="label_5">
|
<font>
|
||||||
<property name="text">
|
<weight>75</weight>
|
||||||
<string>Address Balance</string>
|
<bold>true</bold>
|
||||||
</property>
|
</font>
|
||||||
</widget>
|
</property>
|
||||||
</item>
|
<property name="text">
|
||||||
<item>
|
<string>Total notarized funds available:</string>
|
||||||
<widget class="QLineEdit" name="sendAddressBalance">
|
</property>
|
||||||
<property name="sizePolicy">
|
</widget>
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
</item>
|
||||||
<horstretch>0</horstretch>
|
<item>
|
||||||
<verstretch>0</verstretch>
|
<widget class="QLabel" name="txtAvailablehush">
|
||||||
</sizepolicy>
|
<property name="text">
|
||||||
</property>
|
<string/>
|
||||||
<property name="alignment">
|
</property>
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
</widget>
|
||||||
</property>
|
</item>
|
||||||
<property name="readOnly">
|
<item>
|
||||||
<bool>true</bool>
|
<widget class="QLabel" name="txtAvailableUSD">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string/>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
</widget>
|
||||||
<widget class="QLabel" name="sendAddressBalanceUSD">
|
</item>
|
||||||
<property name="text">
|
<item>
|
||||||
<string/>
|
<spacer name="horizontalSpacer_8">
|
||||||
</property>
|
<property name="orientation">
|
||||||
</widget>
|
<enum>Qt::Horizontal</enum>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
<property name="sizeHint" stdset="0">
|
||||||
<spacer name="horizontalSpacer_6">
|
<size>
|
||||||
<property name="orientation">
|
<width>40</width>
|
||||||
<enum>Qt::Horizontal</enum>
|
<height>20</height>
|
||||||
</property>
|
</size>
|
||||||
<property name="sizeHint" stdset="0">
|
</property>
|
||||||
<size>
|
</spacer>
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -359,8 +392,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>920</width>
|
<width>1226</width>
|
||||||
<height>301</height>
|
<height>504</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="sendToLayout">
|
<layout class="QVBoxLayout" name="sendToLayout">
|
||||||
@@ -899,6 +932,9 @@
|
|||||||
<property name="selectionBehavior">
|
<property name="selectionBehavior">
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<attribute name="horizontalHeaderStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@@ -1051,7 +1087,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>968</width>
|
<width>1274</width>
|
||||||
<height>22</height>
|
<height>22</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -1063,7 +1099,7 @@
|
|||||||
<addaction name="actionPay_URI"/>
|
<addaction name="actionPay_URI"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExport_All_Private_Keys"/>
|
<addaction name="actionExport_All_Private_Keys"/>
|
||||||
<addaction name="actionBackup_wallet_dat"/>
|
<addaction name="actionExport_Seed"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExport_transactions"/>
|
<addaction name="actionExport_transactions"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
@@ -1093,6 +1129,9 @@
|
|||||||
<addaction name="action_Address_Book"/>
|
<addaction name="action_Address_Book"/>
|
||||||
<addaction name="actionSettings"/>
|
<addaction name="actionSettings"/>
|
||||||
<addaction name="action_Recurring_Payments"/>
|
<addaction name="action_Recurring_Payments"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionEncrypt_Wallet"/>
|
||||||
|
<addaction name="actionRemove_Wallet_Encryption"/>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
<addaction name="menu_Edit"/>
|
<addaction name="menu_Edit"/>
|
||||||
@@ -1120,7 +1159,7 @@
|
|||||||
</action>
|
</action>
|
||||||
<action name="actionDonate">
|
<action name="actionDonate">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Send Duke Feedback</string>
|
<string>&Send DenioD Feedback</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDiscord">
|
<action name="actionDiscord">
|
||||||
@@ -1151,9 +1190,9 @@
|
|||||||
<string>Ctrl+B</string>
|
<string>Ctrl+B</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionBackup_wallet_dat">
|
<action name="actionExport_Seed">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Backup wallet.dat</string>
|
<string>&Export seed phrase</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionExport_transactions">
|
<action name="actionExport_transactions">
|
||||||
@@ -1189,6 +1228,16 @@
|
|||||||
<string>File a bug...</string>
|
<string>File a bug...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionEncrypt_Wallet">
|
||||||
|
<property name="text">
|
||||||
|
<string>Encrypt Wallet</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRemove_Wallet_Encryption">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove Wallet Encryption</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
@@ -1210,7 +1259,6 @@
|
|||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>tabWidget</tabstop>
|
<tabstop>tabWidget</tabstop>
|
||||||
<tabstop>inputsCombo</tabstop>
|
|
||||||
<tabstop>Address1</tabstop>
|
<tabstop>Address1</tabstop>
|
||||||
<tabstop>Amount1</tabstop>
|
<tabstop>Amount1</tabstop>
|
||||||
<tabstop>Max1</tabstop>
|
<tabstop>Max1</tabstop>
|
||||||
@@ -1229,7 +1277,6 @@
|
|||||||
<tabstop>transactionsTable</tabstop>
|
<tabstop>transactionsTable</tabstop>
|
||||||
<tabstop>balancesTable</tabstop>
|
<tabstop>balancesTable</tabstop>
|
||||||
<tabstop>minerFeeAmt</tabstop>
|
<tabstop>minerFeeAmt</tabstop>
|
||||||
<tabstop>sendAddressBalance</tabstop>
|
|
||||||
<tabstop>sendToScrollArea</tabstop>
|
<tabstop>sendToScrollArea</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons">
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok|QDialogButtonBox::Save</set>
|
<set>QDialogButtonBox::Close|QDialogButtonBox::Save</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "camount.h"
|
||||||
#include "ui_newrecurring.h"
|
#include "ui_newrecurring.h"
|
||||||
#include "ui_recurringdialog.h"
|
#include "ui_recurringdialog.h"
|
||||||
#include "ui_recurringpayments.h"
|
#include "ui_recurringpayments.h"
|
||||||
@@ -69,7 +70,7 @@ QJsonObject RecurringPaymentInfo::toJson() {
|
|||||||
{"desc", desc},
|
{"desc", desc},
|
||||||
{"from", fromAddr},
|
{"from", fromAddr},
|
||||||
{"to", toAddr},
|
{"to", toAddr},
|
||||||
{"amt", Settings::getDecimalString(amt)},
|
{"amt", amt},
|
||||||
{"memo", memo},
|
{"memo", memo},
|
||||||
{"currency", currency},
|
{"currency", currency},
|
||||||
{"schedule", (int)schedule},
|
{"schedule", (int)schedule},
|
||||||
@@ -81,7 +82,8 @@ QJsonObject RecurringPaymentInfo::toJson() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString RecurringPaymentInfo::getAmountPretty() const {
|
QString RecurringPaymentInfo::getAmountPretty() const {
|
||||||
return currency == "USD" ? Settings::getUSDFormat(amt) : Settings::gethushDisplayFormat(amt);
|
CAmount amount = CAmount::fromDouble(amt);
|
||||||
|
return currency == "USD" ? amount.toDecimalUSDString() : amount.toDecimalhushString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RecurringPaymentInfo::getScheduleDescription() const {
|
QString RecurringPaymentInfo::getScheduleDescription() const {
|
||||||
@@ -135,7 +137,7 @@ RecurringPaymentInfo* Recurring::getNewRecurringFromTx(QWidget* parent, MainWind
|
|||||||
ui.lblTo->setText(tx.toAddrs[0].addr);
|
ui.lblTo->setText(tx.toAddrs[0].addr);
|
||||||
|
|
||||||
// Default is USD
|
// Default is USD
|
||||||
ui.lblAmt->setText(Settings::getUSDFormat(tx.toAddrs[0].amount));
|
ui.lblAmt->setText(tx.toAddrs[0].amount.toDecimalUSDString());
|
||||||
|
|
||||||
ui.txtMemo->setPlainText(tx.toAddrs[0].memo);
|
ui.txtMemo->setPlainText(tx.toAddrs[0].memo);
|
||||||
ui.txtMemo->setEnabled(false);
|
ui.txtMemo->setEnabled(false);
|
||||||
@@ -147,10 +149,10 @@ RecurringPaymentInfo* Recurring::getNewRecurringFromTx(QWidget* parent, MainWind
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (c == "USD") {
|
if (c == "USD") {
|
||||||
ui.lblAmt->setText(Settings::getUSDFormat(tx.toAddrs[0].amount));
|
ui.lblAmt->setText(tx.toAddrs[0].amount.toDecimalUSDString());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui.lblAmt->setText(Settings::getDecimalString(tx.toAddrs[0].amount));
|
ui.lblAmt->setText(tx.toAddrs[0].amount.toDecimalString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -201,13 +203,13 @@ void Recurring::updateInfoWithTx(RecurringPaymentInfo* r, Tx tx) {
|
|||||||
r->toAddr = tx.toAddrs[0].addr;
|
r->toAddr = tx.toAddrs[0].addr;
|
||||||
r->memo = tx.toAddrs[0].memo;
|
r->memo = tx.toAddrs[0].memo;
|
||||||
r->fromAddr = tx.fromAddr;
|
r->fromAddr = tx.fromAddr;
|
||||||
if (r->currency.isEmpty() || r->currency == "usd") {
|
if (r->currency.isEmpty() || r->currency == "USD") {
|
||||||
r->currency = "usd";
|
r->currency = "USD";
|
||||||
r->amt = tx.toAddrs[0].amount * Settings::getInstance()->gethushPrice();
|
r->amt = tx.toAddrs[0].amount.toqint64() * Settings::getInstance()->getZECPrice();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
r->currency = Settings::getTokenName();
|
r->currency = Settings::getTokenName();
|
||||||
r->amt = tx.toAddrs[0].amount;
|
r->amt = tx.toAddrs[0].amount.toqint64();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that the number of payments is properly listed in the array
|
// Make sure that the number of payments is properly listed in the array
|
||||||
@@ -459,11 +461,11 @@ void Recurring::processMultiplePending(RecurringPaymentInfo rpi, MainWindow* mai
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo rpi, QList<int> paymentNumbers) {
|
void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo rpi, QList<int> paymentNumbers) {
|
||||||
// Amount is in USD or hush?
|
// Amount is in USD or Hush?
|
||||||
auto amt = rpi.amt;
|
double amount = rpi.amt;
|
||||||
if (rpi.currency == "usd") {
|
if (rpi.currency == "USD") {
|
||||||
// If there is no price, then fail the payment
|
// If there is no price, then fail the payment
|
||||||
if (Settings::getInstance()->gethushPrice() == 0) {
|
if (Settings::getInstance()->getZECPrice() == 0) {
|
||||||
for (auto paymentNumber: paymentNumbers) {
|
for (auto paymentNumber: paymentNumbers) {
|
||||||
updatePaymentItem(rpi.getHash(), paymentNumber,
|
updatePaymentItem(rpi.getHash(), paymentNumber,
|
||||||
"", QObject::tr("No hush price was available to convert from USD"),
|
"", QObject::tr("No hush price was available to convert from USD"),
|
||||||
@@ -473,7 +475,7 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Translate it into hush
|
// Translate it into hush
|
||||||
amt = rpi.amt / Settings::getInstance()->gethushPrice();
|
amount = rpi.amt / Settings::getInstance()->getZECPrice();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a Tx
|
// Build a Tx
|
||||||
@@ -483,9 +485,9 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r
|
|||||||
|
|
||||||
// If this is a multiple payment, we'll add up all the amounts
|
// If this is a multiple payment, we'll add up all the amounts
|
||||||
if (paymentNumbers.size() > 1)
|
if (paymentNumbers.size() > 1)
|
||||||
amt *= paymentNumbers.size();
|
amount *= paymentNumbers.size();
|
||||||
|
|
||||||
tx.toAddrs.append(ToFields { rpi.toAddr, amt, rpi.memo });
|
tx.toAddrs.append(ToFields { rpi.toAddr, CAmount::fromDouble(amount), rpi.memo });
|
||||||
|
|
||||||
// To prevent some weird race conditions, we immediately mark the payment as paid.
|
// To prevent some weird race conditions, we immediately mark the payment as paid.
|
||||||
// If something goes wrong, we'll get the error callback below, and the status will be
|
// If something goes wrong, we'll get the error callback below, and the status will be
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ void RequestDialog::showPaymentConfirmation(MainWindow* main, QString paymentURI
|
|||||||
req.txtFrom->setText(payInfo.addr);
|
req.txtFrom->setText(payInfo.addr);
|
||||||
req.txtMemo->setPlainText(payInfo.memo);
|
req.txtMemo->setPlainText(payInfo.memo);
|
||||||
req.txtAmount->setText(payInfo.amt);
|
req.txtAmount->setText(payInfo.amt);
|
||||||
req.txtAmountUSD->setText(Settings::getUSDFormat(req.txtAmount->text().toDouble()));
|
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
|
||||||
|
req.txtAmountUSD->setText(amount.toDecimalUSDString());
|
||||||
|
|
||||||
req.buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Pay"));
|
req.buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Pay"));
|
||||||
|
|
||||||
@@ -112,9 +113,11 @@ void RequestDialog::showRequesthush(MainWindow* main) {
|
|||||||
// Amount textbox
|
// Amount textbox
|
||||||
req.txtAmount->setValidator(main->getAmountValidator());
|
req.txtAmount->setValidator(main->getAmountValidator());
|
||||||
QObject::connect(req.txtAmount, &QLineEdit::textChanged, [=] (auto text) {
|
QObject::connect(req.txtAmount, &QLineEdit::textChanged, [=] (auto text) {
|
||||||
req.txtAmountUSD->setText(Settings::getUSDFormat(text.toDouble()));
|
CAmount amount = CAmount::fromDecimalString(text);
|
||||||
|
req.txtAmountUSD->setText(amount.toDecimalUSDString());
|
||||||
});
|
});
|
||||||
req.txtAmountUSD->setText(Settings::getUSDFormat(req.txtAmount->text().toDouble()));
|
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
|
||||||
|
req.txtAmountUSD->setText(amount.toDecimalUSDString());
|
||||||
|
|
||||||
req.txtMemo->setAcceptButton(req.buttonBox->button(QDialogButtonBox::Ok));
|
req.txtMemo->setAcceptButton(req.buttonBox->button(QDialogButtonBox::Ok));
|
||||||
req.txtMemo->setLenDisplayLabel(req.lblMemoLen);
|
req.txtMemo->setLenDisplayLabel(req.lblMemoLen);
|
||||||
@@ -124,8 +127,9 @@ void RequestDialog::showRequesthush(MainWindow* main) {
|
|||||||
|
|
||||||
if (d.exec() == QDialog::Accepted) {
|
if (d.exec() == QDialog::Accepted) {
|
||||||
// Construct a hush Payment URI with the data and pay it immediately.
|
// Construct a hush Payment URI with the data and pay it immediately.
|
||||||
|
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
|
||||||
QString memoURI = "hush:" + req.cmbMyAddress->currentText()
|
QString memoURI = "hush:" + req.cmbMyAddress->currentText()
|
||||||
+ "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble())
|
+ "?amt=" + amount.toDecimalString()
|
||||||
+ "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
|
+ "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
|
||||||
|
|
||||||
QString sendURI = "hush:" + AddressBook::addressFromAddressLabel(req.txtFrom->text())
|
QString sendURI = "hush:" + AddressBook::addressFromAddressLabel(req.txtFrom->text())
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=silentdragon
|
Name=SilentDragonLite
|
||||||
Comment=Full node and wallet for hush
|
Comment=Lightclient UI wallet for Hush
|
||||||
GenericName=Wallet
|
GenericName=Wallet
|
||||||
Exec=/usr/local/bin/silentdragon %u
|
Exec=/usr/local/bin/silentdragonlite %u
|
||||||
Icon=silentdragon.xpm
|
Icon=silentdragonlite.xpm
|
||||||
Type=Application
|
Type=Application
|
||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
StartupWMClass=silentdragon
|
StartupWMClass=silentdragonlite
|
||||||
Categories=Utility;
|
Categories=Utility;
|
||||||
MimeType=x-scheme-handler/hush;
|
MimeType=x-scheme-handler/hush;
|
||||||
Keywords=silentdragon;
|
Keywords=silentdragonlite;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ if [ -z $QT_STATIC ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f res/*.qm
|
rm -f res/*.qm
|
||||||
$QT_STATIC/bin/lrelease silentdragonlite.pro
|
$QT_STATIC/bin/lrelease silentdragon-lite.pro
|
||||||
|
|
||||||
# Then update the qt base translations. First, get all languages
|
# Then update the qt base translations. First, get all languages
|
||||||
ls res/*.qm | awk -F '[_.]' '{print $4}' | while read -r language ; do
|
ls res/*.qm | awk -F '[_.]' '{print $4}' | while read -r language ; do
|
||||||
|
|||||||
@@ -35,21 +35,11 @@ if [ -z $QT_PATH ]; then
|
|||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z $hush_DIR ]; then
|
|
||||||
echo "hush_DIR is not set. Please set it to the base directory of a compiled hushd";
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z $APP_VERSION ]; then
|
if [ -z $APP_VERSION ]; then
|
||||||
echo "APP_VERSION is not set. Please set it to the current release version of the app";
|
echo "APP_VERSION is not set. Please set it to the current release version of the app";
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f $hush_DIR/src/hushd ]; then
|
|
||||||
echo "Could not find compiled hushd in $hush_DIR/src/.";
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! cat src/version.h | grep -q "$APP_VERSION"; then
|
if ! cat src/version.h | grep -q "$APP_VERSION"; then
|
||||||
echo "Version mismatch in src/version.h"
|
echo "Version mismatch in src/version.h"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -60,14 +50,14 @@ export PATH=$PATH:/usr/local/bin
|
|||||||
#Clean
|
#Clean
|
||||||
echo -n "Cleaning..............."
|
echo -n "Cleaning..............."
|
||||||
make distclean >/dev/null 2>&1
|
make distclean >/dev/null 2>&1
|
||||||
rm -f artifacts/macOS-silentdragon-v$APP_VERSION.dmg
|
rm -f artifacts/macOS-silentdragonlite-v$APP_VERSION.dmg
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Configuring............"
|
echo -n "Configuring............"
|
||||||
# Build
|
# Build
|
||||||
QT_STATIC=$QT_PATH src/scripts/dotranslations.sh >/dev/null
|
QT_STATIC=$QT_PATH src/scripts/dotranslations.sh >/dev/null
|
||||||
$QT_PATH/bin/qmake silentdragonlite.pro CONFIG+=release >/dev/null
|
$QT_PATH/bin/qmake silentdragon-lite.pro CONFIG+=release >/dev/null
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
@@ -78,27 +68,17 @@ echo "[OK]"
|
|||||||
#Qt deploy
|
#Qt deploy
|
||||||
echo -n "Deploying.............."
|
echo -n "Deploying.............."
|
||||||
mkdir artifacts >/dev/null 2>&1
|
mkdir artifacts >/dev/null 2>&1
|
||||||
rm -f artifcats/silentdragon.dmg >/dev/null 2>&1
|
rm -f artifcats/Silentdragonlite.dmg >/dev/null 2>&1
|
||||||
rm -f artifacts/rw* >/dev/null 2>&1
|
rm -f artifacts/rw* >/dev/null 2>&1
|
||||||
cp $hush_DIR/src/hushd silentdragon.app/Contents/MacOS/
|
$QT_PATH/bin/macdeployqt Silentdragonlite.app
|
||||||
cp $hush_DIR/src/hush-cli silentdragon.app/Contents/MacOS/
|
|
||||||
$QT_PATH/bin/macdeployqt silentdragon.app
|
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Building dmg..........."
|
echo -n "Building dmg..........."
|
||||||
mv silentdragon.app silentdragon.app
|
mv silentdragonlite.app Silentdragonlite.app
|
||||||
create-dmg --volname "silentdragon-v$APP_VERSION" --volicon "res/logo.icns" --window-pos 200 120 --icon "silentdragon.app" 200 190 --app-drop-link 600 185 --hide-extension "silentdragon.app" --window-size 800 400 --hdiutil-quiet --background res/dmgbg.png artifacts/macOS-silentdragon-v$APP_VERSION.dmg silentdragon.app >/dev/null 2>&1
|
create-dmg --volname "SilentDragonLite-v$APP_VERSION" --volicon "res/logo.icns" --window-pos 200 120 --icon "SilentDragonLite.app" 200 190 --app-drop-link 600 185 --hide-extension "SilentDragonLite.app" --window-size 800 400 --hdiutil-quiet --background res/dmgbg.png artifacts/macOS-SilentDragonLite-v$APP_VERSION.dmg SilentDragonLite.app >/dev/null 2>&1
|
||||||
|
|
||||||
#mkdir bin/dmgbuild >/dev/null 2>&1
|
if [ ! -f artifacts/macOS-SilentDragonLite-v$APP_VERSION.dmg ]; then
|
||||||
#sed "s/RELEASE_VERSION/${APP_VERSION}/g" res/appdmg.json > bin/dmgbuild/appdmg.json
|
|
||||||
#cp res/logo.icns bin/dmgbuild/
|
|
||||||
#cp res/dmgbg.png bin/dmgbuild/
|
|
||||||
|
|
||||||
#cp -r silentdragon.app bin/dmgbuild/
|
|
||||||
|
|
||||||
#appdmg --quiet bin/dmgbuild/appdmg.json artifacts/macOS-silentdragon-v$APP_VERSION.dmg >/dev/null
|
|
||||||
if [ ! -f artifacts/macOS-silentdragon-v$APP_VERSION.dmg ]; then
|
|
||||||
echo "[ERROR]"
|
echo "[ERROR]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -7,43 +7,9 @@ fi
|
|||||||
if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi
|
if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi
|
||||||
if [ -z $PREV_VERSION ]; then echo "PREV_VERSION is not set"; exit 1; fi
|
if [ -z $PREV_VERSION ]; then echo "PREV_VERSION is not set"; exit 1; fi
|
||||||
|
|
||||||
if [ -z $hush_DIR ]; then
|
|
||||||
echo "hush_DIR is not set. Please set it to the base directory of a hush project with built hush binaries."
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f $hush_DIR/artifacts/hushd ]; then
|
|
||||||
echo "Couldn't find hushd in $hush_DIR/artifacts/. Please build hushd."
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f $hush_DIR/artifacts/hush-cli ]; then
|
|
||||||
echo "Couldn't find hush-cli in $hush_DIR/artifacts/. Please build hushd."
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure that hushd is the right build
|
|
||||||
echo -n "hushd version........."
|
|
||||||
if grep -q "zqwMagicBean" $hush_DIR/artifacts/hushd && ! readelf -s $hush_DIR/artifacts/hushd | grep -q "GLIBC_2\.25"; then
|
|
||||||
echo "[OK]"
|
|
||||||
else
|
|
||||||
echo "[ERROR]"
|
|
||||||
echo "hushd doesn't seem to be a zqwMagicBean build or hushd is built with libc 2.25"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -n "hushd.exe version....."
|
|
||||||
if grep -q "zqwMagicBean" $hush_DIR/artifacts/hushd.exe; then
|
|
||||||
echo "[OK]"
|
|
||||||
else
|
|
||||||
echo "[ERROR]"
|
|
||||||
echo "hushd doesn't seem to be a zqwMagicBean build"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -n "Version files.........."
|
echo -n "Version files.........."
|
||||||
# Replace the version number in the .pro file so it gets picked up everywhere
|
# Replace the version number in the .pro file so it gets picked up everywhere
|
||||||
sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" silentdragonlite.pro > /dev/null
|
sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" silentdragon-lite.pro > /dev/null
|
||||||
|
|
||||||
# Also update it in the README.md
|
# Also update it in the README.md
|
||||||
sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" README.md > /dev/null
|
sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" README.md > /dev/null
|
||||||
@@ -60,21 +26,21 @@ echo "[Building on" `lsb_release -r`"]"
|
|||||||
|
|
||||||
echo -n "Configuring............"
|
echo -n "Configuring............"
|
||||||
QT_STATIC=$QT_STATIC bash src/scripts/dotranslations.sh >/dev/null
|
QT_STATIC=$QT_STATIC bash src/scripts/dotranslations.sh >/dev/null
|
||||||
$QT_STATIC/bin/qmake silentdragonlite.pro -spec linux-clang CONFIG+=release > /dev/null
|
$QT_STATIC/bin/qmake silentdragon-lite.pro -spec linux-clang CONFIG+=release > /dev/null
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Building..............."
|
echo -n "Building..............."
|
||||||
rm -rf bin/silentdragonlite* > /dev/null
|
rm -rf bin/silentdragonlite* > /dev/null
|
||||||
rm -rf bin/silentdragon* > /dev/null
|
# Build the lib first
|
||||||
make clean > /dev/null
|
cd lib && make release && cd ..
|
||||||
make -j$(nproc) > /dev/null
|
make -j$(nproc) > /dev/null
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
# Test for Qt
|
# Test for Qt
|
||||||
echo -n "Static link............"
|
echo -n "Static link............"
|
||||||
if [[ $(ldd silentdragon | grep -i "Qt") ]]; then
|
if [[ $(ldd silentdragonlite | grep -i "Qt") ]]; then
|
||||||
echo "FOUND QT; ABORT";
|
echo "FOUND QT; ABORT";
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -82,27 +48,25 @@ echo "[OK]"
|
|||||||
|
|
||||||
|
|
||||||
echo -n "Packaging.............."
|
echo -n "Packaging.............."
|
||||||
mkdir bin/silentdragon-v$APP_VERSION > /dev/null
|
mkdir bin/silentdragonlite-v$APP_VERSION > /dev/null
|
||||||
strip silentdragon
|
strip silentdragonlite
|
||||||
|
|
||||||
cp silentdragon bin/silentdragon-v$APP_VERSION > /dev/null
|
cp silentdragonlite bin/silentdragonlite-v$APP_VERSION > /dev/null
|
||||||
cp $hush_DIR/artifacts/hushd bin/silentdragon-v$APP_VERSION > /dev/null
|
cp README.md bin/silentdragonlite-v$APP_VERSION > /dev/null
|
||||||
cp $hush_DIR/artifacts/hush-cli bin/silentdragon-v$APP_VERSION > /dev/null
|
cp LICENSE bin/silentdragonlite-v$APP_VERSION > /dev/null
|
||||||
cp README.md bin/silentdragon-v$APP_VERSION > /dev/null
|
|
||||||
cp LICENSE bin/silentdragon-v$APP_VERSION > /dev/null
|
|
||||||
|
|
||||||
cd bin && tar czf linux-silentdragon-v$APP_VERSION.tar.gz silentdragon-v$APP_VERSION/ > /dev/null
|
cd bin && tar czf linux-silentdragonlite-v$APP_VERSION.tar.gz silentdragonlite-v$APP_VERSION/ > /dev/null
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
mkdir artifacts >/dev/null 2>&1
|
mkdir artifacts >/dev/null 2>&1
|
||||||
cp bin/linux-silentdragon-v$APP_VERSION.tar.gz ./artifacts/linux-binaries-silentdragon-v$APP_VERSION.tar.gz
|
cp bin/linux-silentdragonlite-v$APP_VERSION.tar.gz ./artifacts/linux-binaries-silentdragonlite-v$APP_VERSION.tar.gz
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
if [ -f artifacts/linux-binaries-silentdragon-v$APP_VERSION.tar.gz ] ; then
|
if [ -f artifacts/linux-binaries-silentdragonlite-v$APP_VERSION.tar.gz ] ; then
|
||||||
echo -n "Package contents......."
|
echo -n "Package contents......."
|
||||||
# Test if the package is built OK
|
# Test if the package is built OK
|
||||||
if tar tf "artifacts/linux-binaries-silentdragon-v$APP_VERSION.tar.gz" | wc -l | grep -q "6"; then
|
if tar tf "artifacts/linux-binaries-silentdragonlite-v$APP_VERSION.tar.gz" | wc -l | grep -q "4"; then
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
else
|
else
|
||||||
echo "[ERROR]"
|
echo "[ERROR]"
|
||||||
@@ -114,24 +78,23 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo -n "Building deb..........."
|
echo -n "Building deb..........."
|
||||||
debdir=bin/deb/silentdragon-v$APP_VERSION
|
debdir=bin/deb/silentdragonlite-v$APP_VERSION
|
||||||
mkdir -p $debdir > /dev/null
|
mkdir -p $debdir > /dev/null
|
||||||
mkdir $debdir/DEBIAN
|
mkdir $debdir/DEBIAN
|
||||||
mkdir -p $debdir/usr/local/bin
|
mkdir -p $debdir/usr/local/bin
|
||||||
|
|
||||||
cat src/scripts/control | sed "s/RELEASE_VERSION/$APP_VERSION/g" > $debdir/DEBIAN/control
|
cat src/scripts/control | sed "s/RELEASE_VERSION/$APP_VERSION/g" > $debdir/DEBIAN/control
|
||||||
|
|
||||||
cp silentdragon $debdir/usr/local/bin/
|
cp silentdragonlite $debdir/usr/local/bin/
|
||||||
cp $hush_DIR/artifacts/hushd $debdir/usr/local/bin/zqw-hushd
|
|
||||||
|
|
||||||
mkdir -p $debdir/usr/share/pixmaps/
|
mkdir -p $debdir/usr/share/pixmaps/
|
||||||
cp res/silentdragon.xpm $debdir/usr/share/pixmaps/
|
cp res/silentdragonlite.xpm $debdir/usr/share/pixmaps/
|
||||||
|
|
||||||
mkdir -p $debdir/usr/share/applications
|
mkdir -p $debdir/usr/share/applications
|
||||||
cp src/scripts/desktopentry $debdir/usr/share/applications/silentdragonlite.desktop
|
cp src/scripts/desktopentry $debdir/usr/share/applications/silentdragonlite.desktop
|
||||||
|
|
||||||
dpkg-deb --build $debdir >/dev/null
|
dpkg-deb --build $debdir >/dev/null
|
||||||
cp $debdir.deb artifacts/linux-deb-silentdragon-v$APP_VERSION.deb
|
cp $debdir.deb artifacts/linux-deb-silentdragonlite-v$APP_VERSION.deb
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
@@ -145,51 +108,40 @@ if [ -z $MXE_PATH ]; then
|
|||||||
exit 0;
|
exit 0;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f $hush_DIR/artifacts/hushd.exe ]; then
|
|
||||||
echo "Couldn't find hushd.exe in $hush_DIR/artifacts/. Please build hushd.exe"
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ ! -f $hush_DIR/artifacts/hush-cli.exe ]; then
|
|
||||||
echo "Couldn't find hush-cli.exe in $hush_DIR/artifacts/. Please build hushd.exe"
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
export PATH=$MXE_PATH:$PATH
|
export PATH=$MXE_PATH:$PATH
|
||||||
|
|
||||||
echo -n "Configuring............"
|
echo -n "Configuring............"
|
||||||
make clean > /dev/null
|
make clean > /dev/null
|
||||||
rm -f silentdragonlite-mingw.pro
|
#rm -f silentdragonlite-mingw.pro
|
||||||
rm -rf release/
|
rm -rf release/
|
||||||
#Mingw seems to have trouble with precompiled headers, so strip that option from the .pro file
|
#Mingw seems to have trouble with precompiled headers, so strip that option from the .pro file
|
||||||
cat silentdragonlite.pro | sed "s/precompile_header/release/g" | sed "s/PRECOMPILED_HEADER.*//g" > silentdragonlite-mingw.pro
|
#cat silentdragon-lite.pro | sed "s/precompile_header/release/g" | sed "s/PRECOMPILED_HEADER.*//g" > silentdragonlite-mingw.pro
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Building..............."
|
echo -n "Building..............."
|
||||||
x86_64-w64-mingw32.static-qmake-qt5 silentdragonlite-mingw.pro CONFIG+=release > /dev/null
|
# Build the lib first
|
||||||
|
cd lib && make winrelease && cd ..
|
||||||
|
x86_64-w64-mingw32.static-qmake-qt5 silentdragonlite.pro CONFIG+=release > /dev/null
|
||||||
make -j32 > /dev/null
|
make -j32 > /dev/null
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Packaging.............."
|
echo -n "Packaging.............."
|
||||||
mkdir release/silentdragon-v$APP_VERSION
|
mkdir release/silentdragonlite-v$APP_VERSION
|
||||||
cp release/silentdragon.exe release/silentdragon-v$APP_VERSION
|
cp release/silentdragonlite.exe release/silentdragonlite-v$APP_VERSION
|
||||||
cp $hush_DIR/artifacts/hushd.exe release/silentdragon-v$APP_VERSION > /dev/null
|
cp README.md release/silentdragonlite-v$APP_VERSION
|
||||||
cp $hush_DIR/artifacts/hush-cli.exe release/silentdragon-v$APP_VERSION > /dev/null
|
cp LICENSE release/silentdragonlite-v$APP_VERSION
|
||||||
cp README.md release/silentdragon-v$APP_VERSION
|
cd release && zip -r Windows-binaries-silentdragonlite-v$APP_VERSION.zip silentdragonlite-v$APP_VERSION/ > /dev/null
|
||||||
cp LICENSE release/silentdragon-v$APP_VERSION
|
|
||||||
cd release && zip -r Windows-binaries-silentdragon-v$APP_VERSION.zip silentdragon-v$APP_VERSION/ > /dev/null
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
mkdir artifacts >/dev/null 2>&1
|
mkdir artifacts >/dev/null 2>&1
|
||||||
cp release/Windows-binaries-silentdragon-v$APP_VERSION.zip ./artifacts/
|
cp release/Windows-binaries-silentdragonlite-v$APP_VERSION.zip ./artifacts/
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
if [ -f artifacts/Windows-binaries-silentdragon-v$APP_VERSION.zip ] ; then
|
if [ -f artifacts/Windows-binaries-silentdragonlite-v$APP_VERSION.zip ] ; then
|
||||||
echo -n "Package contents......."
|
echo -n "Package contents......."
|
||||||
if unzip -l "artifacts/Windows-binaries-silentdragon-v$APP_VERSION.zip" | wc -l | grep -q "11"; then
|
if unzip -l "artifacts/Windows-binaries-silentdragonlite-v$APP_VERSION.zip" | wc -l | grep -q "9"; then
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
else
|
else
|
||||||
echo "[ERROR]"
|
echo "[ERROR]"
|
||||||
|
|||||||
259
src/sendtab.cpp
@@ -22,10 +22,6 @@ void MainWindow::setupSendTab() {
|
|||||||
// Cancel Button
|
// Cancel Button
|
||||||
QObject::connect(ui->cancelSendButton, &QPushButton::clicked, this, &MainWindow::cancelButton);
|
QObject::connect(ui->cancelSendButton, &QPushButton::clicked, this, &MainWindow::cancelButton);
|
||||||
|
|
||||||
// Input Combobox current text changed
|
|
||||||
QObject::connect(ui->inputsCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
|
||||||
this, &MainWindow::inputComboTextChanged);
|
|
||||||
|
|
||||||
// Hook up add address button click
|
// Hook up add address button click
|
||||||
QObject::connect(ui->addAddressButton, &QPushButton::clicked, this, &MainWindow::addAddressSection);
|
QObject::connect(ui->addAddressButton, &QPushButton::clicked, this, &MainWindow::addAddressSection);
|
||||||
|
|
||||||
@@ -59,18 +55,19 @@ void MainWindow::setupSendTab() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Fee amount changed
|
// Fee amount changed
|
||||||
// Disable custom fees if settings say no
|
ui->minerFeeAmt->setReadOnly(true);
|
||||||
ui->minerFeeAmt->setReadOnly(!Settings::getInstance()->getAllowCustomFees());
|
|
||||||
QObject::connect(ui->minerFeeAmt, &QLineEdit::textChanged, [=](auto txt) {
|
QObject::connect(ui->minerFeeAmt, &QLineEdit::textChanged, [=](auto txt) {
|
||||||
ui->lblMinerFeeUSD->setText(Settings::getUSDFormat(txt.toDouble()));
|
CAmount fee = CAmount::fromDecimalString(txt);
|
||||||
|
ui->lblMinerFeeUSD->setText(fee.toDecimalUSDString());
|
||||||
});
|
});
|
||||||
ui->minerFeeAmt->setText(Settings::getDecimalString(Settings::getMinerFee()));
|
ui->minerFeeAmt->setText(Settings::getMinerFee().toDecimalString());
|
||||||
|
|
||||||
// Set up focus enter to set fees
|
// Set up focus enter to set fees
|
||||||
QObject::connect(ui->tabWidget, &QTabWidget::currentChanged, [=] (int pos) {
|
QObject::connect(ui->tabWidget, &QTabWidget::currentChanged, [=] (int pos) {
|
||||||
if (pos == 1) {
|
if (pos == 1) {
|
||||||
QString txt = ui->minerFeeAmt->text();
|
QString txt = ui->minerFeeAmt->text();
|
||||||
ui->lblMinerFeeUSD->setText(Settings::getUSDFormat(txt.toDouble()));
|
QString feeUSD = CAmount::fromDecimalString(txt).toDecimalUSDString();
|
||||||
|
ui->lblMinerFeeUSD->setText(feeUSD);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -167,70 +164,6 @@ void MainWindow::updateLabelsAutoComplete() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setDefaultPayFrom() {
|
|
||||||
auto findMax = [=] (QString startsWith) {
|
|
||||||
double max_amt = 0;
|
|
||||||
int idx = -1;
|
|
||||||
|
|
||||||
for (int i=0; i < ui->inputsCombo->count(); i++) {
|
|
||||||
auto addr = ui->inputsCombo->itemText(i);
|
|
||||||
if (addr.startsWith(startsWith)) {
|
|
||||||
auto amt = rpc->getModel()->getAllBalances().value(addr);
|
|
||||||
if (max_amt < amt) {
|
|
||||||
max_amt = amt;
|
|
||||||
idx = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
// By default, select the z-address with the most balance from the inputs combo
|
|
||||||
auto maxZ = findMax("zs1");
|
|
||||||
if (maxZ >= 0) {
|
|
||||||
ui->inputsCombo->setCurrentIndex(maxZ);
|
|
||||||
} else {
|
|
||||||
auto maxT = findMax("R");
|
|
||||||
maxT = maxT >= 0 ? maxT : 0;
|
|
||||||
ui->inputsCombo->setCurrentIndex(maxT);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void MainWindow::updateFromCombo() {
|
|
||||||
if (!rpc)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto lastFromAddr = ui->inputsCombo->currentText();
|
|
||||||
|
|
||||||
ui->inputsCombo->clear();
|
|
||||||
auto i = rpc->getModel()->getAllBalances().constBegin();
|
|
||||||
|
|
||||||
// Add all the addresses into the inputs combo box
|
|
||||||
while (i != rpc->getModel()->getAllBalances().constEnd()) {
|
|
||||||
ui->inputsCombo->addItem(i.key(), i.value());
|
|
||||||
if (i.key() == lastFromAddr) ui->inputsCombo->setCurrentText(i.key());
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastFromAddr.isEmpty()) {
|
|
||||||
setDefaultPayFrom();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ui->inputsCombo->setCurrentText(lastFromAddr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::inputComboTextChanged(int index) {
|
|
||||||
auto addr = ui->inputsCombo->itemText(index);
|
|
||||||
auto bal = rpc->getModel()->getAllBalances().value(addr);
|
|
||||||
auto balFmt = Settings::gethushDisplayFormat(bal);
|
|
||||||
|
|
||||||
ui->sendAddressBalance->setText(balFmt);
|
|
||||||
ui->sendAddressBalanceUSD->setText(Settings::getUSDFormat(bal));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::addAddressSection() {
|
void MainWindow::addAddressSection() {
|
||||||
int itemNumber = ui->sendToWidgets->children().size() - 1;
|
int itemNumber = ui->sendToWidgets->children().size() - 1;
|
||||||
@@ -341,7 +274,8 @@ void MainWindow::addressChanged(int itemNumber, const QString& text) {
|
|||||||
|
|
||||||
void MainWindow::amountChanged(int item, const QString& text) {
|
void MainWindow::amountChanged(int item, const QString& text) {
|
||||||
auto usd = ui->sendToWidgets->findChild<QLabel*>(QString("AmtUSD") % QString::number(item));
|
auto usd = ui->sendToWidgets->findChild<QLabel*>(QString("AmtUSD") % QString::number(item));
|
||||||
usd->setText(Settings::getUSDFormat(text.toDouble()));
|
CAmount amt = CAmount::fromDecimalString(text);
|
||||||
|
usd->setText(amt.toDecimalUSDString());
|
||||||
|
|
||||||
// If there is a recurring payment, update the info there as well
|
// If there is a recurring payment, update the info there as well
|
||||||
if (sendTxRecurringInfo != nullptr) {
|
if (sendTxRecurringInfo != nullptr) {
|
||||||
@@ -386,12 +320,9 @@ void MainWindow::memoButtonClicked(int number, bool includeReplyTo) {
|
|||||||
memoDialog.memoTxt->setAcceptButton(memoDialog.buttonBox->button(QDialogButtonBox::Ok));
|
memoDialog.memoTxt->setAcceptButton(memoDialog.buttonBox->button(QDialogButtonBox::Ok));
|
||||||
|
|
||||||
auto fnAddReplyTo = [=, &dialog]() {
|
auto fnAddReplyTo = [=, &dialog]() {
|
||||||
QString replyTo = ui->inputsCombo->currentText();
|
auto replyTo = rpc->getDefaultSaplingAddress();
|
||||||
if (!Settings::isZAddress(replyTo)) {
|
if (replyTo.isEmpty())
|
||||||
replyTo = rpc->getDefaultSaplingAddress();
|
return;
|
||||||
if (replyTo.isEmpty())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memoDialog.memoTxt->includeReplyTo(replyTo);
|
memoDialog.memoTxt->includeReplyTo(replyTo);
|
||||||
|
|
||||||
@@ -435,7 +366,7 @@ void MainWindow::clearSendForm() {
|
|||||||
setMemoEnabled(1, false);
|
setMemoEnabled(1, false);
|
||||||
|
|
||||||
// Reset the fee
|
// Reset the fee
|
||||||
ui->minerFeeAmt->setText(Settings::getDecimalString(Settings::getMinerFee()));
|
ui->minerFeeAmt->setText(Settings::getMinerFee().toDecimalString());
|
||||||
|
|
||||||
// Start the deletion after the first item, since we want to keep 1 send field there all there
|
// Start the deletion after the first item, since we want to keep 1 send field there all there
|
||||||
for (int i=1; i < totalItems; i++) {
|
for (int i=1; i < totalItems; i++) {
|
||||||
@@ -462,29 +393,22 @@ void MainWindow::maxAmountChecked(int checked) {
|
|||||||
if (rpc == nullptr) return;
|
if (rpc == nullptr) return;
|
||||||
|
|
||||||
// Calculate maximum amount
|
// Calculate maximum amount
|
||||||
double sumAllAmounts = 0.0;
|
CAmount sumAllAmounts;
|
||||||
// Calculate all other amounts
|
// Calculate all other amounts
|
||||||
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
|
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
|
||||||
// Start counting the sum skipping the first one, because the MAX button is on the first one, and we don't
|
// Start counting the sum skipping the first one, because the MAX button is on the first one, and we don't
|
||||||
// want to include it in the sum.
|
// want to include it in the sum.
|
||||||
for (int i=1; i < totalItems; i++) {
|
for (int i=1; i < totalItems; i++) {
|
||||||
auto amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1));
|
auto amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1));
|
||||||
sumAllAmounts += amt->text().toDouble();
|
sumAllAmounts = sumAllAmounts + CAmount::fromDecimalString(amt->text());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::getInstance()->getAllowCustomFees()) {
|
sumAllAmounts = sumAllAmounts + Settings::getMinerFee();
|
||||||
sumAllAmounts = ui->minerFeeAmt->text().toDouble();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sumAllAmounts += Settings::getMinerFee();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto addr = ui->inputsCombo->currentText();
|
auto maxamount = rpc->getModel()->getAvailableBalance() - sumAllAmounts;
|
||||||
|
maxamount = (maxamount < 0) ? CAmount::fromqint64(0): maxamount;
|
||||||
|
|
||||||
auto maxamount = rpc->getModel()->getAllBalances().value(addr) - sumAllAmounts;
|
ui->Amount1->setText(maxamount.toDecimalString());
|
||||||
maxamount = (maxamount < 0) ? 0 : maxamount;
|
|
||||||
|
|
||||||
ui->Amount1->setText(Settings::getDecimalString(maxamount));
|
|
||||||
} else if (checked == Qt::Unchecked) {
|
} else if (checked == Qt::Unchecked) {
|
||||||
// Just remove the readonly part, don't change the content
|
// Just remove the readonly part, don't change the content
|
||||||
ui->Amount1->setReadOnly(false);
|
ui->Amount1->setReadOnly(false);
|
||||||
@@ -495,60 +419,37 @@ void MainWindow::maxAmountChecked(int checked) {
|
|||||||
Tx MainWindow::createTxFromSendPage() {
|
Tx MainWindow::createTxFromSendPage() {
|
||||||
Tx tx;
|
Tx tx;
|
||||||
|
|
||||||
bool sendChangeToSapling = Settings::getInstance()->getAutoShield();
|
|
||||||
|
|
||||||
// Gather the from / to addresses
|
|
||||||
tx.fromAddr = ui->inputsCombo->currentText();
|
|
||||||
sendChangeToSapling = sendChangeToSapling && Settings::isTAddress(tx.fromAddr);
|
|
||||||
|
|
||||||
// For each addr/amt in the sendTo tab
|
// For each addr/amt in the sendTo tab
|
||||||
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
|
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
|
||||||
double totalAmt = 0;
|
CAmount totalAmt;
|
||||||
for (int i=0; i < totalItems; i++) {
|
for (int i=0; i < totalItems; i++) {
|
||||||
QString addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") % QString::number(i+1))->text().trimmed();
|
QString addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") % QString::number(i+1))->text().trimmed();
|
||||||
// Remove label if it exists
|
// Remove label if it exists
|
||||||
addr = AddressBook::addressFromAddressLabel(addr);
|
addr = AddressBook::addressFromAddressLabel(addr);
|
||||||
|
|
||||||
// If address is sprout, then we can't send change to sapling, because of turnstile.
|
QString amtStr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1))->text().trimmed();
|
||||||
sendChangeToSapling = sendChangeToSapling && !Settings::getInstance()->isSproutAddress(addr);
|
if (amtStr.isEmpty()) {
|
||||||
double amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1))->text().trimmed().toDouble();
|
amtStr = "-1";; // The user didn't specify an amount
|
||||||
totalAmt += amt;
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
CAmount amt;
|
||||||
|
|
||||||
|
// Make sure it parses
|
||||||
|
amtStr.toDouble(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
amt = CAmount::fromqint64(-1);
|
||||||
|
} else {
|
||||||
|
amt = CAmount::fromDecimalString(amtStr);
|
||||||
|
totalAmt = totalAmt + amt;
|
||||||
|
}
|
||||||
|
|
||||||
QString memo = ui->sendToWidgets->findChild<QLabel*>(QString("MemoTxt") % QString::number(i+1))->text().trimmed();
|
QString memo = ui->sendToWidgets->findChild<QLabel*>(QString("MemoTxt") % QString::number(i+1))->text().trimmed();
|
||||||
|
|
||||||
tx.toAddrs.push_back( ToFields{addr, amt, memo,} );
|
tx.toAddrs.push_back( ToFields{addr, amt, memo,} );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::getInstance()->getAllowCustomFees()) {
|
tx.fee = Settings::getMinerFee();
|
||||||
tx.fee = ui->minerFeeAmt->text().toDouble();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tx.fee = Settings::getMinerFee();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Settings::getInstance()->getAutoShield() && sendChangeToSapling) {
|
|
||||||
auto saplingAddr = std::find_if(rpc->getModel()->getAllZAddresses().begin(), rpc->getModel()->getAllZAddresses().end(), [=](auto i) -> bool {
|
|
||||||
// We're finding a sapling address that is not one of the To addresses, because hush doesn't allow duplicated addresses
|
|
||||||
bool isSapling = Settings::getInstance()->isSaplingAddress(i);
|
|
||||||
if (!isSapling) return false;
|
|
||||||
|
|
||||||
// Also check all the To addresses
|
|
||||||
for (auto t : tx.toAddrs) {
|
|
||||||
if (t.addr == i)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (saplingAddr != rpc->getModel()->getAllZAddresses().end()) {
|
|
||||||
double change = rpc->getModel()->getAllBalances().value(tx.fromAddr) - totalAmt - tx.fee;
|
|
||||||
|
|
||||||
if (Settings::getDecimalString(change) != "0") {
|
|
||||||
QString changeMemo = tr("Change from ") + tx.fromAddr;
|
|
||||||
tx.toAddrs.push_back(ToFields{ *saplingAddr, change, changeMemo});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
@@ -588,8 +489,6 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
|
|||||||
confirm.setupUi(&d);
|
confirm.setupUi(&d);
|
||||||
Settings::saveRestore(&d);
|
Settings::saveRestore(&d);
|
||||||
|
|
||||||
const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
|
|
||||||
|
|
||||||
// Remove all existing address/amt qlabels on the confirm dialog.
|
// Remove all existing address/amt qlabels on the confirm dialog.
|
||||||
int totalConfirmAddrItems = confirm.sendToAddrs->children().size();
|
int totalConfirmAddrItems = confirm.sendToAddrs->children().size();
|
||||||
for (int i = 0; i < totalConfirmAddrItems / 3; i++) {
|
for (int i = 0; i < totalConfirmAddrItems / 3; i++) {
|
||||||
@@ -613,7 +512,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
|
|||||||
|
|
||||||
// For each addr/amt/memo, construct the JSON and also build the confirm dialog box
|
// For each addr/amt/memo, construct the JSON and also build the confirm dialog box
|
||||||
int row = 0;
|
int row = 0;
|
||||||
double totalSpending = 0;
|
CAmount totalSpending;
|
||||||
|
|
||||||
for (int i=0; i < tx.toAddrs.size(); i++) {
|
for (int i=0; i < tx.toAddrs.size(); i++) {
|
||||||
auto toAddr = tx.toAddrs[i];
|
auto toAddr = tx.toAddrs[i];
|
||||||
@@ -625,21 +524,20 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
|
|||||||
Addr->setObjectName(QString("Addr") % QString::number(i + 1));
|
Addr->setObjectName(QString("Addr") % QString::number(i + 1));
|
||||||
Addr->setWordWrap(true);
|
Addr->setWordWrap(true);
|
||||||
Addr->setText(fnSplitAddressForWrap(toAddr.addr));
|
Addr->setText(fnSplitAddressForWrap(toAddr.addr));
|
||||||
Addr->setFont(fixedFont);
|
|
||||||
confirm.gridLayout->addWidget(Addr, row, 0, 1, 1);
|
confirm.gridLayout->addWidget(Addr, row, 0, 1, 1);
|
||||||
|
|
||||||
// Amount (hush)
|
// Amount (hush)
|
||||||
auto Amt = new QLabel(confirm.sendToAddrs);
|
auto Amt = new QLabel(confirm.sendToAddrs);
|
||||||
Amt->setObjectName(QString("Amt") % QString::number(i + 1));
|
Amt->setObjectName(QString("Amt") % QString::number(i + 1));
|
||||||
Amt->setText(Settings::gethushDisplayFormat(toAddr.amount));
|
Amt->setText(toAddr.amount.toDecimalhushString());
|
||||||
Amt->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
|
Amt->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
|
||||||
confirm.gridLayout->addWidget(Amt, row, 1, 1, 1);
|
confirm.gridLayout->addWidget(Amt, row, 1, 1, 1);
|
||||||
totalSpending += toAddr.amount;
|
totalSpending = totalSpending + toAddr.amount;
|
||||||
|
|
||||||
// Amount (USD)
|
// Amount (USD)
|
||||||
auto AmtUSD = new QLabel(confirm.sendToAddrs);
|
auto AmtUSD = new QLabel(confirm.sendToAddrs);
|
||||||
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
|
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
|
||||||
AmtUSD->setText(Settings::getUSDFormat(toAddr.amount));
|
AmtUSD->setText(toAddr.amount.toDecimalUSDString());
|
||||||
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
|
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
|
||||||
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
|
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
|
||||||
|
|
||||||
@@ -681,8 +579,8 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
|
|||||||
minerFee->setObjectName(QStringLiteral("minerFee"));
|
minerFee->setObjectName(QStringLiteral("minerFee"));
|
||||||
minerFee->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
|
minerFee->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
|
||||||
confirm.gridLayout->addWidget(minerFee, row, 1, 1, 1);
|
confirm.gridLayout->addWidget(minerFee, row, 1, 1, 1);
|
||||||
minerFee->setText(Settings::gethushDisplayFormat(tx.fee));
|
minerFee->setText(tx.fee.toDecimalhushString());
|
||||||
totalSpending += tx.fee;
|
totalSpending = totalSpending + tx.fee;
|
||||||
|
|
||||||
auto minerFeeUSD = new QLabel(confirm.sendToAddrs);
|
auto minerFeeUSD = new QLabel(confirm.sendToAddrs);
|
||||||
QSizePolicy sizePolicy1(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
QSizePolicy sizePolicy1(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||||
@@ -690,14 +588,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
|
|||||||
minerFeeUSD->setObjectName(QStringLiteral("minerFeeUSD"));
|
minerFeeUSD->setObjectName(QStringLiteral("minerFeeUSD"));
|
||||||
minerFeeUSD->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
|
minerFeeUSD->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
|
||||||
confirm.gridLayout->addWidget(minerFeeUSD, row, 2, 1, 1);
|
confirm.gridLayout->addWidget(minerFeeUSD, row, 2, 1, 1);
|
||||||
minerFeeUSD->setText(Settings::getUSDFormat(tx.fee));
|
minerFeeUSD->setText(tx.fee.toDecimalUSDString());
|
||||||
|
|
||||||
if (Settings::getInstance()->getAllowCustomFees() && tx.fee != Settings::getMinerFee()) {
|
|
||||||
confirm.warningLabel->setVisible(true);
|
|
||||||
} else {
|
|
||||||
// Default fee
|
|
||||||
confirm.warningLabel->setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurring payment info, show only if there is exactly one destination address
|
// Recurring payment info, show only if there is exactly one destination address
|
||||||
@@ -712,17 +603,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
|
|||||||
// Syncing warning
|
// Syncing warning
|
||||||
confirm.syncingWarning->setVisible(Settings::getInstance()->isSyncing());
|
confirm.syncingWarning->setVisible(Settings::getInstance()->isSyncing());
|
||||||
|
|
||||||
// No peers warning
|
|
||||||
confirm.nopeersWarning->setVisible(Settings::getInstance()->getPeers() == 0);
|
|
||||||
|
|
||||||
// And FromAddress in the confirm dialog
|
|
||||||
confirm.sendFrom->setText(fnSplitAddressForWrap(tx.fromAddr));
|
|
||||||
confirm.sendFrom->setFont(fixedFont);
|
|
||||||
QString tooltip = tr("Current balance : ") +
|
|
||||||
Settings::gethushUSDDisplayFormat(rpc->getModel()->getAllBalances().value(tx.fromAddr));
|
|
||||||
tooltip += "\n" + tr("Balance after this Tx: ") +
|
|
||||||
Settings::gethushUSDDisplayFormat(rpc->getModel()->getAllBalances().value(tx.fromAddr) - totalSpending);
|
|
||||||
confirm.sendFrom->setToolTip(tooltip);
|
|
||||||
|
|
||||||
// Show the dialog and submit it if the user confirms
|
// Show the dialog and submit it if the user confirms
|
||||||
return d.exec() == QDialog::Accepted;
|
return d.exec() == QDialog::Accepted;
|
||||||
@@ -735,6 +616,7 @@ void MainWindow::sendButton() {
|
|||||||
Tx tx = createTxFromSendPage();
|
Tx tx = createTxFromSendPage();
|
||||||
|
|
||||||
QString error = doSendTxValidations(tx);
|
QString error = doSendTxValidations(tx);
|
||||||
|
|
||||||
if (!error.isEmpty()) {
|
if (!error.isEmpty()) {
|
||||||
// Something went wrong, so show an error and exit
|
// Something went wrong, so show an error and exit
|
||||||
QMessageBox msg(QMessageBox::Critical, tr("Transaction Error"), error,
|
QMessageBox msg(QMessageBox::Critical, tr("Transaction Error"), error,
|
||||||
@@ -762,11 +644,39 @@ void MainWindow::sendButton() {
|
|||||||
// Then delete the additional fields from the sendTo tab
|
// Then delete the additional fields from the sendTo tab
|
||||||
clearSendForm();
|
clearSendForm();
|
||||||
|
|
||||||
|
// Create a new Dialog to show that we are computing/sending the Tx
|
||||||
|
auto d = new QDialog(this);
|
||||||
|
auto connD = new Ui_ConnectionDialog();
|
||||||
|
connD->setupUi(d);
|
||||||
|
QPixmap logo(":/img/res/logobig.gif");
|
||||||
|
connD->topIcon->setBasePixmap(logo.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||||
|
|
||||||
|
connD->status->setText(tr("Please wait..."));
|
||||||
|
connD->statusDetail->setText(tr("Computing your transaction"));
|
||||||
|
|
||||||
|
d->show();
|
||||||
|
|
||||||
// And send the Tx
|
// And send the Tx
|
||||||
rpc->executeTransaction(tx,
|
rpc->executeTransaction(tx,
|
||||||
[=] (QString txid) {
|
[=] (QString txid) {
|
||||||
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
|
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
|
||||||
|
|
||||||
|
connD->status->setText(tr("Done!"));
|
||||||
|
connD->statusDetail->setText(txid);
|
||||||
|
|
||||||
|
QTimer::singleShot(1000, [=]() {
|
||||||
|
d->accept();
|
||||||
|
d->close();
|
||||||
|
delete connD;
|
||||||
|
delete d;
|
||||||
|
|
||||||
|
// And switch to the balances tab
|
||||||
|
ui->tabWidget->setCurrentIndex(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Force a UI update so we get the unconfirmed Tx
|
||||||
|
rpc->refresh(true);
|
||||||
|
|
||||||
// If this was a recurring payment, update the payment with the info
|
// If this was a recurring payment, update the payment with the info
|
||||||
if (!recurringPaymentHash.isEmpty()) {
|
if (!recurringPaymentHash.isEmpty()) {
|
||||||
// Since this is the send button payment, this is the first payment
|
// Since this is the send button payment, this is the first payment
|
||||||
@@ -778,6 +688,11 @@ void MainWindow::sendButton() {
|
|||||||
[=] (QString opid, QString errStr) {
|
[=] (QString opid, QString errStr) {
|
||||||
ui->statusBar->showMessage(QObject::tr(" Tx ") % opid % QObject::tr(" failed"), 15 * 1000);
|
ui->statusBar->showMessage(QObject::tr(" Tx ") % opid % QObject::tr(" failed"), 15 * 1000);
|
||||||
|
|
||||||
|
d->accept();
|
||||||
|
d->close();
|
||||||
|
delete connD;
|
||||||
|
delete d;
|
||||||
|
|
||||||
if (!opid.isEmpty())
|
if (!opid.isEmpty())
|
||||||
errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr;
|
errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr;
|
||||||
|
|
||||||
@@ -795,8 +710,9 @@ void MainWindow::sendButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString MainWindow::doSendTxValidations(Tx tx) {
|
QString MainWindow::doSendTxValidations(Tx tx) {
|
||||||
if (!Settings::isValidAddress(tx.fromAddr)) return QString(tr("From Address is Invalid"));
|
// Check to see if we have enough verified funds to send the Tx.
|
||||||
|
|
||||||
|
CAmount total;
|
||||||
for (auto toAddr : tx.toAddrs) {
|
for (auto toAddr : tx.toAddrs) {
|
||||||
if (!Settings::isValidAddress(toAddr.addr)) {
|
if (!Settings::isValidAddress(toAddr.addr)) {
|
||||||
QString addr = (toAddr.addr.length() > 100 ? toAddr.addr.left(100) + "..." : toAddr.addr);
|
QString addr = (toAddr.addr.length() > 100 ? toAddr.addr.left(100) + "..." : toAddr.addr);
|
||||||
@@ -805,13 +721,22 @@ QString MainWindow::doSendTxValidations(Tx tx) {
|
|||||||
|
|
||||||
// This technically shouldn't be possible, but issue #62 seems to have discovered a bug
|
// This technically shouldn't be possible, but issue #62 seems to have discovered a bug
|
||||||
// somewhere, so just add a check to make sure.
|
// somewhere, so just add a check to make sure.
|
||||||
if (toAddr.amount < 0) {
|
if (toAddr.amount.toqint64() < 0) {
|
||||||
return QString(tr("Amount for address '%1' is invalid!").arg(toAddr.addr));
|
return QString(tr("Amount for address '%1' is invalid!").arg(toAddr.addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
total = total + toAddr.amount;
|
||||||
|
}
|
||||||
|
total = total + tx.fee;
|
||||||
|
|
||||||
|
auto available = rpc->getModel()->getAvailableBalance();
|
||||||
|
|
||||||
|
if (available < total) {
|
||||||
|
return tr("Not enough available funds to send this transaction\n\nHave: %1\nNeed: %2\n\nNote: Funds need 5 confirmations before they can be spent")
|
||||||
|
.arg(available.toDecimalhushString(), total.toDecimalhushString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
return QString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::cancelButton() {
|
void MainWindow::cancelButton() {
|
||||||
|
|||||||
167
src/settings.cpp
@@ -1,5 +1,6 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "camount.h"
|
||||||
|
|
||||||
Settings* Settings::instance = nullptr;
|
Settings* Settings::instance = nullptr;
|
||||||
|
|
||||||
@@ -18,33 +19,24 @@ Config Settings::getSettings() {
|
|||||||
// Load from the QT Settings.
|
// Load from the QT Settings.
|
||||||
QSettings s;
|
QSettings s;
|
||||||
|
|
||||||
auto host = s.value("connection/host").toString();
|
auto server = s.value("connection/server").toString();
|
||||||
auto port = s.value("connection/port").toString();
|
if (server.trimmed().isEmpty()) {
|
||||||
auto username = s.value("connection/rpcuser").toString();
|
server = Settings::getDefaultServer();
|
||||||
auto password = s.value("connection/rpcpassword").toString();
|
}
|
||||||
|
|
||||||
return Config{host, port, username, password};
|
return Config{server};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::saveSettings(const QString& host, const QString& port, const QString& username, const QString& password) {
|
void Settings::saveSettings(const QString& server) {
|
||||||
QSettings s;
|
QSettings s;
|
||||||
|
|
||||||
s.setValue("connection/host", host);
|
s.setValue("connection/server", server);
|
||||||
s.setValue("connection/port", port);
|
|
||||||
s.setValue("connection/rpcuser", username);
|
|
||||||
s.setValue("connection/rpcpassword", password);
|
|
||||||
|
|
||||||
s.sync();
|
s.sync();
|
||||||
|
|
||||||
// re-init to load correct settings
|
// re-init to load correct settings
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::setUsinghushConf(QString confLocation) {
|
|
||||||
if (!confLocation.isEmpty())
|
|
||||||
_confLocation = confLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Settings::isTestnet() {
|
bool Settings::isTestnet() {
|
||||||
return _isTestnet;
|
return _isTestnet;
|
||||||
}
|
}
|
||||||
@@ -72,7 +64,7 @@ bool Settings::isZAddress(QString addr) {
|
|||||||
if (!isValidAddress(addr))
|
if (!isValidAddress(addr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return addr.startsWith("z");
|
return addr.startsWith("zs");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::isTAddress(QString addr) {
|
bool Settings::isTAddress(QString addr) {
|
||||||
@@ -110,17 +102,8 @@ bool Settings::isSaplingActive() {
|
|||||||
return (isTestnet() && getBlockNumber() > 0) || (!isTestnet() && getBlockNumber() > 0);
|
return (isTestnet() && getBlockNumber() > 0) || (!isTestnet() && getBlockNumber() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Settings::gethushPrice() {
|
double Settings::getZECPrice() {
|
||||||
return hushPrice;
|
return ZECPrice;
|
||||||
}
|
|
||||||
|
|
||||||
bool Settings::getAutoShield() {
|
|
||||||
// Load from Qt settings
|
|
||||||
return QSettings().value("options/autoshield", false).toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Settings::setAutoShield(bool allow) {
|
|
||||||
QSettings().setValue("options/autoshield", allow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::getCheckForUpdates() {
|
bool Settings::getCheckForUpdates() {
|
||||||
@@ -139,15 +122,6 @@ void Settings::setAllowFetchPrices(bool allow) {
|
|||||||
QSettings().setValue("options/allowfetchprices", allow);
|
QSettings().setValue("options/allowfetchprices", allow);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::getAllowCustomFees() {
|
|
||||||
// Load from the QT Settings.
|
|
||||||
return QSettings().value("options/customfees", false).toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Settings::setAllowCustomFees(bool allow) {
|
|
||||||
QSettings().setValue("options/customfees", allow);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Settings::get_theme_name() {
|
QString Settings::get_theme_name() {
|
||||||
// Load from the QT Settings.
|
// Load from the QT Settings.
|
||||||
return QSettings().value("options/theme_name", false).toString();
|
return QSettings().value("options/theme_name", false).toString();
|
||||||
@@ -157,22 +131,7 @@ void Settings::set_theme_name(QString theme_name) {
|
|||||||
QSettings().setValue("options/theme_name", theme_name);
|
QSettings().setValue("options/theme_name", theme_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::getSaveZtxs() {
|
|
||||||
// Load from the QT Settings.
|
|
||||||
return QSettings().value("options/savesenttx", true).toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Settings::setSaveZtxs(bool save) {
|
|
||||||
QSettings().setValue("options/savesenttx", save);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Settings::setPeers(int peers) {
|
|
||||||
_peerConnections = peers;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Settings::getPeers() {
|
|
||||||
return _peerConnections;
|
|
||||||
}
|
|
||||||
//=================================
|
//=================================
|
||||||
// Static Stuff
|
// Static Stuff
|
||||||
//=================================
|
//=================================
|
||||||
@@ -193,6 +152,10 @@ void Settings::saveRestoreTableHeader(QTableView* table, QDialog* d, QString tab
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Settings::getDefaultServer() {
|
||||||
|
return "https://hush-lightwallet.de:443";
|
||||||
|
}
|
||||||
|
|
||||||
void Settings::openAddressInExplorer(QString address) {
|
void Settings::openAddressInExplorer(QString address) {
|
||||||
QString url;
|
QString url;
|
||||||
if (Settings::getInstance()->isTestnet()) {
|
if (Settings::getInstance()->isTestnet()) {
|
||||||
@@ -216,37 +179,6 @@ void Settings::openTxInExplorer(QString txid) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QString Settings::getUSDFormat(double bal) {
|
|
||||||
return "$" + QLocale(QLocale::English).toString(bal * Settings::getInstance()->gethushPrice(), 'f', 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Settings::getDecimalString(double amt) {
|
|
||||||
QString f = QString::number(amt, 'f', 8);
|
|
||||||
|
|
||||||
while (f.contains(".") && (f.right(1) == "0" || f.right(1) == ".")) {
|
|
||||||
f = f.left(f.length() - 1);
|
|
||||||
}
|
|
||||||
if (f == "-0")
|
|
||||||
f = "0";
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Settings::gethushDisplayFormat(double bal) {
|
|
||||||
// This is idiotic. Why doesn't QString have a way to do this?
|
|
||||||
return getDecimalString(bal) % " " % Settings::getTokenName();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Settings::gethushUSDDisplayFormat(double bal) {
|
|
||||||
auto usdFormat = getUSDFormat(bal);
|
|
||||||
if (!usdFormat.isEmpty())
|
|
||||||
return gethushDisplayFormat(bal) % " (" % getUSDFormat(bal) % ")";
|
|
||||||
else
|
|
||||||
return gethushDisplayFormat(bal);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const QString Settings::txidStatusMessage = QString(QObject::tr("Tx submitted (right click to copy) txid:"));
|
const QString Settings::txidStatusMessage = QString(QObject::tr("Tx submitted (right click to copy) txid:"));
|
||||||
|
|
||||||
QString Settings::getTokenName() {
|
QString Settings::getTokenName() {
|
||||||
@@ -261,72 +193,12 @@ QString Settings::getDonationAddr() {
|
|||||||
if (Settings::getInstance()->isTestnet())
|
if (Settings::getInstance()->isTestnet())
|
||||||
return "ztestsaplingXXX";
|
return "ztestsaplingXXX";
|
||||||
else
|
else
|
||||||
return "zs1aq4xnrkjlnxx0zesqye7jz3dfrf3rjh7q5z6u8l6mwyqqaam3gx3j2fkqakp33v93yavq46j83q";
|
return "zs1kwp3h4rwz76zfqzmwqqextq696kndtjskg4fzc80l9ygfal4hchcsst83ua8tjwzzy9nja7v5rr";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::addTohushConf(QString confLocation, QString line) {
|
CAmount Settings::getMinerFee() {
|
||||||
QFile file(confLocation);
|
return CAmount::fromqint64(10000);
|
||||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Append))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
|
||||||
QTextStream out(&file);
|
|
||||||
out << line << "\n";
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Settings::removeFromhushConf(QString confLocation, QString option) {
|
|
||||||
if (confLocation.isEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// To remove an option, we'll create a new file, and copy over everything but the option.
|
|
||||||
QFile file(confLocation);
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QList<QString> lines;
|
|
||||||
QTextStream in(&file);
|
|
||||||
while (!in.atEnd()) {
|
|
||||||
QString line = in.readLine();
|
|
||||||
auto s = line.indexOf("=");
|
|
||||||
QString name = line.left(s).trimmed().toLower();
|
|
||||||
if (name != option) {
|
|
||||||
lines.append(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
QFile newfile(confLocation);
|
|
||||||
if (!newfile.open(QIODevice::ReadWrite | QIODevice::Truncate))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QTextStream out(&newfile);
|
|
||||||
for (QString line : lines) {
|
|
||||||
out << line << endl;
|
|
||||||
}
|
|
||||||
newfile.close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Settings::getMinerFee() {
|
|
||||||
return 0.0001;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Settings::getZboardAmount() {
|
|
||||||
return 0.0001;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Settings::getZboardAddr() {
|
|
||||||
if (Settings::getInstance()->isTestnet()) {
|
|
||||||
return getDonationAddr();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "zs10m00rvkhfm4f7n23e4sxsx275r7ptnggx39ygl0vy46j9mdll5c97gl6dxgpk0njuptg2mn9w5s";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::isValidSaplingPrivateKey(QString pk) {
|
bool Settings::isValidSaplingPrivateKey(QString pk) {
|
||||||
@@ -349,7 +221,8 @@ bool Settings::isValidAddress(QString addr) {
|
|||||||
|
|
||||||
// Get a pretty string representation of this Payment URI
|
// Get a pretty string representation of this Payment URI
|
||||||
QString Settings::paymentURIPretty(PaymentURI uri) {
|
QString Settings::paymentURIPretty(PaymentURI uri) {
|
||||||
return QString() + "Payment Request\n" + "Pay: " + uri.addr + "\nAmount: " + gethushDisplayFormat(uri.amt.toDouble())
|
CAmount amount = CAmount::fromDecimalString(uri.amt);
|
||||||
|
return QString() + "Payment Request\n" + "Pay: " + uri.addr + "\nAmount: " + amount.toDecimalhushString()
|
||||||
+ "\nMemo:" + QUrl::fromPercentEncoding(uri.memo.toUtf8());
|
+ "\nMemo:" + QUrl::fromPercentEncoding(uri.memo.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
#define SETTINGS_H
|
#define SETTINGS_H
|
||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
#include "camount.h"
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
QString host;
|
QString server;
|
||||||
QString port;
|
|
||||||
QString rpcuser;
|
|
||||||
QString rpcpassword;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ToFields;
|
struct ToFields;
|
||||||
@@ -29,7 +29,7 @@ public:
|
|||||||
static Settings* getInstance();
|
static Settings* getInstance();
|
||||||
|
|
||||||
Config getSettings();
|
Config getSettings();
|
||||||
void saveSettings(const QString& host, const QString& port, const QString& username, const QString& password);
|
void saveSettings(const QString& server);
|
||||||
|
|
||||||
bool isTestnet();
|
bool isTestnet();
|
||||||
void setTestnet(bool isTestnet);
|
void setTestnet(bool isTestnet);
|
||||||
@@ -54,15 +54,6 @@ public:
|
|||||||
int getBlockNumber();
|
int getBlockNumber();
|
||||||
void setBlockNumber(int number);
|
void setBlockNumber(int number);
|
||||||
|
|
||||||
bool getSaveZtxs();
|
|
||||||
void setSaveZtxs(bool save);
|
|
||||||
|
|
||||||
bool getAutoShield();
|
|
||||||
void setAutoShield(bool allow);
|
|
||||||
|
|
||||||
bool getAllowCustomFees();
|
|
||||||
void setAllowCustomFees(bool allow);
|
|
||||||
|
|
||||||
bool getAllowFetchPrices();
|
bool getAllowFetchPrices();
|
||||||
void setAllowFetchPrices(bool allow);
|
void setAllowFetchPrices(bool allow);
|
||||||
|
|
||||||
@@ -74,14 +65,8 @@ public:
|
|||||||
|
|
||||||
bool isSaplingActive();
|
bool isSaplingActive();
|
||||||
|
|
||||||
void setUsinghushConf(QString confLocation);
|
void setZECPrice(double p) { ZECPrice = p; }
|
||||||
const QString& gethushdConfLocation() { return _confLocation; }
|
double getZECPrice();
|
||||||
|
|
||||||
void sethushPrice(double p) { hushPrice = p; }
|
|
||||||
double gethushPrice();
|
|
||||||
|
|
||||||
void setPeers(int peers);
|
|
||||||
int getPeers();
|
|
||||||
|
|
||||||
// Static stuff
|
// Static stuff
|
||||||
static const QString txidStatusMessage;
|
static const QString txidStatusMessage;
|
||||||
@@ -98,26 +83,17 @@ public:
|
|||||||
static bool isZAddress(QString addr);
|
static bool isZAddress(QString addr);
|
||||||
static bool isTAddress(QString addr);
|
static bool isTAddress(QString addr);
|
||||||
|
|
||||||
static QString getDecimalString(double amt);
|
|
||||||
static QString getUSDFormat(double bal);
|
|
||||||
|
|
||||||
|
|
||||||
static QString gethushDisplayFormat(double bal);
|
|
||||||
static QString gethushUSDDisplayFormat(double bal);
|
|
||||||
|
|
||||||
static QString getTokenName();
|
static QString getTokenName();
|
||||||
static QString getDonationAddr();
|
static QString getDonationAddr();
|
||||||
|
|
||||||
static double getMinerFee();
|
static QString getDefaultServer();
|
||||||
static double getZboardAmount();
|
static CAmount getMinerFee();
|
||||||
static QString getZboardAddr();
|
|
||||||
|
|
||||||
static int getMaxMobileAppTxns() { return 30; }
|
static int getMaxMobileAppTxns() { return 30; }
|
||||||
|
|
||||||
static bool isValidAddress(QString addr);
|
static int getNumberOfDecimalPlaces() {return 8;}
|
||||||
|
|
||||||
static bool addTohushConf(QString confLocation, QString line);
|
static bool isValidAddress(QString addr);
|
||||||
static bool removeFromhushConf(QString confLocation, QString option);
|
|
||||||
|
|
||||||
static QString getChainName() { return QString("main"); }
|
static QString getChainName() { return QString("main"); }
|
||||||
|
|
||||||
@@ -134,7 +110,6 @@ private:
|
|||||||
|
|
||||||
static Settings* instance;
|
static Settings* instance;
|
||||||
|
|
||||||
QString _confLocation;
|
|
||||||
QString _executable;
|
QString _executable;
|
||||||
bool _isTestnet = false;
|
bool _isTestnet = false;
|
||||||
bool _isSyncing = false;
|
bool _isSyncing = false;
|
||||||
@@ -142,9 +117,19 @@ private:
|
|||||||
int _hushdVersion = 0;
|
int _hushdVersion = 0;
|
||||||
bool _useEmbedded = false;
|
bool _useEmbedded = false;
|
||||||
bool _headless = false;
|
bool _headless = false;
|
||||||
int _peerConnections = 0;
|
|
||||||
|
|
||||||
double hushPrice = 0.0;
|
double ZECPrice = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline bool isJsonResultSuccess(const json& res) {
|
||||||
|
return res.find("result") != res.end() &&
|
||||||
|
QString::fromStdString(res["result"].get<json::string_t>()) == "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isJsonError(const json& res) {
|
||||||
|
return res.find("error") != res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // SETTINGS_H
|
#endif // SETTINGS_H
|
||||||
|
|||||||
353
src/settings.ui
@@ -26,11 +26,11 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>1</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="tab">
|
<widget class="QWidget" name="tab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>hushd connection</string>
|
<string>Connection</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
@@ -43,13 +43,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="Line" name="line">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
@@ -59,69 +52,17 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Host</string>
|
<string>Server</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="hostname">
|
<widget class="QLineEdit" name="txtServer">
|
||||||
<property name="placeholderText">
|
<property name="placeholderText">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Port</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="port">
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>RPC Username</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="rpcuser"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>RPC Password</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="rpcpassword"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2"/>
|
<layout class="QVBoxLayout" name="verticalLayout_2"/>
|
||||||
</item>
|
</item>
|
||||||
@@ -145,165 +86,7 @@
|
|||||||
<string>Options</string>
|
<string>Options</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="10" column="0" colspan="2">
|
<item row="6" column="1">
|
||||||
<widget class="QLabel" name="label_8">
|
|
||||||
<property name="text">
|
|
||||||
<string>Connect to github on startup to check for updates</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="0" colspan="2">
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="text">
|
|
||||||
<string>Normally, change from t-Addresses goes to another t-Address. Checking this option will send the change to your shielded sapling address instead. Check this option to increase your privacy.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QPushButton" name="btnClearSaved">
|
|
||||||
<property name="text">
|
|
||||||
<string>Clear History</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="chkSaveTxs">
|
|
||||||
<property name="text">
|
|
||||||
<string>Remember shielded transactions</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="12" column="0" colspan="2">
|
|
||||||
<widget class="QLabel" name="label_10">
|
|
||||||
<property name="text">
|
|
||||||
<string>Connect to the internet to fetch hush prices</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0" colspan="2">
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>Allow overriding the default fees when sending transactions. Enabling this option may compromise your privacy since fees are transparent. </string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="9" column="0" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="chkCheckUpdates">
|
|
||||||
<property name="text">
|
|
||||||
<string>Check github for updates at startup</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0" colspan="2">
|
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="text">
|
|
||||||
<string>Shielded transactions are saved locally and shown in the transactions tab. If you uncheck this, shielded transactions will not appear in the transactions tab.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="0" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="chkAutoShield">
|
|
||||||
<property name="text">
|
|
||||||
<string>Shield change from t-Addresses to your sapling address</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="16" column="0" colspan="2">
|
|
||||||
<widget class="Line" name="line_2">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="8" column="0" colspan="2">
|
|
||||||
<widget class="QLabel" name="lblTor">
|
|
||||||
<property name="text">
|
|
||||||
<string>Connect to the Tor network via SOCKS proxy running on 127.0.0.1:9050. Please note that you'll have to install and run the Tor service externally.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="17" column="0" colspan="2">
|
|
||||||
<spacer name="verticalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="0">
|
|
||||||
<widget class="QCheckBox" name="chkTor">
|
|
||||||
<property name="text">
|
|
||||||
<string>Connect via Tor</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QCheckBox" name="chkCustomFees">
|
|
||||||
<property name="text">
|
|
||||||
<string>Allow custom fees</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="11" column="0" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="chkFetchPrices">
|
|
||||||
<property name="text">
|
|
||||||
<string>Fetch hush / USD prices</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="15" column="0">
|
|
||||||
<widget class="QLabel" name="label_20">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Theme</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="15" column="1">
|
|
||||||
<widget class="QComboBox" name="comboBoxTheme">
|
<widget class="QComboBox" name="comboBoxTheme">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
@@ -333,6 +116,76 @@
|
|||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="chkFetchPrices">
|
||||||
|
<property name="text">
|
||||||
|
<string>Fetch hush / USD prices</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="chkCheckUpdates">
|
||||||
|
<property name="text">
|
||||||
|
<string>Check github for updates at startup</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Connect to github on startup to check for updates</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_20">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Theme</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0" colspan="2">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0" colspan="2">
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Connect to the internet to fetch hush prices</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="tab_3">
|
<widget class="QWidget" name="tab_3">
|
||||||
@@ -341,37 +194,6 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="5" column="0">
|
<item row="5" column="0">
|
||||||
<widget class="QCheckBox" name="chkReindex">
|
|
||||||
<property name="text">
|
|
||||||
<string>Reindex</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_9">
|
|
||||||
<property name="text">
|
|
||||||
<string>Rescan the blockchain for any missing wallet transactions and to correct your wallet balance. This may take several hours. You need to restart silentdragon for this to take effect</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QCheckBox" name="chkRescan">
|
|
||||||
<property name="text">
|
|
||||||
<string>Rescan</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="Line" name="line_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="9" column="0">
|
|
||||||
<spacer name="verticalSpacer_3">
|
<spacer name="verticalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@@ -385,33 +207,26 @@
|
|||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_12">
|
<widget class="Line" name="line_3">
|
||||||
<property name="text">
|
<property name="orientation">
|
||||||
<string/>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_11">
|
<widget class="QLabel" name="label_9">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Rebuild the entire blockchain from the genesis block, by rescanning all the block files. This may take several hours to days, depending on your hardware. You need to restart silentdragon for this to take effect</string>
|
<string>Rescan the blockchain for any missing wallet transactions and to correct your wallet balance. This may take several hours. You need to restart hushWallet for this to take effect</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="Line" name="line_4">
|
<widget class="QCheckBox" name="chkRescan">
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="0">
|
|
||||||
<widget class="QLabel" name="label_13">
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string>Rescan</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -69,10 +69,20 @@ bool TxTableModel::exportToCsv(QString fileName) const {
|
|||||||
return headers.size();
|
return headers.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString TxTableModel::concatMultipleMemos(const TransactionItem& dat) const {
|
||||||
|
// Concat all the memos
|
||||||
|
QString memo;
|
||||||
|
for (auto item : dat.items) {
|
||||||
|
if (!item.memo.trimmed().isEmpty()) {
|
||||||
|
memo += item.address + ": \"" + item.memo + "\"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVariant TxTableModel::data(const QModelIndex &index, int role) const
|
return memo;
|
||||||
{
|
};
|
||||||
// Align numeric columns (confirmations, amount) right
|
|
||||||
|
QVariant TxTableModel::data(const QModelIndex &index, int role) const {
|
||||||
|
// Align numeric columns (confirmations, amount) right
|
||||||
if (role == Qt::TextAlignmentRole &&
|
if (role == Qt::TextAlignmentRole &&
|
||||||
(index.column() == Column::Confirmations || index.column() == Column::Amount))
|
(index.column() == Column::Confirmations || index.column() == Column::Amount))
|
||||||
return QVariant(Qt::AlignRight | Qt::AlignVCenter);
|
return QVariant(Qt::AlignRight | Qt::AlignVCenter);
|
||||||
@@ -105,11 +115,11 @@ bool TxTableModel::exportToCsv(QString fileName) const {
|
|||||||
case Column::Confirmations: return QString::number(dat.confirmations);
|
case Column::Confirmations: return QString::number(dat.confirmations);
|
||||||
case Column::Amount: {
|
case Column::Amount: {
|
||||||
// Sum up all the amounts
|
// Sum up all the amounts
|
||||||
double total = 0;
|
CAmount total;
|
||||||
for (int i=0; i < dat.items.length(); i++) {
|
for (int i=0; i < dat.items.length(); i++) {
|
||||||
total += dat.items[i].amount;
|
total = total + dat.items[i].amount;
|
||||||
}
|
}
|
||||||
return Settings::gethushDisplayFormat(total);
|
return total.toDecimalhushString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +137,7 @@ bool TxTableModel::exportToCsv(QString fileName) const {
|
|||||||
(memo.isEmpty() ? "" : " tx memo: \"" + memo + "\"");
|
(memo.isEmpty() ? "" : " tx memo: \"" + memo + "\"");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return "Multiple";
|
return concatMultipleMemos(dat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Column::Address: {
|
case Column::Address: {
|
||||||
@@ -141,11 +151,11 @@ bool TxTableModel::exportToCsv(QString fileName) const {
|
|||||||
case Column::Confirmations: return QString("%1 Network Confirmations").arg(QString::number(dat.confirmations));
|
case Column::Confirmations: return QString("%1 Network Confirmations").arg(QString::number(dat.confirmations));
|
||||||
case Column::Amount: {
|
case Column::Amount: {
|
||||||
// Sum up all the amounts
|
// Sum up all the amounts
|
||||||
double total = 0;
|
CAmount total;
|
||||||
for (int i=0; i < dat.items.length(); i++) {
|
for (int i=0; i < dat.items.length(); i++) {
|
||||||
total += dat.items[i].amount;
|
total = total + dat.items[i].amount;
|
||||||
}
|
}
|
||||||
return Settings::getInstance()->getUSDFormat(total);
|
return total.toDecimalUSDString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,20 +212,8 @@ QString TxTableModel::getTxId(int row) const {
|
|||||||
|
|
||||||
QString TxTableModel::getMemo(int row) const {
|
QString TxTableModel::getMemo(int row) const {
|
||||||
auto dat = modeldata->at(row);
|
auto dat = modeldata->at(row);
|
||||||
bool hasMemo = false;
|
|
||||||
for (int i=0; i < dat.items.length(); i++) {
|
|
||||||
if (!dat.items[i].memo.isEmpty()) {
|
|
||||||
hasMemo = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dat.items.length() == 1) {
|
return concatMultipleMemos(dat);
|
||||||
return dat.items[0].memo;
|
|
||||||
} else if (hasMemo) {
|
|
||||||
return "(Multiple)";
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 TxTableModel::getConfirmations(int row) const {
|
qint64 TxTableModel::getConfirmations(int row) const {
|
||||||
@@ -237,9 +235,9 @@ QString TxTableModel::getType(int row) const {
|
|||||||
QString TxTableModel::getAmt(int row) const {
|
QString TxTableModel::getAmt(int row) const {
|
||||||
auto dat = modeldata->at(row);
|
auto dat = modeldata->at(row);
|
||||||
|
|
||||||
double total = 0;
|
CAmount total;
|
||||||
for (int i=0; i < dat.items.length(); i++) {
|
for (int i=0; i < dat.items.length(); i++) {
|
||||||
total += dat.items[i].amount;
|
total = total + dat.items[i].amount;
|
||||||
}
|
}
|
||||||
return Settings::getDecimalString(total);
|
return total.toDecimalString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ public:
|
|||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString concatMultipleMemos(const TransactionItem&) const;
|
||||||
|
|
||||||
QList<TransactionItem>* modeldata = nullptr;
|
QList<TransactionItem>* modeldata = nullptr;
|
||||||
|
|
||||||
QList<QString> headers;
|
QList<QString> headers;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define APP_VERSION "0.7.9"
|
#define APP_VERSION "1.0"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "viewalladdresses.h"
|
#include "viewalladdresses.h"
|
||||||
|
#include "camount.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
ViewAllAddressesModel::ViewAllAddressesModel(QTableView *parent, QList<QString> taddrs, Controller* rpc)
|
ViewAllAddressesModel::ViewAllAddressesModel(QTableView *parent, QList<QString> taddrs, Controller* rpc)
|
||||||
@@ -22,7 +23,7 @@ QVariant ViewAllAddressesModel::data(const QModelIndex &index, int role) const {
|
|||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
switch(index.column()) {
|
switch(index.column()) {
|
||||||
case 0: return address;
|
case 0: return address;
|
||||||
case 1: return rpc->getModel()->getAllBalances().value(address, 0.0);
|
case 1: return rpc->getModel()->getAllBalances().value(address, CAmount::fromqint64(0)).toDecimalString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ void AppDataServer::updateUIWithNewQRCode(MainWindow* mainwindow) {
|
|||||||
if (ipv4Addr.isEmpty())
|
if (ipv4Addr.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString uri = "ws://" + ipv4Addr + ":8237";
|
QString uri = "ws://" + ipv4Addr + ":8777";
|
||||||
|
|
||||||
// Get a new secret
|
// Get a new secret
|
||||||
unsigned char* secretBin = new unsigned char[crypto_secretbox_KEYBYTES];
|
unsigned char* secretBin = new unsigned char[crypto_secretbox_KEYBYTES];
|
||||||
@@ -658,9 +658,9 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st
|
|||||||
tx.fee = Settings::getMinerFee();
|
tx.fee = Settings::getMinerFee();
|
||||||
|
|
||||||
// Find a from address that has at least the sending amout
|
// Find a from address that has at least the sending amout
|
||||||
double amt = sendTx["amount"].toString().toDouble();
|
CAmount amt = CAmount::fromDecimalString(sendTx["amount"].toString());
|
||||||
auto allBalances = mainwindow->getRPC()->getModel()->getAllBalances();
|
auto allBalances = mainwindow->getRPC()->getModel()->getAllBalances();
|
||||||
QList<QPair<QString, double>> bals;
|
QList<QPair<QString, CAmount>> bals;
|
||||||
for (auto i : allBalances.keys()) {
|
for (auto i : allBalances.keys()) {
|
||||||
// Filter out sprout addresses
|
// Filter out sprout addresses
|
||||||
if (Settings::getInstance()->isSproutAddress(i))
|
if (Settings::getInstance()->isSproutAddress(i))
|
||||||
@@ -669,7 +669,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st
|
|||||||
if (allBalances.value(i) < amt)
|
if (allBalances.value(i) < amt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bals.append(QPair<QString, double>(i, allBalances.value(i)));
|
bals.append(QPair<QString, CAmount>(i, allBalances.value(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bals.isEmpty()) {
|
if (bals.isEmpty()) {
|
||||||
@@ -677,7 +677,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(bals.begin(), bals.end(), [=](const QPair<QString, double>a, const QPair<QString, double> b) -> bool {
|
std::sort(bals.begin(), bals.end(), [=](const QPair<QString, CAmount>a, const QPair<QString, CAmount> b) -> bool {
|
||||||
// Sort z addresses first
|
// Sort z addresses first
|
||||||
return a.first > b.first;
|
return a.first > b.first;
|
||||||
});
|
});
|
||||||
@@ -736,8 +736,8 @@ void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Max spendable safely from a z address and from any address
|
// Max spendable safely from a z address and from any address
|
||||||
double maxZSpendable = 0;
|
CAmount maxZSpendable;
|
||||||
double maxSpendable = 0;
|
CAmount maxSpendable;
|
||||||
for (auto a : mainWindow->getRPC()->getModel()->getAllBalances().keys()) {
|
for (auto a : mainWindow->getRPC()->getModel()->getAllBalances().keys()) {
|
||||||
if (Settings::getInstance()->isSaplingAddress(a)) {
|
if (Settings::getInstance()->isSaplingAddress(a)) {
|
||||||
if (mainWindow->getRPC()->getModel()->getAllBalances().value(a) > maxZSpendable) {
|
if (mainWindow->getRPC()->getModel()->getAllBalances().value(a) > maxZSpendable) {
|
||||||
@@ -751,16 +751,16 @@ void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std
|
|||||||
|
|
||||||
setConnectedName(connectedName);
|
setConnectedName(connectedName);
|
||||||
|
|
||||||
auto r = QJsonDocument(QJsonObject{
|
auto r = QJsonDocument(QJsonObject {
|
||||||
{"version", 1.0},
|
{"version", 1.0},
|
||||||
{"command", "getInfo"},
|
{"command", "getInfo"},
|
||||||
{"saplingAddress", mainWindow->getRPC()->getDefaultSaplingAddress()},
|
{"saplingAddress", mainWindow->getRPC()->getDefaultSaplingAddress()},
|
||||||
{"tAddress", mainWindow->getRPC()->getDefaultTAddress()},
|
{"tAddress", mainWindow->getRPC()->getDefaultTAddress()},
|
||||||
{"balance", AppDataModel::getInstance()->getTotalBalance()},
|
{"balance", AppDataModel::getInstance()->getTotalBalance().toDecimalDouble()},
|
||||||
{"maxspendable", maxSpendable},
|
{"maxspendable", maxSpendable.toDecimalDouble()},
|
||||||
{"maxzspendable", maxZSpendable},
|
{"maxzspendable", maxZSpendable.toDecimalDouble()},
|
||||||
{"tokenName", Settings::getTokenName()},
|
{"tokenName", Settings::getTokenName()},
|
||||||
{"hushprice", Settings::getInstance()->gethushPrice()},
|
{"zecprice", Settings::getInstance()->getZECPrice()},
|
||||||
{"serverversion", QString(APP_VERSION)}
|
{"serverversion", QString(APP_VERSION)}
|
||||||
}).toJson();
|
}).toJson();
|
||||||
pClient->sendTextMessage(encryptOutgoing(r));
|
pClient->sendTextMessage(encryptOutgoing(r));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
#include "camount.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mobileappconnector.h"
|
#include "ui_mobileappconnector.h"
|
||||||
|
|
||||||
@@ -151,11 +152,11 @@ public:
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
double getTBalance() { return balTransparent; }
|
CAmount getTBalance() { return balTransparent; }
|
||||||
double getZBalance() { return balShielded; }
|
CAmount getZBalance() { return balShielded; }
|
||||||
double getTotalBalance() { return balTotal; }
|
CAmount getTotalBalance() { return balTotal; }
|
||||||
|
|
||||||
void setBalances(double transparent, double shielded) {
|
void setBalances(CAmount transparent, CAmount shielded) {
|
||||||
balTransparent = transparent;
|
balTransparent = transparent;
|
||||||
balShielded = shielded;
|
balShielded = shielded;
|
||||||
balTotal = balTransparent + balShielded;
|
balTotal = balTransparent + balShielded;
|
||||||
@@ -164,9 +165,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
AppDataModel() = default; // Private, for singleton
|
AppDataModel() = default; // Private, for singleton
|
||||||
|
|
||||||
double balTransparent;
|
CAmount balTransparent;
|
||||||
double balShielded;
|
CAmount balShielded;
|
||||||
double balTotal;
|
CAmount balTotal;
|
||||||
|
|
||||||
QString saplingAddress;
|
QString saplingAddress;
|
||||||
|
|
||||||
|
|||||||