Compare commits

...

115 Commits

Author SHA1 Message Date
dsc 858a76f0b4 Wownero fork
3 years ago
tobtoht 72f33da508 Merge pull request 'Improve row background color contrast for QDarkStyle' (#179) from tobtoht/feather:darkstyle_readability into master
4 years ago
tobtoht 480ecfd047 Improve row background color contrast for QDarkStyle
4 years ago
tobtoht 1a6024c697 Merge pull request 'MorphToken: Add Qr code for deposit address' (#178) from tobtoht/feather:morphtoken_qr into master
4 years ago
tobtoht a11dd576e4 MorphToken: Add Qr code for deposit address
4 years ago
tobtoht 9fed3eb171 Merge pull request 'update PKGBUILD' (#177) from wowario/feather:master into master
4 years ago
wowario 20156a7440
update PKGBUILD
4 years ago
tobtoht ca5b1df7df Merge pull request 'XMRig: don't disable mining on Tails' (#176) from tobtoht/feather:xmrig_mining_tails into master
4 years ago
tobtoht 474ee2100c XMRig: don't disable mining on Tails
4 years ago
tobtoht 1ccedea1dd Merge pull request 'Settings: temporarily remove warn on update checkbox' (#175) from tobtoht/feather:settings_update into master
4 years ago
tobtoht 70dd25c477 Settings: temporarily remove warn on update checkbox
4 years ago
tobtoht bce983a6a5 Merge pull request 'Menu: add shortcuts' (#174) from tobtoht/feather:shortcuts into master
4 years ago
tobtoht eb8d150a9d Menu: add shortcuts
4 years ago
tobtoht 841739cee9 Merge pull request 'SeedDialog: show restore height for 25 word seeds' (#173) from tobtoht/feather:seed_restore_height into master
4 years ago
tobtoht d4dbc748c8 SeedDialog: show restore height for 25 word seeds
4 years ago
tobtoht 5ce6c8933d Merge pull request 'MorphToken: get rates' (#171) from tobtoht/feather:morphtoken_rates into master
4 years ago
tobtoht f61355c409 MorphToken: get rates
4 years ago
tobtoht edad1928ab Merge pull request 'TickerWidget: Format fiat currency using locale' (#170) from tobtoht/feather:ticker_locale into master
4 years ago
tobtoht 4201167477 TickerWidget: Format fiat currency using locale
4 years ago
tobtoht 16414ba2e9 Merge pull request 'Send: Always include pref. currency in combobox' (#169) from tobtoht/feather:send_pref_cur into master
4 years ago
tobtoht 1d001322cc Send: Always include pref. currency in combobox
4 years ago
tobtoht 9d781d1b57 Merge pull request 'VerifyProofDialog: minor fixes' (#166) from tobtoht/feather:tx_proof_width into master
4 years ago
tobtoht 3453e5ef34 Merge pull request 'WalletInfoDialog: fix open wallet directory on macOS' (#168) from tobtoht/feather:open_url into master
4 years ago
tobtoht 76da957b81 Merge pull request 'Settings: raise window' (#167) from tobtoht/feather:settings_bring_to_front into master
4 years ago
tobtoht 35438792a0 Settings: raise window
4 years ago
tobtoht 01966df866 WalletInfoDialog: fix open wallet directory on macOS
4 years ago
tobtoht e2eb32ce78 VerifyProofDialog: minor fixes
4 years ago
tobtoht 03f484c2ae Merge pull request 'PasswordDialog: show warning if password incorrect' (#165) from tobtoht/feather:incorrect_password into master
4 years ago
tobtoht c44ee73ed0 PasswordDialog: show warning if password incorrect
4 years ago
tobtoht e6e669845c Merge pull request 'Misc networking fixes' (#160) from tobtoht/feather:nodes into master
4 years ago
tobtoht 5a08bc353e Misc networking fixes
4 years ago
tobtoht c8bc66a287 Merge pull request 'DebugInfoDialog: add target height' (#159) from tobtoht/feather:target-height into master
4 years ago
tobtoht 3beb470bbd DebugInfoDialog: add target height
4 years ago
tobtoht b875ee362e Merge pull request 'Menu: remove About QT' (#157) from tobtoht/feather:about_qt into master
4 years ago
tobtoht 4e3a977995 Menu: remove About QT
4 years ago
tobtoht eb801ed9d4 Merge pull request 'Mitigate target_height denial of service attack in wsMode' (#156) from tobtoht/feather:target_height into master
4 years ago
tobtoht d9dfef021f Mitigate target_height attack
4 years ago
tobtoht d2d3978de6 Change websocket .onion
4 years ago
tobtoht 02f7249e6e Merge pull request 'Revert "Syncing hotfix"' (#154) from tobtoht/feather:sync_hotfix into master
4 years ago
tobtoht a3309cea91 Revert "Syncing hotfix"
4 years ago
tobtoht 137ef6da72 Merge pull request 'Syncing hotfix' (#153) from tobtoht/feather:sync_hotfix into master
4 years ago
tobtoht 4f56147319 Syncing hotfix
4 years ago
tobtoht d58259cefe Merge pull request 'Receive: Fix qr code segfault' (#152) from tobtoht/feather:qr_code_crash into master
4 years ago
tobtoht 9be79bba48 Receive: Fix qr code segfault
4 years ago
tobtoht 64db32dca9 Wallet: do not emit updated on refresh
4 years ago
tobtoht 774b4ed15f Merge pull request 'DebugInfoDialog: make some text selectable' (#151) from tobtoht/feather:text_select into master
4 years ago
tobtoht d337653e53 DebugInfoDialog: make some text selectable
4 years ago
tobtoht b06b7fca2a Merge pull request 'Add missing license headers' (#150) from tobtoht/feather:missing_licence into master
4 years ago
tobtoht 169720002c Add missing license headers
4 years ago
tobtoht d7135393cd Merge pull request 'PasswordDialog: misc improvements' (#149) from tobtoht/feather:password_dialog into master
4 years ago
tobtoht 1e4a442b16 PasswordDialog: misc improvements
4 years ago
tobtoht 519df3f5a1 Merge pull request 'Nodes: don't connect to out of sync nodes in wsmode' (#148) from tobtoht/feather:node_height_mode into master
4 years ago
tobtoht 2a03ca9eda Nodes: don't connect to out of sync nodes in wsmode
4 years ago
tobtoht ff5dff26bb Merge pull request 'SeedDialog: add 25 word seed toggle' (#147) from tobtoht/feather:seed_25 into master
4 years ago
tobtoht cbd29e6290 Merge pull request 'MorphToken: allow disabling module' (#146) from tobtoht/feather:morphtoken into master
4 years ago
tobtoht 0f3c005b60 SeedDialog: add 25 word seed toggle
4 years ago
tobtoht 39c1d3bbf7 MorphToken: allow disabling module
4 years ago
tobtoht b66aceccc8 Merge pull request 'Initial MorphToken support' (#145) from tobtoht/feather:morphtoken into master
4 years ago
tobtoht e9a4a828d6 Initial MorphToken support
4 years ago
tobtoht bd60e30c3f Merge pull request 'Import transaction' (#143) from tobtoht/feather:import_tx into master
4 years ago
tobtoht 046b2cfc4c Import transaction
4 years ago
tobtoht 24133ac390 Merge pull request 'History: don't show copy spend proof on incoming transactions' (#115) from mrdeveloper/feather:hide-spend-proof-incoming-tx into master
4 years ago
tobtoht 8aecf79647 Merge pull request 'TransactionInfoDialog: add copy spendproof, in/outproof' (#142) from tobtoht/feather:txproof into master
4 years ago
tobtoht 780a35fabe TransactionInfoDialog: add copy spendproof, in/outproof
4 years ago
mrdeveloper 0e7c773bfd Remove unused declared method
4 years ago
mrdeveloper 11f8406be3 History: don't show copy spend proof on incoming transactions
4 years ago
tobtoht 2c99454565 Merge pull request 'FutureScheduler: update with upstream v0.17.1.3' (#141) from tobtoht/feather:scheduler into master
4 years ago
tobtoht cd96abe545 FutureScheduler: update with upstream v0.17.1.3
4 years ago
tobtoht d76b688ec4 Merge pull request 'Libwalletqt: update with upstream' (#140) from tobtoht/feather:libwalletqt_syncing into master
4 years ago
tobtoht ed47e8e05c Merge pull request 'Added cryptonote-social mining pool to XMRig' (#136) from mrdeveloper/feather:cryptonote-social into master
4 years ago
tobtoht 268b87a803 Libwalletqt: update with upstream
4 years ago
tobtoht 318690681b Merge pull request 'Update for v0.17.1.3' (#139) from tobtoht/feather:v0.17.1.3 into master
4 years ago
tobtoht b1e37e714d Update for v0.17.1.3
4 years ago
mrdeveloper 18b514351d Added cryptonote-social mining pool to XMRig
4 years ago
tobtoht 63c120bdb0 Merge pull request 'Stylesheets: Breeze: misc fixes' (#135) from tobtoht/feather:stylesheet_breeze_fixes into master
4 years ago
tobtoht 96409ecc17 Stylesheets: Breeze: misc fixes
4 years ago
tobtoht c1cba44cba Merge pull request 'AppContext: updateBalance: don't throw runtime error' (#134) from tobtoht/feather:no_runtime_error into master
4 years ago
tobtoht 7a1ac42b1e AppContext: updateBalance: don't throw runtime error
4 years ago
tobtoht 87fd142ffd Merge pull request 'Settings: add hide balance feature' (#133) from tobtoht/feather:hide_balance into master
4 years ago
tobtoht 62ad0d9527 Settings: add hide balance feature
4 years ago
tobtoht 4f9e4ac93d Merge pull request 'Utils: add blockchair.com block explorer' (#132) from tobtoht/feather:blockchair into master
4 years ago
tobtoht cb6f2873a9 Utils: add blockchair.com block explorer
4 years ago
tobtoht 20b741d30d Merge pull request 'Coins: numerical sort for amount column' (#105) from tobtoht/feather:coins_amount_sort into master
4 years ago
tobtoht 7ed2ff15d5 Merge pull request 'CCSWidget: fix misspelling' (#131) from tobtoht/feather:fix_ccs into master
4 years ago
tobtoht da4b2d16ef CCSWidget: fix misspelling
4 years ago
tobtoht 4521223413 Merge pull request 'Simplify and remove white space on recipient (Pay to)' (#124) from mrdeveloper/feather:simplified-recipient-addr into master
4 years ago
mrdeveloper 0dd81c4873 Simplify and remove white space on recipient (Pay to)
4 years ago
dsc df2ff26c0f Merge pull request 'MacOS: add touchbar support' (#121) from dsc/feather:macos-touchbar-submodule into master
4 years ago
mrdeveloper e657e2a6b0 MacOS: add touchbar support
4 years ago
dsc 34a63897d6 Merge pull request 'BugFix: show message box if no wallet is selected' (#118) from mrdeveloper/feather:bug-wallet-select into master
4 years ago
dsc 6279591d1b Merge pull request 'Check if given node URL has https so we can append https for get_info call' (#120) from mrdeveloper/feather:node-check-for-https into master
4 years ago
mrdeveloper 403b8140b3 Check if given node URL has https so we can append https for get_info call
4 years ago
mrdeveloper 71ba9f6d4a BugFix: show message box if no wallet is selected
4 years ago
dsc 3d5dae1f42 Merge pull request 'Coins: disable sweep instead of hide when output unconfirmed' (#111) from tobtoht/feather:coins_hide_sweep into master
4 years ago
tobtoht 78eabc5ae7 Coins: disable sweep instead of hide when output unconfirmed
4 years ago
dsc 485fb89941 Merge pull request 'Include QtMultimedia for buildbots' (#108) from dsc/feather:include-qtmultimedia into master
4 years ago
dsc df280cdd91 Merge pull request 'Write proper .exe on Windows' (#109) from dsc/feather:write-exe-windows into master
4 years ago
dsc 9b96ece2f9 Merge pull request 'XMRig: Donate level 1' (#110) from dsc/feather:xmrig-donate-level into master
4 years ago
dsc a44087b750
XMRig: Donate level 1
4 years ago
dsc 70cbf59ce8
Write proper .exe on Windows
4 years ago
dsc 4aeaf2660f
Include QtMultimedia for buildbots
4 years ago
tobtoht 9b7849c5be Coins: numerical sort for amount column
4 years ago
tobtoht 51a0f86652 Move cdiv to globals.h
4 years ago
dsc fa6ee35fb0 Merge pull request 'Mainwindow: fix tab order and stylization' (#104) from tobtoht/feather:tabs_order into master
4 years ago
tobtoht b1160280fe Mainwindow: fix tab order and stylization
4 years ago
tobtoht 7441d6cb4a Merge pull request 'XMRig: fix stop on windows' (#102) from tobtoht/feather:xmrrig_stop_windows into master
4 years ago
mrdeveloper 23000c6e60 Merge pull request 'PasswordDialog: Show wallet name' (#103) from mrdeveloper/feather:password-dialog-show-wallet-name into master
4 years ago
mrdeveloper 75edc6e5bb Merge branch 'master' into password-dialog-show-wallet-name
4 years ago
mrdeveloper 06f649cbb7 Merge pull request 'Contacts: import via csv file' (#100) from mrdeveloper/feather:contacts-import-csv into master
4 years ago
tobtoht ff78b5a6c2 XMRig: fix stop on windows
4 years ago
mrdeveloper 47d965c6cd Make format csv import as same as export
4 years ago
mrdeveloper d6c26d4159 PasswordDialog: Show wallet name
4 years ago
mrdeveloper 78516f4546 Contacts: import via csv file
4 years ago
dsc 49f072eea4 Merge pull request 'TransactionInfoDialog: add tx key' (#96) from tobtoht/feather:tx_key into master
4 years ago
tobtoht 302c258e6b TransactionInfoDialog: add tx key
4 years ago

@ -28,21 +28,21 @@ steps:
- name: files_linux_release
path: /files
commands:
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export FN="feather-wow-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
- mkdir -p "$TARGET_DIR"
- echo "writing to $TARGET_DIR/$FN"
- strip -s build/bin/feather
- zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather
- echo "[*] written to https://build.featherwallet.org/files/linux-release/$DRONE_SOURCE_BRANCH/$FN"
- strip -s build/bin/feather-wow
- zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather-wow
- echo "[*] written to https://build.featherwallet.org/files-wow/linux-release/$DRONE_SOURCE_BRANCH/$FN"
volumes:
- name: ccache_linux_release
host:
path: /var/drone/ccache_linux_release/
path: /var/drone/ccache_wow_linux_release/
- name: files_linux_release
host:
path: /build/feather_files/files/linux-release/
path: /build/feather-wow_files/files-wow/linux-release/
---
@ -54,7 +54,7 @@ steps:
- name: build
image: feather:appimage
commands:
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export FN="feather-wow-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export BRANCH="$DRONE_SOURCE_BRANCH"
- bash ./contrib/build-appimage.sh
- name: deploy
@ -63,17 +63,18 @@ steps:
- name: files_linux_appimage
path: /files
commands:
- export FN="feather-`git rev-parse --short HEAD`.AppImage"
- find /drone/src/
- export FN="feather-wow-`git rev-parse --short HEAD`.AppImage"
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
- mkdir -p "$TARGET_DIR"
- echo "writing to $TARGET_DIR/$FN"
- mv "Feather-1.0-x86_64.AppImage" "$TARGET_DIR/$FN"
- echo "[*] written to https://build.featherwallet.org/files/linux-release-appimage/$DRONE_SOURCE_BRANCH/$FN"
- mv "Feather-WOW-1.0-x86_64.AppImage" "$TARGET_DIR/$FN"
- echo "[*] written to https://build.featherwallet.org/files-wow/linux-release-appimage/$DRONE_SOURCE_BRANCH/$FN"
volumes:
- name: files_linux_appimage
host:
path: /build/feather_files/files/linux-release-appimage/
path: /build/feather-wow_files/files-wow/linux-release-appimage/
---
@ -105,20 +106,20 @@ steps:
- name: files_win_release
path: /files
commands:
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export FN="feather-wow-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
- mkdir -p "$TARGET_DIR"
- echo "writing to $TARGET_DIR/$FN"
- zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather.exe
- echo "[*] written to https://build.featherwallet.org/files/windows-mxe-release/$DRONE_SOURCE_BRANCH/$FN"
- zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather-wow.exe
- echo "[*] written to https://build.featherwallet.org/files-wow/windows-mxe-release/$DRONE_SOURCE_BRANCH/$FN"
volumes:
- name: ccache_win_release
host:
path: /var/drone/ccache_win_release/
path: /var/drone/ccache_wow_win_release/
- name: files_win_release
host:
path: /build/feather_files/files/windows-mxe-release/
path: /build/feather-wow_files/files-wow/windows-mxe-release/
---
@ -134,26 +135,26 @@ steps:
path: /files
commands:
- mkdir -p build
- scp -P22 utils/build_macos.sh administrator@steve.jobs.xmr.pm:build_macos.sh
- ssh administrator@steve.jobs.xmr.pm "chmod +x build_macos.sh && PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin ~/build_macos.sh $DRONE_COMMIT_SHA"
- scp -P22 administrator@steve.jobs.xmr.pm:feather.zip build/feather.zip
- scp -P22 utils/build_macos.sh administrator@steve.jobs.xmr.pm:build_wow_macos.sh
- ssh administrator@steve.jobs.xmr.pm "chmod +x build_wow_macos.sh && PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin ~/build_wow_macos.sh $DRONE_COMMIT_SHA"
- scp -P22 administrator@steve.jobs.xmr.pm:feather-wow.zip build/feather-wow.zip
- name: deploy
image: feather:mac
volumes:
- name: files_mac_release
path: /files
commands:
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export FN="feather-wow-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
- mkdir -p "$TARGET_DIR"
- echo "writing to $TARGET_DIR/$FN"
- mv build/feather.zip "$TARGET_DIR/$FN"
- echo "[*] written to https://build.featherwallet.org/files/mac-release/$DRONE_SOURCE_BRANCH/$FN"
- mv build/feather-wow.zip "$TARGET_DIR/$FN"
- echo "[*] written to https://build.featherwallet.org/files-wow/mac-release/$DRONE_SOURCE_BRANCH/$FN"
volumes:
- name: files_mac_release
host:
path: /build/feather_files/files/mac-release/
path: /build/feather-wow_files/files-wow/mac-release/
---
kind: signature
hmac: 527d334190a8a824b3b781a05ae4c7d87f4fa2bc37ebc53a96db91f925fa4a52

5
.gitmodules vendored

@ -1,9 +1,12 @@
[submodule "monero"]
path = monero
url = https://git.wownero.com/feather/monero.git
url = https://git.wownero.com/feather/wownero.git
[submodule "contrib/torsocks"]
path = contrib/torsocks
url = https://git.torproject.org/torsocks.git
[submodule "contrib/tor"]
path = contrib/tor
url = https://git.torproject.org/tor.git
[submodule "contrib/KDMacTouchBar"]
path = contrib/KDMacTouchBar
url = https://github.com/KDAB/KDMacTouchBar.git

@ -10,7 +10,7 @@ set(VERSION_REVISION "0")
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}")
option(FETCH_DEPS "Download dependencies if they are not found" ON)
option(XMRTO "Include Xmr.To module" ON)
option(XMRTO "Include Xmr.To module" OFF)
option(XMRIG "Path to XMRig binary to embed inside Feather" OFF)
option(TOR "Path to Tor binary to embed inside Feather" OFF)
option(TOR_VERSION "Optional git hash or tag of embedded Tor version" "tor-0.4.3.5")
@ -30,7 +30,7 @@ if(DEBUG)
set(CMAKE_VERBOSE_MAKEFILE ON)
endif()
set(MONERO_HEAD "a39fd7ea978053929da63dcdb8073806573be5ba")
set(WOWNERO_HEAD "9d6a7bcc14e512ccb04f5f286c1710fca19e4762")
set(BUILD_GUI_DEPS ON)
set(ARCH "x86-64")
set(BUILD_64 ON)
@ -83,11 +83,11 @@ endfunction()
find_package(Git)
if(GIT_FOUND)
execute_process(COMMAND git rev-parse "HEAD" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero OUTPUT_VARIABLE _MONERO_HEAD OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT _MONERO_HEAD STREQUAL MONERO_HEAD)
message(FATAL_ERROR "[submodule] Monero HEAD was at ${_MONERO_HEAD} but should be at ${MONERO_HEAD}")
execute_process(COMMAND git rev-parse "HEAD" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero OUTPUT_VARIABLE _WOWNERO_HEAD OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT _WOWNERO_HEAD STREQUAL WOWNERO_HEAD)
message(FATAL_ERROR "[submodule] Monero HEAD was at ${_WOWNERO_HEAD} but should be at ${WOWNERO_HEAD}")
else()
message(STATUS "[submodule] Monero HEAD @ ${MONERO_HEAD}")
message(STATUS "[submodule] Monero HEAD @ ${WOWNERO_HEAD}")
endif()
endif()

@ -191,7 +191,7 @@ RUN cd /qt-everywhere-src-5.15.0 && \
-skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qttools \
-skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebview \
-skip qtwinextras -skip qtx11extras -skip gamepad -skip serialbus -skip location -skip webengine \
-skip qtdeclarative -skip qtmultimedia \
-skip qtdeclarative \
-no-feature-cups -no-feature-ftp -no-feature-pdf -no-feature-animation \
-nomake examples -nomake tests -nomake tools

@ -50,7 +50,7 @@ RUN apt install -y \
RUN git clone -b feather-patch --depth 1 https://git.wownero.com/feather/mxe.git && \
cd mxe && \
make -j$THREADS MXE_TARGETS='x86_64-w64-mingw32.static' gcc libqrencode pkgconf libgpg_error libgcrypt cmake libsodium lzma readline libzmq boost qtbase qtsvg qtwebsockets qtimageformats
make -j$THREADS MXE_TARGETS='x86_64-w64-mingw32.static' gcc libqrencode pkgconf libgpg_error libgcrypt cmake libsodium lzma readline libzmq boost qtbase qtsvg qtwebsockets qtimageformats qtmultimedia
# plugins
RUN cd mxe && make -j$THREADS MXE_PLUGIN_DIRS='/mxe/plugins/apps/' MXE_TARGETS='x86_64-w64-mingw32.static' tor

@ -42,6 +42,7 @@ via the `CMAKE_PREFIX_PATH` definition. For me this is:
There are some Monero/Feather related options/definitions that you may pass:
- `-DXMRTO=OFF` - disable Xmr.To feature
- `-DMORPHTOKEN=OFF` - diable MorphToken feature
- `-DTOR=/path/to/tor` - Embed a Tor executable inside Feather
- `-DXMRIG=/path/to/xmrig` - Embed a XMRig executable inside Feather
- `-DDONATE_BEG=OFF` - disable the dreaded donate requests

@ -30,7 +30,7 @@ CMAKEFLAGS = \
-DARCH=x86_64 \
-DBUILD_64=On \
-DBUILD_TESTS=Off \
-DXMRTO=ON \
-DXMRTO=Off \
-DXMRIG=Off \
-DTOR=Off \
-DCMAKE_CXX_STANDARD=11 \
@ -73,4 +73,4 @@ mac-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
mac-release:
cmake -Bbuild $(CMAKEFLAGS)
$(MAKE) -Cbuild
$(MAKE) -Cbuild deploy
$(MAKE) -Cbuild deploy

@ -1,16 +1,15 @@
# Maintainer: wowario <wowario[at]protonmail[dot]com>
# Contributor: wowario <wowario[at]protonmail[dot]com>
pkgbase=('monero-feather-git')
pkgname=('monero-feather-git')
pkgver=v0.1.0.0.cd1cd5cb75
pkgrel=1
pkgdesc="a free Monero desktop wallet"
pkgbase='monero-feather-git'
pkgname='monero-feather-git'
pkgver='v0.1.0.0.ca5b1df7df'
pkgrel='1'
pkgdesc='a free Monero desktop wallet'
license=('BSD')
arch=('x86_64')
url="https://featherwallet.org"
depends=('boost-libs' 'libunwind' 'openssl' 'readline' 'zeromq' 'pcsclite' 'hidapi' 'protobuf' 'miniupnpc'
'libgcrypt' 'qrencode' 'ccache' 'libsodium' 'libpgm' 'expat' 'base-devel' 'qt5-base')
depends=('boost-libs' 'libunwind' 'openssl' 'readline' 'zeromq' 'pcsclite' 'hidapi' 'protobuf' 'miniupnpc' 'libgcrypt' 'qrencode' 'ccache' 'libsodium' 'libpgm' 'expat' 'qt5-base' 'qt5-websockets' 'tor')
makedepends=('git' 'cmake' 'boost')
provides=('monero-feather-git')
@ -18,17 +17,16 @@ source=("${pkgname}"::"git+https://git.wownero.com/feather/feather")
sha256sums=('SKIP')
pkgver() {
cd "$srcdir/$pkgname"
git describe --long --tags | sed 's/\([^-]*-\)g/r\1/;s/-/./g'
}
build() {
cd "${srcdir}/${pkgname}"
mkdir build && cd build && cmake .. && make release-static -j2
git submodule update --init --recursive
mkdir build
cd build
cmake ..
make -j2
}
package_feather-git() {
package_monero-feather-git() {
install -Dm644 "${srcdir}/${pkgname}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
install -Dm755 "${srcdir}/${pkgname}/build/bin/feather" "${pkgdir}/usr/bin/feather"
}

@ -1,35 +1,13 @@
# Feather - a free Monero desktop wallet
# Feather-WOW - a free Wownero desktop wallet
[![Build Status](https://build.featherwallet.org/api/badges/feather/feather/status.svg)](https://build.featherwallet.org/feather/feather)
[![Build Status](https://build.featherwallet.org/api/badges/feather/feather-wow/status.svg)](https://build.featherwallet.org/feather/feather-wow)
Feather is a free, open-source Monero client Linux with ports for Mac OS and Windows written in C++ with the Qt framework. It is created and maintained by [dsc](dsc@xmr.pm) and [tobtoht](thotbot@protonmail.com).
Feather is a free, open-source Wownero client for Linux with ports for Mac OS and Windows.
## Development resources
* Web: [featherwallet.org](https://featherwallet.org)
* Git: [git.wownero.com/feather/feather](https://git.wownero.com/feather/feather)
* Git: [git.wownero.com/feather/feather-wow](https://git.wownero.com/feather/feather-wow)
* IRC: `#feather` on OFTC
* Development builds: [build.featherwallet.org/files](https://build.featherwallet.org/files/)
* Development builds: [build.featherwallet.org/files-wow](https://build.featherwallet.org/files-wow/)
Copyright (c) 2020-2021 The Monero Project.
## Compiling Feather from source
Feather uses Monero, as such it requires the same dependencies as outlined in [Monero's README](https://github.com/monero-project/monero#compiling-monero-from-source). Additionally, Feather uses:
- Qt 5.15.0
- libqrencode
- openpgp
See [BUILDING.md](https://git.wownero.com/feather/feather/src/branch/master/BUILDING.md) for information on how to compile a build.
## Supporting the project
Feather is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially.
`47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f`
## Developers
See [HACKING.md](https://git.wownero.com/feather/feather/src/branch/master/HACKING.md) for useful development resources.
It is HIGHLY recommended that you join the `#feather` IRC channel on OFTC if you are hacking on Feather. Due to the nature of this open source software project, joining this channel and idling is the best way to stay updated on best practices and new developments.

@ -7,7 +7,7 @@ if(APPLE OR (WIN32 AND NOT STATIC))
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
add_custom_command(TARGET deploy
POST_BUILD
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "$<TARGET_FILE_DIR:feather>/../.." -always-overwrite
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "$<TARGET_FILE_DIR:feather-wow>/../.." -always-overwrite
COMMENT "Running macdeployqt..."
)
@ -16,11 +16,11 @@ if(APPLE OR (WIN32 AND NOT STATIC))
if(_qt_svg_dylib)
add_custom_command(TARGET deploy
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${_qt_svg_dylib} $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtGui.framework/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/libqsvg.dylib
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtWidgets.framework/Versions/5/QtWidgets" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/libqsvg.dylib
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtSvg.framework/Versions/5/QtSvg" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/libqsvg.dylib
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtCore.framework/Versions/5/QtCore" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/libqsvg.dylib
COMMAND ${CMAKE_COMMAND} -E copy ${_qt_svg_dylib} $<TARGET_FILE_DIR:feather-wow>/../PlugIns/imageformats/
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtGui.framework/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather-wow>/../PlugIns/imageformats/libqsvg.dylib
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtWidgets.framework/Versions/5/QtWidgets" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather-wow>/../PlugIns/imageformats/libqsvg.dylib
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtSvg.framework/Versions/5/QtSvg" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather-wow>/../PlugIns/imageformats/libqsvg.dylib
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtCore.framework/Versions/5/QtCore" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather-wow>/../PlugIns/imageformats/libqsvg.dylib
COMMENT "Copying libqsvg.dylib, running install_name_tool"
)
endif()

@ -0,0 +1 @@
Subproject commit 470c4316460bb8c3e23bfa37c79c8621ef3f1b4c

@ -21,20 +21,20 @@ function download_if_not_exist() {
fi
}
APPDIR="$PWD/feather.AppDir"
APPDIR="$PWD/feather-wow.AppDir"
mkdir -p "$APPDIR"
mkdir -p "$APPDIR/usr/share/applications/"
mkdir -p "$APPDIR/usr/bin"
echo "Downloading dependencies"
download_if_not_exist "feather.zip" "https://build.featherwallet.org/files/linux-release/$BRANCH/$FN"
unzip -q feather.zip
download_if_not_exist "feather-wow.zip" "https://build.featherwallet.org/files-wow/linux-release/$BRANCH/$FN"
unzip -q feather-wow.zip
cp "$PWD/src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop"
cp "$PWD/src/assets/images/appicons/64x64.png" "$APPDIR/feather.png"
cp "$PWD/feather" "$APPDIR/usr/bin/feather"
cp "$PWD/src/assets/feather-wow.desktop" "$APPDIR/usr/share/applications/feather-wow.desktop"
cp "$PWD/src/assets/images/appicons/64x64.png" "$APPDIR/feather-wow.png"
cp "$PWD/feather-wow" "$APPDIR/usr/bin/feather-wow"
/appimagetool deploy "$APPDIR/usr/share/applications/feather.desktop"
VERSION=1.0 /appimagetool ./feather.AppDir
/appimagetool deploy "$APPDIR/usr/share/applications/feather-wow.desktop"
VERSION=1.0 /appimagetool ./feather-wow.AppDir

@ -1 +1 @@
Subproject commit a39fd7ea978053929da63dcdb8073806573be5ba
Subproject commit 9d6a7bcc14e512ccb04f5f286c1710fca19e4762

@ -73,7 +73,7 @@ if(APPLE)
list(APPEND RESOURCES ${ICON})
endif()
add_executable(feather ${EXECUTABLE_FLAG} main.cpp
add_executable(feather-wow ${EXECUTABLE_FLAG} main.cpp
${SOURCE_FILES}
${RESOURCES}
${ASSETS_TOR}
@ -81,21 +81,21 @@ add_executable(feather ${EXECUTABLE_FLAG} main.cpp
)
# mac os bundle
set_target_properties(feather PROPERTIES
set_target_properties(feather-wow PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/utils/Info.plist"
)
set_property(TARGET feather PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set_property(TARGET feather-wow PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
target_include_directories(feather PUBLIC ${OPENGL_INCLUDE_DIR})
target_include_directories(feather PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
target_include_directories(feather-wow PUBLIC ${OPENGL_INCLUDE_DIR})
target_include_directories(feather-wow PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
file(GLOB_RECURSE SRC_SOURCES *.cpp)
file(GLOB_RECURSE SRC_HEADERS *.h)
target_include_directories(feather PUBLIC
target_include_directories(feather-wow PUBLIC
${CMAKE_BINARY_DIR}/src/feather_autogen/include
${CMAKE_SOURCE_DIR}/monero/include
${CMAKE_SOURCE_DIR}/monero/src
@ -122,38 +122,46 @@ target_include_directories(feather PUBLIC
)
if(DONATE_BEG)
target_compile_definitions(feather PRIVATE DONATE_BEG=1)
target_compile_definitions(feather-wow PRIVATE DONATE_BEG=1)
endif()
if(XMRTO)
target_compile_definitions(feather PRIVATE XMRTO=1)
target_compile_definitions(feather-wow PRIVATE XMRTO=1)
endif()
if(MORPHTOKEN)
target_compile_definitions(feather PRIVATE HAS_MORPHTOKEN=1)
endif()
if(TOR)
target_compile_definitions(feather PRIVATE HAS_TOR=1)
target_compile_definitions(feather-wow PRIVATE HAS_TOR=1)
endif()
if(XMRIG)
target_compile_definitions(feather PRIVATE HAS_XMRIG=1)
target_compile_definitions(feather-wow PRIVATE HAS_XMRIG=1)
endif()
if(HAVE_SYS_PRCTL_H)
target_compile_definitions(feather PRIVATE HAVE_SYS_PRCTL_H=1)
target_compile_definitions(feather-wow PRIVATE HAVE_SYS_PRCTL_H=1)
endif()
if(STATIC)
target_compile_definitions(feather-wow PRIVATE STATIC=1)
endif()
if(STATIC)
target_compile_definitions(feather PRIVATE STATIC=1)
target_compile_definitions(feather-wow PRIVATE STATIC=1)
endif()
if("$ENV{DRONE}" STREQUAL "true")
target_compile_definitions(feather PRIVATE DRONE=1)
target_compile_definitions(feather-wow PRIVATE DRONE=1)
endif()
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(feather PRIVATE QT_NO_DEBUG=1)
target_compile_definitions(feather-wow PRIVATE QT_NO_DEBUG=1)
endif()
target_compile_definitions(feather
target_compile_definitions(feather-wow
PUBLIC
${Qt5Core_DEFINITIONS}
${Qt5Widgets_DEFINITIONS}
@ -169,12 +177,12 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
if(UNIX AND NOT APPLE)
# https://stackoverflow.com/questions/57766620/cmake-add-library-doesnt-initialize-static-global-variable
# so that contrib/monero-seed/src/gf_elem.cpp properly initializes. A better solution is welcome.
target_link_libraries(feather -Wl,--whole-archive monero-seed::monero-seed -Wl,--no-whole-archive)
target_link_libraries(feather-wow -Wl,--whole-archive monero-seed::monero-seed -Wl,--no-whole-archive)
else()
target_link_libraries(feather monero-seed::monero-seed)
target_link_libraries(feather-wow monero-seed::monero-seed)
endif()
target_link_libraries(feather
target_link_libraries(feather-wow
wallet_merged
${LMDB_LIBRARY}
epee
@ -201,31 +209,39 @@ target_link_libraries(feather
${QRENCODE_LIBRARY}
)
if(NOT APPLE)
if(APPLE)
target_link_libraries(feather
KDMacTouchBar
)
target_include_directories(feather
PUBLIC ../contrib/KDMacTouchBar)
endif()
if(NOT APPLE)
target_link_libraries(feather-wow
Qt5::QSvgIconPlugin
Qt5::QSvgPlugin
)
endif()
if(STATIC)
target_link_libraries(feather
target_link_libraries(feather-wow
Qt5::QSvgIconPlugin
Qt5::QSvgPlugin)
if(UNIX AND NOT APPLE)
target_link_libraries(feather
target_link_libraries(feather-wow
Qt5::QXcbIntegrationPlugin)
endif()
endif()
if(X11_FOUND)
target_link_libraries(feather ${X11_LIBRARIES})
target_link_libraries(feather-wow ${X11_LIBRARIES})
endif()
if(APPLE)
include(Deploy)
endif()
install(TARGETS feather
install(TARGETS feather-wow
DESTINATION ${CMAKE_INSTALL_PREFIX}
)

@ -0,0 +1,226 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include "MorphTokenWidget.h"
#include "ui_MorphTokenWidget.h"
#include "mainwindow.h"
#include "qrcode/QrCode.h"
#include "dialog/qrcodedialog.h"
#include <QMessageBox>
MorphTokenWidget::MorphTokenWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MorphTokenWidget)
{
ui->setupUi(this);
m_ctx = MainWindow::getContext();
m_network = new UtilsNetworking(this->m_ctx->network);
m_api = new MorphTokenApi(this, m_network);
connect(ui->btnCreateTrade, &QPushButton::clicked, this, &MorphTokenWidget::createTrade);
connect(ui->btn_lookupTrade, &QPushButton::clicked, this, &MorphTokenWidget::lookupTrade);
connect(ui->btn_getRates, &QPushButton::clicked, this, &MorphTokenWidget::getRates);
connect(m_api, &MorphTokenApi::ApiResponse, this, &MorphTokenWidget::onApiResponse);
connect(ui->combo_From, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index){
this->displayRate();
ui->label_refundAddress->setText(QString("Refund address (%1):").arg(ui->combo_From->currentText()));
});
connect(ui->combo_To, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index){
this->displayRate();
ui->label_destinationAddress->setText(QString("Destination address (%1):").arg(ui->combo_To->currentText()));
});
connect(ui->check_autorefresh, &QCheckBox::toggled, [this](bool toggled){
m_countdown = 30;
toggled ? m_countdownTimer.start(1000) : m_countdownTimer.stop();
ui->check_autorefresh->setText("Autorefresh");
});
connect(&m_countdownTimer, &QTimer::timeout, this, &MorphTokenWidget::onCountdown);
connect(ui->line_Id, &QLineEdit::textChanged, [this](const QString &text){
ui->btn_lookupTrade->setEnabled(!text.isEmpty());
ui->check_autorefresh->setEnabled(!text.isEmpty());
});
// Default to BTC -> XMR
ui->combo_From->setCurrentIndex(1);
ui->combo_To->setCurrentIndex(0);
ui->label_rate->setVisible(false);
m_ratesTimer.setSingleShot(true);
connect(&m_ratesTimer, &QTimer::timeout, [this]{
ui->label_rate->setVisible(false);
});
ui->qrCode->setVisible(false);
ui->label_depositAddress->setVisible(false);
connect(ui->qrCode, &ClickableLabel::clicked, this, &MorphTokenWidget::showQrCodeDialog);
ui->tabWidget->setTabVisible(2, false);
}
void MorphTokenWidget::createTrade() {
QString inputAsset = ui->combo_From->currentText();
QString outputAsset = ui->combo_To->currentText();
QString refundAddress = ui->line_refundAddress->text();
QString destinationAddress = ui->line_destinationAddress->text();
m_api->createTrade(inputAsset, outputAsset, refundAddress, destinationAddress);
}
void MorphTokenWidget::lookupTrade() {
QString morphId = ui->line_Id->text();
if (!morphId.isEmpty())
m_api->getTrade(morphId);
}
void MorphTokenWidget::getRates() {
m_api->getRates();
}
void MorphTokenWidget::onApiResponse(const MorphTokenApi::MorphTokenResponse &resp) {
if (!resp.ok) {
ui->check_autorefresh->setChecked(false);
QMessageBox::warning(this, "MorphToken error", QString("Request failed:\n\n%1").arg(resp.message));
return;
}
ui->debugInfo->setPlainText(QJsonDocument(resp.obj).toJson(QJsonDocument::Indented));
bool shouldShowQr = (resp.endpoint == MorphTokenApi::Endpoint::CREATE_TRADE || resp.endpoint == MorphTokenApi::Endpoint::GET_TRADE);
ui->qrCode->setVisible(shouldShowQr);
ui->label_depositAddress->setVisible(shouldShowQr);
if (resp.endpoint == MorphTokenApi::Endpoint::CREATE_TRADE || resp.endpoint == MorphTokenApi::Endpoint::GET_TRADE) {
ui->tabWidget->setCurrentIndex(1);
ui->line_Id->setText(resp.obj.value("id").toString());
auto obj = resp.obj;
auto input = obj["input"].toObject();
auto output = obj["output"].toArray()[0].toObject();
QString state = obj.value("state").toString();
QString statusText;
ui->trade->setTitle(QString("Trade (%1)").arg(state));
statusText += QString("Morph ID: %1\n\n").arg(obj["id"].toString());
if (state == "PENDING") {
statusText += QString("Waiting for a deposit, send %1 to %2\n").arg(input["asset"].toString(),
input["deposit_address"].toString());
statusText += QString("Rate: 1 %1 -> %2 %3\n\n").arg(input["asset"].toString(),
output["seen_rate"].toString(),
output["asset"].toString());
statusText += "Limits:\n";
statusText += QString(" Minimum amount accepted: %1 %2\n").arg(formatAmount(input["asset"].toString(), input["limits"].toObject()["min"].toDouble()),
input["asset"].toString());
statusText += QString(" Maximum amount accepted: %1 %2\n").arg(formatAmount(input["asset"].toString(), input["limits"].toObject()["max"].toDouble()),
input["asset"].toString());
statusText += QString("\nSend a single deposit. If the amount is outside the limits, a refund will happen.");
m_depositAddress = input["deposit_address"].toString();
const QrCode qrc(m_depositAddress, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::MEDIUM);
int width = ui->qrCode->width();
if (qrc.isValid()) {
ui->qrCode->setPixmap(qrc.toPixmap(1).scaled(width, width, Qt::KeepAspectRatio));
}
} else if (state == "PROCESSING" || state == "TRADING" || state == "CONFIRMING") {
if (state == "CONFIRMING") {
statusText += QString("Waiting for confirmations\n");
} else if (state == "TRADING") {
statusText += QString("Your transaction has been received and is confirmed. MorphToken is now executing your trade.\n"
"Usually this step takes no longer than a minute, "
"but in rare cases it can take a couple hours.\n"
"Wait a bit before contacting support.\n");
}
statusText += QString("Converting %1 to %2\n").arg(input["asset"].toString(), output["asset"].toString());
statusText += QString("Sending to %1\n").arg(output["address"].toString());
statusText += QString("Stuck? Contact support at contact@morphtoken.com");
} else if (state == "COMPLETE") {
if (output["txid"].toString().isEmpty()) {
statusText += QString("MorphToken is sending your transaction.\n");
statusText += QString("MorphToken will send %1 %2 to %2").arg(this->formatAmount(output["asset"].toString(), output["converted_amount"].toDouble() - output["network_fee"].toObject()["fee"].toDouble()),
output["asset"].toString(),
output["address"].toString());
} else {
statusText += QString("Sent %1 %2 to %3\ntxid: {}").arg(this->formatAmount(output["asset"].toString(), output["converted_amount"].toDouble() - output["network_fee"].toObject()["fee"].toDouble()),
output["asset"].toString(),
output["address"].toString(),
output["txid"].toString());
}
} else if (state == "PROCESSING_REFUND" || state == "COMPLETE_WITH_REFUND") {
statusText += QString("MorphToken will refund %1 %2\nReason: %3\n").arg(obj["final_amount"].toString(),
obj["asset"].toString(),
obj["reason"].toString());
if (obj.contains("txid")) {
statusText += QString("txid: %1").arg(obj["txid"].toString());
}
} else if (state == "COMPLETE_WITHOUT_REFUND") {
statusText += "Deposit amount below network fee, too small to refund.";
}
ui->label_status->setText(statusText);
} else if (resp.endpoint == MorphTokenApi::Endpoint::GET_RATES) {
m_rates = resp.obj.value("data").toObject();
this->displayRate();
ui->label_rate->setVisible(true);
m_ratesTimer.start(120 * 1000);
}
if (resp.endpoint == MorphTokenApi::Endpoint::CREATE_TRADE) {
QMessageBox::information(this, "MorphToken", "Trade created!\n\nMake sure to save your Morph ID. You may need it in case something goes wrong.");
}
}
void MorphTokenWidget::onCountdown() {
if (m_countdown > 0) {
m_countdown -= 1;
} else {
this->lookupTrade();
m_countdown = 30;
}
ui->check_autorefresh->setText(QString("Autorefresh (%1)").arg(m_countdown));
}
void MorphTokenWidget::displayRate() {
QString inputAsset = ui->combo_From->currentText();
QString outputAsset = ui->combo_To->currentText();
QString outputRate = m_rates.value(inputAsset).toObject().value(outputAsset).toString("1");
QString rateStr = QString("1 %1 -> %2 %3").arg(inputAsset, outputRate, outputAsset);
ui->label_rate->setText(rateStr);
}
void MorphTokenWidget::showQrCodeDialog() {
QrCode qr(m_depositAddress, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::HIGH);
auto *dialog = new QrCodeDialog(this, qr, "Deposit address");
dialog->exec();
dialog->deleteLater();
}
QString MorphTokenWidget::formatAmount(const QString &asset, double amount) {
double displayAmount;
double div;
if (asset == "ETH")
div = 1e18;
else if (asset == "XMR")
div = 1e12;
else
div = 1e8;
displayAmount = amount / div;
return QString::number(displayAmount, 'f', 8);
}
MorphTokenWidget::~MorphTokenWidget() {
delete ui;
}

@ -0,0 +1,47 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_MORPHTOKENWIDGET_H
#define FEATHER_MORPHTOKENWIDGET_H
#include <QWidget>
#include "appcontext.h"
#include "utils/MorphTokenApi.h"
namespace Ui {
class MorphTokenWidget;
}
class MorphTokenWidget : public QWidget
{
Q_OBJECT
public:
explicit MorphTokenWidget(QWidget *parent = nullptr);
~MorphTokenWidget() override;
private:
void createTrade();
void lookupTrade();
void getRates();
void onApiResponse(const MorphTokenApi::MorphTokenResponse &resp);
void onCountdown();
void displayRate();
void showQrCodeDialog();
QString formatAmount(const QString &asset, double amount);
Ui::MorphTokenWidget *ui;
AppContext *m_ctx;
MorphTokenApi *m_api;
UtilsNetworking *m_network;
QTimer m_countdownTimer;
int m_countdown = 30;
QJsonObject m_rates;
QTimer m_ratesTimer;
QString m_depositAddress;
};
#endif //FEATHER_MORPHTOKENWIDGET_H

@ -0,0 +1,423 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MorphTokenWidget</class>
<widget class="QWidget" name="MorphTokenWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1036</width>
<height>614</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="tabCreateTrade">
<attribute name="title">
<string>Create trade</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>From:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="combo_From">
<item>
<property name="text">
<string>XMR</string>
</property>
</item>
<item>
<property name="text">
<string>BTC</string>
</property>
</item>
<item>
<property name="text">
<string>ETH</string>
</property>
</item>
<item>
<property name="text">
<string>BCH</string>
</property>
</item>
<item>
<property name="text">
<string>LTC</string>
</property>
</item>
<item>
<property name="text">
<string>DASH</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>To:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="combo_To">
<item>
<property name="text">
<string>XMR</string>
</property>
</item>
<item>
<property name="text">
<string>BTC</string>
</property>
</item>
<item>
<property name="text">
<string>ETH</string>
</property>
</item>
<item>
<property name="text">
<string>BCH</string>
</property>
</item>
<item>
<property name="text">
<string>LTC</string>
</property>
</item>
<item>
<property name="text">
<string>DASH</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<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>
<widget class="QLabel" name="label_rate">
<property name="text">
<string>rate</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_refundAddress">
<property name="text">
<string>Refund address (XMR):</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="line_refundAddress"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_destinationAddress">
<property name="text">
<string>Destination address (XMR):</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="line_destinationAddress"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Powered by MorphToken.com</string>
</property>
</widget>
</item>
<item>
<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>
<widget class="QPushButton" name="btn_getRates">
<property name="text">
<string>Get Rates</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCreateTrade">
<property name="text">
<string>Create Trade</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<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>
</layout>
</widget>
<widget class="QWidget" name="tabLookupTrade">
<attribute name="title">
<string>Lookup trade</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Morph ID or MorphToken deposit address:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="line_Id"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="check_autorefresh">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Autorefresh</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<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>
<widget class="QPushButton" name="btn_lookupTrade">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Lookup trade</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="trade">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Trade</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_status">
<property name="text">
<string>No trade loaded.</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="ClickableLabel" name="qrCode">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>qrcode</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_depositAddress">
<property name="text">
<string>Deposit address</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</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>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabDebug">
<attribute name="title">
<string>Debug</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QPlainTextEdit" name="debugInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ClickableLabel</class>
<extends>QLabel</extends>
<header>components.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

@ -9,12 +9,14 @@
#include <QDesktopWidget>
#include "appcontext.h"
#include "globals.h"
#include "utils/tails.h"
#include "utils/whonix.h"
#include "utils/utils.h"
#include "utils/prices.h"
#include "utils/networktype.h"
#include "utils/wsclient.h"
#include "utils/config.h"
// libwalletqt
#include "libwalletqt/WalletManager.h"
@ -28,7 +30,6 @@
#include "model/SubaddressModel.h"
#include "utils/keysfiles.h"
#include "utils/networktype.h"
#include "utils/config.h"
Prices *AppContext::prices = nullptr;
@ -60,11 +61,11 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
QString appImagePath = qgetenv("APPIMAGE");
if (appImagePath.isEmpty()) {
qDebug() << "Not an appimage, using currentPath()";
return QDir::currentPath() + "/.feather";
return QDir::currentPath() + "/.feather-wow";
}
QFileInfo appImageDir(appImagePath);
return appImageDir.absoluteDir().path() + "/.feather";
return appImageDir.absoluteDir().path() + "/.feather-wow";
}();
@ -79,10 +80,10 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
this->homeDir = QDir::homePath();
#if defined(Q_OS_LINUX) or defined(Q_OS_MAC)
this->defaultWalletDir = QString("%1/Monero/wallets").arg(this->configRoot);
this->defaultWalletDirRoot = QString("%1/Monero").arg(this->configRoot);
this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->configRoot);
this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->configRoot);
#elif defined(Q_OS_WIN)
this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Monero";
this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Wownero";
this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
#endif
@ -90,7 +91,7 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
if (!QDir().mkpath(defaultWalletDir))
qCritical() << "Unable to create dir: " << defaultWalletDir;
this->configDirectory = QString("%1/.config/feather/").arg(this->configRoot);
this->configDirectory = QString("%1/.config/feather-wow/").arg(this->configRoot);
#if defined(Q_OS_UNIX)
if(!this->configDirectory.endsWith('/'))
this->configDirectory = QString("%1/").arg(this->configDirectory);
@ -100,19 +101,18 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
// Config
createConfigDirectory(this->configDirectory);
if(this->cmdargs->isSet("stagenet"))
this->networkType = NetworkType::STAGENET;
else if(this->cmdargs->isSet("testnet"))
this->networkType = NetworkType::TESTNET;
else
this->networkType = NetworkType::MAINNET;
// if(this->cmdargs->isSet("stagenet"))
// this->networkType = NetworkType::STAGENET;
// else if(this->cmdargs->isSet("testnet"))
// this->networkType = NetworkType::TESTNET;
// else
this->networkType = NetworkType::MAINNET;
// auto nodeSourceUInt = config()->get(Config::nodeSource).toUInt();
// AppContext::nodeSource = static_cast<NodeSource>(nodeSourceUInt);
this->nodes = new Nodes(this, this->networkClearnet);
connect(this, &AppContext::nodeSourceChanged, this->nodes, &Nodes::onNodeSourceChanged);
connect(this, &AppContext::setCustomNodes, this->nodes, &Nodes::setCustomNodes);
connect(this, &AppContext::walletClosing, this->nodes, &Nodes::onWalletClosing);
// Tor & socks proxy
this->ws = new WSClient(this, m_wsUrl);
@ -154,8 +154,7 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
// XMRig
#ifdef HAS_XMRIG
this->XMRig = new XmRig(this->configDirectory, this);
if(!this->isTails)
this->XMRig->prepare();
this->XMRig->prepare();
#endif
this->walletManager = WalletManager::instance();
@ -180,7 +179,7 @@ void AppContext::initTor() {
this->tor = new Tor(this, this);
this->tor->start();
if (!(isTails || isWhonix)) {
if (!(isWhonix)) {
auto networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
this->network->setProxy(*networkProxy);
if (m_wsUrl.host().endsWith(".onion"))
@ -195,7 +194,7 @@ void AppContext::initWS() {
void AppContext::onCancelTransaction(PendingTransaction *tx, const QString &address) {
// tx cancelled by user
double amount = tx->amount() / AppContext::cdiv;
double amount = tx->amount() / globals::cdiv;
emit createTransactionCancelled(address, amount);
this->currentWallet->disposeTransaction(tx);
}
@ -234,8 +233,8 @@ void AppContext::onCreateTransaction(const QString &address, const double amount
return;
}
auto balance = this->currentWallet->balance() / AppContext::cdiv;
auto unlocked_balance = this->currentWallet->unlockedBalance() / AppContext::cdiv;
auto balance = this->currentWallet->balance() / globals::cdiv;
auto unlocked_balance = this->currentWallet->unlockedBalance() / globals::cdiv;
if(!all && amount > unlocked_balance) {
emit createTransactionError("Not enough money to spend");
return;
@ -244,7 +243,7 @@ void AppContext::onCreateTransaction(const QString &address, const double amount
return;
}
auto amount_num = static_cast<quint64>(amount * AppContext::cdiv);
auto amount_num = static_cast<quint64>(amount * globals::cdiv);
qDebug() << "creating tx";
if(all || amount == balance)
this->currentWallet->createTransactionAllAsync(address, "", this->tx_mixin, this->tx_priority);
@ -260,7 +259,6 @@ void AppContext::onCreateTransactionError(const QString &msg) {
}
void AppContext::walletClose(bool emitClosedSignal) {
this->nodes->stopTimer();
if(this->currentWallet == nullptr) return;
emit walletClosing();
//ctx->currentWallet->store(); @TODO: uncomment to store on wallet close
@ -283,6 +281,10 @@ void AppContext::onOpenWallet(const QString &path, const QString &password){
return;
}
if (password.isEmpty()) {
this->walletPassword = "";
}
config()->set(Config::firstRun, false);
this->walletPath = path;
@ -317,7 +319,7 @@ void AppContext::onWalletOpened(Wallet *wallet) {
emit walletOpenedError(errMsg);
} else {
this->walletClose(false);
emit walletOpenPasswordNeeded(this->walletPassword.isEmpty());
emit walletOpenPasswordNeeded(!this->walletPassword.isEmpty(), wallet->path());
}
return;
}
@ -340,6 +342,9 @@ void AppContext::onWalletOpened(Wallet *wallet) {
emit walletOpened();
connect(this->currentWallet, &Wallet::connectionStatusChanged, [this]{
this->nodes->autoConnect();
});
this->nodes->connectToNode();
this->updateBalance();
@ -425,7 +430,7 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
this->onWSReddit(reddit_data);
}
else if(cmd == "ccs") {
else if(cmd == "wfs") {
auto ccs_data = msg.value("data").toArray();
this->onWSCCS(ccs_data);
}
@ -458,7 +463,8 @@ void AppContext::onWSNodes(const QJsonArray &nodes) {
auto node = new FeatherNode(
obj.value("address").toString(),
(unsigned int)obj.value("height").toInt(),
obj.value("height").toInt(),
obj.value("target_height").toInt(),
obj.value("online").toBool());
QSharedPointer<FeatherNode> r = QSharedPointer<FeatherNode>(node);
l.append(r);
@ -595,9 +601,9 @@ void AppContext::createWalletFinish(const QString &password) {
}
void AppContext::initRestoreHeights() {
restoreHeights[NetworkType::TESTNET] = new RestoreHeightLookup(NetworkType::TESTNET);
restoreHeights[NetworkType::STAGENET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_monero_stagenet.txt", NetworkType::STAGENET);
restoreHeights[NetworkType::MAINNET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_monero_mainnet.txt", NetworkType::MAINNET);
restoreHeights[NetworkType::TESTNET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_wownero_mainnet.txt", NetworkType::TESTNET);
restoreHeights[NetworkType::STAGENET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_wownero_mainnet.txt", NetworkType::STAGENET);
restoreHeights[NetworkType::MAINNET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_wownero_mainnet.txt", NetworkType::MAINNET);
}
void AppContext::onSetRestoreHeight(unsigned int height){
@ -609,7 +615,7 @@ void AppContext::onSetRestoreHeight(unsigned int height){
}
this->currentWallet->setWalletCreationHeight(height);
this->currentWallet->setPassword(this->walletPassword); // trigger .keys write
this->currentWallet->setPassword(this->currentWallet->getPassword()); // trigger .keys write
// nuke wallet cache
const auto fn = this->currentWallet->path();
@ -691,23 +697,23 @@ AppContext::~AppContext() {
// ############################################## LIBWALLET QT #########################################################
void AppContext::onMoneySpent(const QString &txId, quint64 amount) {
auto amount_num = amount / AppContext::cdiv;
auto amount_num = amount / globals::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
}
void AppContext::onMoneyReceived(const QString &txId, quint64 amount) {
// Incoming tx included in a block.
auto amount_num = amount / AppContext::cdiv;
auto amount_num = amount / globals::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
}
void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) {
// Incoming transaction in pool
auto amount_num = amount / AppContext::cdiv;
auto amount_num = amount / globals::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
if(this->currentWallet->synchronized()) {
auto notify = QString("%1 XMR (pending)").arg(amount_num);
auto notify = QString("%1 WOW (pending)").arg(amount_num);
Utils::desktopNotify("Payment received", notify, 5000);
}
}
@ -721,13 +727,15 @@ void AppContext::onWalletUpdate() {
this->storeWallet();
}
void AppContext::onWalletRefreshed() {
void AppContext::onWalletRefreshed(bool success) {
if (!this->refreshed) {
refreshModels();
this->refreshed = true;
this->storeWallet();
}
qDebug() << "Wallet refresh status: " << success;
this->currentWallet->refreshHeightAsync();
}
@ -744,7 +752,7 @@ void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) {
void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) {
qDebug() << Q_FUNC_INFO << walletHeight << daemonHeight << targetHeight;
if (!this->currentWallet->connected())
if (this->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected)
return;
if (daemonHeight < targetHeight) {
@ -790,12 +798,12 @@ void AppContext::storeWallet() {
void AppContext::updateBalance() {
if(!this->currentWallet)
throw std::runtime_error("this should not happen, ever");
return;
AppContext::balance = this->currentWallet->balance() / AppContext::cdiv;
AppContext::balance = this->currentWallet->balance() / globals::cdiv;
auto balance_str = QString::number(balance, 'f');
double unlocked = this->currentWallet->unlockedBalance() / AppContext::cdiv;
double unlocked = this->currentWallet->unlockedBalance() / globals::cdiv;
auto unlocked_str = QString::number(unlocked, 'f');
emit balanceUpdated(balance, unlocked, balance_str, unlocked_str);

@ -39,13 +39,13 @@ public:
bool isTails = false;
bool isWhonix = false;
bool isDebug = false;
const QString featherDonationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f";
const int featherDonationAmount = 50; // euro
const QString featherDonationAddress = "WW2xGxtet29WxM6RBaxkTaBZoXC4mHGYoiHM5rPgViwNjnTLR452skNTsBMFp9JgMbdGucFQWF3PG95Hau9MnFjp2rmKgrcC7";
const int featherDonationAmount = 25; // euro
bool featherDonationSending = false;
QCommandLineParser *cmdargs;
QString coinName = "monero";
QString coinName = "wownero";
bool isTorSocks = false;
QString homeDir;
QString accountName;
@ -69,7 +69,7 @@ public:
const unsigned int kdfRounds = 1;
PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
quint32 tx_mixin = static_cast<const quint32 &>(10);
static constexpr const double cdiv = 1e12;
static constexpr const double cdiv = 1e11;
QString seedLanguage = "English"; // 14 word `monero-seed` only has English
QNetworkAccessManager *network;
@ -175,7 +175,7 @@ private:
const unsigned int m_donationBoundary = 15;
UtilsNetworking *m_utilsNetworkingNodes;
QTimer *m_storeTimer = new QTimer(this);
QUrl m_wsUrl = QUrl(QStringLiteral("ws://dtg2clrd6iand4mwp2x6nhbqd3nqbxlbiw65f6vkwmmutxy2sijsnjyd.onion/ws"));
QUrl m_wsUrl = QUrl(QStringLiteral("ws://dtg2clrd6iand4mwp2x6nhbqd3nqbxlbiw65f6vkwmmutxy2sijsnjyd.onion/wow/ws"));
};
#endif //FEATHER_APPCONTEXT_H

@ -3,7 +3,7 @@
<file>assets/about.txt</file>
<file>assets/ack.txt</file>
<file>assets/contributors.txt</file>
<file>assets/feather.desktop</file>
<file>assets/feather-wow.desktop</file>
<file>assets/images/appicons/32x32.png</file>
<file>assets/images/appicons/48x48.png</file>
<file>assets/images/appicons/64x64.png</file>
@ -48,10 +48,31 @@
<file>assets/images/lock_icon.png</file>
<file>assets/images/lock.svg</file>
<file>assets/images/microphone.png</file>
<file>assets/images/mining.png</file>
<file>assets/images/network.png</file>
<file>assets/images/offline_tx.png</file>
<file>assets/images/person.svg</file>
<file>assets/images/photos/1.png</file>
<file>assets/images/photos/illiterate_illuminati.png</file>
<file>assets/images/photos/wow1.png</file>
<file>assets/images/photos/wow2.png</file>
<file>assets/images/photos/wow3.png</file>
<file>assets/images/photos/wow4.png</file>
<file>assets/images/photos/wow5.png</file>
<file>assets/images/photos/wow6.png</file>
<file>assets/images/photos/wow7.png</file>
<file>assets/images/photos/wow8.png</file>
<file>assets/images/photos/wow9.png</file>
<file>assets/images/photos/wow10.png</file>
<file>assets/images/photos/wow11.png</file>
<file>assets/images/photos/wow12.png</file>
<file>assets/images/photos/wow13.png</file>
<file>assets/images/photos/wow14.png</file>
<file>assets/images/photos/wow15.png</file>
<file>assets/images/photos/wow16.png</file>
<file>assets/images/photos/wow17.png</file>
<file>assets/images/photos/wow18.png</file>
<file>assets/images/photos/wow19.png</file>
<file>assets/images/preferences.png</file>
<file>assets/images/preferences.svg</file>
<file>assets/images/qrcode.png</file>
@ -100,8 +121,7 @@
<file>assets/images/xmrig.svg</file>
<file>assets/images/zoom.png</file>
<file>assets/mnemonic_25_english.txt</file>
<file>assets/restore_heights_monero_mainnet.txt</file>
<file>assets/restore_heights_monero_stagenet.txt</file>
<file>assets/restore_heights_wownero_mainnet.txt</file>
<file>assets/user_agents.txt</file>
</qresource>
</RCC>

@ -6,5 +6,4 @@ The wallet UI is heavily inspired by Electrum. We would like to recognize Thomas
Huge thanks to nioc, fluffypony, wowario, thrmo for help during development.
Some more shoutouts for people for hosting nodes and/or having good ideas:
dnale0r, dEBRUYNE, binaryFate, lza_menace, jwinterm, kico, wowario
rottensox for testing :-)

@ -0,0 +1,14 @@
[Desktop Entry]
Comment=Lightweight Wownero Wallet
Exec=feather-wow
GenericName[en_US]=Wownero Wallet
GenericName=Wownero Wallet
Icon=feather-wow
Name[en_US]=Feather-WOW
Name=Feather-WOW
Categories=Finance;Network;
StartupNotify=false
StartupWMClass=feather
Terminal=false
Type=Application
MimeType=x-scheme-handler/wownero;

@ -1,14 +0,0 @@
[Desktop Entry]
Comment=Lightweight Monero Wallet
Exec=feather
GenericName[en_US]=Monero Wallet
GenericName=Monero Wallet
Icon=feather
Name[en_US]=Feather
Name=Feather
Categories=Finance;Network;
StartupNotify=false
StartupWMClass=feather
Terminal=false
Type=Application
MimeType=x-scheme-handler/monero;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 801 B

After

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 KiB

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 151 KiB

File diff suppressed because it is too large Load Diff

@ -1,444 +0,0 @@
1518932025:1
1519057016:1500
1519148374:3000
1519251680:4500
1519344568:6000
1519443436:7500
1519538388:9000
1519630287:10500
1519706564:12000
1519797372:13500
1519887275:15000
1519977816:16500
1520068127:18000
1520163067:19500
1520267595:21000
1520378423:22500
1520470528:24000
1520547672:25500
1520637599:27000
1520727714:28500
1520817129:30000
1520907017:31500
1521042482:33000
1521203259:34500
1521379791:36000
1521565539:37500
1521768004:39000
1521952047:40500
1522127660:42000
1522284923:43500
1522510139:45000
1522676022:46500
1522871613:48000
1522969561:49500
1523145200:51000
1523316302:52500
1523550884:54000
1523758049:55500
1523917524:57000
1524106084:58500
1524290437:60000
1524464139:61500
1524728732:63000
1524905041:64500
1525093135:66000
1525239917:67500
1525443579:69000
1525663214:70500
1525839621:72000
1525989826:73500
1526182919:75000
1526437405:76500
1526649137:78000
1526812889:79500
1526991726:81000
1527184073:82500
1527351889:84000
1527567839:85500
1527759754:87000
1527916443:88500
1528110008:90000
1528285005:91500
1528486806:93000
1528666327:94500
1528872096:96000
1529015390:97500
1529205809:99000
1529384415:100500
1529595764:102000
1529770640:103500
1529950955:105000
1530115141:106500
1530306273:108000
1530491510:109500
1530677550:111000
1530823854:112500
1531032372:114000
1531175619:115500
1531371373:117000
1531541897:118500
1531706629:120000
1531888223:121500
1532104373:123000
1532314129:124500
1532503060:126000
1532663651:127500
1532894128:129000
1533095950:130500
1533302631:132000
1533464469:133500
1533670723:135000
1533833911:136500
1534030841:138000
1534203160:139500
1534397055:141000
1534577048:142500
1534752236:144000
1534931462:145500
1535119263:147000
1535300364:148500
1535471540:150000
1535640429:151500
1535836082:153000
1536059510:154500
1536209710:156000
1536366875:157500
1536560444:159000
1536749043:160500
1536926345:162000
1537105693:163500
1537296613:165000
1537501175:166500
1537667740:168000
1537844801:169500
1538000228:171000
1538199137:172500
1538418406:174000
1538612473:175500
1538979696:177000
1539147054:178500
1539303989:180000
1539488395:181500
1539652212:183000
1539819281:184500
1539971301:186000
1540146343:187500
1540330288:189000
1540505588:190500
1540688044:192000
1540869374:193500
1541049379:195000
1541223210:196500
1541393586:198000
1541577202:199500
1541762094:201000
1541909862:202500
1542199063:204000
1542399873:205500
1542579333:207000
1542763985:208500
1542947442:210000
1543124804:211500
1543323933:213000
1543489307:214500
1543672244:216000
1543837576:217500
1544042420:219000
1544222096:220500
1544402628:222000
1544546843:223500
1544730464:225000
1545134663:226500
1545301874:228000
1545488939:229500
1545664263:231000
1545834607:232500
1546014630:234000
1546192930:235500
1546373750:237000
1546556089:238500
1546738764:240000
1546917228:241500
1547091360:243000
1547272679:244500
1547463907:246000
1547636722:247500
1547817060:249000
1548001021:250500
1548185375:252000
1548380319:253500
1548555267:255000
1548741069:256500
1548926544:258000
1549140801:259500
1549297081:261000
1549478379:262500
1549651888:264000
1549860339:265500
1550024455:267000
1550217332:268500
1551312389:270000
1551527936:271500
1551665288:273000
1551836443:274500
1552026339:276000
1552218441:277500
1552443760:279000
1552680291:280500
1552854334:282000
1553030527:283500
1553211359:285000
1553385763:286500
1553588198:288000
1553760642:289500
1553937158:291000
1554121990:292500
1554302691:294000
1554479953:295500
1554666762:297000
1554850956:298500
1555057081:300000
1555228611:301500
1555400592:303000
1555615005:304500
1555789135:306000
1555995570:307500
1556183867:309000
1556362195:310500
1556541232:312000
1556728140:313500
1556903453:315000
1557065264:316500
1557273415:318000
1557443047:319500
1557618850:321000
1557798876:322500
1557976530:324000
1558172356:325500
1558356032:327000
1558534222:328500
1558719934:330000
1558892036:331500
1559075695:333000
1559253052:334500
1559462339:336000
1559647394:337500
1559827424:339000
1560002042:340500
1560189126:342000
1560343483:343500
1560548477:345000
1560709613:346500
1560888640:348000
1561072261:349500
1561249189:351000
1561433494:352500
1561609875:354000
1561789136:355500
1561971530:357000
1562146235:358500
1562283612:360000
1562536678:361500
1562727970:363000
1562896064:364500
1563081360:366000
1563222147:367500
1563471753:369000
1563648133:370500
1563844968:372000
1564019071:373500
1564194349:375000
1564378444:376500
1564557884:378000
1564733144:379500
1564931656:381000
1565088150:382500
1565272766:384000
1565457895:385500
1565632566:387000
1565824568:388500
1565992971:390000
1566155025:391500
1566345274:393000
1566534162:394500
1566736618:396000
1566937517:397500
1567128136:399000
1567296600:400500
1567482630:402000
1567671945:403500
1567828904:405000
1568061755:406500
1568241437:408000
1568413206:409500
1568589427:411000
1568777072:412500
1568950797:414000
1569140033:415500
1569321139:417000
1569497726:418500
1569685524:420000
1569858754:421500
1570025222:423000
1570195891:424500
1570412169:426000
1570568122:427500
1570772965:429000
1570968490:430500
1571107236:432000
1571359933:433500
1571520970:435000
1571737619:436500
1571890574:438000
1572104152:439500
1572299391:441000
1572483040:442500
1572663772:444000
1572839626:445500
1573049256:447000
1573229282:448500
1573407580:450000
1573589178:451500
1573735333:453000
1573840717:454500
1574096272:456000
1574280161:457500
1574455892:459000
1574604632:460500
1574809987:462000
1574975801:463500
1575140569:465000
1575422392:466500
1575583824:468000
1575763253:469500
1575944350:471000
1576125074:472500
1576324269:474000
1576508865:475500
1576669612:477000
1576891906:478500
1577078563:480000
1577265105:481500
1577431370:483000
1577744409:484500
1577874268:486000
1578038130:487500
1578231375:489000
1578439644:490500
1578625982:492000
1578808598:493500
1578985283:495000
1579175621:496500
1579347774:498000
1579517894:499500
1579687667:501000
1579868646:502500
1580046838:504000
1580240961:505500
1580428207:507000
1580572904:508500
1580823996:510000
1580994064:511500
1581183924:513000
1581351893:514500
1581521085:516000
1581702405:517500
1581943619:519000
1582098842:520500
1582299537:522000
1582480013:523500
1582659742:525000
1582839127:526500
1583020057:528000
1583266489:529500
1583429819:531000
1583615548:532500
1583785190:534000
1584011766:535500
1584192961:537000
1584342104:538500
1584521327:540000
1584706894:541500
1584883565:543000
1585062315:544500
1585244138:546000
1585427591:547500
1585600165:549000
1585784601:550500
1585961031:552000
1586147565:553500
1586322716:555000
1586513730:556500
1586698639:558000
1586878453:559500
1587062131:561000
1587234968:562500
1587391529:564000
1587591247:565500
1587752262:567000
1587969335:568500
1588148503:570000
1588405392:571500
1588593609:573000
1588778703:574500
1588949467:576000
1589172941:577500
1589358899:579000
1589536247:580500
1589730950:582000
1589882572:583500
1590062931:585000
1590237283:586500
1590430792:588000
1590599140:589500
1590807968:591000
1590987339:592500
1591166304:594000
1591348974:595500
1591542069:597000
1591723208:598500
1591908870:600000
1592060567:601500
1592259549:603000
1592465269:604500
1592647205:606000
1592828242:607500
1593006687:609000
1593201658:610500
1593492855:612000
1593636856:613500
1593811224:615000
1594004429:616500
1594162422:618000
1594348191:619500
1594523256:621000
1594685351:622500
1594890677:624000
1595073577:625500
1595269373:627000
1595477524:628500
1595668392:630000
1595867552:631500
1596043173:633000
1596209876:634500
1596419711:636000
1596600935:637500
1596770710:639000
1596979435:640500
1597172685:642000
1597347250:643500
1597508807:645000
1597698614:646500
1597871525:648000
1598058524:649500
1598368966:651000
1598552832:652500
1598715002:654000
1598902853:655500
1599078705:657000
1599253008:658500
1599430407:660000
1599636188:661500
1599809533:663000
1600001474:664500

@ -0,0 +1,170 @@
1522624244:1
1522919763:1500
1523409727:3000
1523960364:4500
1524369547:6000
1524784400:7500
1525233663:9000
1525687037:10500
1526135584:12000
1526578718:13500
1527063859:15000
1527518523:16500
1527977555:18000
1528436212:19500
1528893646:21000
1529347707:22500
1529812899:24000
1530272289:25500
1530735091:27000
1531195321:28500
1531660804:30000
1532117133:31500
1532568099:33000
1533015693:34500
1533470854:36000
1533923432:37500
1534374443:39000
1534823621:40500
1535290349:42000
1535735446:43500
1536201310:45000
1536655339:46500
1537109771:48000
1537565159:49500
1538015344:51000
1538470517:52500
1538927269:54000
1539379855:55500
1539826869:57000
1540311781:58500
1540788117:60000
1541297876:61500
1541794302:63000
1542407858:64500
1543204218:66000
1543955252:67500
1544703247:69000
1545372024:70500
1546002226:72000
1546636335:73500
1547342810:75000
1548268561:76500
1548921502:78000
1549481994:79500
1550247894:81000
1550743647:82500
1551184199:84000
1551626083:85500
1552086272:87000
1552546202:88500
1552994646:90000
1553451645:91500
1553898976:93000
1554352300:94500
1554801655:96000
1555254551:97500
1555700170:99000
1556151520:100500
1556602014:102000
1557057709:103500
1557508808:105000
1557961787:106500
1558413175:108000
1558860703:109500
1559310651:111000
1559759587:112500
1560207825:114000
1560635185:115500
1561076902:117000
1561514633:118500
1561983210:120000
1562435722:121500
1562903313:123000
1563367656:124500
1563794760:126000
1564249987:127500
1564698967:129000
1565154467:130500
1565606876:132000
1566053072:133500
1566496455:135000
1566940483:136500
1567391114:138000
1567840593:139500
1568290979:141000
1568739494:142500
1569196321:144000
1569643702:145500
1570095074:147000
1570533207:148500
1570991907:150000
1571447301:151500
1571895478:153000
1572343106:154500
1572791579:156000
1573241814:157500
1573692641:159000
1574137867:160500
1574600312:162000
1575051207:163500
1575500955:165000
1575953057:166500
1576401859:168000
1576850419:169500
1577301553:171000
1577753392:172500
1578199780:174000
1578655276:175500
1579104342:177000
1579549362:178500
1580004525:180000
1580451365:181500
1580900062:183000
1581350016:184500
1581795609:186000
1582251322:187500
1582703447:189000
1583152160:190500
1583601824:192000
1584051198:193500
1584499159:195000
1584949547:196500
1585404000:198000
1585843662:199500
1586292852:201000
1586738236:202500
1587201986:204000
1587663936:205500
1588119101:207000
1588586510:208500
1589057972:210000
1589520509:211500
1589974638:213000
1590425544:214500
1590876865:216000
1591326399:217500
1591759684:219000
1592226165:220500
1592681388:222000
1593141896:223500
1593595859:225000
1594048319:226500
1594489197:228000
1594955184:229500
1595408732:231000
1595854685:232500
1596303095:234000
1596732814:235500
1597198383:237000
1597650820:238500
1598099448:240000
1598553007:241500
1599004645:243000
1599459515:244500
1599914532:246000
1600357718:247500
1600811447:249000
1601257433:250500
1601710572:252000
1602154921:253500

@ -123,7 +123,7 @@ void CalcWidget::initComboBox() {
ui->comboCalcFrom->addItems(marketsKeys);
ui->comboCalcFrom->insertSeparator(marketsKeys.count());
ui->comboCalcFrom->addItems(ratesKeys);
ui->comboCalcFrom->setCurrentIndex(marketsKeys.indexOf("XMR"));
ui->comboCalcFrom->setCurrentIndex(marketsKeys.indexOf("WOW"));
ui->comboCalcTo->addItems(marketsKeys);
ui->comboCalcTo->insertSeparator(marketsKeys.count());

@ -58,7 +58,7 @@ void CLI::onWalletOpenedError(const QString &err) {
return this->finishedError(err);
}
void CLI::onWalletOpenPasswordRequired(bool invalidPassword) {
void CLI::onWalletOpenPasswordRequired(bool invalidPassword, const QString &path) {
if(mode == CLIMode::CLIModeExportContacts ||
mode == CLIMode::CLIModeExportTxHistory)
return this->finishedError("invalid password");

@ -26,7 +26,7 @@ public slots:
//libwalletqt
void onWalletOpened();
void onWalletOpenedError(const QString& err);
void onWalletOpenPasswordRequired(bool invalidPassword);
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);
private:
AppContext *ctx;

@ -42,14 +42,14 @@ CoinsWidget::CoinsWidget(QWidget *parent)
// context menu
ui->coins->setContextMenuPolicy(Qt::CustomContextMenu);
m_thawOutputAction = new QAction("Thaw output");
m_freezeOutputAction = new QAction("Freeze output");
m_thawOutputAction = new QAction("Thaw output", this);
m_freezeOutputAction = new QAction("Freeze output", this);
m_freezeAllSelectedAction = new QAction("Freeze selected");
m_thawAllSelectedAction = new QAction("Thaw selected");
m_freezeAllSelectedAction = new QAction("Freeze selected", this);
m_thawAllSelectedAction = new QAction("Thaw selected", this);
m_viewOutputAction = new QAction(QIcon(":/assets/images/info.png"), "Details");
m_sweepOutputAction = new QAction("Sweep output");
m_viewOutputAction = new QAction(QIcon(":/assets/images/info.png"), "Details", this);
m_sweepOutputAction = new QAction("Sweep output", this);
connect(m_freezeOutputAction, &QAction::triggered, this, &CoinsWidget::freezeOutput);
connect(m_thawOutputAction, &QAction::triggered, this, &CoinsWidget::thawOutput);
connect(m_viewOutputAction, &QAction::triggered, this, &CoinsWidget::viewOutput);
@ -65,7 +65,7 @@ CoinsWidget::CoinsWidget(QWidget *parent)
void CoinsWidget::setModel(CoinsModel * model, Coins * coins) {
m_coins = coins;
m_model = model;
m_proxyModel = new CoinsProxyModel;
m_proxyModel = new CoinsProxyModel(this);
m_proxyModel->setSourceModel(m_model);
ui->coins->setModel(m_proxyModel);
ui->coins->setColumnHidden(CoinsModel::Spent, true);
@ -111,10 +111,15 @@ void CoinsWidget::showContextMenu(const QPoint &point) {
if (!isSpent) {
isFrozen ? menu->addAction(m_thawOutputAction) : menu->addAction(m_freezeOutputAction);
}
if (!isFrozen && isUnlocked) {
menu->addAction(m_sweepOutputAction);
if (isFrozen || !isUnlocked) {
m_sweepOutputAction->setDisabled(true);
} else {
m_sweepOutputAction->setEnabled(true);
}
}
menu->addAction(m_viewOutputAction);
}
@ -202,6 +207,7 @@ void CoinsWidget::onSweepOutput() {
qCritical() << "key image: " << keyImage;
emit sweepOutput(keyImage, dialog->address(), dialog->churn(), dialog->outputs());
dialog->deleteLater();
}
void CoinsWidget::copy(copyField field) {

@ -68,9 +68,7 @@ HelpLabel::HelpLabel(QWidget *parent) : QLabel(parent)
void HelpLabel::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event)
QMessageBox msgBox(QApplication::activeWindow());
msgBox.setText(this->help_text);
msgBox.exec();
QMessageBox::information(this, "Help", this->help_text);
}
void HelpLabel::enterEvent(QEvent *event)

@ -12,8 +12,8 @@ AboutDialog::AboutDialog(QWidget *parent)
{
ui->setupUi(this);
this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png"));
// cute fox (c) Diego "rehrar" Salazar :-D
QPixmap p(":assets/images/cutexmrfox.png");
QPixmap p(":assets/images/photos/illiterate_illuminati.png");
ui->aboutImage->setPixmap(p.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation));
auto about = Utils::fileOpenQRC(":assets/about.txt");
auto about_text = Utils::barrayToString(about);

@ -43,7 +43,7 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>a free, open-source Monero wallet</string>
<string>a free, open-source Wownero wallet</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>

@ -73,7 +73,7 @@ QString DebugInfoDialog::statusToString(Wallet::ConnectionStatus status) {
void DebugInfoDialog::copyToClipboad() {
QString text = "";
text += QString("Feather version: %1\n").arg(ui->label_featherVersion->text());
text += QString("Monero version: %1\n").arg(ui->label_moneroVersion->text());
text += QString("Wownero version: %1\n").arg(ui->label_moneroVersion->text());
text += QString("Wallet height: %1\n").arg(ui->label_walletHeight->text());
text += QString("Daemon height: %1\n").arg(ui->label_daemonHeight->text());

@ -23,6 +23,10 @@ public:
private:
QString statusToString(Wallet::ConnectionStatus status);
void copyToClipboad();
void updateInfo();
QTimer m_updateTimer;
AppContext *m_ctx;
Ui::DebugInfoDialog *ui;
};

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>693</width>
<height>580</height>
<height>612</height>
</rect>
</property>
<property name="windowTitle">
@ -36,7 +36,7 @@
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Monero version:</string>
<string>Wownero version:</string>
</property>
</widget>
</item>
@ -91,14 +91,14 @@
</property>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Restore height:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QLabel" name="label_restoreHeight">
<property name="text">
<string>TextLabel</string>
@ -108,14 +108,14 @@
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Synchronized:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="7" column="1">
<widget class="QLabel" name="label_synchronized">
<property name="text">
<string>TextLabel</string>
@ -125,21 +125,21 @@
</property>
</widget>
</item>
<item row="7" column="1">
<item row="8" column="1">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="8" column="0">
<item row="9" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Remote node:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="9" column="1">
<widget class="QLabel" name="label_remoteNode">
<property name="text">
<string>TextLabel</string>
@ -149,14 +149,14 @@
</property>
</widget>
</item>
<item row="9" column="0">
<item row="10" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Wallet status:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="10" column="1">
<widget class="QLabel" name="label_walletStatus">
<property name="text">
<string>TextLabel</string>
@ -166,14 +166,14 @@
</property>
</widget>
</item>
<item row="10" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Tor status:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<item row="11" column="1">
<widget class="QLabel" name="label_torStatus">
<property name="text">
<string>TextLabel</string>
@ -183,14 +183,14 @@
</property>
</widget>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Websocket status:</string>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="12" column="1">
<widget class="QLabel" name="label_websocketStatus">
<property name="text">
<string>TextLabel</string>
@ -200,21 +200,21 @@
</property>
</widget>
</item>
<item row="12" column="1">
<item row="13" column="1">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="13" column="0">
<item row="14" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Network type:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<item row="14" column="1">
<widget class="QLabel" name="label_netType">
<property name="text">
<string>TextLabel</string>
@ -224,14 +224,14 @@
</property>
</widget>
</item>
<item row="14" column="0">
<item row="15" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Seed type:</string>
</property>
</widget>
</item>
<item row="14" column="1">
<item row="15" column="1">
<widget class="QLabel" name="label_seedType">
<property name="text">
<string>TextLabel</string>
@ -241,14 +241,14 @@
</property>
</widget>
</item>
<item row="15" column="0">
<item row="16" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>View only:</string>
</property>
</widget>
</item>
<item row="15" column="1">
<item row="16" column="1">
<widget class="QLabel" name="label_viewOnly">
<property name="text">
<string>TextLabel</string>
@ -258,14 +258,14 @@
</property>
</widget>
</item>
<item row="18" column="0">
<item row="19" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Timestamp:</string>
</property>
</widget>
</item>
<item row="18" column="1">
<item row="19" column="1">
<widget class="QLabel" name="label_timestamp">
<property name="text">
<string>TextLabel</string>
@ -275,27 +275,47 @@
</property>
</widget>
</item>
<item row="17" column="0">
<item row="18" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Operating system:</string>
</property>
</widget>
</item>
<item row="17" column="1">
<item row="18" column="1">
<widget class="QLabel" name="label_OS">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="16" column="1">
<item row="17" column="1">
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Target height:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_targetHeight">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
<item>

@ -28,7 +28,7 @@ OutputInfoDialog::OutputInfoDialog(CoinsInfo *cInfo, QWidget *parent)
QString status = cInfo->spent() ? "spent" : (cInfo->frozen() ? "frozen" : "unspent");
ui->label_status->setText(status);
ui->label_amount->setText(QString("%1 XMR").arg(cInfo->displayAmount()));
ui->label_amount->setText(QString("%1 WOW").arg(cInfo->displayAmount()));
ui->label_creationHeight->setText(QString::number(cInfo->blockHeight()));
ui->label_globalIndex->setText(QString::number(cInfo->globalOutputIndex()));
ui->label_internalIndex->setText(QString::number(cInfo->internalOutputIndex()));

@ -5,17 +5,39 @@
#include "ui_passwordchangedialog.h"
#include <QPushButton>
#include <QMessageBox>
PasswordChangeDialog::PasswordChangeDialog(QWidget *parent)
PasswordChangeDialog::PasswordChangeDialog(QWidget *parent, Wallet *wallet)
: QDialog(parent)
, ui(new Ui::PasswordChangeDialog)
, m_wallet(wallet)
{
ui->setupUi(this);
ui->icon->setPixmap(QPixmap(":/assets/images/lock.png").scaledToWidth(32, Qt::SmoothTransformation));
bool noPassword = wallet->getPassword().isEmpty();
QString warning_str = noPassword ? "Your wallet is not password protected. Use this dialog to add a password to your wallet." :
"Your wallet is password protected and encrypted. Use this dialog to change your password.";
ui->label_warning->setText(warning_str);
QPixmap pixmap = noPassword ? QPixmap(":/assets/images/unlock.png") : QPixmap(":/assets/images/lock.png");
ui->icon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation));
if (noPassword) {
ui->label_currentPassword->hide();
ui->lineEdit_currentPassword->hide();
}
connect(ui->lineEdit_newPassword, &QLineEdit::textChanged, this, &PasswordChangeDialog::passwordsMatch);
connect(ui->lineEdit_confirmPassword, &QLineEdit::textChanged, this, &PasswordChangeDialog::passwordsMatch);
connect(ui->btn_Cancel, &QPushButton::clicked, [this]{
this->reject();
});
connect(ui->btn_OK, &QPushButton::clicked, this, &PasswordChangeDialog::setPassword);
ui->label_match->setVisible(false);
this->adjustSize();
}
@ -24,15 +46,28 @@ PasswordChangeDialog::~PasswordChangeDialog()
delete ui;
}
QString PasswordChangeDialog::getCurrentPassword() {
return ui->lineEdit_currentPassword->text();
void PasswordChangeDialog::passwordsMatch() {
bool match = ui->lineEdit_newPassword->text() == ui->lineEdit_confirmPassword->text();
ui->btn_OK->setEnabled(match);
ui->label_match->setHidden(match);
}
QString PasswordChangeDialog::getNewPassword() {
return ui->lineEdit_newPassword->text();
}
void PasswordChangeDialog::setPassword() {
QString currentPassword = ui->lineEdit_currentPassword->text();
QString newPassword = ui->lineEdit_newPassword->text();
void PasswordChangeDialog::passwordsMatch() {
bool match = ui->lineEdit_newPassword->text() == ui->lineEdit_confirmPassword->text();
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(match);
if (currentPassword != m_wallet->getPassword()) {
QMessageBox::warning(this, "Error", "Incorrect password");
ui->lineEdit_currentPassword->setText("");
ui->lineEdit_currentPassword->setFocus();
return;
}
if (m_wallet->setPassword(newPassword)) {
QMessageBox::information(this, "Information", "Password changed successfully");
this->accept();
}
else {
QMessageBox::warning(this, "Error", QString("Error: %1").arg(m_wallet->errorString()));
}
}

@ -5,6 +5,7 @@
#define FEATHER_PASSWORDCHANGEDIALOG_H
#include <QDialog>
#include "libwalletqt/Wallet.h"
namespace Ui {
class PasswordChangeDialog;
@ -15,16 +16,15 @@ class PasswordChangeDialog : public QDialog
Q_OBJECT
public:
explicit PasswordChangeDialog(QWidget *parent = nullptr);
explicit PasswordChangeDialog(QWidget *parent, Wallet *wallet);
~PasswordChangeDialog() override;
QString getCurrentPassword();
QString getNewPassword();
private:
Ui::PasswordChangeDialog *ui;
Wallet *m_wallet;
void passwordsMatch();
void setPassword();
};
#endif //FEATHER_PASSWORDCHANGEDIALOG_H

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>237</height>
<width>556</width>
<height>309</height>
</rect>
</property>
<property name="sizePolicy">
@ -30,7 +30,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="label_warning">
<property name="text">
<string>Your wallet is password protected and encrypted. Use this dialog to change your password.</string>
</property>
@ -41,6 +41,22 @@
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
@ -65,7 +81,7 @@
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_currentPassword">
<property name="text">
<string>Current Password:</string>
</property>
@ -88,14 +104,45 @@
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_match">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Passwords do not match</string>
</property>
</widget>
</item>
<item>
<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>
<widget class="QPushButton" name="btn_Cancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_OK">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -105,38 +152,5 @@
<tabstop>lineEdit_confirmPassword</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PasswordChangeDialog</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>PasswordChangeDialog</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>
<connections/>
</ui>

@ -0,0 +1,26 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include "passworddialog.h"
#include "ui_passworddialog.h"
PasswordDialog::PasswordDialog(QWidget *parent, const QString &walletName, bool incorrectPassword)
: QDialog(parent)
, ui(new Ui::PasswordDialog)
{
ui->setupUi(this);
ui->label_wallet->setText(QString("Please enter password for wallet: %1").arg(walletName));
ui->label_incorrectPassword->setVisible(incorrectPassword);
connect(ui->buttonBox, &QDialogButtonBox::accepted, [this]{
password = ui->line_password->text();
});
this->adjustSize();
}
PasswordDialog::~PasswordDialog()
{
delete ui;
}

@ -0,0 +1,27 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_PASSWORDDIALOG_H
#define FEATHER_PASSWORDDIALOG_H
#include <QDialog>
namespace Ui {
class PasswordDialog;
}
class PasswordDialog : public QDialog
{
Q_OBJECT
public:
explicit PasswordDialog(QWidget *parent, const QString &walletName, bool incorrectPassword);
~PasswordDialog() override;
QString password = "";
private:
Ui::PasswordDialog *ui;
};
#endif //FEATHER_PASSWORDDIALOG_H

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PasswordDialog</class>
<widget class="QDialog" name="PasswordDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>832</width>
<height>158</height>
</rect>
</property>
<property name="windowTitle">
<string>Password required</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_wallet">
<property name="text">
<string>Please enter password for wallet: </string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_incorrectPassword">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; color:#a40000;&quot;&gt;Incorrect password, try again.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="line_password">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PasswordDialog</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>PasswordDialog</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>

@ -4,27 +4,51 @@
#include "ui_seeddialog.h"
#include "seeddialog.h"
SeedDialog::SeedDialog(const QString &seed, QWidget *parent)
SeedDialog::SeedDialog(Wallet *wallet, QWidget *parent)
: QDialog(parent)
, ui(new Ui::SeedDialog)
{
ui->setupUi(this);
ui->label_seedIcon->setPixmap(QPixmap(":/assets/images/seed.png").scaledToWidth(64, Qt::SmoothTransformation));
ui->label_restoreHeight->setText(QString::number(wallet->getWalletCreationHeight()));
QString seed_14_words = wallet->getCacheAttribute("feather.seed");
QString seed_25_words = wallet->getSeed();
if (seed_14_words.isEmpty()) {
ui->check_toggleSeedType->hide();
this->setSeed(seed_25_words);
} else {
this->setSeed(seed_14_words);
ui->widgetRestoreHeight->setVisible(false);
}
connect(ui->check_toggleSeedType, &QCheckBox::toggled, [this, seed_25_words, seed_14_words](bool toggled){
this->setSeed(toggled ? seed_25_words : seed_14_words);
ui->widgetRestoreHeight->setVisible(toggled);
});
ui->label_restoreHeightHelp->setHelpText("Should you restore your wallet in the future, "
"specifying this block number will recover your wallet quicker.");
this->adjustSize();
}
void SeedDialog::setSeed(const QString &seed) {
ui->seed->setPlainText(seed);
int words = seed.split(" ").size();
ui->label_warning->setText(QString("<p>Please save these %1 words on paper (order is important). "
"This seed will allow you to recover your wallet in case "
"of computer failure."
"</p>"
"<b>WARNING:</b>"
"<ul>"
"<li>Never disclose your seed.</li>"
"<li>Never type it on a website</li>"
"<li>Do not store it electronically</li>"
"</ul>").arg(words));
this->adjustSize();
"This seed will allow you to recover your wallet in case "
"of computer failure."
"</p>"
"<b>WARNING:</b>"
"<ul>"
"<li>Never disclose your seed.</li>"
"<li>Never type it on a website</li>"
"<li>Do not store it electronically</li>"
"</ul>").arg(words));
}
SeedDialog::~SeedDialog()

@ -5,6 +5,7 @@
#define FEATHER_SEEDDIALOG_H
#include <QDialog>
#include "libwalletqt/Wallet.h"
namespace Ui {
class SeedDialog;
@ -15,10 +16,12 @@ class SeedDialog : public QDialog
Q_OBJECT
public:
explicit SeedDialog(const QString& seed, QWidget *parent = nullptr);
explicit SeedDialog(Wallet *wallet, QWidget *parent = nullptr);
~SeedDialog() override;
private:
void setSeed(const QString &seed);
Ui::SeedDialog *ui;
};

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>542</width>
<height>244</height>
<width>590</width>
<height>346</height>
</rect>
</property>
<property name="windowTitle">
@ -34,29 +34,94 @@
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="seed">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>125</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPlainTextEdit" name="seed">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>125</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>300</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetRestoreHeight" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="HelpLabel" name="label_restoreHeightHelp">
<property name="text">
<string>Restore height:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_restoreHeight">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<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>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="check_toggleSeedType">
<property name="text">
<string>Show 25 word seed</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_warning">
<property name="text">
@ -79,6 +144,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>HelpLabel</class>
<extends>QLabel</extends>
<header>components.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>

@ -6,18 +6,29 @@
#include "libwalletqt/CoinsInfo.h"
#include "libwalletqt/WalletManager.h"
#include <QDebug>
#include "utils.h"
TransactionInfoDialog::TransactionInfoDialog(Coins *coins, TransactionInfo *txInfo, QWidget *parent)
#include <QMessageBox>
TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent)
: QDialog(parent)
, ui(new Ui::TransactionInfoDialog)
, m_coins(coins)
, m_wallet(wallet)
, m_txInfo(txInfo)
{
ui->setupUi(this);
ui->txid->setText(QString(txInfo->hash()));
ui->txid->setCursorPosition(0);
m_txProofWidget = new TxProofWidget(this, wallet, txInfo);
ui->label_txid->setText(QString(txInfo->hash()));
if (txInfo->direction() == TransactionInfo::Direction_In) {
ui->txKey->hide();
} else {
QString txKey = m_wallet->getTxKey(txInfo->hash());
txKey = txKey.isEmpty() ? "unknown" : txKey;
ui->label_txKey->setText(txKey);
}
ui->label_status->setText(QString("Status: %1 confirmations").arg(txInfo->confirmations()));
ui->label_date->setText(QString("Date: %1").arg(txInfo->timestamp().toString("yyyy-MM-dd HH:mm")));
@ -30,7 +41,7 @@ TransactionInfoDialog::TransactionInfoDialog(Coins *coins, TransactionInfo *txIn
ui->label_fee->setText(QString("Fee: %1").arg(txInfo->isCoinbase() ? WalletManager::displayAmount(0) : fee));
ui->label_unlockTime->setText(QString("Unlock time: %1 (height)").arg(txInfo->unlockTime()));
qDebug() << m_coins->coins_from_txid(txInfo->hash());
qDebug() << m_wallet->coins()->coins_from_txid(txInfo->hash());
QString destinations = txInfo->destinations_formatted();
if (destinations.isEmpty()) {
@ -41,6 +52,8 @@ TransactionInfoDialog::TransactionInfoDialog(Coins *coins, TransactionInfo *txIn
ui->destinations->setText(destinations);
}
ui->txProofWidget->addWidget(m_txProofWidget);
this->adjustSize();
}

@ -8,6 +8,8 @@
#include <QtSvg/QSvgWidget>
#include "libwalletqt/Coins.h"
#include "libwalletqt/TransactionInfo.h"
#include "libwalletqt/Wallet.h"
#include "widgets/txproofwidget.h"
namespace Ui {
class TransactionInfoDialog;
@ -18,14 +20,15 @@ class TransactionInfoDialog : public QDialog
Q_OBJECT
public:
explicit TransactionInfoDialog(Coins *coins, TransactionInfo *txInfo, QWidget *parent = nullptr);
explicit TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr);
~TransactionInfoDialog() override;
private:
Ui::TransactionInfoDialog *ui;
TransactionInfo *m_txInfo;
Coins *m_coins;
Wallet *m_wallet;
TxProofWidget *m_txProofWidget;
};
#endif //FEATHER_TRANSACTIONINFODIALOG_H

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>547</width>
<height>332</height>
<width>829</width>
<height>570</height>
</rect>
</property>
<property name="windowTitle">
@ -15,32 +15,41 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label">
<property name="text">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Transaction ID:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_txid">
<property name="text">
<string>txid</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txid">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>525</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>txid</string>
</property>
<property name="readOnly">
<bool>true</bool>
<widget class="QGroupBox" name="txKey">
<property name="title">
<string>Transaction key:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="label_txKey">
<property name="text">
<string>txKey</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@ -149,6 +158,16 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="txProofWidget"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

@ -8,6 +8,7 @@
#include "model/ModelUtils.h"
#include "libwalletqt/WalletManager.h"
#include "txconfadvdialog.h"
#include "globals.h"
#include <QMessageBox>
@ -27,19 +28,19 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin
QString preferredCur = config()->get(Config::preferredFiatCurrency).toString();
auto convert = [preferredCur](double amount){
return QString::number(AppContext::prices->convert("XMR", preferredCur, amount), 'f', 2);
return QString::number(AppContext::prices->convert("WOW", preferredCur, amount), 'f', 2);
};
QString amount = WalletManager::displayAmount(tx->amount());
QString amount_fiat = convert(tx->amount() / AppContext::cdiv);
QString amount_fiat = convert(tx->amount() / globals::cdiv);
ui->label_amount->setText(QString("%1 (%2 %3)").arg(amount, amount_fiat, preferredCur));
QString fee = WalletManager::displayAmount(tx->fee());
QString fee_fiat = convert(tx->fee() / AppContext::cdiv);
QString fee_fiat = convert(tx->fee() / globals::cdiv);
ui->label_fee->setText(QString("%1 (%2 %3)").arg(fee, fee_fiat, preferredCur));
QString total = WalletManager::displayAmount(tx->amount() + tx->fee());
QString total_fiat = convert((tx->amount() + tx->fee()) / AppContext::cdiv);
QString total_fiat = convert((tx->amount() + tx->fee()) / globals::cdiv);
ui->label_total->setText(QString("%1 (%2 %3)").arg(total, total_fiat, preferredCur));
ui->label_address->setText(ModelUtils::displayAddress(address, 2));

@ -0,0 +1,102 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include "tximportdialog.h"
#include "ui_tximportdialog.h"
#include <QMessageBox>
TxImportDialog::TxImportDialog(QWidget *parent, AppContext *ctx)
: QDialog(parent)
, m_ctx(ctx)
, m_loadTimer(new QTimer(this))
, ui(new Ui::TxImportDialog)
{
ui->setupUi(this);
ui->resp->hide();
ui->label_loading->hide();
m_network = new UtilsNetworking(m_ctx->network, this);
auto node = ctx->nodes->connection();
m_rpc = new DaemonRpc(this, m_network, node.full);
connect(ui->btn_load, &QPushButton::clicked, this, &TxImportDialog::loadTx);
connect(ui->btn_import, &QPushButton::clicked, this, &TxImportDialog::onImport);
connect(m_rpc, &DaemonRpc::ApiResponse, this, &TxImportDialog::onApiResponse);
connect(m_loadTimer, &QTimer::timeout, [this]{
ui->label_loading->setText(ui->label_loading->text() + ".");
});
this->adjustSize();
}
void TxImportDialog::loadTx() {
QString txid = ui->line_txid->text();
QString node = m_ctx->nodes->connection().full;
if (!node.startsWith("http://"))
node = QString("http://%1").arg(node);
m_rpc->setDaemonAddress(node);
m_rpc->getTransactions(QStringList() << txid, false, true);
ui->label_loading->setText("Loading transaction");
ui->label_loading->setHidden(false);
m_loadTimer->start(1000);
}
void TxImportDialog::onApiResponse(const DaemonRpc::DaemonResponse &resp) {
m_loadTimer->stop();
ui->label_loading->setHidden(true);
if (!resp.ok) {
QMessageBox::warning(this, "Import transaction", resp.status);
return;
}
if (resp.endpoint == DaemonRpc::Endpoint::GET_TRANSACTIONS) {
ui->resp->setVisible(true);
ui->resp->setPlainText(QJsonDocument(resp.obj).toJson(QJsonDocument::Indented));
this->adjustSize();
if (resp.obj.contains("missed_tx")) {
ui->btn_import->setEnabled(false);
QMessageBox::warning(this, "Load transaction", "Transaction could not be found. Make sure the txid is correct, or try connecting to a different node.");
return;
}
QMessageBox::information(this, "Load transaction", "Transaction loaded successfully.\n\nAfter closing this message box click the Import button to import the transaction into your wallet.");
m_transaction = resp.obj;
ui->btn_import->setEnabled(true);
}
}
void TxImportDialog::onImport() {
QJsonObject tx = m_transaction.value("txs").toArray().first().toObject();
QString txid = tx.value("tx_hash").toString();
QVector<quint64> output_indices;
for (const auto &o: tx.value("output_indices").toArray()) {
output_indices.push_back(o.toInt());
}
quint64 height = tx.value("block_height").toInt();
quint64 timestamp = tx.value("block_timestamp").toInt();
bool pool = tx.value("in_pool").toBool();
bool double_spend_seen = tx.value("double_spend_seen").toBool();
if (m_ctx->currentWallet->importTransaction(tx.value("tx_hash").toString(), output_indices, height, timestamp, false, pool, double_spend_seen)) {
QMessageBox::information(this, "Import transaction", "Transaction imported successfully.");
} else {
QMessageBox::warning(this, "Import transaction", "Transaction import failed.");
}
m_ctx->refreshModels();
}
TxImportDialog::~TxImportDialog() {
delete ui;
}

@ -0,0 +1,39 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_TXIMPORTDIALOG_H
#define FEATHER_TXIMPORTDIALOG_H
#include <QDialog>
#include "appcontext.h"
#include "utils/daemonrpc.h"
namespace Ui {
class TxImportDialog;
}
class TxImportDialog : public QDialog
{
Q_OBJECT
public:
explicit TxImportDialog(QWidget *parent, AppContext *ctx);
~TxImportDialog() override;
private slots:
void loadTx();
void onImport();
void onApiResponse(const DaemonRpc::DaemonResponse &resp);
private:
Ui::TxImportDialog *ui;
UtilsNetworking *m_network;
AppContext *m_ctx;
DaemonRpc *m_rpc;
QTimer *m_loadTimer;
QJsonObject m_transaction;
};
#endif //FEATHER_TXIMPORTDIALOG_H

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TxImportDialog</class>
<widget class="QDialog" name="TxImportDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>700</width>
<height>442</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>700</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Import Transaction</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="line_txid">
<property name="placeholderText">
<string>Transaction ID</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="resp">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Debug info..</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="btn_load">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_import">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Import</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_loading">
<property name="text">
<string>Loading transaction</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>TxImportDialog</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>TxImportDialog</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>

@ -16,26 +16,28 @@ VerifyProofDialog::VerifyProofDialog(Wallet *wallet, QWidget *parent)
{
ui->setupUi(this);
connect(ui->btn_verifySpendProof, &QPushButton::clicked, this, &VerifyProofDialog::checkSpendProof);
connect(ui->btn_verifyOutProof, &QPushButton::clicked, this, &VerifyProofDialog::checkOutProof);
connect(ui->btn_verifyInProof, &QPushButton::clicked, this, &VerifyProofDialog::checkInProof);
connect(ui->btn_spendClear, &QPushButton::clicked, [this](){
ui->lineEdit_spendTxID->clear();
ui->lineEdit_spendMessage->clear();
ui->input_SpendProof->clear();
});
connect(ui->btn_outClear, &QPushButton::clicked, [this](){
ui->lineEdit_outTxID->clear();
ui->lineEdit_outAddress->clear();
ui->lineEdit_outMessage->clear();
ui->input_OutProof->clear();
});
connect(ui->btn_inClear, &QPushButton::clicked, [this](){
ui->lineEdit_inTxID->clear();
ui->lineEdit_inAddress->clear();
ui->lineEdit_inMessage->clear();
ui->input_InProof->clear();
connect(ui->btn_verify, &QPushButton::clicked, this, &VerifyProofDialog::checkProof);
connect(ui->btn_clear, &QPushButton::clicked, [this]{
switch (ui->tabWidget->currentIndex()) {
case 0:
ui->lineEdit_spendTxID->clear();
ui->lineEdit_spendMessage->clear();
ui->input_SpendProof->clear();
break;
case 1:
ui->lineEdit_outTxID->clear();
ui->lineEdit_outAddress->clear();
ui->lineEdit_outMessage->clear();
ui->input_OutProof->clear();
break;
case 2:
ui->lineEdit_inTxID->clear();
ui->lineEdit_inAddress->clear();
ui->lineEdit_inMessage->clear();
ui->input_InProof->clear();
break;
}
});
}
@ -44,6 +46,20 @@ VerifyProofDialog::~VerifyProofDialog()
delete ui;
}
void VerifyProofDialog::checkProof() {
switch (ui->tabWidget->currentIndex()) {
case 0:
this->checkSpendProof();
break;
case 1:
this->checkOutProof();
break;
case 2:
this->checkInProof();
break;
}
}
void VerifyProofDialog::checkSpendProof() {
auto r = m_wallet->checkSpendProof(ui->lineEdit_spendTxID->text(), ui->lineEdit_spendMessage->text(), ui->input_SpendProof->toPlainText());
@ -78,6 +94,6 @@ void VerifyProofDialog::checkTxProof(const QString &txId, const QString &address
return;
}
QString msg = QString("This address received %1 monero, with %2 confirmation(s)").arg(WalletManager::displayAmount(r.received), QString::number(r.confirmations));
QString msg = QString("This address received %1 wownero, with %2 confirmation(s)").arg(WalletManager::displayAmount(r.received), QString::number(r.confirmations));
QMessageBox::information(this, "Information", QString("Proof is valid.\n\n%1").arg(msg));
}

@ -20,12 +20,13 @@ public:
~VerifyProofDialog() override;
private slots:
void checkSpendProof();
void checkOutProof();
void checkInProof();
void checkProof();
private:
void checkTxProof(const QString &txId, const QString &address, const QString &message, const QString &signature);
void checkSpendProof();
void checkOutProof();
void checkInProof();
Ui::VerifyProofDialog *ui;
Wallet *m_wallet;

@ -39,17 +39,7 @@
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Transaction ID:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_spendTxID"/>
</item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
@ -57,10 +47,13 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_spendTxID"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>SpendProof:</string>
<string>Transaction ID:</string>
</property>
</widget>
</item>
@ -71,6 +64,13 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>SpendProof:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="input_SpendProof">
<property name="overwriteMode">
@ -96,37 +96,6 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<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>
<widget class="QPushButton" name="btn_spendClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_verifySpendProof">
<property name="text">
<string>Verify</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="OutProof">
@ -213,37 +182,6 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<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>
<widget class="QPushButton" name="btn_outClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_verifyOutProof">
<property name="text">
<string>Verify</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="InProof">
@ -331,41 +269,44 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_3">
<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>
<widget class="QPushButton" name="btn_inClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_verifyInProof">
<property name="text">
<string>Verify</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<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>
<widget class="QPushButton" name="btn_clear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_verify">
<property name="text">
<string>Verify</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>

@ -31,7 +31,7 @@ WalletInfoDialog::WalletInfoDialog(AppContext *ctx, QWidget *parent)
void WalletInfoDialog::openWalletDir() {
QFileInfo file(m_ctx->walletPath);
QDesktopServices::openUrl(file.absolutePath());
QDesktopServices::openUrl(QUrl(QString("file://%1").arg(file.absolutePath()), QUrl::TolerantMode));
}
WalletInfoDialog::~WalletInfoDialog() {

@ -0,0 +1,14 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_GLOBALS_H
#define FEATHER_GLOBALS_H
#include <QtGlobal>
namespace globals
{
const qreal cdiv = 1e12;
}
#endif //FEATHER_GLOBALS_H

@ -25,12 +25,17 @@ HistoryWidget::HistoryWidget(QWidget *parent)
m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);});
m_copyMenu->addAction("Date", this, [this]{copy(copyField::Date);});
m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);});
m_copyMenu->addAction("Spend proof", this, &HistoryWidget::getSpendProof);
auto spendProof = m_copyMenu->addAction("Spend proof", this, &HistoryWidget::getSpendProof);
ui->history->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->history, &QTreeView::customContextMenuRequested, [=](const QPoint & point){
QModelIndex index = ui->history->indexAt(point);
if (index.isValid()) {
TransactionInfo::Direction direction;
m_txHistory->transaction(m_model->mapToSource(index).row(), [&direction](TransactionInfo &tInfo) {
direction = tInfo.direction();
});
spendProof->setVisible(direction == TransactionInfo::Direction_Out);
m_contextMenu->exec(ui->history->viewport()->mapToGlobal(point));
}
});
@ -45,11 +50,11 @@ HistoryWidget::HistoryWidget(QWidget *parent)
}
void HistoryWidget::setModel(Coins *coins, TransactionHistoryProxyModel *model, TransactionHistory *txHistory)
void HistoryWidget::setModel(TransactionHistoryProxyModel *model, Wallet *wallet)
{
m_coins = coins;
m_model = model;
m_txHistory = txHistory;
m_wallet = wallet;
m_txHistory = m_wallet->history();
ui->history->setModel(m_model);
ui->history->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
@ -66,7 +71,7 @@ void HistoryWidget::showTxDetails() {
});
if (i != nullptr) {
auto * dialog = new TransactionInfoDialog(m_coins, i, this);
auto * dialog = new TransactionInfoDialog(m_wallet, i, this);
dialog->exec();
}
}

@ -7,6 +7,7 @@
#include "model/TransactionHistoryModel.h"
#include "model/TransactionHistoryProxyModel.h"
#include "libwalletqt/Coins.h"
#include "libwalletqt/Wallet.h"
#include <QWidget>
#include <QMenu>
@ -21,7 +22,7 @@ Q_OBJECT
public:
explicit HistoryWidget(QWidget *parent = nullptr);
void setModel(Coins * coins, TransactionHistoryProxyModel * model, TransactionHistory * txHistory);
void setModel(TransactionHistoryProxyModel *model, Wallet *wallet);
~HistoryWidget() override;
public slots:
@ -51,7 +52,7 @@ private:
QMenu *m_copyMenu;
TransactionHistory *m_txHistory;
TransactionHistoryProxyModel *m_model;
Coins *m_coins;
Wallet *m_wallet = nullptr;
};
#endif //FEATHER_HISTORYWIDGET_H

@ -28,6 +28,11 @@ bool TransactionInfo::isCoinbase() const
return m_coinbase;
}
quint64 TransactionInfo::balanceDelta() const
{
return m_amount + m_fee;
}
double TransactionInfo::amount() const
{
// there's no unsigned uint64 for JS, so better use double
@ -44,6 +49,11 @@ QString TransactionInfo::displayAmount() const
return WalletManager::displayAmount(m_amount);
}
quint64 TransactionInfo::atomicFee() const
{
return m_fee;
}
QString TransactionInfo::fee() const
{
if(m_fee == 0)
@ -83,7 +93,7 @@ quint64 TransactionInfo::confirmations() const
quint64 TransactionInfo::confirmationsRequired() const
{
return (m_blockHeight < m_unlockTime) ? m_unlockTime - m_blockHeight : 10;
return (m_blockHeight < m_unlockTime) ? m_unlockTime - m_blockHeight : 4;
}
quint64 TransactionInfo::unlockTime() const
@ -127,6 +137,15 @@ QString TransactionInfo::destinations_formatted() const
return destinations;
}
QList<QString> TransactionInfo::destinations() const
{
QList<QString> dests;
for (auto const& t: m_transfers) {
dests.append(t->address());
}
return dests;
}
QString TransactionInfo::rings_formatted() const
{
QString rings;

@ -52,10 +52,12 @@ public:
bool isPending() const;
bool isFailed() const;
bool isCoinbase() const;
quint64 balanceDelta() const;
double amount() const;
quint64 atomicAmount() const;
QString displayAmount() const;
QString fee() const;
quint64 atomicFee() const;
quint64 blockHeight() const;
QString description() const;
QSet<quint32> subaddrIndex() const;
@ -72,6 +74,7 @@ public:
QString paymentId() const;
//! only applicable for output transactions
//! used in tx details popup
QList<QString> destinations() const;
QString destinations_formatted() const;
QString rings_formatted() const;

@ -3,6 +3,10 @@
#include "Wallet.h"
#include <chrono>
#include <stdexcept>
#include <thread>
#include "PendingTransaction.h"
#include "UnsignedTransaction.h"
#include "TransactionHistory.h"
@ -28,6 +32,8 @@
#include <QVector>
#include <QMutexLocker>
#include "utils/ScopeGuard.h"
namespace {
static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5;
static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 30;
@ -41,6 +47,11 @@ Wallet::Wallet(QObject * parent)
{
}
Wallet::ConnectionStatus Wallet::connectionStatus() const
{
return m_connectionStatus;
}
QString Wallet::getSeed() const
{
return QString::fromStdString(m_walletImpl->seed());
@ -66,39 +77,26 @@ NetworkType::Type Wallet::nettype() const
return static_cast<NetworkType::Type>(m_walletImpl->nettype());
}
bool Wallet::disconnected() const
{
return m_disconnected;
}
void Wallet::updateConnectionStatusAsync()
bool Wallet::refreshing() const
{
m_scheduler.run([this] {
if (m_connectionStatus == Wallet::ConnectionStatus_Disconnected)
{
setConnectionStatus(ConnectionStatus_Connecting);
}
ConnectionStatus newStatus = static_cast<ConnectionStatus>(m_walletImpl->connected());
if (newStatus != m_connectionStatus || !m_initialized) {
m_initialized = true;
setConnectionStatus(newStatus);
}
// Release lock
m_connectionStatusRunning = false;
});
return m_refreshing;
}
Wallet::ConnectionStatus Wallet::connected(bool forceCheck)
void Wallet::refreshingSet(bool value)
{
// cache connection status
if (forceCheck || !m_initialized || (m_connectionStatusTime.elapsed() / 1000 > m_connectionStatusTtl && !m_connectionStatusRunning) || m_connectionStatusTime.elapsed() > 30000) {
m_connectionStatusRunning = true;
m_connectionStatusTime.restart();
updateConnectionStatusAsync();
if (m_refreshing.exchange(value) != value)
{
emit refreshingChanged();
}
return m_connectionStatus;
}
bool Wallet::disconnected() const
{
return m_disconnected;
void Wallet::setConnectionTimeout(int timeout) {
m_connectionTimeout = timeout;
}
void Wallet::setConnectionStatus(ConnectionStatus value)
@ -159,6 +157,11 @@ bool Wallet::setPassword(const QString &password)
return m_walletImpl->setPassword(password.toStdString());
}
QString Wallet::getPassword()
{
return QString::fromStdString(m_walletImpl->getPassword());
}
QString Wallet::address(quint32 accountIndex, quint32 addressIndex) const
{
return QString::fromStdString(m_walletImpl->address(accountIndex, addressIndex));
@ -207,16 +210,16 @@ bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 uppe
{
QMutexLocker locker(&m_proxyMutex);
if (!m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), false, false, proxyAddress.toStdString()))
if (!m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), m_useSSL, false, proxyAddress.toStdString()))
{
return false;
}
m_proxyAddress = proxyAddress;
}
emit proxyAddressChanged();
setTrustedDaemon(trustedDaemon);
setTrustedDaemon(trustedDaemon);
return true;
}
@ -244,8 +247,8 @@ void Wallet::initAsync(
{
emit walletCreationHeightChanged();
qDebug() << "init async finished - starting refresh";
connected(true);
m_walletImpl->startRefresh();
refreshHeightAsync();
startRefresh();
}
});
if (future.first)
@ -288,6 +291,11 @@ void Wallet::setTrustedDaemon(bool arg)
m_walletImpl->setTrustedDaemon(arg);
}
void Wallet::setUseSSL(bool ssl)
{
m_useSSL = ssl;
}
bool Wallet::viewOnly() const
{
return m_walletImpl->watchOnly();
@ -400,6 +408,8 @@ void Wallet::refreshHeightAsync()
daemonHeightFuture.second.waitForFinished();
targetHeightFuture.second.waitForFinished();
setConnectionStatus(ConnectionStatus_Connected);
emit heightRefreshed(walletHeight, daemonHeight, targetHeight);
});
}
@ -414,7 +424,8 @@ quint64 Wallet::daemonBlockChainHeight() const
// cache daemon blockchain height for some time (60 seconds by default)
if (m_daemonBlockChainHeight == 0
|| m_daemonBlockChainHeightTime.elapsed() / 1000 > m_daemonBlockChainHeightTtl) {
|| m_daemonBlockChainHeightTime.elapsed() / 1000 > m_daemonBlockChainHeightTtl)
{
m_daemonBlockChainHeight = m_walletImpl->daemonBlockChainHeight();
m_daemonBlockChainHeightTime.restart();
}
@ -424,7 +435,8 @@ quint64 Wallet::daemonBlockChainHeight() const
quint64 Wallet::daemonBlockChainTargetHeight() const
{
if (m_daemonBlockChainTargetHeight <= 1
|| m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl) {
|| m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl)
{
m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight();
// Target height is set to 0 if daemon is synced.
@ -440,36 +452,56 @@ quint64 Wallet::daemonBlockChainTargetHeight() const
bool Wallet::exportKeyImages(const QString& path, bool all)
{
return m_walletImpl->exportKeyImages(path.toStdString(), all);
// @TODO: remove after WOW 0.9.0.2 tagged + feather libwallet patch
//return m_walletImpl->exportKeyImages(path.toStdString(), all);
return false;
}
bool Wallet::importKeyImages(const QString& path)
{
return m_walletImpl->importKeyImages(path.toStdString());
// @TODO: remove after WOW 0.9.0.2 tagged + feather libwallet patch
//return m_walletImpl->importKeyImages(path.toStdString());
return false;
}
bool Wallet::exportOutputs(const QString& path, bool all) {
return m_walletImpl->exportOutputs(path.toStdString(), all);
// @TODO: remove after WOW 0.9.0.2 tagged + feather libwallet patch
//return m_walletImpl->exportOutputs(path.toStdString(), all);
return false;
}
bool Wallet::importOutputs(const QString& path) {
return m_walletImpl->importOutputs(path.toStdString());
// @TODO: remove after WOW 0.9.0.2 tagged + feather libwallet patch
// return m_walletImpl->importOutputs(path.toStdString());
return false;
}
bool Wallet::refresh()
{
qDebug() << "refresh async";
m_walletImpl->refreshAsync();
bool Wallet::importTransaction(const QString& txid, const QVector<quint64>& output_indeces, quint64 height, quint64 timestamp, bool miner_tx, bool pool, bool double_spend_seen) {
std::vector<uint64_t> o_indeces;
for (const auto &o : output_indeces) {
o_indeces.push_back(o);
}
return m_walletImpl->importTransaction(
txid.toStdString(),
o_indeces,
height,
17, // todo: get actual block_version
timestamp,
miner_tx,
pool,
double_spend_seen);
}
void Wallet::startRefresh() const
void Wallet::startRefresh()
{
m_walletImpl->startRefresh();
m_refreshEnabled = true;
m_refreshNow = true;
}
void Wallet::pauseRefresh() const
void Wallet::pauseRefresh()
{
m_walletImpl->pauseRefresh();
m_refreshEnabled = false;
}
PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
@ -580,6 +612,28 @@ bool Wallet::submitTxFile(const QString &fileName) const
return m_walletImpl->importKeyImages(fileName.toStdString() + "_keyImages");
}
bool Wallet::refresh(bool historyAndSubaddresses /* = true */)
{
refreshingSet(true);
const auto cleanup = sg::make_scope_guard([this]() noexcept {
refreshingSet(false);
});
{
QMutexLocker locker(&m_asyncMutex);
bool result = m_walletImpl->refresh();
if (historyAndSubaddresses)
{
m_history->refresh(currentSubaddressAccount());
m_subaddress->refresh(currentSubaddressAccount());
m_subaddressAccount->getAll();
}
return result;
}
}
void Wallet::commitTransactionAsync(PendingTransaction *t)
{
m_scheduler.run([this, t] {
@ -755,12 +809,10 @@ QString Wallet::checkTxKey(const QString &txid, const QString &tx_key, const QSt
return QString::fromStdString(result);
}
QString Wallet::getTxProof(const QString &txid, const QString &address, const QString &message) const
TxProof Wallet::getTxProof(const QString &txid, const QString &address, const QString &message) const
{
std::string result = m_walletImpl->getTxProof(txid.toStdString(), address.toStdString(), message.toStdString());
if (result.empty())
result = "error|" + m_walletImpl->errorString();
return QString::fromStdString(result);
return TxProof(QString::fromStdString(result), QString::fromStdString(m_walletImpl->errorString()));
}
//void Wallet::getTxProofAsync(const QString &txid, const QString &address, const QString &message, const QJSValue &callback)
@ -780,12 +832,10 @@ TxProofResult Wallet::checkTxProof(const QString &txid, const QString &address,
return {success, good, received, in_pool, confirmations};
}
Q_INVOKABLE QString Wallet::getSpendProof(const QString &txid, const QString &message) const
Q_INVOKABLE TxProof Wallet::getSpendProof(const QString &txid, const QString &message) const
{
std::string result = m_walletImpl->getSpendProof(txid.toStdString(), message.toStdString());
if (result.empty())
result = "error|" + m_walletImpl->errorString();
return QString::fromStdString(result);
return TxProof(QString::fromStdString(result), QString::fromStdString(m_walletImpl->errorString()));
}
//void Wallet::getSpendProofAsync(const QString &txid, const QString &message, const QJSValue &callback)
@ -1035,6 +1085,14 @@ void Wallet::onWalletPassphraseNeeded(bool on_device)
emit this->walletPassphraseNeeded(on_device);
}
quint64 Wallet::getBytesReceived() const {
return m_walletImpl->getBytesReceived();
}
quint64 Wallet::getBytesSent() const {
return m_walletImpl->getBytesSent();
}
void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort)
{
if (m_walletListener != nullptr)
@ -1063,7 +1121,11 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
, m_subaddressAccount(nullptr)
, m_subaddressAccountModel(nullptr)
, m_coinsModel(nullptr)
, m_refreshNow(false)
, m_refreshEnabled(false)
, m_refreshing(false)
, m_scheduler(this)
, m_useSSL(true)
{
m_history = new TransactionHistory(m_walletImpl->history(), this);
m_addressBook = new AddressBook(m_walletImpl->addressBook(), this);
@ -1081,12 +1143,17 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
m_connectionStatusRunning = false;
m_daemonUsername = "";
m_daemonPassword = "";
startRefreshThread();
}
Wallet::~Wallet()
{
qDebug("~Wallet: Closing wallet");
pauseRefresh();
m_walletImpl->stop();
m_scheduler.shutdownWaitForFinished();
delete m_addressBook;
@ -1116,3 +1183,41 @@ Wallet::~Wallet()
m_walletListener = NULL;
qDebug("m_walletImpl deleted");
}
void Wallet::startRefreshThread()
{
const auto future = m_scheduler.run([this] {
constexpr const std::chrono::seconds refreshInterval{10};
constexpr const std::chrono::milliseconds intervalResolution{100};
auto last = std::chrono::steady_clock::now();
while (!m_scheduler.stopping())
{
if (m_refreshEnabled)
{
const auto now = std::chrono::steady_clock::now();
const auto elapsed = now - last;
if (elapsed >= refreshInterval || m_refreshNow)
{
m_refreshNow = false;
refresh(false);
last = std::chrono::steady_clock::now();
}
}
std::this_thread::sleep_for(intervalResolution);
}
});
if (!future.first)
{
throw std::runtime_error("failed to start auto refresh thread");
}
}
void Wallet::onRefreshed(bool success) {
if (success) {
setConnectionStatus(ConnectionStatus_Connected);
} else {
setConnectionStatus(ConnectionStatus_Disconnected);
}
}

@ -22,6 +22,13 @@ namespace Monero {
struct Wallet; // forward declaration
}
struct TxProof {
TxProof(QString proof, QString error = "")
: proof(std::move(proof)), error(std::move(error)){}
QString proof;
QString error;
};
class TransactionHistory;
class TransactionHistoryModel;
@ -50,11 +57,12 @@ class Wallet : public QObject, public PassprasePrompter
{
Q_OBJECT
Q_PROPERTY(bool disconnected READ disconnected NOTIFY disconnectedChanged)
Q_PROPERTY(bool refreshing READ refreshing NOTIFY refreshingChanged)
Q_PROPERTY(QString seed READ getSeed)
Q_PROPERTY(QString seedLanguage READ getSeedLanguage)
Q_PROPERTY(Status status READ status)
Q_PROPERTY(NetworkType::Type nettype READ nettype)
// Q_PROPERTY(ConnectionStatus connected READ connected)
Q_PROPERTY(ConnectionStatus connectionStatus READ connectionStatus)
Q_PROPERTY(quint32 currentSubaddressAccount READ currentSubaddressAccount NOTIFY currentSubaddressAccountChanged)
Q_PROPERTY(bool synchronized READ synchronized)
Q_PROPERTY(QString errorString READ errorString)
@ -97,6 +105,9 @@ public:
Q_ENUM(ConnectionStatus)
//! return connection status
ConnectionStatus connectionStatus() const;
//! returns mnemonic seed
QString getSeed() const;
@ -112,10 +123,6 @@ public:
//! returns network type of the wallet.
NetworkType::Type nettype() const;
//! returns whether the wallet is connected, and version status
Q_INVOKABLE ConnectionStatus connected(bool forceCheck = false);
void updateConnectionStatusAsync();
//! returns true if wallet was ever synchronized
bool synchronized() const;
@ -126,6 +133,9 @@ public:
//! changes the password using existing parameters (path, seed, seed lang)
Q_INVOKABLE bool setPassword(const QString &password);
//! get current wallet password
Q_INVOKABLE QString getPassword();
//! returns wallet's public address
Q_INVOKABLE QString address(quint32 accountIndex, quint32 addressIndex) const;
@ -156,9 +166,15 @@ public:
//! connects to daemon
Q_INVOKABLE bool connectToDaemon();
//! indicates id daemon is trusted
//! set connect to daemon timeout
Q_INVOKABLE void setConnectionTimeout(int timeout);
//! indicates if daemon is trusted
Q_INVOKABLE void setTrustedDaemon(bool arg);
//! indicates if ssl should be used to connect to daemon
Q_INVOKABLE void setUseSSL(bool ssl);
//! returns balance
Q_INVOKABLE quint64 balance() const;
Q_INVOKABLE quint64 balance(quint32 accountIndex) const;
@ -198,12 +214,15 @@ public:
Q_INVOKABLE bool exportOutputs(const QString& path, bool all = false);
Q_INVOKABLE bool importOutputs(const QString& path);
//! import a transaction
Q_INVOKABLE bool importTransaction(const QString& txid, const QVector<quint64>& output_indeces, quint64 height, quint64 timestamp, bool miner_tx, bool pool, bool double_spend_seen);
//! refreshes the wallet
Q_INVOKABLE bool refresh();
Q_INVOKABLE bool refresh(bool historyAndSubaddresses = false);
// pause/resume refresh
Q_INVOKABLE void startRefresh() const;
Q_INVOKABLE void pauseRefresh() const;
Q_INVOKABLE void startRefresh();
Q_INVOKABLE void pauseRefresh();
//! returns current wallet's block height
//! (can be less than daemon's blockchain height when wallet sync in progress)
@ -335,11 +354,11 @@ public:
Q_INVOKABLE QString getTxKey(const QString &txid) const;
//Q_INVOKABLE void getTxKeyAsync(const QString &txid, const QJSValue &callback);
Q_INVOKABLE QString checkTxKey(const QString &txid, const QString &tx_key, const QString &address);
Q_INVOKABLE QString getTxProof(const QString &txid, const QString &address, const QString &message) const;
Q_INVOKABLE TxProof getTxProof(const QString &txid, const QString &address, const QString &message) const;
// Q_INVOKABLE void getTxProofAsync(const QString &txid, const QString &address, const QString &message, const QJSValue &callback);
//Q_INVOKABLE QString checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
Q_INVOKABLE TxProofResult checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
Q_INVOKABLE QString getSpendProof(const QString &txid, const QString &message) const;
Q_INVOKABLE TxProof getSpendProof(const QString &txid, const QString &message) const;
// Q_INVOKABLE void getSpendProofAsync(const QString &txid, const QString &message, const QJSValue &callback);
Q_INVOKABLE QPair<bool, bool> checkSpendProof(const QString &txid, const QString &message, const QString &signature) const;
// Rescan spent outputs
@ -380,6 +399,9 @@ public:
Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
virtual void onWalletPassphraseNeeded(bool on_device) override;
Q_INVOKABLE quint64 getBytesReceived() const;
Q_INVOKABLE quint64 getBytesSent() const;
// TODO: setListenter() when it implemented in API
signals:
// emitted on every event happened with wallet
@ -388,7 +410,7 @@ signals:
// emitted when refresh process finished (could take a long time)
// signalling only after we
void refreshed();
void refreshed(bool success);
void moneySpent(const QString &txId, quint64 amount);
void moneyReceived(const QString &txId, quint64 amount);
@ -411,6 +433,7 @@ signals:
void currentSubaddressAccountChanged() const;
void disconnectedChanged() const;
void proxyAddressChanged() const;
void refreshingChanged() const;
private:
Wallet(QObject * parent = nullptr);
@ -428,9 +451,14 @@ private:
const QString& proxyAddress);
bool disconnected() const;
bool refreshing() const;
void refreshingSet(bool value);
void onRefreshed(bool success);
void setConnectionStatus(ConnectionStatus value);
QString getProxyAddress() const;
void setProxyAddress(QString address);
void startRefreshThread();
private:
friend class WalletManager;
@ -470,10 +498,13 @@ private:
QString m_daemonPassword;
QString m_proxyAddress;
mutable QMutex m_proxyMutex;
std::atomic<bool> m_refreshNow;
std::atomic<bool> m_refreshEnabled;
std::atomic<bool> m_refreshing;
WalletListenerImpl *m_walletListener;
FutureScheduler m_scheduler;
int m_connectionTimeout = 30;
bool m_useSSL;
};

@ -41,10 +41,11 @@ void WalletListenerImpl::updated()
}
// called when wallet refreshed by background thread or explicitly
void WalletListenerImpl::refreshed()
void WalletListenerImpl::refreshed(bool success)
{
qDebug() << __FUNCTION__;
emit m_wallet->refreshed();
m_wallet->onRefreshed(success);
emit m_wallet->refreshed(success);
}
void WalletListenerImpl::onDeviceButtonRequest(uint64_t code)

@ -25,7 +25,7 @@ public:
virtual void updated() override;
// called when wallet refreshed by background thread or explicitly
virtual void refreshed() override;
virtual void refreshed(bool success) override;
virtual void onDeviceButtonRequest(uint64_t code) override;

@ -26,7 +26,7 @@ public:
virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; };
virtual void newBlock(uint64_t height) override { (void) height; };
virtual void updated() override {};
virtual void refreshed() override {};
virtual void refreshed(bool success) override {};
virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) override
{
@ -335,7 +335,7 @@ bool WalletManager::isMining() const
{
{
QMutexLocker locker(&m_mutex);
if (m_currentWallet == nullptr || !m_currentWallet->connected())
if (m_currentWallet == nullptr || !m_currentWallet->connectionStatus())
{
return false;
}

@ -38,7 +38,7 @@ int main(int argc, char *argv[])
}
QCommandLineParser parser;
parser.setApplicationDescription("feather");
parser.setApplicationDescription("feather-wow");
parser.addHelpOption();
parser.addVersionOption();
@ -54,11 +54,11 @@ int main(int argc, char *argv[])
QCommandLineOption quietModeOption(QStringList() << "quiet", "Limit console output");
parser.addOption(quietModeOption);
QCommandLineOption stagenetOption(QStringList() << "stagenet", "Stagenet is for development purposes only.");
parser.addOption(stagenetOption);
QCommandLineOption testnetOption(QStringList() << "testnet", "Testnet is for development purposes only.");
parser.addOption(testnetOption);
// QCommandLineOption stagenetOption(QStringList() << "stagenet", "Stagenet is for development purposes only.");
// parser.addOption(stagenetOption);
//
// QCommandLineOption testnetOption(QStringList() << "testnet", "Testnet is for development purposes only.");
// parser.addOption(testnetOption);
QCommandLineOption walletPathOption(QStringList() << "wallet-file", "Path to wallet keys file.", "file");
parser.addOption(walletPathOption);
@ -84,8 +84,8 @@ int main(int argc, char *argv[])
const QStringList args = parser.positionalArguments();
bool debugMode = parser.isSet(debugModeOption);
bool localTor = parser.isSet(useLocalTorOption);
bool stagenet = parser.isSet(stagenetOption);
bool testnet = parser.isSet(testnetOption);
bool stagenet = false;
bool testnet = false;
bool quiet = parser.isSet(quietModeOption);
bool exportContacts = parser.isSet(exportContactsOption);
bool exportTxHistory = parser.isSet(exportTxHistoryOption);
@ -93,7 +93,7 @@ int main(int argc, char *argv[])
if(cliMode) {
QCoreApplication cli_app(argc, argv);
QCoreApplication::setApplicationName("feather");
QCoreApplication::setApplicationName("feather-wow");
QCoreApplication::setOrganizationDomain("featherwallet.org");
QCoreApplication::setOrganizationName("featherwallet.org");
@ -126,7 +126,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
QApplication::setApplicationName("feather");
QApplication::setApplicationName("feather-wow");
QApplication::setOrganizationDomain("featherwallet.org");
QApplication::setOrganizationName("featherwallet.org");
@ -135,7 +135,7 @@ int main(int argc, char *argv[])
if(!quiet) {
QMap<QString, QString> info;
info["Qt"] = QT_VERSION_STR;
info["Feather"] = FEATHER_VERSION;
info["Feather-WOW"] = FEATHER_VERSION;
if (stagenet) info["Mode"] = "Stagenet";
else if (testnet) info["Mode"] = "Testnet";
else info["Mode"] = "Mainnet";

@ -95,7 +95,7 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
connect(ui->actionReport_bug, &QAction::triggered, [this](){
QMessageBox::information(this, "Reporting Bugs",
"<body>Please report any bugs as issues on our git repo:<br>\n"
"<a href=\"https://git.wownero.com/feather/feather/issues\" style=\"color: #33A4DF\">https://git.wownero.com/feather/feather/issues</a><br/><br/>"
"<a href=\"https://git.wownero.com/feather/feather-wow/issues\" style=\"color: #33A4DF\">https://git.wownero.com/feather/feather-wow/issues</a><br/><br/>"
"\n"
"Before reporting a bug, upgrade to the most recent version of Feather "
"(latest release or git HEAD), and include the version number in your report. "
@ -131,7 +131,7 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
m_trayActionCalc->setStatusTip("Calculator");
m_trayActionSend = new QAction("Send", this);
m_trayActionSend->setStatusTip("Send XMR payment");
m_trayActionSend->setStatusTip("Send WOW payment");
m_trayActionHistory = new QAction("History", this);
m_trayActionHistory->setStatusTip("View incoming transfers");
@ -153,13 +153,13 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
#endif
// ticker widgets
m_tickerWidgets.append(new TickerWidget(this, "XMR"));
m_tickerWidgets.append(new TickerWidget(this, "WOW"));
m_tickerWidgets.append(new TickerWidget(this, "BTC"));
for(auto tickerWidget: m_tickerWidgets) {
ui->tickerLayout->addWidget(tickerWidget);
}
m_balanceWidget = new TickerWidget(this, "XMR", "Balance", true);
m_balanceWidget = new TickerWidget(this, "WOW", "Balance", true);
ui->fiatTickerLayout->addWidget(m_balanceWidget);
// Send widget
@ -195,13 +195,6 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
ui->coolLayout->addWidget(m_ccsWidget);
ui->coolLayout->addWidget(m_redditWidget);
connect(m_ctx, &AppContext::ccsEmpty, [=] {
if(m_ccsWidget->isVisible()) {
// display Reddit widget instead
m_ccsWidget->show();
m_redditWidget->show();
}
});
connect(m_ctx, &AppContext::ccsUpdated, m_ccsWidget->model(), &CCSModel::updateEntries);
connect(m_ctx, &AppContext::redditUpdated, m_redditWidget->model(), &RedditModel::updatePosts);
connect(m_ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen);
@ -469,7 +462,7 @@ void MainWindow::initMenu() {
if(targetDir.isEmpty()) return;
qint64 now = QDateTime::currentDateTime().currentMSecsSinceEpoch();
QString fn = QString("%1/monero-contacts_%2.csv").arg(targetDir, QString::number(now / 1000));
QString fn = QString("%1/wownero-contacts_%2.csv").arg(targetDir, QString::number(now / 1000));
if(model->writeCSV(fn))
Utils::showMessageBox("Address book exported", QString("Address book exported to %1").arg(fn), false);
});
@ -628,9 +621,9 @@ void MainWindow::onWalletOpened() {
void MainWindow::onBalanceUpdated(double balance, double unlocked, const QString &balance_str, const QString &unlocked_str) {
qDebug() << Q_FUNC_INFO;
auto label_str = QString("Balance: %1 XMR").arg(unlocked_str);
auto label_str = QString("Balance: %1 WOW").arg(unlocked_str);
if(balance > unlocked)
label_str += QString(" (+%1 XMR unconfirmed)").arg(QString::number(balance - unlocked, 'f'));
label_str += QString(" (+%1 WOW unconfirmed)").arg(QString::number(balance - unlocked, 'f'));
m_statusLabelBalance->setText(label_str);
}
@ -773,7 +766,7 @@ void MainWindow::create_status_bar() {
m_statusLabelStatus->setTextInteractionFlags(Qt::TextSelectableByMouse);
this->statusBar()->addWidget(m_statusLabelStatus);
m_statusLabelBalance = new QLabel("Balance: 0.00 XMR", this);
m_statusLabelBalance = new QLabel("Balance: 0.00 WOW", this);
m_statusLabelBalance->setTextInteractionFlags(Qt::TextSelectableByMouse);
this->statusBar()->addPermanentWidget(m_statusLabelBalance);
@ -1003,7 +996,7 @@ void MainWindow::closeEvent(QCloseEvent *event) {
}
void MainWindow::donateButtonClicked() {
double donation = AppContext::prices->convert("EUR", "XMR", m_ctx->featherDonationAmount);
double donation = AppContext::prices->convert("EUR", "WOW", m_ctx->featherDonationAmount);
if(donation <= 0)
donation = 1.337;

@ -4,6 +4,10 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#ifdef Q_OS_MAC
#include "src/kdmactouchbar.h"
#endif
#include <QMainWindow>
#include <QSystemTrayIcon>
#include <QScreen>
@ -65,6 +69,18 @@ public:
qreal screenDpiPhysical;
qreal screenRatio;
enum Tabs {
HOME = 0,
HISTORY,
SEND,
RECEIVE,
COINS,
CALC,
MORPHTOKEN,
XMR_TO,
XMRIG
};
public slots:
void initWidgets();
void initMenu();
@ -96,10 +112,12 @@ public slots:
void onWalletCreated(Wallet *wallet);
void menuWalletCloseClicked();
void menuWalletOpenClicked();
void onWalletOpenPasswordRequired(bool invalidPassword);
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);
void onViewOnBlockExplorer(const QString &txid);
void onAddContact(const QString &address, const QString &name);
void importContacts();
void showRestoreHeightDialog();
void importTransaction();
// offline tx signing
void exportKeyImages();
@ -142,6 +160,10 @@ private:
void showNodeExhaustedMessage();
void showWSNodeExhaustedMessage();
void createUnsignedTxDialog(UnsignedTransaction *tx);
void touchbarShowWizard();
void touchbarShowWallet();
void updatePasswordIcon();
void updateNetStats();
WalletWizard *createWizard(WalletWizard::Page startPage);
@ -171,6 +193,7 @@ private:
// lower status bar
QLabel *m_statusLabelBalance;
QLabel *m_statusLabelStatus;
QLabel *m_statusLabelNetStats;
StatusBarButton *m_statusBtnConnectionStatusIndicator;
StatusBarButton *m_statusBtnPassword;
StatusBarButton *m_statusBtnPreferences;
@ -180,13 +203,20 @@ private:
SubaddressProxyModel *subaddressProxyModel;
TransactionHistoryModel *txHistModel;
CoinsModel *coinsModel;
#ifdef Q_OS_MAC
QAction *m_touchbarActionWelcome;
KDMacTouchBar *m_touchbar;
QList<QAction *> m_touchbarWalletItems;
QList<QAction *> m_touchbarWizardItems;
#endif
QSignalMapper *m_tabShowHideSignalMapper;
QMap<QString, ToggleTab*> m_tabShowHideMapper;
WalletWizard *m_wizard = nullptr;
QMap<QString, QString> m_skins;
QTimer m_updateBytes;
private slots:
void menuToggleTabVisible(const QString &key);
};

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

Loading…
Cancel
Save