├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG ├── Etherwall.pro ├── LICENSE ├── README.md ├── deployment.pri ├── generate_protobuf.sh ├── i18n └── etherwall.ts ├── icon.ico ├── qml ├── components │ ├── AccountDetails.qml │ ├── AccountDialog.qml │ ├── AccountsTab.qml │ ├── ArgNumber.qml │ ├── Badge.qml │ ├── BusyIndicatorFixed.qml │ ├── CallContractContent.qml │ ├── ContractCalls.qml │ ├── ContractContent.qml │ ├── ContractDeploy.qml │ ├── ContractDetails.qml │ ├── ContractsTab.qml │ ├── CurrencyRow.qml │ ├── CurrencyTab.qml │ ├── DeployContractContent.qml │ ├── EWToolTip.qml │ ├── EventContent.qml │ ├── EventDetails.qml │ ├── FilterDetails.qml │ ├── FiltersContent.qml │ ├── FirstTimeDialog.qml │ ├── FunctionResultsContent.qml │ ├── GethTab.qml │ ├── InfoTab.qml │ ├── InputDialog.qml │ ├── LogTab.qml │ ├── PasswordDialog.qml │ ├── PinMatrixDialog.qml │ ├── QRCode.qml │ ├── QRExportDialog.qml │ ├── SendTransactionContent.qml │ ├── SettingsContent.qml │ ├── SettingsTab.qml │ ├── TableViewBase.qml │ ├── TransactionDetails.qml │ ├── TransactionDialog.qml │ ├── TransactionsTab.qml │ └── TrezorImportDialog.qml ├── images │ ├── all.png │ ├── block.png │ ├── btc.png │ ├── cad.png │ ├── cryptocompare.png │ ├── error.png │ ├── eth.png │ ├── eur.png │ ├── gas.png │ ├── gbp.png │ ├── high_connection.png │ ├── homescreen.png │ ├── icon.icns │ ├── icon.png │ ├── locked.png │ ├── low_connection.png │ ├── medium_connection.png │ ├── no_connection.png │ ├── ok.png │ ├── trezor.png │ ├── unlocked.png │ ├── usd.png │ └── warning.png ├── js │ └── qqr.js ├── main.qml └── qml.qrc ├── src ├── accountmodel.cpp ├── accountmodel.h ├── accountproxymodel.cpp ├── accountproxymodel.h ├── cert.h ├── clipboard.cpp ├── clipboard.h ├── contractinfo.cpp ├── contractinfo.h ├── contractmodel.cpp ├── contractmodel.h ├── currencymodel.cpp ├── currencymodel.h ├── etherlogapp.cpp ├── etherlogapp.h ├── eventmodel.cpp ├── eventmodel.h ├── filtermodel.cpp ├── filtermodel.h ├── gethlogapp.cpp ├── gethlogapp.h ├── initializer.cpp ├── initializer.h ├── main.cpp ├── nodeipc.cpp ├── nodemanager.cpp ├── nodemanager.h ├── platform │ ├── devicemanager.cpp │ └── devicemanager.h ├── settings.cpp ├── settings.h ├── tokenmodel.cpp ├── tokenmodel.h ├── transactionmodel.cpp ├── transactionmodel.h └── trezor │ ├── hdpath.cpp │ ├── hdpath.h │ ├── trezor.cpp │ ├── trezor.h │ ├── wire.cpp │ └── wire.h └── tests └── conversions.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: almindor 2 | custom: ["https://flattr.com/submit/auto?user_id=Almindor&url=https://github.com/almindor/etherwall&title=Etherwall&language=&tags=github&category=software"] 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binary 2 | Etherwall 3 | Etherwall.exe 4 | 5 | # C++ objects and libs 6 | 7 | .DS_Store 8 | 9 | *.slo 10 | *.lo 11 | *.o 12 | *.a 13 | *.la 14 | *.lai 15 | *.so 16 | *.dll 17 | *.dylib 18 | 19 | # Qt-es 20 | 21 | /.qmake.cache 22 | /.qmake.stash 23 | *.pro.user 24 | *.pro.user.* 25 | *.qbs.user 26 | *.qbs.user.* 27 | *.moc 28 | moc_*.cpp 29 | qrc_*.cpp 30 | ui_*.h 31 | Makefile* 32 | *-build-* 33 | 34 | # QtCreator 35 | 36 | *.autosave 37 | 38 | #QtCtreator Qml 39 | *.qmlproject.user 40 | *.qmlproject.user.* 41 | 42 | data.etherwall.com.crt 43 | src/trezor/proto 44 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/trezor/trezor-common"] 2 | path = src/trezor/trezor-common 3 | url = https://github.com/trezor/trezor-common.git 4 | [submodule "src/ew-node"] 5 | path = src/ew-node 6 | url = https://github.com/almindor/ew-node.git 7 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | * 3.0.4 - fix remove trezor account dialog 2 | * 3.0.0 - redo UI in new qtquick2 3 | ---- 4 | * 2.2.2 - fix macOS X specific modal dialog issues 5 | * 2.2.1 - fix eth_estimateGas errors 6 | * 2.1.1 - fix eth_getLogs missing internalFilterID 7 | * 2.1.0 - add ERC20 support, performance improvements 8 | ---- 9 | * 2.0.4 - fix minor bugs introduced in 2.0.3 refactor, add initial ERC20 support (WIP) 10 | * 2.0.3 - fix contract constant method calls (eth_call), add geth log copy to clipboard 11 | * 2.0.2 - fix comma crash, transaction account alias fix 12 | * 2.0.1 - fix account aliasing 13 | * 2.0.0 - add thin client mode, TREZOR and rinkeby support 14 | -------------------------------------------------------------------------------- /Etherwall.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += qml quick widgets network websockets 4 | # CONFIG += c++11 5 | DEFINES += QT_DEPRECATED_WARNINGS 6 | 7 | INCLUDEPATH += src src/ew-node/src 8 | DEPENDPATH += src src/ew-node/src 9 | 10 | linux { 11 | CONFIG += link_pkgconfig 12 | PKGCONFIG += hidapi-libusb libusb-1.0 protobuf libudev 13 | } 14 | 15 | win32 { 16 | INCLUDEPATH += C:\msys64\mingw64\include 17 | # PKGCONFIG += hidapi libusb-1.0 protobuf libudev 18 | LIBS += -lprotobuf -lusb-1.0 -lhidapi -lsetupapi -lws2_32 19 | RC_ICONS = icon.ico 20 | } 21 | 22 | macx { 23 | QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.15 24 | INCLUDEPATH += /usr/local/include 25 | INCLUDEPATH += /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Headers 26 | INCLUDEPATH += /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreFoundation.framework/Headers 27 | QMAKE_LFLAGS += -F/System/Library/Frameworks/CoreFoundation.framework -F/System/Library/Frameworks/IOKit.framework 28 | LIBS += -framework CoreFoundation 29 | LIBS += -framework IOKit 30 | LIBS += /usr/local/lib/libhidapi.a /usr/local/lib/libprotobuf.a /usr/local/lib/libusb-1.0.a 31 | ICON=qml/images/icon.icns 32 | } 33 | 34 | SOURCES += src/main.cpp \ 35 | src/accountmodel.cpp \ 36 | src/settings.cpp \ 37 | src/transactionmodel.cpp \ 38 | src/clipboard.cpp \ 39 | src/currencymodel.cpp \ 40 | src/accountproxymodel.cpp \ 41 | src/contractmodel.cpp \ 42 | src/contractinfo.cpp \ 43 | src/eventmodel.cpp \ 44 | src/filtermodel.cpp \ 45 | src/trezor/trezor.cpp \ 46 | src/trezor/proto/messages.pb.cc \ 47 | src/trezor/proto/messages-common.pb.cc \ 48 | src/trezor/proto/messages-management.pb.cc \ 49 | src/trezor/proto/messages-ethereum.pb.cc \ 50 | src/trezor/wire.cpp \ 51 | src/trezor/hdpath.cpp \ 52 | src/platform/devicemanager.cpp \ 53 | src/initializer.cpp \ 54 | src/tokenmodel.cpp \ 55 | src/ew-node/src/etherlog.cpp \ 56 | src/ew-node/src/gethlog.cpp \ 57 | src/ew-node/src/helpers.cpp \ 58 | src/ew-node/src/types.cpp \ 59 | src/ew-node/src/ethereum/tx.cpp \ 60 | src/ew-node/src/ethereum/bigint.cpp \ 61 | src/ew-node/src/nodeipc.cpp \ 62 | src/ew-node/src/nodews.cpp \ 63 | src/gethlogapp.cpp \ 64 | src/etherlogapp.cpp \ 65 | src/ew-node/src/networkchainmanager.cpp \ 66 | src/nodemanager.cpp 67 | 68 | RESOURCES += qml/qml.qrc 69 | 70 | # Additional import path used to resolve QML modules in Qt Creator's code model 71 | QML_IMPORT_PATH = qml 72 | 73 | # Default rules for deployment. 74 | include(deployment.pri) 75 | 76 | TRANSLATIONS += \ 77 | i18n/etherwall.ts 78 | 79 | lupdate_only { 80 | SOURCES += \ 81 | qml/*.qml \ 82 | qml/components/*.qml 83 | } 84 | 85 | HEADERS += \ 86 | src/accountmodel.h \ 87 | src/settings.h \ 88 | src/transactionmodel.h \ 89 | src/clipboard.h \ 90 | src/currencymodel.h \ 91 | src/accountproxymodel.h \ 92 | src/contractmodel.h \ 93 | src/contractinfo.h \ 94 | src/eventmodel.h \ 95 | src/filtermodel.h \ 96 | src/trezor/trezor.h \ 97 | src/trezor/proto/messages.pb.h \ 98 | src/trezor/proto/messages-common.pb.h \ 99 | src/trezor/proto/messages-management.pb.h \ 100 | src/trezor/proto/messages-ethereum.pb.h \ 101 | src/trezor/wire.h \ 102 | src/trezor/hdpath.h \ 103 | src/platform/devicemanager.h \ 104 | src/initializer.h \ 105 | src/tokenmodel.h \ 106 | src/cert.h \ 107 | src/ew-node/src/types.h \ 108 | src/ew-node/src/etherlog.h \ 109 | src/ew-node/src/gethlog.h \ 110 | src/ew-node/src/helpers.h \ 111 | src/ew-node/src/nodeipc.h \ 112 | src/ew-node/src/nodews.h \ 113 | src/ew-node/src/ethereum/bigint.h \ 114 | src/ew-node/src/ethereum/tx.h \ 115 | src/ew-node/src/ethereum/keccak.h \ 116 | src/gethlogapp.h \ 117 | src/etherlogapp.h \ 118 | src/ew-node/src/networkchainmanager.h \ 119 | src/nodemanager.h 120 | 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # etherwall 2 | 3 | Ethereum Qt5 Wallet 4 | 5 | Etherwall is a free software wallet/front-end for Ethereum. 6 | 7 | #### Gitter 8 | 9 | [![Join the chat at https://gitter.im/almindor/etherwall](https://badges.gitter.im/almindor/etherwall.svg)](https://gitter.im/almindor/etherwall?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 10 | 11 | ## Donations 12 | 13 | #### Github 14 | 15 | [Sponsor on github](https://github.com/sponsors/almindor) 16 | 17 | #### Flattr 18 | [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=Almindor&url=https://github.com/almindor/etherwall&title=Etherwall&language=&tags=github&category=software) 19 | 20 | #### Bitcoin 21 | `1NcJoao879C1pSKvFqnUKD6wKtFpCMppP6` 22 | 23 | #### Litecoin 24 | `LcTfGmqpXCiG7UikBDTa4ZiJMS5cRxSXHm` 25 | 26 | #### Ether 27 | `0xC64B50dB57c0362e27A32b65Bd29363f29FDFa59` 28 | 29 | 30 | ## Usage 31 | 32 | Latest geth is required to be running for Etherwall to work. Geth is provided if downloaded from the main website for windows and mac os x. 33 | 34 | Default geth path on linux points to `/usr/bin/geth` 35 | 36 | ## License 37 | 38 | Etherwall is licensed under the GPLv3 license. See LICENSE for more info. 39 | 40 | ## Development 41 | 42 | ### General Requirements 43 | 44 | [Latest Geth](https://github.com/ethereum/go-ethereum/releases) 45 | 46 | [Qt5.15+ with qmake](https://www.qt.io/developers/) 47 | 48 | Qt5 modules: 49 | * qt5-declarative 50 | * qt5-graphicaleffects 51 | * qt5-quickcontrols 52 | * qt5-websockets 53 | 54 | On Ubuntu you also need `qml-module-qtquick-extras` 55 | 56 | [google protobuf](https://github.com/google/protobuf) 57 | 58 | [hidapi](https://github.com/signal11/hidapi) 59 | 60 | #### Linux Requirements 61 | 62 | Udev 63 | 64 | #### Windows Requirements 65 | 66 | Mingw 67 | The project is set to use static (.a) files on Windows with absolute paths. 68 | You need to update the paths in the `Etherwall.pro` file to point to your compiled libraries. 69 | 70 | For Qt5 runtime/deployment see: [Qt5 for windows](http://doc.qt.io/qt-5/windows-deployment.html) 71 | 72 | *NOTE:* there is no protobuf generation script on windows atm. You need to run `protoc --cpp_out` into `src/trezor/proto` for all the trezor protocol files manually or use a unix-environment to run the script (e.g. MinGW) 73 | 74 | #### Mac OS X Requirements 75 | 76 | The project is set to use static (.a) files on Mac OS X with absolute paths. 77 | You need to update the paths in the `Etherwall.pro` file to point to your compiled libraries. 78 | You need protobuf compiled with `CXXFLAGS=-mmacosx-version-min=10.15` to support older Mac versions (for releases) 79 | 80 | For Qt5 runtime/deployment see: [Qt5 for macos](http://doc.qt.io/qt-5/osx.html#deploying-applications-on-macos) 81 | 82 | ### Building 83 | 84 | ``` 85 | git submodule init 86 | git submodule update 87 | ./generate_protobuf.sh 88 | qmake -config release && make 89 | ``` 90 | 91 | ### Roadmap 92 | 93 | #### DONE 94 | 95 | - 3.0 update UX 96 | - 2.0 add "remote IPC" node support 97 | - 1.6 add TREZOR support 98 | - 1.4 add contract deployment 99 | - 1.3 added contract support [invoking and watches] 100 | - 0.9 add transaction history support [done] 101 | - 0.8 initial release [done] 102 | 103 | ### Caveats & bugs 104 | 105 | Only supported client at the moment is Geth. 106 | 107 | If etherwall freezes with TREZOR inserted just remove TREZOR and restart Etherwall. Then insert TREZOR in again. This happens from time to time on Linux, probably a bug in hidapi. 108 | -------------------------------------------------------------------------------- /deployment.pri: -------------------------------------------------------------------------------- 1 | android-no-sdk { 2 | target.path = /data/user/qt 3 | export(target.path) 4 | INSTALLS += target 5 | } else:android { 6 | x86 { 7 | target.path = /libs/x86 8 | } else: armeabi-v7a { 9 | target.path = /libs/armeabi-v7a 10 | } else { 11 | target.path = /libs/armeabi 12 | } 13 | export(target.path) 14 | INSTALLS += target 15 | } else:unix { 16 | isEmpty(target.path) { 17 | qnx { 18 | target.path = /tmp/$${TARGET}/bin 19 | } else { 20 | target.path = /opt/$${TARGET}/bin 21 | } 22 | export(target.path) 23 | } 24 | INSTALLS += target 25 | } 26 | 27 | export(INSTALLS) 28 | -------------------------------------------------------------------------------- /generate_protobuf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | CURDIR=$(pwd) 3 | DESTDIR="$CURDIR/src/trezor/proto" 4 | SRCDIR=${SRCDIR:-"$CURDIR/src/trezor/trezor-common/protob"} 5 | PROTOC="${PROTOC_PATH}protoc" 6 | 7 | mkdir -p "$DESTDIR" 8 | cd "$SRCDIR" 9 | 10 | for i in messages messages-common messages-management messages-ethereum ; do 11 | $PROTOC --cpp_out="$DESTDIR" -I/usr/include -I. $i.proto 12 | done 13 | -------------------------------------------------------------------------------- /i18n/etherwall.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AccountsTab 6 | 7 | Accounts 8 | 9 | 10 | 11 | New account 12 | 13 | 14 | 15 | Delete account 16 | 17 | 18 | 19 | Locked 20 | 21 | 22 | 23 | Hash 24 | 25 | 26 | 27 | Balance (Ether) 28 | 29 | 30 | 31 | Sent Trans. 32 | 33 | 34 | 35 | Copy 36 | 37 | 38 | 39 | Delete 40 | 41 | 42 | 43 | 44 | ConfirmDialog 45 | 46 | Confirm 47 | 48 | 49 | 50 | 51 | ErrorDialog 52 | 53 | Error 54 | 55 | 56 | 57 | 58 | LogTab 59 | 60 | Logs 61 | 62 | 63 | 64 | Log level: 65 | 66 | 67 | 68 | Date 69 | 70 | 71 | 72 | Severity 73 | 74 | 75 | 76 | Message 77 | 78 | 79 | 80 | 81 | PasswordDialog 82 | 83 | Password: 84 | 85 | 86 | 87 | 88 | SettingsTab 89 | 90 | Settings 91 | 92 | 93 | 94 | Set 95 | 96 | 97 | 98 | Account unlock duration (s): 99 | 100 | 101 | 102 | Update interval (s): 103 | 104 | 105 | 106 | 107 | TransactionDetails 108 | 109 | Hash: 110 | 111 | 112 | 113 | From: 114 | 115 | 116 | 117 | To: 118 | 119 | 120 | 121 | Value: 122 | 123 | 124 | 125 | Gas: 126 | 127 | 128 | 129 | GasPrice: 130 | 131 | 132 | 133 | Block #: 134 | 135 | 136 | 137 | Block hash: 138 | 139 | 140 | 141 | Index: 142 | 143 | 144 | 145 | Nonce: 146 | 147 | 148 | 149 | 150 | TransactionsTab 151 | 152 | Transactions 153 | 154 | 155 | 156 | From: 157 | 158 | 159 | 160 | To: 161 | 162 | 163 | 164 | Sender account not selected 165 | 166 | 167 | 168 | Sender account invalid 169 | 170 | 171 | 172 | From account is locked 173 | 174 | 175 | 176 | Recipient account invalid 177 | 178 | 179 | 180 | Invalid value 181 | 182 | 183 | 184 | Value: 185 | 186 | 187 | 188 | Gas: 189 | 190 | 191 | 192 | Total: 193 | 194 | 195 | 196 | Block# 197 | 198 | 199 | 200 | Sender 201 | 202 | 203 | 204 | Receiver 205 | 206 | 207 | 208 | Value (Ether) 209 | 210 | 211 | 212 | Depth 213 | 214 | 215 | 216 | Details 217 | 218 | 219 | 220 | Copy Sender 221 | 222 | 223 | 224 | Copy Receiver 225 | 226 | 227 | 228 | 229 | main 230 | 231 | Etherdiene Ethereum Wallet 232 | 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/icon.ico -------------------------------------------------------------------------------- /qml/components/AccountDetails.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file AccountDetails.qml 15 | * @author Ales Katona 16 | * @date 2017 17 | * 18 | * AccountDetails window 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Layouts 1.4 24 | 25 | Dialog { 26 | // modality: Qt.WindowModal 27 | visible: false 28 | focus: true 29 | standardButtons: Dialog.Save | Dialog.Cancel 30 | title: accountModel.selectedAccount 31 | width: 8 * dpi 32 | height: 6 * dpi 33 | property int accountIndex : -1 34 | anchors.centerIn: parent 35 | 36 | function display(index) { 37 | accountIndex = index 38 | open() 39 | } 40 | 41 | onAccepted: if ( aliasField.text.length ) { 42 | accountModel.renameAccount(aliasField.text, accountIndex); 43 | } 44 | 45 | GridLayout { 46 | id: detailLayout 47 | anchors.top: parent.top 48 | anchors.left: parent.left 49 | anchors.right: parent.right 50 | anchors.margins: 20 51 | columns: 2 52 | 53 | Label { 54 | text: qsTr("Address: ") 55 | } 56 | 57 | TextField { 58 | readOnly: true 59 | text: accountModel.selectedAccount 60 | Layout.minimumWidth: detailLayout.width * 0.75 61 | } 62 | 63 | Label { 64 | text: qsTr("Alias: ") 65 | } 66 | 67 | TextField { 68 | id: aliasField 69 | text: accountModel.selectedAccountAlias 70 | Layout.minimumWidth: detailLayout.width * 0.75 71 | } 72 | 73 | Label { 74 | text: qsTr("Balance: ") 75 | } 76 | 77 | TextField { 78 | id: balanceField 79 | text: accountModel.selectedAccountBalance 80 | Layout.minimumWidth: detailLayout.width * 0.75 81 | } 82 | 83 | Label { 84 | text: qsTr("Sent Transactions: ") 85 | } 86 | 87 | TextField { 88 | readOnly: true 89 | text: accountModel.selectedAccountSentTrans 90 | Layout.minimumWidth: detailLayout.width * 0.75 91 | } 92 | 93 | Label { 94 | text: qsTr("DeviceID: ") 95 | } 96 | 97 | TextField { 98 | readOnly: true 99 | text: accountModel.selectedAccountDeviceID 100 | Layout.minimumWidth: detailLayout.width * 0.75 101 | } 102 | 103 | Label { 104 | text: qsTr("HD Path: ") 105 | } 106 | 107 | TextField { 108 | readOnly: true 109 | text: accountModel.selectedAccountHDPath 110 | Layout.minimumWidth: detailLayout.width * 0.75 111 | } 112 | 113 | CheckBox { 114 | id: defaultCheck 115 | enabled: false 116 | text: qsTr("Default") 117 | checked: accountModel.selectedAccountDefault 118 | } 119 | 120 | Button { 121 | text: qsTr("Set as default") 122 | onClicked: { 123 | accountModel.setAsDefault(accountModel.selectedAccount) 124 | defaultCheck.checked = true 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /qml/components/AccountDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file AccountDialog.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Account dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Controls.Styles 1.4 24 | 25 | Dialog { 26 | // modality: Qt.WindowModal 27 | property string password 28 | signal validPassword(string password) 29 | signal invalidPassword() 30 | standardButtons: Dialog.Save | Dialog.Cancel 31 | focus: true 32 | anchors.centerIn: parent 33 | 34 | function checkMatch(pw1, pw2) { 35 | if ( accountPW0.text === accountPW1.text && accountPW0.text.length > 0 ) { 36 | pwcheck.color = "green" 37 | return true 38 | } 39 | 40 | pwcheck.color = "red" 41 | return false 42 | } 43 | 44 | onAccepted: { 45 | if (checkMatch(accountPW0.text, accountPW1.text)) { 46 | validPassword(accountPW0.text) 47 | } else { 48 | invalidPassword() 49 | } 50 | } 51 | 52 | onVisibleChanged: { 53 | if ( visible ) { 54 | accountPW0.text = "" 55 | accountPW1.text = "" 56 | accountPW0.focus = true 57 | } 58 | } 59 | 60 | Column { 61 | width: 5 * dpi 62 | Row { 63 | Keys.onEscapePressed: { 64 | close() 65 | accountPW0.text = "" 66 | password = "" 67 | } 68 | 69 | Label { 70 | text: qsTr("Password: ") 71 | width: 1.2 * dpi 72 | } 73 | 74 | TextField { 75 | id: accountPW0 76 | echoMode: TextInput.Password 77 | width: parent.parent.width * 0.6 78 | onTextChanged: checkMatch(text, accountPW1.text) 79 | } 80 | 81 | } 82 | 83 | Row { 84 | Keys.onEscapePressed: { 85 | close() 86 | accountPW1.text = "" 87 | password = "" 88 | } 89 | 90 | Label { 91 | text: qsTr("Repeat: ", "password") 92 | width: 1.2 * dpi 93 | } 94 | 95 | Column { 96 | width: parent.parent.width * 0.6 97 | spacing: 1 98 | 99 | TextField { 100 | id: accountPW1 101 | width: parent.width 102 | echoMode: TextInput.Password 103 | onTextChanged: checkMatch(text, accountPW0.text) 104 | } 105 | 106 | Rectangle { 107 | id: pwcheck 108 | width: parent.width 109 | height: 1 110 | color: "white" 111 | } 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /qml/components/ArgNumber.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file TransactionsTab.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Contract Argument Component - number 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Row { 25 | property string title : "" 26 | property real value : 0 27 | property real fieldWidth : 2 * dpi 28 | 29 | Label { 30 | width: 1 * dpi 31 | text: title 32 | } 33 | 34 | TextField { 35 | width: fieldWidth 36 | text: value 37 | readOnly: true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /qml/components/Badge.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | 4 | Rectangle { 5 | id: badge 6 | 7 | property alias text: label.text 8 | property var stack : [] 9 | 10 | visible: opacity !== 0.0 11 | opacity: 0.0 12 | border.color: "black" 13 | border.width: 1 14 | 15 | function show(value) { 16 | showTimer.stop() 17 | stack.push(value) 18 | if ( visible ) { 19 | return 20 | } 21 | 22 | text = stack.pop() 23 | opacity = 1.0 24 | hideTimer.start() 25 | } 26 | 27 | function hide() { 28 | opacity = 0.0 29 | hideTimer.stop() 30 | } 31 | 32 | function button_msg(code) { 33 | var code_map = { 34 | 1: qsTr("Other", "button request type"), 35 | 2: qsTr("Fee over treshold", "button request type"), 36 | 3: qsTr("Confirm output", "button request type"), 37 | 4: qsTr("Reset device", "button request type"), 38 | 5: qsTr("Confirm word", "button request type"), 39 | 6: qsTr("Wipe device", "button request type"), 40 | 7: qsTr("Protect Call", "button request type"), 41 | 8: qsTr("Sign Transaction", "button request type"), 42 | 9: qsTr("Firmware check", "button request type"), 43 | 10: qsTr("Address", "button request type"), 44 | 11: qsTr("Public Key", "button request type"), 45 | 12: qsTr("Mnemonic Word Count", "button request type"), 46 | 13: qsTr("Mnemonic Input", "button request type"), 47 | 14: qsTr("Passphrase Type", "button request type"), 48 | } 49 | 50 | return qsTr("Confirm operation on TREZOR: ") + code_map[code] 51 | } 52 | 53 | Behavior on opacity {NumberAnimation{}} 54 | 55 | anchors.centerIn: parent 56 | 57 | SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } 58 | 59 | color: myPalette.highlight 60 | 61 | height: 1 * dpi 62 | width: parent.width * 0.95 63 | 64 | Timer { 65 | id: showTimer 66 | interval: 1000 67 | running: false 68 | repeat: false 69 | onTriggered: { 70 | show(stack.pop()) 71 | } 72 | } 73 | 74 | Timer { 75 | id: hideTimer 76 | interval: 3000 77 | running: false 78 | repeat: false 79 | onTriggered: { 80 | if ( stack.length ) { 81 | showTimer.start() 82 | } 83 | hide() 84 | } 85 | } 86 | 87 | MouseArea { 88 | anchors.fill: parent 89 | onClicked: hide() 90 | } 91 | 92 | Text { 93 | id: label 94 | color: "black" 95 | wrapMode: Text.Wrap 96 | width: parent.width * 0.9 97 | anchors.centerIn: parent 98 | verticalAlignment: Text.AlignVCenter 99 | horizontalAlignment: Text.AlignHCenter 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /qml/components/BusyIndicatorFixed.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | 4 | BusyIndicator { 5 | id: control 6 | 7 | contentItem: Item { 8 | implicitWidth: 64 9 | implicitHeight: 64 10 | 11 | Item { 12 | id: item 13 | x: parent.width / 2 - 32 14 | y: parent.height / 2 - 32 15 | width: 64 16 | height: 64 17 | opacity: control.running ? 1 : 0 18 | 19 | RotationAnimator { 20 | target: item 21 | running: helpers.xdgSessionType() !== "wayland" // bugged in wayland, causes slowdowns 22 | from: 0 23 | to: 360 24 | loops: Animation.Infinite 25 | duration: 1500 26 | } 27 | 28 | Repeater { 29 | id: repeater 30 | model: 6 31 | 32 | Rectangle { 33 | x: item.width / 2 - width / 2 34 | y: item.height / 2 - height / 2 35 | implicitWidth: 10 36 | implicitHeight: 10 37 | radius: 5 38 | color: "#aeaeae" 39 | transform: [ 40 | Translate { 41 | y: -Math.min(item.width, item.height) * 0.5 + 5 42 | }, 43 | Rotation { 44 | angle: index / repeater.count * 360 45 | origin.x: 5 46 | origin.y: 5 47 | } 48 | ] 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /qml/components/ContractCalls.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file ContractCalls.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * FirstTime dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Layouts 1.12 24 | 25 | Dialog { 26 | id: contractCalls 27 | title: qsTr("Call Contract") 28 | standardButtons: Dialog.Close 29 | // modality: Qt.WindowModal 30 | visible: false 31 | width: 7 * dpi 32 | height: 7 * dpi 33 | focus: true 34 | anchors.centerIn: parent 35 | 36 | function display( index ) { 37 | stcTab.children[0].toAddress = contractModel.getAddress(index) 38 | stcTab.children[0].contractData = "0x" 39 | stcTab.children[0].contractName = "" 40 | stcTab.children[0].contractAbi = "" 41 | stcTab.children[0].tokenAddress = "" 42 | 43 | cccTab.children[0].open(index) // ensure first function is selected ok 44 | 45 | open() 46 | } 47 | 48 | Badge { 49 | id: ccBadge 50 | z: 999 51 | 52 | Connections { 53 | target: trezor 54 | function onButtonRequest(code) { 55 | if ( code === 8 && contractCalls.visible ) { 56 | ccBadge.show(ccBadge.button_msg(code)) 57 | } 58 | } 59 | } 60 | 61 | Connections { 62 | target: ipc 63 | 64 | function onCallDone(result, index, userData) { 65 | if ( userData["type"] === "functionCall" ) { 66 | tabs.currentIndex = 2 67 | } 68 | } 69 | } 70 | } 71 | 72 | TabBar { 73 | id: tabs 74 | anchors.left: parent.left 75 | anchors.top: parent.top 76 | anchors.right: parent.right 77 | 78 | TabButton { 79 | text: qsTr("Function") 80 | } 81 | TabButton { 82 | text: qsTr("Transaction") 83 | enabled: false 84 | } 85 | TabButton { 86 | text: qsTr("Results") 87 | } 88 | } 89 | 90 | StackLayout { 91 | id: cccStack 92 | anchors.top: tabs.bottom 93 | anchors.left: parent.left 94 | anchors.right: parent.right 95 | anchors.bottom: parent.bottom 96 | 97 | currentIndex: tabs.currentIndex 98 | 99 | Item { 100 | id: cccTab 101 | CallContractContent { 102 | onDone: { 103 | contractCalls.close() 104 | } 105 | 106 | onContractError: { 107 | stcTab.enabled = false 108 | tabs.currentIndex = 0 109 | } 110 | 111 | onContractReady: { 112 | rsTab.children[0].callIndex = callIndex 113 | rsTab.enabled = constant 114 | 115 | stcTab.children[0].contractData = encoded 116 | stcTab.children[0].functionIsConstant = constant 117 | stcTab.children[0].callIndex = callIndex 118 | stcTab.children[0].userData = userData 119 | stcTab.children[0].prepare() 120 | stcTab.enabled = true 121 | if ( next ) { 122 | tabs.currentIndex = 1 123 | } 124 | } 125 | } 126 | } 127 | 128 | Item { 129 | id: stcTab 130 | enabled: false 131 | SendTransactionContent { 132 | onDone: contractCalls.close() 133 | } 134 | } 135 | 136 | Item { 137 | id: rsTab 138 | FunctionResultsContent { 139 | onDone: contractCalls.close() 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /qml/components/ContractContent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Controls.Universal 2.12 4 | 5 | Loader { 6 | anchors.fill: parent // bugged see https://bugreports.qt.io/browse/QTBUG-59711 7 | 8 | Column { 9 | anchors.fill: parent 10 | anchors.margins: 0.05 * dpi 11 | anchors.topMargin: 0.1 * dpi 12 | 13 | ContractDetails { 14 | id: details 15 | } 16 | 17 | ContractCalls { 18 | id: calls 19 | } 20 | 21 | ContractDeploy { 22 | id: deploy 23 | } 24 | 25 | Item { 26 | id: controlsRow 27 | height: 1 * dpi 28 | width: parent.width 29 | 30 | Button { 31 | id: addButton 32 | text: qsTr("Add Existing Contract") 33 | width: parent.width / 2.0 34 | height: parent.height / 2.0 - 0.025 * dpi 35 | 36 | onClicked: details.display(-1) 37 | } 38 | 39 | Button { 40 | id: deployButton 41 | anchors.topMargin: 0.05 * dpi 42 | text: qsTr("Deploy New Contract") 43 | anchors.top: addButton.bottom 44 | width: parent.width / 2.0 45 | height: parent.height / 2.0 - 0.025 * dpi 46 | 47 | onClicked: deploy.display() 48 | } 49 | 50 | Button { 51 | id: invokeButton 52 | anchors.leftMargin: 0.05 * dpi 53 | anchors.left: addButton.right 54 | text: qsTr("Invoke ") + contractModel.getName(contractView.currentRow) 55 | visible: contractView.currentRow >= 0 56 | width: parent.width / 2.0 - 0.05 * dpi 57 | height: parent.height 58 | 59 | onClicked: calls.display(contractView.currentRow) 60 | } 61 | } 62 | 63 | TableViewBase { 64 | id: contractView 65 | anchors.left: parent.left 66 | anchors.right: parent.right 67 | height: parent.height - parent.spacing - controlsRow.height 68 | model: contractModel 69 | columns: [["Name", width - 9 * dpi], ["Token (ERC20)", 4 * dpi], ["Address", 5 * dpi]] 70 | onItemDoubleClicked: function() { 71 | if ( currentRow >= 0 ) { 72 | calls.display(contractView.currentRow) 73 | } 74 | } 75 | 76 | Menu { 77 | id: rowMenu 78 | enabled: contractView.currentRow >= 0 79 | 80 | MenuItem { 81 | text: qsTr("Invoke") 82 | onTriggered: calls.display(contractView.currentRow) 83 | } 84 | 85 | MenuItem { 86 | text: qsTr("Edit") 87 | onTriggered: details.display(contractView.currentRow) 88 | } 89 | 90 | MenuItem { 91 | text: qsTr("Find on blockchain explorer") 92 | onTriggered: { 93 | var url = "https://" + (ipc.testnet ? "rinkeby." : "") + "etherscan.io/address/" + contractModel.getAddress(contractView.currentRow) 94 | Qt.openUrlExternally(url) 95 | } 96 | } 97 | 98 | MenuItem { 99 | text: qsTr("Copy Address") 100 | onTriggered: clipboard.setText(contractModel.getAddress(contractView.currentRow)) 101 | } 102 | 103 | MenuItem { 104 | text: qsTr("Delete") 105 | onTriggered: contractModel.deleteContract(contractView.currentRow) 106 | } 107 | } 108 | 109 | MouseArea { 110 | anchors.fill: parent 111 | propagateComposedEvents: true 112 | acceptedButtons: Qt.RightButton 113 | 114 | onReleased: rowMenu.popup() 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /qml/components/ContractDeploy.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file ContractDeploy.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * FirstTime dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Layouts 1.12 24 | 25 | Dialog { 26 | id: contractDeploy 27 | title: qsTr("Deploy Contract") 28 | standardButtons: Dialog.Cancel 29 | // modality: Qt.WindowModal 30 | visible: false 31 | width: 7 * dpi 32 | height: 7 * dpi 33 | focus: true 34 | anchors.centerIn: parent 35 | 36 | function display() { 37 | stcTab.children[0].toAddress = "" 38 | stcTab.children[0].contractData = "0x" 39 | stcTab.children[0].contractName = "" 40 | stcTab.children[0].contractAbi = "" 41 | stcTab.children[0].tokenAddress = "" 42 | stcTab.children[0].functionIsConstant = false 43 | stcTab.children[0].prepare() 44 | 45 | tabs.currentIndex = 0 46 | open() 47 | } 48 | 49 | Badge { 50 | id: cdBadge 51 | z: 999 52 | 53 | Connections { 54 | target: trezor 55 | function onButtonRequest(code) { 56 | if ( code === 8 && contractDeploy.visible ) { 57 | cdBadge.show(cdBadge.button_msg(code)) 58 | } 59 | } 60 | } 61 | } 62 | 63 | TabBar { 64 | id: tabs 65 | anchors.top: parent.top 66 | anchors.left: parent.left 67 | anchors.right: parent.right 68 | 69 | TabButton { 70 | text: qsTr("Contract") 71 | } 72 | 73 | TabButton { 74 | text: qsTr("Transaction") 75 | } 76 | } 77 | 78 | StackLayout { 79 | anchors.top: tabs.bottom 80 | anchors.left: parent.left 81 | anchors.right: parent.right 82 | anchors.bottom: parent.bottom 83 | 84 | currentIndex: tabs.currentIndex 85 | 86 | Item { 87 | id: cccTab 88 | DeployContractContent { 89 | onDone: { 90 | contractDeploy.close() 91 | } 92 | 93 | onContractError: { 94 | stcTab.enabled = false 95 | tabs.currentIndex = 0 96 | } 97 | 98 | onContractReady: { 99 | stcTab.children[0].contractData = encoded 100 | stcTab.children[0].contractName = name 101 | stcTab.children[0].contractAbi = abi 102 | stcTab.enabled = true 103 | stcTab.children[0].prepare() 104 | if ( next ) { 105 | tabs.currentIndex = 1 106 | } 107 | } 108 | } 109 | } 110 | 111 | Item { 112 | id: stcTab 113 | SendTransactionContent { 114 | onDone: { 115 | contractDeploy.close() 116 | } 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /qml/components/ContractsTab.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file TransactionsTab.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Contracts tab 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Layouts 1.12 24 | 25 | Loader { 26 | anchors.fill: parent // bugged see https://bugreports.qt.io/browse/QTBUG-59711 27 | enabled: !ipc.busy && !ipc.starting && (ipc.connectionState > 0) 28 | 29 | TabBar { 30 | id: conTab 31 | anchors.left: parent.left 32 | anchors.right: parent.right 33 | 34 | TabButton { 35 | text: qsTr("Contracts") 36 | } 37 | TabButton { 38 | text: qsTr("Watches") 39 | } 40 | TabButton { 41 | text: qsTr("Events") 42 | } 43 | } 44 | 45 | StackLayout { 46 | anchors.left: parent.left 47 | anchors.right: parent.right 48 | anchors.top: conTab.bottom 49 | anchors.bottom: parent.bottom 50 | 51 | currentIndex: conTab.currentIndex 52 | 53 | ContractContent {} 54 | FiltersContent {} 55 | EventContent {} 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /qml/components/CurrencyRow.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | 3 | Item { 4 | property string currency 5 | property real heightInches : 1 6 | property string leftText 7 | property string rightText : "1" 8 | width: itemRow.width 9 | height: itemRow.height 10 | 11 | EWToolTip { 12 | id: toolTipCurrency 13 | width: 1 * dpi 14 | target: parent 15 | text: currency 16 | } 17 | 18 | Row { 19 | id: itemRow 20 | spacing: heightInches / 5.0 * dpi 21 | Text { 22 | font.pixelSize: heightInches * dpi 23 | text: leftText 24 | visible: leftText.length > 0 25 | } 26 | 27 | Image { 28 | id: rowImg 29 | 30 | anchors.verticalCenter: parent.verticalCenter 31 | sourceSize.height: heightInches * dpi 32 | source: "/images/" + currency.toLowerCase() 33 | } 34 | 35 | Text { 36 | font.pixelSize: heightInches * dpi 37 | text: rightText 38 | visible: rightText.length > 0 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /qml/components/CurrencyTab.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file AccountsTab.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Currency tab 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Layouts 1.12 24 | 25 | Loader { 26 | id: logTab 27 | anchors.fill: parent // bugged see https://bugreports.qt.io/browse/QTBUG-59711 28 | enabled: !ipc.busy && !ipc.starting && (ipc.connectionState > 0) 29 | 30 | Column { 31 | anchors.margins: 0.2 * dpi 32 | anchors.top: parent.top 33 | spacing: 0.1 * dpi 34 | 35 | Item { 36 | anchors.left: parent.left 37 | anchors.margins: 0.1 * dpi 38 | width: ccText.width + ccImg.width 39 | height: Math.max(ccImg.height, ccText.height) 40 | 41 | Text { 42 | id: ccText 43 | anchors.verticalCenter: parent.verticalCenter 44 | anchors.margins: 0.2 * dpi 45 | textFormat: Text.RichText 46 | text: qsTr('Prices courtesy of ') 47 | } 48 | 49 | Image { 50 | id: ccImg 51 | anchors.left: ccText.right 52 | sourceSize.height: 0.5 * dpi 53 | source: "/images/cc" 54 | } 55 | 56 | MouseArea { 57 | anchors.fill: parent 58 | cursorShape: Qt.OpenHandCursor 59 | onClicked: { 60 | Qt.openUrlExternally("http://cryptocompare.com") 61 | } 62 | } 63 | } 64 | 65 | Row { 66 | spacing: 0.5 * dpi 67 | anchors.margins: 0.2 * dpi 68 | 69 | CurrencyRow { 70 | anchors.verticalCenter: parent.verticalCenter 71 | leftText: "1" 72 | rightText: "" 73 | currency: "ETH" 74 | heightInches: 1.7 75 | } 76 | 77 | Column { 78 | spacing: 0.3 * dpi 79 | anchors.verticalCenter: parent.verticalCenter 80 | 81 | Repeater { 82 | model: currencyModel 83 | 84 | delegate: CurrencyRow { 85 | visible: index > 0 86 | heightInches: 2.5 / currencyModel.count 87 | leftText: "=" 88 | currency: currencyModel.getCurrencyName(index) 89 | rightText: Number(currencyModel.getCurrencyPrice(index)).toFixed(5) 90 | } 91 | } 92 | } 93 | } 94 | 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /qml/components/DeployContractContent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Controls.Styles 1.4 4 | 5 | Item { 6 | id: mainColumn 7 | anchors.fill: parent 8 | 9 | signal done 10 | signal contractReady(string name, string abi, string encoded, bool next) 11 | signal contractError 12 | 13 | BusyIndicator { 14 | anchors.centerIn: parent 15 | z: 10 16 | running: ipc.starting || ipc.busy || ipc.syncing 17 | } 18 | 19 | Column { 20 | anchors.fill: parent 21 | anchors.margins: 0.1 * dpi 22 | spacing: 0.2 * dpi 23 | 24 | Row { 25 | Label { 26 | width: 1 * dpi 27 | text: qsTr("Name: ") 28 | } 29 | 30 | TextField { 31 | id: nameField 32 | width: mainColumn.width - 1.2 * dpi 33 | 34 | maximumLength: 255 35 | 36 | onTextChanged: deployButton.refresh() 37 | } 38 | } 39 | 40 | Row { 41 | Label { 42 | text: qsTr("Interface: ") 43 | width: 1 * dpi 44 | } 45 | 46 | TextArea { 47 | id: abiField 48 | width: mainColumn.width - 1.2 * dpi 49 | wrapMode: TextEdit.WrapAnywhere 50 | height: 1.0 * dpi 51 | 52 | onTextChanged: deployButton.refresh() 53 | } 54 | } 55 | 56 | Row { 57 | Label { 58 | id: byteCodeLabel 59 | text: qsTr("Bytecode:") + '?' 60 | MouseArea { 61 | anchors.fill: parent 62 | acceptedButtons: Qt.NoButton // we don't want to eat clicks on the Text 63 | cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor 64 | } 65 | onLinkActivated: Qt.openUrlExternally(link) 66 | width: 1 * dpi 67 | } 68 | 69 | TextArea { 70 | id: bcField 71 | wrapMode: TextEdit.WrapAnywhere 72 | width: mainColumn.width - 1.2 * dpi 73 | height: 1.0 * dpi 74 | 75 | onTextChanged: deployButton.refresh() 76 | } 77 | } 78 | 79 | Row { 80 | id: errorRow 81 | visible: errorText.length > 0 82 | 83 | Label { 84 | text: qsTr("Status: ") 85 | width: 1 * dpi 86 | } 87 | 88 | TextField { 89 | id: errorText 90 | width: mainColumn.width - 1.2 * dpi 91 | readOnly: true 92 | property bool ready: false 93 | 94 | // style: TextFieldStyle { 95 | // textColor: "black" 96 | // background: Rectangle { 97 | // radius: 2 98 | // border.color: errorText.ready ? "green" : "red" 99 | // border.width: 1 100 | // } 101 | // } 102 | } 103 | 104 | } 105 | 106 | Button { 107 | id: deployButton 108 | width: parent.width 109 | height: 0.6 * dpi 110 | text: errorText.ready ? qsTr("Setup Transaction") : qsTr("Invalid Input") 111 | 112 | Image { 113 | id: callIcon 114 | anchors.left: parent.left 115 | anchors.top: parent.top 116 | anchors.bottom: parent.bottom 117 | anchors.margins: parent.height * 0.15 118 | width: height 119 | source: errorText.ready ? "/images/ok" : "/images/warning" 120 | } 121 | 122 | // style: ButtonStyle { 123 | // label: Text { 124 | // renderType: Text.NativeRendering 125 | // verticalAlignment: Text.AlignVCenter 126 | // horizontalAlignment: Text.AlignHCenter 127 | // font.pixelSize: deployButton.height / 2.0 128 | // text: control.text 129 | // } 130 | // } 131 | 132 | function check() { 133 | var result = { 134 | error: null 135 | } 136 | 137 | if ( !nameField.text.length ) { 138 | result.error = "Name not defined" 139 | return result 140 | } 141 | 142 | if ( !abiField.text.length ) { 143 | result.error = "Interface not defined" 144 | return result 145 | } 146 | 147 | if ( !bcField.text.length ) { 148 | result.error = "Bytecode not defined" 149 | return result 150 | } 151 | 152 | result.bc = bcField.text.trim() 153 | if ( !result.bc.match(/^(0\x)?[a-f,A-Z,0-9]+$/) || (result.bc.length % 2 !== 0) ) { 154 | result.error = qsTr("Invalid bytecode") 155 | return result 156 | } 157 | 158 | try { 159 | var parsed = JSON.parse(abiField.text) 160 | if ( !parsed || !parsed.length ) { 161 | result.error = "API not an array" 162 | return result 163 | } 164 | 165 | result.abi = abiField.text 166 | } catch ( err ) { 167 | result.error = "Interface parse error: " + err 168 | return result 169 | } 170 | 171 | return result 172 | } 173 | 174 | function refresh() { 175 | var result = check() 176 | if ( result.error !== null ) { 177 | errorText.ready = false 178 | errorText.text = result.error 179 | } else { 180 | errorText.ready = true 181 | errorText.text = qsTr("Ready") 182 | } 183 | } 184 | 185 | onClicked: { 186 | var result = check() 187 | if ( result.error !== null ) { 188 | errorDialog.text = result.error 189 | errorDialog.open() 190 | return 191 | } 192 | 193 | contractReady(nameField.text, result.abi, result.bc, true) 194 | } 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /qml/components/EWToolTip.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | import QtGraphicalEffects 1.0 4 | 5 | Item { 6 | id: toolTipRoot 7 | width: toolTip.contentWidth 8 | height: toolTipContainer.height 9 | visible: false 10 | clip: false 11 | z: 999999999 12 | 13 | property alias text: toolTip.text 14 | property alias radius: content.radius 15 | property alias backgroundColor: content.color 16 | property alias textColor: toolTip.color 17 | property alias font: toolTip.font 18 | property var target: null 19 | 20 | function onMouseHover(x, y) 21 | { 22 | var obj = toolTipRoot.target.mapToItem(toolTipRoot.parent, x, y); 23 | toolTipRoot.x = obj.x; 24 | toolTipRoot.y = obj.y + 5; 25 | } 26 | 27 | function onVisibleStatus(flag) 28 | { 29 | toolTipRoot.visible = flag; 30 | } 31 | 32 | Component.onCompleted: { 33 | var itemParent = toolTipRoot.target; 34 | 35 | var newObject = Qt.createQmlObject('import QtQuick 2.12; MouseArea {signal mouserHover(int x, int y); signal showChanged(bool flag); anchors.fill:parent; hoverEnabled: true; onPositionChanged: {mouserHover(mouseX, mouseY)} onEntered: {showChanged(true)} onExited:{showChanged(false)} onClicked:{parent.focus = true}}', 36 | itemParent, "mouseItem"); 37 | newObject.mouserHover.connect(onMouseHover); 38 | newObject.showChanged.connect(onVisibleStatus); 39 | } 40 | 41 | Item { 42 | id: toolTipContainer 43 | z: toolTipRoot.z + 1 44 | width: content.width + (2*toolTipShadow.radius) 45 | height: content.height + (2*toolTipShadow.radius) 46 | 47 | Rectangle { 48 | id: content 49 | anchors.centerIn: parent 50 | width: toolTipRoot.width 51 | height: toolTip.contentHeight + 10 52 | radius: 3 53 | 54 | Text { 55 | id: toolTip 56 | anchors {fill: parent; margins: 5} 57 | wrapMode: Text.WrapAnywhere 58 | } 59 | } 60 | } 61 | 62 | DropShadow { 63 | id: toolTipShadow 64 | z: toolTipRoot.z + 1 65 | anchors.fill: source 66 | cached: true 67 | horizontalOffset: 4 68 | verticalOffset: 4 69 | radius: 8.0 70 | samples: 16 71 | color: "#80000000" 72 | smooth: true 73 | source: toolTipContainer 74 | } 75 | 76 | Behavior on visible { NumberAnimation { duration: 200 }} 77 | } 78 | -------------------------------------------------------------------------------- /qml/components/EventContent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | 4 | Loader { 5 | anchors.fill: parent 6 | 7 | Column { 8 | anchors.fill: parent 9 | anchors.margins: 0.05 * dpi 10 | anchors.topMargin: 0.1 * dpi 11 | 12 | EventDetails { 13 | id: details 14 | } 15 | 16 | TableViewBase { 17 | id: eventView 18 | anchors.left: parent.left 19 | anchors.right: parent.right 20 | height: parent.height - parent.spacing 21 | itemImplicitHeight: 0.5 * dpi 22 | model: eventModel 23 | columns: [["Name", 3 * dpi], ["Contract", width - 4 * dpi], ["Block#", 1 * dpi]] 24 | onItemDoubleClicked: function() { 25 | if ( currentRow >= 0 ) { 26 | details.display(currentRow) 27 | } 28 | } 29 | 30 | Menu { 31 | id: rowMenu 32 | enabled: parent.currentRow >= 0 33 | 34 | MenuItem { 35 | text: qsTr("Details") 36 | onTriggered: { 37 | details.display(eventView.currentRow) 38 | } 39 | } 40 | 41 | MenuItem { 42 | text: qsTr("Find on blockchain explorer") 43 | onTriggered: { 44 | var url = "https://" + (ipc.testnet ? "rinkeby." : "") + "etherscan.io/tx/" + eventModel.getTransactionHash(eventView.currentRow) + "#eventlog" 45 | Qt.openUrlExternally(url) 46 | } 47 | } 48 | } 49 | 50 | MouseArea { 51 | anchors.fill: parent 52 | acceptedButtons: Qt.RightButton 53 | propagateComposedEvents: true 54 | onReleased: rowMenu.popup() 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /qml/components/EventDetails.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file EventDetails.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Filter Details dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Controls 1.4 as C 24 | import QtQuick.Controls.Styles 1.4 25 | 26 | Dialog { 27 | id: eventDetails 28 | title: qsTr("Event Details") 29 | standardButtons: Dialog.Close 30 | // modality: Qt.WindowModal 31 | visible: false 32 | width: 7 * dpi 33 | height: 7 * dpi 34 | focus: true 35 | anchors.centerIn: parent 36 | 37 | function display( index ) { 38 | if ( index >= 0 ) { 39 | nameField.text = eventModel.getName(index); 40 | contractField.text = eventModel.getContract(index); 41 | dataField.text = eventModel.getData(index); 42 | addressField.text = eventModel.getAddress(index); 43 | blockNumField.text = eventModel.getBlockNumber(index); 44 | blockHashField.text = eventModel.getBlockHash(index); 45 | transactionHashField.text = eventModel.getTransactionHash(index); 46 | topicsField.text = eventModel.getTopics(index); 47 | argsField.model = eventModel.getArgModel(index); 48 | } 49 | 50 | open() 51 | } 52 | 53 | BusyIndicator { 54 | anchors.centerIn: parent 55 | z: 10 56 | running: ipc.starting || ipc.busy || ipc.syncing 57 | } 58 | 59 | Column { 60 | id: mainColumn 61 | anchors.left: parent.left 62 | anchors.right: parent.right 63 | anchors.margins: 0.1 * dpi 64 | spacing: 0.1 * dpi 65 | 66 | Label { 67 | text: qsTr("Event Parameters") 68 | width: parent.width 69 | horizontalAlignment: Text.AlignHCenter 70 | } 71 | 72 | C.TableView { 73 | id: argsField 74 | anchors.left: parent.left 75 | anchors.right: parent.right 76 | height: 1 * dpi 77 | 78 | C.TableViewColumn { 79 | role: "name" 80 | title: qsTr("Name") 81 | width: 1 * dpi 82 | } 83 | 84 | C.TableViewColumn { 85 | role: "type" 86 | title: qsTr("Type") 87 | width: 1 * dpi 88 | } 89 | 90 | C.TableViewColumn { 91 | role: "value" 92 | title: qsTr("Value") 93 | width: argsField.width - 2.1 * dpi 94 | } 95 | 96 | Menu { 97 | id: rowMenu 98 | 99 | MenuItem { 100 | text: qsTr("Copy Value") 101 | onTriggered: { 102 | if ( argsField.currentRow >= 0 ) { 103 | clipboard.setText(eventModel.getParamValue(argsField.currentRow)) 104 | } 105 | } 106 | } 107 | 108 | } 109 | 110 | MouseArea { 111 | anchors.fill: parent 112 | propagateComposedEvents: true 113 | acceptedButtons: Qt.RightButton 114 | 115 | onReleased: { 116 | if ( argsField.currentRow >= 0 ) { 117 | rowMenu.popup() 118 | } 119 | } 120 | } 121 | } 122 | 123 | Row { 124 | Label { 125 | width: 1 * dpi 126 | text: qsTr("Name: ") 127 | } 128 | 129 | TextField { 130 | id: nameField 131 | readOnly: true 132 | width: mainColumn.width - 1 * dpi 133 | 134 | maximumLength: 255 135 | } 136 | } 137 | 138 | Row { 139 | Label { 140 | width: 1 * dpi 141 | text: qsTr("Contract: ") 142 | } 143 | 144 | TextField { 145 | id: contractField 146 | readOnly: true 147 | width: mainColumn.width - 1 * dpi 148 | 149 | maximumLength: 255 150 | } 151 | } 152 | 153 | Row { 154 | Label { 155 | text: qsTr("Data: ") 156 | width: 1 * dpi 157 | } 158 | 159 | TextField { 160 | id: dataField 161 | readOnly: true 162 | width: mainColumn.width - 1 * dpi 163 | 164 | maximumLength: 255 165 | } 166 | } 167 | 168 | Row { 169 | Label { 170 | text: qsTr("Address: ") 171 | width: 1 * dpi 172 | } 173 | 174 | TextField { 175 | id: addressField 176 | readOnly: true 177 | width: mainColumn.width - 1 * dpi 178 | 179 | maximumLength: 255 180 | } 181 | } 182 | 183 | Row { 184 | Label { 185 | text: qsTr("Block #: ") 186 | width: 1 * dpi 187 | } 188 | 189 | TextField { 190 | id: blockNumField 191 | readOnly: true 192 | width: mainColumn.width - 1 * dpi 193 | 194 | maximumLength: 255 195 | } 196 | } 197 | 198 | Row { 199 | Label { 200 | text: qsTr("Block hash: ") 201 | width: 1 * dpi 202 | } 203 | 204 | TextField { 205 | id: blockHashField 206 | readOnly: true 207 | width: mainColumn.width - 1 * dpi 208 | 209 | maximumLength: 255 210 | } 211 | } 212 | 213 | Row { 214 | Label { 215 | text: qsTr("Transaction: ") 216 | width: 1 * dpi 217 | } 218 | 219 | TextField { 220 | id: transactionHashField 221 | readOnly: true 222 | width: mainColumn.width - 1 * dpi 223 | 224 | maximumLength: 255 225 | } 226 | } 227 | 228 | Row { 229 | Label { 230 | text: qsTr("Topics: ") 231 | width: 1 * dpi 232 | } 233 | 234 | TextField { 235 | id: topicsField 236 | readOnly: true 237 | width: mainColumn.width - 1 * dpi 238 | 239 | maximumLength: 255 240 | } 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /qml/components/FiltersContent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Controls.Universal 2.12 4 | 5 | Loader { 6 | anchors.fill: parent // bugged see https://bugreports.qt.io/browse/QTBUG-59711 7 | 8 | Column { 9 | anchors.fill: parent 10 | anchors.margins: 0.05 * dpi 11 | anchors.topMargin: 0.1 * dpi 12 | 13 | FilterDetails { 14 | id: details 15 | } 16 | 17 | Button { 18 | id: addButton 19 | text: qsTr("Add Watch") 20 | width: parent.width 21 | height: 1 * dpi 22 | 23 | onClicked: details.display() 24 | } 25 | 26 | TableViewBase { 27 | id: filterView 28 | anchors.left: parent.left 29 | anchors.right: parent.right 30 | height: parent.height - parent.spacing - addButton.height 31 | columns: [["Name", width - 5.5 * dpi], ["Contract", 4.5 * dpi], ["Active", 1 * dpi]] 32 | model: filterModel 33 | 34 | onItemDoubleClicked: function() { 35 | if ( currentRow >= 0 ) { 36 | details.display(filterView.currentRow) 37 | } 38 | } 39 | 40 | Menu { 41 | id: rowMenu 42 | enabled: filterView.currentRow >= 0 43 | 44 | MenuItem { 45 | text: qsTr("Activate/Deactivate") 46 | onTriggered: { 47 | filterModel.setFilterActive(filterView.currentRow, !filterModel.getActive(filterView.currentRow)) 48 | } 49 | } 50 | 51 | MenuItem { 52 | text: qsTr("Edit") 53 | onTriggered: { 54 | details.display(filterView.currentRow) 55 | } 56 | } 57 | 58 | MenuItem { 59 | text: qsTr("Delete") 60 | onTriggered: { 61 | filterModel.deleteFilter(filterView.currentRow) 62 | } 63 | } 64 | } 65 | 66 | MouseArea { 67 | anchors.fill: parent 68 | propagateComposedEvents: true 69 | acceptedButtons: Qt.RightButton 70 | 71 | onReleased: rowMenu.popup() 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /qml/components/FirstTimeDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file FirstTimeDialog.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * FirstTime dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Dialog { 25 | title: qsTr("First time setup wizard") 26 | standardButtons: Dialog.Save | Dialog.Close 27 | // modality: Qt.ApplicationModal 28 | visible: false 29 | width: 9 * dpi 30 | height: appWindow.height - 0.5 * dpi 31 | focus: true 32 | anchors.centerIn: parent 33 | 34 | onAccepted: { 35 | settings.setValue("program/v2firstrun", new Date()) 36 | initializer.start(); 37 | } 38 | 39 | ScrollView { 40 | anchors.fill: parent 41 | contentWidth: 8.7 * dpi 42 | contentHeight: 5.5 * dpi 43 | 44 | Column { 45 | id: infoCol 46 | anchors.left: parent.left 47 | anchors.right: parent.right 48 | spacing: 0.1 * dpi 49 | 50 | Text { 51 | id: info1 52 | anchors.left: parent.left 53 | anchors.right: parent.right 54 | anchors.margins: 0.1 * dpi 55 | font.pixelSize: 0.16 * dpi 56 | font.bold: true 57 | textFormat: Text.RichText 58 | wrapMode: Text.WrapAtWordBoundaryOrAnywhere 59 | onLinkActivated: Qt.openUrlExternally(link) 60 | text: qsTr("Accounts are stored in the geth datadir folder! Click here for more info.") 61 | MouseArea { 62 | anchors.fill: parent 63 | acceptedButtons: Qt.NoButton // we don't want to eat clicks on the Text 64 | cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor 65 | } 66 | } 67 | 68 | Text { 69 | visible: content.thinClient 70 | anchors.left: parent.left 71 | anchors.right: parent.right 72 | anchors.margins: 0.1 * dpi 73 | font.pixelSize: 0.16 * dpi 74 | font.bold: true 75 | textFormat: Text.RichText 76 | wrapMode: Text.WrapAtWordBoundaryOrAnywhere 77 | onLinkActivated: Qt.openUrlExternally(link) 78 | text: qsTr("Running local geth is not recommended due to chaindata size. Click here for more info.") 79 | MouseArea { 80 | anchors.fill: parent 81 | acceptedButtons: Qt.NoButton // we don't want to eat clicks on the Text 82 | cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor 83 | } 84 | } 85 | 86 | Text { 87 | visible: !content.thinClient 88 | anchors.left: parent.left 89 | anchors.right: parent.right 90 | anchors.margins: 0.1 * dpi 91 | font.pixelSize: 0.16 * dpi 92 | font.bold: true 93 | textFormat: Text.RichText 94 | wrapMode: Text.WrapAtWordBoundaryOrAnywhere 95 | onLinkActivated: Qt.openUrlExternally(link) 96 | text: qsTr("Ethereum blockchain requires a ludicrous amount of space and takes a long time to synchronize. Use of remote node is preferred. Click here for more info.") 97 | MouseArea { 98 | anchors.fill: parent 99 | acceptedButtons: Qt.NoButton // we don't want to eat clicks on the Text 100 | cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor 101 | } 102 | } 103 | } 104 | 105 | SettingsContent { 106 | id: content 107 | anchors.top: infoCol.bottom 108 | anchors.topMargin: 1 * dpi 109 | anchors.left: parent.left 110 | anchors.right: parent.right 111 | hideTrezor: true 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /qml/components/FunctionResultsContent.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file FunctionResultContent.qml 15 | * @author Ales Katona 16 | * @date 2017 17 | * 18 | * Function results content 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Controls 1.4 as C 24 | 25 | Item { 26 | id: itemID 27 | anchors.fill: parent 28 | anchors.topMargin: 0.1 * dpi 29 | property int callIndex : -1 30 | signal done() 31 | 32 | Connections { 33 | target: ipc 34 | 35 | function onCallDone(result, index, userData) { 36 | if ( userData["type"] === "functionCall" ) { 37 | responseField.model = contractModel.parseResponse(index, result, userData) 38 | } 39 | } 40 | } 41 | 42 | BusyIndicator { 43 | anchors.centerIn: parent 44 | z: 10 45 | running: ipc.starting || ipc.busy || ipc.syncing 46 | } 47 | 48 | C.TableView { 49 | id: responseField 50 | anchors.fill: itemID 51 | // headerVisible: true 52 | 53 | C.TableViewColumn { 54 | role: "number" 55 | title: "#" 56 | width: 0.5 * dpi 57 | } 58 | 59 | C.TableViewColumn { 60 | role: "type" 61 | title: qsTr("Type") 62 | width: 1 * dpi 63 | } 64 | 65 | C.TableViewColumn { 66 | role: "value" 67 | title: qsTr("Value") 68 | width: responseField.width - 2.6 * dpi 69 | } 70 | 71 | Menu { 72 | id: rowMenu 73 | 74 | MenuItem { 75 | text: qsTr("Copy Value") 76 | onTriggered: { 77 | if ( responseField.currentRow >= 0 ) { 78 | clipboard.setText(responseField.model[0].value) 79 | } 80 | } 81 | } 82 | 83 | } 84 | 85 | MouseArea { 86 | anchors.fill: parent 87 | propagateComposedEvents: true 88 | acceptedButtons: Qt.RightButton 89 | 90 | onReleased: { 91 | if ( responseField.currentRow >= 0 ) { 92 | rowMenu.popup() 93 | } 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /qml/components/GethTab.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file AccountsTab.qml 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Log tab 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Loader { 25 | Column { 26 | id: col 27 | anchors.margins: 0.2 * dpi 28 | anchors.fill: parent 29 | spacing: 0.1 * dpi 30 | 31 | Row { 32 | id: gethLogControlRow 33 | 34 | Button { 35 | id: gethLogClipButton 36 | text: "Save to clipboard" 37 | onClicked: { 38 | geth.saveToClipboard() 39 | } 40 | } 41 | } 42 | 43 | GroupBox { 44 | anchors.left: parent.left 45 | anchors.right: parent.right 46 | anchors.margins: 0.1 * dpi 47 | height: parent.height - gethLogControlRow.height 48 | 49 | ScrollView { 50 | anchors.fill: parent 51 | 52 | ListView { 53 | anchors.fill: parent 54 | model: geth 55 | 56 | delegate: Text { 57 | anchors.left: parent.left 58 | anchors.right: parent.right 59 | text: msg 60 | wrapMode: Text.WrapAtWordBoundaryOrAnywhere 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /qml/components/InfoTab.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file AccountsTab.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Info tab 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Layouts 1.12 24 | 25 | Loader { 26 | id: infoTab 27 | anchors.fill: parent 28 | 29 | Item { 30 | anchors.fill: parent 31 | 32 | TabBar { 33 | id: infoTabBar 34 | anchors.left: parent.left 35 | anchors.right: parent.right 36 | position: TabBar.Footer 37 | 38 | TabButton { 39 | text: qsTr("Application") 40 | } 41 | 42 | TabButton { 43 | text: qsTr("Geth") 44 | } 45 | } 46 | 47 | StackLayout { 48 | anchors.left: parent.left 49 | anchors.right: parent.right 50 | anchors.top: infoTabBar.bottom 51 | anchors.bottom: parent.bottom 52 | 53 | currentIndex: infoTabBar.currentIndex 54 | 55 | LogTab {} 56 | GethTab {} 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /qml/components/InputDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file InputDialog.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Text input dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Dialog { 25 | // modality: Qt.WindowModal 26 | width: 5 * dpi 27 | standardButtons: Dialog.Apply | Dialog.Cancel 28 | anchors.centerIn: parent 29 | 30 | focus: true 31 | signal acceptedInput(string value) 32 | property string query: qsTr("Value: ", "Generic query question") 33 | 34 | function openFocused(m) { 35 | title = m || "Confirm operation" 36 | inputField.focus = true 37 | open() 38 | } 39 | 40 | onAccepted: { 41 | if ( inputField.text.length === 0 ) { 42 | return; 43 | } 44 | 45 | close() 46 | acceptedInput(inputField.text) 47 | inputField.text = "" 48 | } 49 | 50 | onApplied: accept() 51 | 52 | Row { 53 | anchors.centerIn: parent 54 | Keys.onEscapePressed: { 55 | close() 56 | inputField.text = "" 57 | } 58 | 59 | Keys.onEnterPressed: accept() 60 | Keys.onReturnPressed: accept() 61 | 62 | Label { 63 | text: qsTr(query) 64 | } 65 | 66 | TextField { 67 | id: inputField 68 | width: parent.parent.width * 0.6 69 | focus: true 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /qml/components/LogTab.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file AccountsTab.qml 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Log tab 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Loader { 25 | id: logTab 26 | 27 | Column { 28 | id: col 29 | anchors.margins: 0.2 * dpi 30 | anchors.fill: parent 31 | spacing: 0.1 * dpi 32 | 33 | Row { 34 | id: logControlRow 35 | spacing: 0.1 * dpi 36 | 37 | Button { 38 | id: logClipButton 39 | text: "Save to clipboard" 40 | onClicked: { 41 | log.saveToClipboard() 42 | } 43 | } 44 | 45 | Label { 46 | anchors.verticalCenter: parent.verticalCenter 47 | text: qsTr("Log level: ") 48 | } 49 | 50 | ComboBox { 51 | id: logLevelCombo 52 | currentIndex: log.logLevel 53 | textRole: "text" 54 | 55 | onActivated: log.logLevel = index 56 | 57 | model: ListModel { 58 | id: llItems 59 | ListElement { text: "Debug"; value: 0 } 60 | ListElement { text: "Info"; value: 1 } 61 | ListElement { text: "Warning"; value: 2 } 62 | ListElement { text: "Error"; value: 3 } 63 | } 64 | } 65 | } 66 | 67 | GroupBox { 68 | anchors.left: parent.left 69 | anchors.right: parent.right 70 | anchors.margins: 0.1 * dpi 71 | height: parent.height - logControlRow.height 72 | 73 | ScrollView { 74 | anchors.fill: parent 75 | 76 | ListView { 77 | anchors.fill: parent 78 | model: log 79 | 80 | delegate: Text { 81 | anchors.left: parent.left 82 | anchors.right: parent.right 83 | text: date + "\t" + severity + "\t" + msg 84 | wrapMode: Text.WrapAtWordBoundaryOrAnywhere 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /qml/components/PasswordDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file PasswordDialog.qml 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Password dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Dialog { 25 | id: theDialog 26 | title: qsTr("Confirm operation", "generic dialog") 27 | width: dpi * 7 28 | standardButtons: Dialog.Yes | Dialog.No 29 | focus: true 30 | anchors.centerIn: parent 31 | 32 | // modality: Qt.platform.os === "osx" ? Qt.ApplicationModal : Qt.WindowModal // mac overlap bug 33 | property string text : "" 34 | signal passwordSubmitted(string password) 35 | signal passwordRejected 36 | 37 | function openFocused(m) { 38 | title = m || title 39 | open() 40 | accountPW.focus = true 41 | } 42 | 43 | onAccepted: { 44 | passwordSubmitted(accountPW.text) 45 | accountPW.text = "" 46 | } 47 | 48 | onRejected: { 49 | passwordRejected() 50 | accountPW.text = "" 51 | } 52 | 53 | function doYes() { 54 | accept() 55 | close() 56 | } 57 | 58 | function doNo() { 59 | reject() 60 | close() 61 | } 62 | 63 | Column { 64 | width: parent.width 65 | 66 | Keys.onEnterPressed: doYes() 67 | Keys.onReturnPressed: doYes() 68 | Keys.onEscapePressed: doNo() 69 | 70 | Label { 71 | text: theDialog.text 72 | visible: theDialog.text.length > 0 73 | } 74 | 75 | Row { 76 | Label { 77 | text: qsTr("Password: ") 78 | } 79 | 80 | TextField { 81 | id: accountPW 82 | echoMode: TextInput.Password 83 | width: parent.parent.width * 0.6 84 | focus: true 85 | } 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /qml/components/PinMatrixDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file PinMatrixDialog.qml 15 | * @author Ales Katona 16 | * @date 2017 17 | * 18 | * PinMatrixDialog dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Dialog { // keep as window, since keys are needed 25 | id: pinMatrixDialog 26 | title: qsTr("Enter your TREZOR pin") 27 | anchors.centerIn: parent 28 | focus: true 29 | width: 4 * dpi 30 | height: 6 * dpi 31 | 32 | property string pin : "" 33 | property bool accepted : false 34 | 35 | // modality: Qt.platform.os === "osx" ? Qt.ApplicationModal : Qt.WindowModal // mac overlap bug 36 | 37 | // Component.onCompleted: { 38 | // setX(Screen.width / 2.0 - width / 2.0) 39 | // setY(Screen.height / 2.0 - height / 2.0) 40 | // } 41 | 42 | onVisibleChanged: { 43 | if ( !visible && !accepted ) { 44 | trezor.cancel() 45 | } else if ( visible ) { 46 | accepted = false 47 | } 48 | } 49 | 50 | function display() { 51 | pin = "" 52 | pinEdit.text = "" 53 | open() 54 | } 55 | 56 | ListModel { 57 | id: numericModel 58 | ListElement { 59 | val: "7" 60 | } 61 | ListElement { 62 | val: "8" 63 | } 64 | ListElement { 65 | val: "9" 66 | } 67 | ListElement { 68 | val: "4" 69 | } 70 | ListElement { 71 | val: "5" 72 | } 73 | ListElement { 74 | val: "6" 75 | } 76 | ListElement { 77 | val: "1" 78 | } 79 | ListElement { 80 | val: "2" 81 | } 82 | ListElement { 83 | val: "3" 84 | } 85 | } 86 | 87 | Component { 88 | id: contactDelegate 89 | Button { 90 | width: grid.cellWidth 91 | height: grid.cellHeight 92 | text: "*" 93 | onClicked: { 94 | pin += val 95 | pinEdit.text += '*'; 96 | } 97 | } 98 | } 99 | 100 | Column { 101 | Keys.onPressed: { 102 | if ( event.key >= Qt.Key_1 && event.key <= Qt.Key_9 ) { 103 | pin += event.text 104 | pinEdit.text += '*'; 105 | } else if ( event.key === Qt.Key_Backspace || event.key === Qt.Key_Delete ) { 106 | var l = pin.length - 1 107 | pin = pin.substring(0, l) 108 | pinEdit.text = pinEdit.text.substring(0, l) 109 | } else if ( event.key === Qt.Key_Return || event.key === Qt.Key_Enter ) { 110 | accepted = true 111 | trezor.submitPin(pin) 112 | pin = "" 113 | pinMatrixDialog.close() 114 | } 115 | } 116 | 117 | 118 | anchors { 119 | left: parent.left 120 | right: parent.right 121 | } 122 | 123 | Item { 124 | width: parent.width 125 | height: pinEdit.height 126 | 127 | TextEdit { 128 | id: pinEdit 129 | font.pixelSize: 0.5 * dpi 130 | anchors { 131 | left: parent.left 132 | right: backButton.left 133 | } 134 | 135 | readOnly: true 136 | text: "" 137 | } 138 | 139 | Button { 140 | id: backButton 141 | anchors { 142 | right: parent.right 143 | } 144 | 145 | height: pinEdit.height 146 | text: "<" 147 | onClicked: { 148 | var l = pin.length - 1 149 | pin = pin.substring(0, l) 150 | pinEdit.text = pinEdit.text.substring(0, l) 151 | } 152 | } 153 | } 154 | 155 | GridView { 156 | id: grid 157 | anchors { 158 | left: parent.left 159 | right: parent.right 160 | } 161 | height: 4 * dpi 162 | 163 | cellWidth: width / 3.0 164 | cellHeight: height / 3.0 165 | 166 | model: numericModel 167 | delegate: contactDelegate 168 | highlight: Rectangle { color: "lightsteelblue"; radius: 5 } 169 | focus: true 170 | } 171 | 172 | Button { 173 | id: submitButton 174 | anchors { 175 | left: parent.left 176 | right: parent.right 177 | } 178 | 179 | height: 0.5 * dpi 180 | text: qsTr("Submit") 181 | onClicked: { 182 | accepted = true 183 | trezor.submitPin(pin) 184 | pin = "" 185 | pinMatrixDialog.close() 186 | } 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /qml/components/QRCode.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import "../js/qqr.js" as QRCodeBackend 3 | 4 | Canvas { 5 | id: canvas 6 | // background colour to be used 7 | property color background : "white" 8 | // foreground colour to be used 9 | property color foreground : "black" 10 | // ECC level to be applied (e.g. L, M, Q, H) 11 | property string level : "L" 12 | // value to be encoded in the generated QR code 13 | property string value : "" 14 | 15 | onPaint : { 16 | var qr = QRCodeBackend.get_qr() 17 | qr.canvas({ 18 | background : canvas.background, 19 | canvas : canvas, 20 | value: canvas.value, 21 | foreground : canvas.foreground, 22 | level : canvas.level, 23 | side : Math.min(canvas.width, canvas.height), 24 | value : canvas.value 25 | }) 26 | } 27 | onHeightChanged : { 28 | requestPaint() 29 | } 30 | 31 | onWidthChanged : { 32 | requestPaint() 33 | } 34 | 35 | onBackgroundChanged : { 36 | requestPaint() 37 | } 38 | 39 | onForegroundChanged : { 40 | requestPaint() 41 | } 42 | 43 | onLevelChanged : { 44 | requestPaint() 45 | } 46 | 47 | onValueChanged : { 48 | requestPaint() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /qml/components/QRExportDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Dialogs 1.3 as D 4 | 5 | Dialog { 6 | id: exportWindow 7 | standardButtons: Dialog.Close | Dialog.Save 8 | width: 6 * dpi 9 | height: 6 * dpi 10 | focus: true 11 | anchors.centerIn: parent 12 | title: qsTr("QR code for: ") + address 13 | property string address 14 | 15 | function display( val, addr ) { 16 | address = addr 17 | code.value = val 18 | open() 19 | } 20 | 21 | onAccepted: saveDialog.open() 22 | 23 | QRCode { 24 | id: code 25 | anchors.fill: parent 26 | } 27 | 28 | D.FileDialog { 29 | id: saveDialog 30 | selectFolder: false 31 | selectExisting: false 32 | selectMultiple: false 33 | folder: shortcuts.documents 34 | nameFilters: [ "PNG (*.png)", "All files (*)" ] 35 | onAccepted: { 36 | var path = helpers.localURLToString(fileUrl) 37 | if ( !code.save(path) ) { 38 | appWindow.showBadge(qsTr("Error saving QR code to ") + path) 39 | } else { 40 | appWindow.showBadge(qsTr("Address saved as QR Code to ") + path) 41 | } 42 | exportWindow.close() 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /qml/components/SettingsTab.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file SettingsTab.qml 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Settings tab 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Loader { 25 | id: settingsTab 26 | anchors.fill: parent // bugged see https://bugreports.qt.io/browse/QTBUG-59711 27 | 28 | ScrollView { 29 | clip: true 30 | contentWidth: parent.width 31 | contentHeight: 7.5 * dpi 32 | anchors.fill: parent 33 | 34 | SettingsContent { 35 | id: settingsContent 36 | anchors.topMargin: 0.2 * dpi 37 | anchors.top: parent.top 38 | anchors.left: parent.left 39 | anchors.right: parent.right 40 | anchors.margins: 0.05 * dpi 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /qml/components/TableViewBase.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Controls.Universal 2.12 4 | 5 | Item { 6 | property var columns: [] 7 | property var model : nil 8 | property int currentRow: -1 9 | property real itemImplicitHeight: 0.5 * dpi 10 | 11 | property var onItemDoubleClicked: function() {} 12 | 13 | onWidthChanged: tableView.forceLayout() 14 | 15 | function refresh() { 16 | tableView.forceLayout() 17 | } 18 | 19 | HorizontalHeaderView { 20 | id: headerView 21 | anchors.top: parent.top 22 | anchors.left: parent.left 23 | anchors.right: parent.right 24 | 25 | syncView: tableView 26 | model: parent.columns.map(c => c[0]) 27 | } 28 | 29 | TableView { 30 | id: tableView 31 | anchors.top: headerView.bottom 32 | anchors.left: parent.left 33 | anchors.right: parent.right 34 | implicitHeight: parent.height 35 | onWidthChanged: forceLayout() 36 | columnWidthProvider: function (column) { 37 | if ( parent.columns.length === 0 ) { 38 | return 1 * dpi 39 | } 40 | 41 | return parent.columns[column][1] 42 | } 43 | 44 | model: parent.model 45 | 46 | delegate: Rectangle { 47 | implicitWidth: cellText.width + 0.2 * dpi 48 | implicitHeight: itemImplicitHeight 49 | color: row === currentRow ? Universal.baseLowColor : Universal.altLowColor 50 | border { 51 | color: Universal.chromeBlackLowColor 52 | width: 1 53 | } 54 | 55 | MouseArea { 56 | id: itemArea 57 | anchors.fill: parent 58 | onClicked: currentRow = row 59 | onDoubleClicked: onItemDoubleClicked() 60 | } 61 | 62 | Text { 63 | id: cellText 64 | anchors.centerIn: parent 65 | text: display 66 | } 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /qml/components/TransactionDetails.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file TransactionDetails.qml 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * TransactionDetails window 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Layouts 1.4 24 | 25 | Dialog { 26 | property var transaction : empty_tx() 27 | standardButtons: Dialog.Close 28 | anchors.centerIn: parent 29 | // modality: Qt.WindowModal 30 | visible: false 31 | title: transaction.hash 32 | width: 8 * dpi 33 | height: 8 * dpi 34 | focus: true 35 | 36 | function empty_tx() { 37 | return { hash: "", from: "", to: "", value: "", gas: "", gasPrice: "", blockNumber: "", blockHash: "", transactionIndex: "", nonce: "", input: "" }; 38 | } 39 | 40 | function display( trans ) { 41 | transaction = trans; 42 | open() 43 | } 44 | 45 | GridLayout { 46 | id: detailLayout 47 | anchors.top: parent.top 48 | anchors.left: parent.left 49 | anchors.right: parent.right 50 | anchors.margins: 20 51 | columns: 2 52 | 53 | Label { 54 | text: qsTr("Hash: ") 55 | } 56 | 57 | TextField { 58 | readOnly: true 59 | text: transaction.hash 60 | Layout.minimumWidth: detailLayout.width * 0.8 61 | } 62 | 63 | Label { 64 | text: qsTr("From: ") 65 | } 66 | 67 | TextField { 68 | readOnly: true 69 | text: transaction.from 70 | Layout.minimumWidth: detailLayout.width * 0.8 71 | } 72 | 73 | Label { 74 | text: qsTr("To: ") 75 | } 76 | 77 | TextField { 78 | readOnly: true 79 | text: transaction.to 80 | Layout.minimumWidth: detailLayout.width * 0.8 81 | } 82 | 83 | Label { 84 | text: qsTr("Value: ") 85 | } 86 | 87 | TextField { 88 | readOnly: true 89 | text: transaction.value 90 | Layout.minimumWidth: detailLayout.width * 0.8 91 | } 92 | 93 | Label { 94 | text: qsTr("Gas: ") 95 | } 96 | 97 | TextField { 98 | readOnly: true 99 | text: transaction.gas 100 | Layout.minimumWidth: detailLayout.width * 0.8 101 | } 102 | 103 | Label { 104 | text: qsTr("GasPrice: ") 105 | } 106 | 107 | TextField { 108 | readOnly: true 109 | text: transaction.gasPrice 110 | Layout.minimumWidth: detailLayout.width * 0.8 111 | } 112 | 113 | Label { 114 | text: qsTr("Block #: ") 115 | } 116 | 117 | TextField { 118 | readOnly: true 119 | text: transaction.blockNumber 120 | Layout.minimumWidth: detailLayout.width * 0.8 121 | } 122 | 123 | Label { 124 | text: qsTr("Block hash: ") 125 | } 126 | 127 | TextField { 128 | readOnly: true 129 | text: transaction.blockHash 130 | Layout.minimumWidth: detailLayout.width * 0.8 131 | } 132 | 133 | Label { 134 | text: qsTr("Index: ") 135 | } 136 | 137 | TextField { 138 | readOnly: true 139 | text: transaction.transactionIndex 140 | Layout.minimumWidth: detailLayout.width * 0.8 141 | } 142 | 143 | Label { 144 | text: qsTr("Nonce: ") 145 | } 146 | 147 | TextField { 148 | readOnly: true 149 | text: transaction.nonce 150 | Layout.minimumWidth: detailLayout.width * 0.8 151 | } 152 | 153 | Label { 154 | text: qsTr("Input: ") 155 | } 156 | 157 | TextField { 158 | readOnly: true 159 | text: transaction.input 160 | Layout.minimumWidth: detailLayout.width * 0.8 161 | } 162 | 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /qml/components/TransactionDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file TransactionDialog.qml 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * FirstTime dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Dialog { 25 | id: sendDialog 26 | title: qsTr("Send Ether") 27 | standardButtons: Dialog.Cancel 28 | // modality: Qt.WindowModal 29 | visible: false 30 | width: 8 * dpi 31 | height: 7 * dpi 32 | focus: true 33 | anchors.centerIn: parent 34 | 35 | function display() { 36 | stc.toAddress = "" 37 | stc.contractData = "" 38 | stc.contractName = "" 39 | stc.contractAbi = "[]" 40 | stc.tokenAddress = "" 41 | 42 | stc.prepare() 43 | open() 44 | } 45 | 46 | SendTransactionContent { 47 | id: stc 48 | contractData: "" 49 | contractAbi: "" 50 | contractName: "" 51 | onDone: sendDialog.close() 52 | } 53 | 54 | Badge { 55 | id: sdBadge 56 | z: 999 57 | 58 | Connections { 59 | target: trezor 60 | function onButtonRequest(code) { 61 | if ( code === 8 && sendDialog.visible ) { 62 | sdBadge.show(sdBadge.button_msg(code)) 63 | } 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /qml/components/TransactionsTab.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file TransactionsTab.qml 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Transactions tab 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | import QtQuick.Controls.Universal 2.12 24 | 25 | Loader { 26 | id: transactionsTab 27 | anchors.fill: parent // bugged see https://bugreports.qt.io/browse/QTBUG-59711 28 | enabled: !ipc.busy && !ipc.starting && (ipc.connectionState > 0) 29 | 30 | Column { 31 | anchors.fill: parent 32 | anchors.margins: 0.05 * dpi 33 | anchors.topMargin: 0.1 * dpi 34 | 35 | TransactionDialog { 36 | id: sendDialog 37 | } 38 | 39 | TransactionDetails { 40 | id: details 41 | } 42 | 43 | Button { 44 | id: sendButton 45 | text: "Send Ether" 46 | width: parent.width 47 | height: 1 * dpi 48 | 49 | onClicked: sendDialog.display() 50 | } 51 | 52 | TableViewBase { 53 | id: transactionView 54 | anchors.left: parent.left 55 | anchors.right: parent.right 56 | height: parent.height - parent.spacing - sendButton.height 57 | itemImplicitHeight: 0.5 * dpi 58 | model: transactionModel 59 | columns: [["Block#", 1 * dpi], ["Sender", width / 2 - 1.25 * dpi], ["Receiver", width / 2 - 1.25 * dpi], ["Value", 1.5 * dpi]] 60 | onItemDoubleClicked: function() { 61 | if ( currentRow >= 0 ) { 62 | details.display(transactionModel.getJson(transactionView.currentRow, true)) 63 | } 64 | } 65 | 66 | Menu { 67 | id: rowMenu 68 | enabled: transactionView.currentRow >= 0 69 | 70 | MenuItem { 71 | text: qsTr("Details") 72 | onTriggered: { 73 | details.display(transactionModel.getJson(transactionView.currentRow, true)) 74 | } 75 | } 76 | 77 | MenuItem { 78 | text: qsTr("Find on blockchain explorer") 79 | onTriggered: { 80 | var url = "https://" + (ipc.testnet ? "rinkeby." : "") + "etherscan.io/tx/" + transactionModel.getHash(transactionView.currentRow) 81 | Qt.openUrlExternally(url) 82 | } 83 | } 84 | 85 | MenuItem { 86 | text: qsTr("Copy Transaction Hash") 87 | onTriggered: { 88 | clipboard.setText(transactionModel.getHash(transactionView.currentRow)) 89 | } 90 | } 91 | 92 | MenuItem { 93 | text: qsTr("Copy Sender") 94 | onTriggered: { 95 | clipboard.setText(transactionModel.getSender(transactionView.currentRow)) 96 | } 97 | } 98 | 99 | MenuItem { 100 | text: qsTr("Copy Receiver") 101 | onTriggered: { 102 | clipboard.setText(transactionModel.getReceiver(transactionView.currentRow)) 103 | } 104 | } 105 | } 106 | 107 | MouseArea { 108 | anchors.fill: parent 109 | propagateComposedEvents: true 110 | acceptedButtons: Qt.RightButton 111 | 112 | onReleased: rowMenu.popup() 113 | } 114 | } 115 | 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /qml/components/TrezorImportDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file TrezorImportDialog.qml 15 | * @author Ales Katona 16 | * @date 2017 17 | * 18 | * Trezor import dialog 19 | */ 20 | 21 | import QtQuick 2.12 22 | import QtQuick.Controls 2.15 23 | 24 | Dialog { 25 | // modality: Qt.platform.os === "osx" ? Qt.ApplicationModal : Qt.WindowModal // mac overlap bug 26 | id: theDialog 27 | width: 6 * dpi 28 | title: qsTr("Import accounts from TREZOR") 29 | standardButtons: Dialog.Yes | Dialog.No | Dialog.Help 30 | focus: true 31 | anchors.centerIn: parent 32 | 33 | onAccepted: accountModel.trezorImport(offsetSpin.value, countSpin.value) 34 | 35 | onHelpRequested: Qt.openUrlExternally("https://www.etherwall.com/faq/#importaccount") 36 | 37 | function display(_msg) { 38 | mainLabel.text = _msg 39 | open() 40 | } 41 | 42 | Column { 43 | anchors.fill: parent 44 | spacing: 0.2 * dpi 45 | 46 | Label { 47 | id: mainLabel 48 | width: parent.width 49 | wrapMode: Text.Wrap 50 | } 51 | 52 | Row { 53 | width: parent.width 54 | spacing: 0.3 * dpi 55 | 56 | Label { 57 | text: qsTr("Offset") 58 | } 59 | 60 | SpinBox { 61 | id: offsetSpin 62 | validator: IntValidator { 63 | bottom: 0 64 | top: 4294967295 - countSpin.value 65 | } 66 | 67 | value: 0 68 | } 69 | 70 | Label { 71 | text: qsTr("Count") 72 | } 73 | 74 | SpinBox { 75 | id: countSpin 76 | validator: IntValidator { 77 | bottom: 1 78 | top: 255 79 | } 80 | value: 5 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /qml/images/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/all.png -------------------------------------------------------------------------------- /qml/images/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/block.png -------------------------------------------------------------------------------- /qml/images/btc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/btc.png -------------------------------------------------------------------------------- /qml/images/cad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/cad.png -------------------------------------------------------------------------------- /qml/images/cryptocompare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/cryptocompare.png -------------------------------------------------------------------------------- /qml/images/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/error.png -------------------------------------------------------------------------------- /qml/images/eth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/eth.png -------------------------------------------------------------------------------- /qml/images/eur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/eur.png -------------------------------------------------------------------------------- /qml/images/gas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/gas.png -------------------------------------------------------------------------------- /qml/images/gbp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/gbp.png -------------------------------------------------------------------------------- /qml/images/high_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/high_connection.png -------------------------------------------------------------------------------- /qml/images/homescreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/homescreen.png -------------------------------------------------------------------------------- /qml/images/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/icon.icns -------------------------------------------------------------------------------- /qml/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/icon.png -------------------------------------------------------------------------------- /qml/images/locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/locked.png -------------------------------------------------------------------------------- /qml/images/low_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/low_connection.png -------------------------------------------------------------------------------- /qml/images/medium_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/medium_connection.png -------------------------------------------------------------------------------- /qml/images/no_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/no_connection.png -------------------------------------------------------------------------------- /qml/images/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/ok.png -------------------------------------------------------------------------------- /qml/images/trezor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/trezor.png -------------------------------------------------------------------------------- /qml/images/unlocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/unlocked.png -------------------------------------------------------------------------------- /qml/images/usd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/usd.png -------------------------------------------------------------------------------- /qml/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almindor/etherwall/fbc48161fcf84c5e5cfe11ae709dfcebf8ea7974/qml/images/warning.png -------------------------------------------------------------------------------- /qml/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | components/PasswordDialog.qml 5 | components/AccountsTab.qml 6 | components/TransactionsTab.qml 7 | components/SettingsTab.qml 8 | components/LogTab.qml 9 | components/TransactionDetails.qml 10 | components/InputDialog.qml 11 | components/CurrencyTab.qml 12 | components/CurrencyRow.qml 13 | components/EWToolTip.qml 14 | components/GethTab.qml 15 | components/FirstTimeDialog.qml 16 | components/SettingsContent.qml 17 | components/AccountDialog.qml 18 | components/TransactionDialog.qml 19 | components/ContractsTab.qml 20 | components/ContractDetails.qml 21 | components/ContractCalls.qml 22 | components/ArgNumber.qml 23 | components/InfoTab.qml 24 | components/SendTransactionContent.qml 25 | components/CallContractContent.qml 26 | components/ContractContent.qml 27 | components/EventContent.qml 28 | components/FiltersContent.qml 29 | components/FilterDetails.qml 30 | components/EventDetails.qml 31 | components/Badge.qml 32 | components/ContractDeploy.qml 33 | components/DeployContractContent.qml 34 | js/qqr.js 35 | components/QRCode.qml 36 | components/QRExportDialog.qml 37 | components/PinMatrixDialog.qml 38 | components/AccountDetails.qml 39 | components/TrezorImportDialog.qml 40 | components/FunctionResultsContent.qml 41 | components/TableViewBase.qml 42 | components/BusyIndicatorFixed.qml 43 | 44 | 45 | images/icon.png 46 | images/block.png 47 | images/high_connection.png 48 | images/medium_connection.png 49 | images/low_connection.png 50 | images/no_connection.png 51 | images/warning.png 52 | images/error.png 53 | images/ok.png 54 | images/locked.png 55 | images/unlocked.png 56 | images/gas.png 57 | images/all.png 58 | images/cryptocompare.png 59 | images/btc.png 60 | images/cad.png 61 | images/eth.png 62 | images/eur.png 63 | images/gbp.png 64 | images/usd.png 65 | images/trezor.png 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/accountmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file accountmodel.h 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Account model header 19 | */ 20 | 21 | #ifndef ACCOUNTMODEL_H 22 | #define ACCOUNTMODEL_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "types.h" 32 | #include "currencymodel.h" 33 | #include "nodeipc.h" 34 | #include "etherlog.h" 35 | #include "trezor/trezor.h" 36 | 37 | namespace Etherwall { 38 | 39 | class AccountModel : public QAbstractTableModel 40 | { 41 | Q_OBJECT 42 | Q_PROPERTY(int selectedAccountRow READ getSelectedAccountRow WRITE setSelectedAccountRow NOTIFY accountSelectionChanged) 43 | Q_PROPERTY(QString selectedAccount READ getSelectedAccount NOTIFY accountSelectionChanged) 44 | Q_PROPERTY(bool selectedAccountDefault READ getSelectedAccountDefault NOTIFY accountSelectionChanged) 45 | Q_PROPERTY(QString selectedAccountAlias READ getSelectedAccountAlias NOTIFY accountSelectionChanged) 46 | Q_PROPERTY(QString selectedAccountBalance READ getSelectedAccountBalance NOTIFY accountSelectionChanged) 47 | Q_PROPERTY(QString selectedAccountDeviceID READ getSelectedAccountDeviceID NOTIFY accountSelectionChanged) 48 | Q_PROPERTY(QString selectedAccountHDPath READ getSelectedAccountHDPath NOTIFY accountSelectionChanged) 49 | Q_PROPERTY(quint64 selectedAccountSentTrans READ getSelectedAccountSentTrans NOTIFY accountSelectionChanged) 50 | Q_PROPERTY(QString total READ getTotal NOTIFY totalChanged) 51 | Q_PROPERTY(bool busy MEMBER fBusy NOTIFY busyChanged) 52 | Q_PROPERTY(int defaultIndex READ getDefaultIndex NOTIFY defaultIndexChanged) 53 | Q_PROPERTY(QString currentToken READ getCurrentToken NOTIFY currentTokenChanged) 54 | public: 55 | AccountModel(NodeIPC& ipc, const CurrencyModel& currencyModel, Trezor::TrezorDevice& trezor); 56 | QString getError() const; 57 | QHash roleNames() const; 58 | int rowCount(const QModelIndex & parent = QModelIndex()) const; 59 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 60 | QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 61 | bool containsAccount(const QString& from, const QString& to, int& i1, int& i2) const; 62 | const QJsonArray getAccountsJsonArray() const; 63 | const QString getAccountAlias(const QString& hash) const; 64 | const QString getTotal() const; 65 | int size() const; 66 | void refreshAccounts(); 67 | const QString getSelectedAccountAlias() const; 68 | const QString getSelectedAccountBalance() const; 69 | quint64 getSelectedAccountSentTrans() const; 70 | const QString getSelectedAccountDeviceID() const; 71 | const QString getSelectedAccountHDPath() const; 72 | bool getSelectedAccountDefault() const; 73 | const AccountList& getAccounts() const; 74 | const QVariantList getAccountAddresses() const; 75 | int getAccountIndex(const QString& address) const; 76 | void selectToken(const QString& name, const QString& tokenAddress); 77 | 78 | Q_INVOKABLE void newAccount(const QString& pw); 79 | Q_INVOKABLE void renameAccount(const QString& name, int index); 80 | Q_INVOKABLE void removeAccounts(); 81 | Q_INVOKABLE void removeAccount(const QString& address); 82 | Q_INVOKABLE const QString getAccountHash(int index) const; 83 | Q_INVOKABLE const QString getAccountHDPath(int index) const; 84 | Q_INVOKABLE quint64 getAccountNonce(int index) const; 85 | Q_INVOKABLE void exportWallet(const QUrl& fileName) const; 86 | Q_INVOKABLE void importWallet(const QUrl& fileName); 87 | Q_INVOKABLE bool exportAccount(const QUrl& fileName, int index); 88 | Q_INVOKABLE void setAsDefault(const QString& address); 89 | Q_INVOKABLE void trezorImport(quint32 offset, quint8 count); 90 | Q_INVOKABLE const QString getMaxTokenValue(int accountIndex, const QString& tokenAddress) const; 91 | public slots: 92 | void onTokenBalanceDone(int accountIndex, const QString& tokenAddress, const QString& balance); 93 | private slots: 94 | void connectToServerDone(); 95 | void getAccountsDone(const QStringList& list); 96 | void newAccountDone(const QString& hash, int index); 97 | void accountBalanceChanged(int index, const QString& balanceStr); 98 | void accountSentTransChanged(int index, quint64 count); 99 | void newBlock(const QJsonObject& block); 100 | void currencyChanged(); 101 | void syncingChanged(bool syncing); 102 | void importWalletDone(); 103 | void onTrezorInitialized(const QString& deviceID); 104 | void onTrezorAddressRetrieved(const QString& address, const QString& hdPath); 105 | signals: 106 | void accountsReady() const; 107 | void accountSelectionChanged(int) const; 108 | void totalChanged() const; 109 | void walletErrorEvent(const QString& error) const; 110 | void walletExportedEvent() const; 111 | void walletImportedEvent() const; 112 | void busyChanged(bool busy) const; 113 | void defaultIndexChanged(int index) const; 114 | void promptForTrezorImport() const; 115 | void accountsRemoved() const; 116 | void currentTokenChanged() const; 117 | void existingAccountImported(const QString& address, int accountIndex) const; 118 | private: 119 | NodeIPC& fIpc; 120 | AccountList fAccountList; 121 | QMap fAliasMap; 122 | Trezor::TrezorDevice& fTrezor; 123 | int fSelectedAccountRow; 124 | QString fSelectedAccount; 125 | const CurrencyModel& fCurrencyModel; 126 | bool fBusy; 127 | QString fCurrentToken; 128 | QString fCurrentTokenAddress; 129 | 130 | int getSelectedAccountRow() const; 131 | int getDefaultIndex() const; 132 | bool hasDefaultIndex() const; 133 | void setSelectedAccountRow(int row); 134 | const QString getSelectedAccount() const; 135 | void storeAccountList() const; 136 | void loadAccountList(); 137 | void setAccountAlias(const QString& hash, const QString& alias); 138 | int exportableAddresses() const; 139 | const QString getCurrentToken() const; 140 | }; 141 | 142 | } 143 | 144 | #endif // ACCOUNTMODEL_H 145 | -------------------------------------------------------------------------------- /src/accountproxymodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file accountproxymodel.h 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Account proxy model header 19 | */ 20 | 21 | #include "accountproxymodel.h" 22 | #include 23 | #include 24 | 25 | namespace Etherwall { 26 | 27 | AccountProxyModel::AccountProxyModel(QObject *parent) : QSortFilterProxyModel(parent) 28 | { 29 | connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged())); 30 | connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged())); 31 | } 32 | 33 | int AccountProxyModel::count() const 34 | { 35 | return rowCount(); 36 | } 37 | 38 | QObject *AccountProxyModel::source() const 39 | { 40 | return sourceModel(); 41 | } 42 | 43 | void AccountProxyModel::setSource(QObject *source) 44 | { 45 | setSourceModel(qobject_cast(source)); 46 | } 47 | 48 | QByteArray AccountProxyModel::sortRole() const 49 | { 50 | return roleNames().value(QSortFilterProxyModel::sortRole()); 51 | } 52 | 53 | void AccountProxyModel::setSortRole(const QByteArray &role) 54 | { 55 | QSortFilterProxyModel::setSortRole(roleKey(role)); 56 | } 57 | 58 | void AccountProxyModel::setSortOrder(Qt::SortOrder order) 59 | { 60 | QSortFilterProxyModel::sort(0, order); 61 | } 62 | 63 | QByteArray AccountProxyModel::filterRole() const 64 | { 65 | return roleNames().value(QSortFilterProxyModel::filterRole()); 66 | } 67 | 68 | void AccountProxyModel::setFilterRole(const QByteArray &role) 69 | { 70 | QSortFilterProxyModel::setFilterRole(roleKey(role)); 71 | } 72 | 73 | QString AccountProxyModel::filterString() const 74 | { 75 | return filterRegExp().pattern(); 76 | } 77 | 78 | void AccountProxyModel::setFilterString(const QString &filter) 79 | { 80 | setFilterRegExp(QRegExp(filter, filterCaseSensitivity(), static_cast(filterSyntax()))); 81 | } 82 | 83 | AccountProxyModel::FilterSyntax AccountProxyModel::filterSyntax() const 84 | { 85 | return static_cast(filterRegExp().patternSyntax()); 86 | } 87 | 88 | void AccountProxyModel::setFilterSyntax(AccountProxyModel::FilterSyntax syntax) 89 | { 90 | setFilterRegExp(QRegExp(filterString(), filterCaseSensitivity(), static_cast(syntax))); 91 | } 92 | 93 | QJSValue AccountProxyModel::get(int idx) const 94 | { 95 | QJSEngine *engine = qmlEngine(this); 96 | QJSValue value = engine->newObject(); 97 | if (idx >= 0 && idx < count()) { 98 | QHash roles = roleNames(); 99 | QHashIterator it(roles); 100 | while (it.hasNext()) { 101 | it.next(); 102 | value.setProperty(QString::fromUtf8(it.value()), data(index(idx, 0), it.key()).toString()); 103 | } 104 | } 105 | return value; 106 | } 107 | 108 | int AccountProxyModel::roleKey(const QByteArray &role) const 109 | { 110 | QHash roles = roleNames(); 111 | QHashIterator it(roles); 112 | while (it.hasNext()) { 113 | it.next(); 114 | if (it.value() == role) 115 | return it.key(); 116 | } 117 | return -1; 118 | } 119 | 120 | QHash AccountProxyModel::roleNames() const 121 | { 122 | if (QAbstractItemModel *source = sourceModel()) 123 | return source->roleNames(); 124 | return QHash(); 125 | } 126 | 127 | bool AccountProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const 128 | { 129 | QRegExp rx = filterRegExp(); 130 | if (rx.isEmpty()) 131 | return true; 132 | QAbstractItemModel *model = sourceModel(); 133 | if (filterRole().isEmpty()) { 134 | QHash roles = roleNames(); 135 | QHashIterator it(roles); 136 | while (it.hasNext()) { 137 | it.next(); 138 | QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent); 139 | QString key = model->data(sourceIndex, it.key()).toString(); 140 | if (key.contains(rx)) 141 | return true; 142 | } 143 | return false; 144 | } 145 | QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent); 146 | if (!sourceIndex.isValid()) 147 | return true; 148 | QString key = model->data(sourceIndex, roleKey(filterRole())).toString(); 149 | return key.contains(rx); 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/accountproxymodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file accountproxymodel.h 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Account proxy model header 19 | */ 20 | 21 | #ifndef SORTFILTERPROXYMODEL_H 22 | #define SORTFILTERPROXYMODEL_H 23 | 24 | #include 25 | #include 26 | 27 | namespace Etherwall { 28 | 29 | class AccountProxyModel : public QSortFilterProxyModel 30 | { 31 | Q_OBJECT 32 | Q_PROPERTY(int count READ count NOTIFY countChanged) 33 | Q_PROPERTY(QObject *source READ source WRITE setSource) 34 | 35 | Q_PROPERTY(QByteArray sortRole READ sortRole WRITE setSortRole) 36 | Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder) 37 | 38 | Q_PROPERTY(QByteArray filterRole READ filterRole WRITE setFilterRole) 39 | Q_PROPERTY(QString filterString READ filterString WRITE setFilterString) 40 | Q_PROPERTY(FilterSyntax filterSyntax READ filterSyntax WRITE setFilterSyntax) 41 | 42 | Q_ENUMS(FilterSyntax) 43 | 44 | public: 45 | explicit AccountProxyModel(QObject *parent = 0); 46 | 47 | QObject *source() const; 48 | void setSource(QObject *source); 49 | 50 | QByteArray sortRole() const; 51 | void setSortRole(const QByteArray &role); 52 | 53 | void setSortOrder(Qt::SortOrder order); 54 | 55 | QByteArray filterRole() const; 56 | void setFilterRole(const QByteArray &role); 57 | 58 | QString filterString() const; 59 | void setFilterString(const QString &filter); 60 | 61 | enum FilterSyntax { 62 | RegExp, 63 | Wildcard, 64 | FixedString 65 | }; 66 | 67 | FilterSyntax filterSyntax() const; 68 | void setFilterSyntax(FilterSyntax syntax); 69 | 70 | int count() const; 71 | Q_INVOKABLE QJSValue get(int index) const; 72 | 73 | signals: 74 | void countChanged(); 75 | 76 | protected: 77 | int roleKey(const QByteArray &role) const; 78 | QHash roleNames() const; 79 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; 80 | }; 81 | 82 | } 83 | 84 | #endif // SORTFILTERPROXYMODEL_H 85 | -------------------------------------------------------------------------------- /src/cert.h: -------------------------------------------------------------------------------- 1 | #ifndef CERT_H 2 | #define CERT_H 3 | 4 | #include 5 | 6 | namespace Etherwall { 7 | 8 | // self signed cert for main server-info api, no need to use a public one here 9 | static const QString EtherWall_Cert = "-----BEGIN CERTIFICATE-----\n" 10 | "MIIDiDCCAnACCQCXJXqGOlAorjANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC\n" 11 | "Q0ExEDAOBgNVBAgMB0FsYmVydGExEDAOBgNVBAcMB0NhbGdhcnkxEjAQBgNVBAoM\n" 12 | "CUV0aGVyZHluZTEbMBkGA1UEAwwSZGF0YS5ldGhlcndhbGwuY29tMSEwHwYJKoZI\n" 13 | "hvcNAQkBFhJhbG1pbmRvckBnbWFpbC5jb20wHhcNMTYwODI4MjM1MjI5WhcNMjIw\n" 14 | "MjE4MjM1MjI5WjCBhTELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB0FsYmVydGExEDAO\n" 15 | "BgNVBAcMB0NhbGdhcnkxEjAQBgNVBAoMCUV0aGVyZHluZTEbMBkGA1UEAwwSZGF0\n" 16 | "YS5ldGhlcndhbGwuY29tMSEwHwYJKoZIhvcNAQkBFhJhbG1pbmRvckBnbWFpbC5j\n" 17 | "b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsraaryUowJKQSQLeV\n" 18 | "4r833OvTrI5ylyww1s3m+aN0eGx2tQa+rVIeklu9vO0bz5qWc6CnWvOx1ZA35Ru+\n" 19 | "OXkYzUe63Bkt0MtBDvfhGQct3vJ5r+6dXf8TuPgSaqBCpGCG4DtIYUxuNVauJ2N7\n" 20 | "HX/KOOY5J2qHlWpas2TNrncbvfc55A8ezP2p3dwmbyITG7IPhwicDDez6xPz0SXH\n" 21 | "USsv3Y3bQlVAh+11tquGcKo14QbRtPIkmaEHuG1nN4LaFhQL7P2gH8x7g2lOmsE+\n" 22 | "JIDAdHV2ExewAfIf4Ep+twPo6jXf96cKLhtKCfVlUKUBEvBxsFmEFlwciW1R7d7R\n" 23 | "TXNBAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIMtS+szahT3ScKAsk3Y1F1Ac/E3\n" 24 | "t9JJZhEGS4b73vlna2Rl0wQd2rPtVMgdTarshhH/jAngWaf52xzMd0MKlYEkzRdx\n" 25 | "D1tSdwqDxQ+XKxMBXwiN2ffgc+r8xcFWK34BU32MC7reVL1sQtjYAiGfSuo4ZZqk\n" 26 | "0WThQ183ERexxwtYQ8qSn3L+kXCPJyVnazt7IJ3rylB9e6t6voaU/eNQUC7Mdwov\n" 27 | "Vw6Ar9fz+sQVccQQDREICKnnK1M+k8kk+g3c+rF3ISFlLPi981tWjGSTH685HH0q\n" 28 | "JkX2TxeYmZl+B/qvVorfPzWK7NoalCBvIxyxBeI3e67Ly0lRWAGIsWEtQP4=\n" 29 | "-----END CERTIFICATE-----\n"; 30 | } 31 | 32 | #endif // CERT_H 33 | -------------------------------------------------------------------------------- /src/clipboard.cpp: -------------------------------------------------------------------------------- 1 | #include "clipboard.h" 2 | 3 | namespace Etherwall { 4 | 5 | ClipboardAdapter::ClipboardAdapter(QObject *parent) : QObject(parent) { 6 | fClipboard = QApplication::clipboard(); 7 | } 8 | 9 | void ClipboardAdapter::setText(QString text) { 10 | fClipboard->setText(text, QClipboard::Clipboard); 11 | fClipboard->setText(text, QClipboard::Selection); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/clipboard.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIPBOARD_H 2 | #define CLIPBOARD_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Etherwall { 9 | 10 | class ClipboardAdapter : public QObject 11 | { 12 | Q_OBJECT 13 | public: 14 | explicit ClipboardAdapter(QObject *parent = 0); 15 | 16 | Q_INVOKABLE void setText(QString text); 17 | private: 18 | QClipboard* fClipboard; 19 | }; 20 | 21 | } 22 | 23 | #endif // CLIPBOARD_H 24 | -------------------------------------------------------------------------------- /src/contractmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file contractmodel.cpp 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Contract model header 19 | */ 20 | 21 | #ifndef CONTRACTMODEL_H 22 | #define CONTRACTMODEL_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "contractinfo.h" 30 | #include "nodeipc.h" 31 | #include "accountmodel.h" 32 | 33 | namespace Etherwall { 34 | 35 | class PendingContract { 36 | public: 37 | PendingContract(); 38 | PendingContract(const QString& name, const QString& abi); 39 | QString fName; 40 | QString fAbi; 41 | }; 42 | 43 | typedef QMap PendingContracts; 44 | 45 | class ContractModel : public QAbstractTableModel 46 | { 47 | Q_OBJECT 48 | Q_PROPERTY(bool busy MEMBER fBusy NOTIFY busyChanged) 49 | public: 50 | ContractModel(NodeIPC& ipc, AccountModel& accountModel); 51 | 52 | QHash roleNames() const; 53 | int rowCount(const QModelIndex & parent = QModelIndex()) const; 54 | Q_INVOKABLE virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; 55 | QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 56 | Q_INVOKABLE bool addContract(const QString& name, const QString& address, const QString& abi); 57 | Q_INVOKABLE bool addPendingContract(const QString& name, const QString& abi, const QString& hash); 58 | Q_INVOKABLE const QString contractDeployed(const QJsonObject& receipt); 59 | Q_INVOKABLE bool deleteContract(int index); 60 | Q_INVOKABLE const QString getName(int index) const; 61 | Q_INVOKABLE int getIndex(const QString name) const; 62 | Q_INVOKABLE int getEventIndex(int index, const QJsonArray& topics) const; 63 | Q_INVOKABLE const QString getAddress(int index) const; 64 | Q_INVOKABLE int getDecimals(int index) const; 65 | Q_INVOKABLE const QString getABI(int index) const; 66 | Q_INVOKABLE const QStringList getFunctions(int index) const; 67 | Q_INVOKABLE const QStringList getEvents(int index) const; 68 | Q_INVOKABLE const QString getMethodID(int index, const QString& functionName) const; 69 | Q_INVOKABLE const QVariantList getArguments(int index, const QString& functionName) const; 70 | Q_INVOKABLE const QVariantList getEventArguments(int index, const QString& eventName, bool indexedOnly) const; 71 | Q_INVOKABLE const QVariantList parseResponse(int contractIndex, const QString& data, const QVariantMap& userData) const; 72 | Q_INVOKABLE const QVariantMap encodeCall(int index, const QString& functionName, const QVariantList& params); 73 | Q_INVOKABLE const QString encodeTransfer(int index, const QString& toAddress, const QString& value); 74 | Q_INVOKABLE const QString encodeTopics(int index, const QString& eventName, const QVariantList& params); 75 | Q_INVOKABLE void requestAbi(const QString& address); 76 | Q_INVOKABLE bool callName(const QString& address, const QString& jsonAbi) const; 77 | signals: 78 | void error(const QString& error) const; // internal error 79 | void callError(const QString& err) const; 80 | void newEvent(const EventInfo& info, bool isNew) const; 81 | void abiResult(const QString& abi) const; 82 | void busyChanged(bool busy) const; 83 | void callNameDone(const QString& name) const; 84 | void tokenBalanceDone(int accountIndex, const QString& tokenAddress, const QString& balance) const; 85 | void receivedTokens(const QString& value, const QString& token, const QString& sender) const; 86 | public slots: 87 | void reload(); 88 | void onNewEvent(const QJsonObject& event, bool isNew, const QString& internalFilterID); 89 | void httpRequestDone(QNetworkReply *reply); 90 | void onCallDone(const QString& result, int index, const QVariantMap& userData); 91 | void onSelectedTokenContract(int index, bool forwardToAccounts = true); 92 | void onConfirmedTransaction(const QString &fromAddress, const QString& toAddress, const QString& hash); 93 | void onExistingAccountImported(const QString& address, int accountIndex); 94 | private: 95 | const QString getPostfix() const; 96 | void loadERC20Data(const ContractInfo& contract, int index) const; 97 | void onCallName(const QString& result) const; 98 | void refreshTokenBalance(const QString& accountAddress, int accountIndex, const ContractInfo& contract, int contractIndex) const; 99 | void onTokenBalance(const QString& result, int contractIndex, int accountIndex) const; 100 | void registerTokensFilter(); 101 | const ContractInfo& getContractByAddress(const QString& address, int& index) const; 102 | 103 | ContractList fList; 104 | NodeIPC& fIpc; 105 | QNetworkAccessManager fNetManager; 106 | bool fBusy; 107 | PendingContracts fPendingContracts; 108 | AccountModel& fAccountModel; 109 | QMap fTokenBalanceTabs; 110 | }; 111 | 112 | } 113 | 114 | #endif // CONTRACTMODEL_H 115 | -------------------------------------------------------------------------------- /src/currencymodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file currencymodel.h 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Currency model body 19 | */ 20 | 21 | #include "currencymodel.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace Etherwall { 30 | 31 | CurrencyModel::CurrencyModel(const QSslConfiguration& sslConfig) : QAbstractListModel(0), fSSLConfig(sslConfig), fIndex(0), fTimer() 32 | { 33 | connect(&fNetManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(loadCurrenciesDone(QNetworkReply*))); 34 | loadCurrencies(); 35 | 36 | fTimer.setInterval(300 * 1000); // once per 5m, update currency prices 37 | connect(&fTimer, &QTimer::timeout, this, &CurrencyModel::loadCurrencies); 38 | fTimer.start(); 39 | } 40 | 41 | QHash CurrencyModel::roleNames() const { 42 | QHash roles; 43 | roles[NameRole] = "name"; 44 | roles[PriceRole] = "price"; 45 | return roles; 46 | } 47 | 48 | int CurrencyModel::rowCount(const QModelIndex & parent __attribute__ ((unused))) const { 49 | return fCurrencies.size(); 50 | } 51 | 52 | QVariant CurrencyModel::data(const QModelIndex & index, int role __attribute__ ((unused))) const { 53 | return QVariant(fCurrencies.at(index.row()).value(role)); 54 | } 55 | 56 | QVariant CurrencyModel::recalculateToHelper(const QVariant ðer) const 57 | { 58 | int index = getHelperIndex(); 59 | 60 | if ( index == 0 ) { 61 | return ether; // no change 62 | } 63 | 64 | double val = fCurrencies.at(index).recalculate(ether.toDouble()); 65 | return QVariant(QString::number(val, 'f', 18)); 66 | } 67 | 68 | QString CurrencyModel::getCurrencyName(int index) const { 69 | if ( index < 0 ) { 70 | index = fIndex; 71 | } 72 | 73 | if ( fCurrencies.size() > index && index >= 0 ) { 74 | return fCurrencies.at(index).value(NameRole).toString(); 75 | } 76 | 77 | return "UNK"; 78 | } 79 | 80 | QVariant CurrencyModel::recalculate(const QVariant& ether) const { 81 | if ( fIndex == 0 ) { 82 | return ether; // no change 83 | } 84 | 85 | double val = fCurrencies.at(fIndex).recalculate(ether.toDouble()); 86 | return QVariant(QString::number(val, 'f', 18)); 87 | } 88 | 89 | int CurrencyModel::getCount() const { 90 | return fCurrencies.size(); 91 | } 92 | 93 | void CurrencyModel::loadCurrencies() { 94 | fCurrencies.clear(); 95 | fCurrencies.append(CurrencyInfo("ETH", 1.0)); 96 | 97 | // get currency data from etherdata 98 | QNetworkRequest request(QUrl("https://api.etherwall.com/api/currencies")); 99 | request.setSslConfiguration(fSSLConfig); 100 | request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); 101 | 102 | QJsonObject objectJson; 103 | QJsonArray currencies; 104 | currencies.append(QJsonValue(QString("BTC"))); 105 | currencies.append(QJsonValue(QString("EUR"))); 106 | currencies.append(QJsonValue(QString("CAD"))); 107 | currencies.append(QJsonValue(QString("USD"))); 108 | currencies.append(QJsonValue(QString("GBP"))); 109 | objectJson["currencies"] = currencies; 110 | objectJson["version"] = 2; 111 | const QByteArray data = QJsonDocument(objectJson).toJson(); 112 | 113 | EtherLog::logMsg("HTTP Post request: " + data, LS_Debug); 114 | 115 | fNetManager.post(request, data); 116 | } 117 | 118 | void CurrencyModel::loadCurrenciesDone(QNetworkReply *reply) { 119 | if ( reply == NULL ) { 120 | return EtherLog::logMsg("Undefined currency reply", LS_Error); 121 | } 122 | 123 | beginResetModel(); 124 | 125 | const QByteArray data = reply->readAll(); 126 | EtherLog::logMsg("HTTP Post reply: " + data, LS_Debug); 127 | 128 | QJsonParseError parseError; 129 | const QJsonDocument resDoc = QJsonDocument::fromJson(data, &parseError); 130 | 131 | if ( parseError.error != QJsonParseError::NoError ) { 132 | return EtherLog::logMsg("Response parse error: " + parseError.errorString(), LS_Error); 133 | } 134 | 135 | const QJsonObject resObj = resDoc.object(); 136 | const bool success = resObj.value("success").toBool(false); 137 | 138 | if ( !success ) { 139 | return reply->close(); 140 | } 141 | 142 | const QJsonObject c = resObj.value("currencies").toObject(); 143 | 144 | foreach ( const QString& key, c.keys() ) { 145 | if ( key == "date") { 146 | continue; 147 | } 148 | const float value = c.value(key).toDouble(0); 149 | fCurrencies.append(CurrencyInfo(key, value)); 150 | } 151 | 152 | reply->close(); 153 | 154 | endResetModel(); 155 | emit currencyChanged(); 156 | emit helperIndexChanged(getHelperIndex()); 157 | } 158 | 159 | int CurrencyModel::getHelperIndex() const 160 | { 161 | const QSettings settings; 162 | 163 | const QString currencyName = settings.value("currencies/helper", "USD").toString(); 164 | int index = 0; 165 | 166 | foreach ( const CurrencyInfo& info, fCurrencies ) { 167 | if ( info.name() == currencyName ) { 168 | return index; 169 | } 170 | index++; 171 | } 172 | 173 | return 0; 174 | } 175 | 176 | const QString CurrencyModel::getHelperName() const 177 | { 178 | int index = getHelperIndex(); 179 | if ( index >= 0 && index < fCurrencies.size() ) { 180 | return fCurrencies.at(index).name(); 181 | } 182 | 183 | return QString(); 184 | } 185 | 186 | void CurrencyModel::setCurrencyIndex(int index) { 187 | if ( index >= 0 && index < fCurrencies.length() ) { 188 | fIndex = index; 189 | emit currencyChanged(); 190 | } 191 | } 192 | 193 | void CurrencyModel::setHelperIndex(int index) 194 | { 195 | if ( index < 0 || index >= fCurrencies.size() ) { 196 | return; 197 | } 198 | 199 | const QString name = fCurrencies.at(index).name(); 200 | QSettings settings; 201 | settings.setValue("currencies/helper", name); 202 | } 203 | 204 | int CurrencyModel::getCurrencyIndex() const { 205 | return fIndex; 206 | } 207 | 208 | double CurrencyModel::getCurrencyPrice(int index) const { 209 | if ( fCurrencies.size() > index && index >= 0 ) { 210 | return fCurrencies.at(index).recalculate(1.0); 211 | } 212 | 213 | return 1.0; 214 | } 215 | 216 | } 217 | -------------------------------------------------------------------------------- /src/currencymodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file currencymodel.h 15 | * @author Ales Katona 16 | * @date 2016 17 | * 18 | * Currency model header 19 | */ 20 | 21 | #ifndef CURRENCYMODEL_H 22 | #define CURRENCYMODEL_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "etherlog.h" 31 | #include "types.h" 32 | 33 | namespace Etherwall { 34 | 35 | class CurrencyModel : public QAbstractListModel 36 | { 37 | Q_OBJECT 38 | Q_PROPERTY(QString currencyName READ getCurrencyName() NOTIFY currencyChanged FINAL) 39 | Q_PROPERTY(int count READ getCount NOTIFY currencyChanged FINAL) 40 | Q_PROPERTY(int helperIndex READ getHelperIndex NOTIFY helperIndexChanged) 41 | Q_PROPERTY(QString helperName READ getHelperName NOTIFY helperIndexChanged) 42 | public: 43 | CurrencyModel(const QSslConfiguration& sslConfig); 44 | QHash roleNames() const; 45 | int rowCount(const QModelIndex & parent = QModelIndex()) const; 46 | QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 47 | int getCount() const; 48 | Q_INVOKABLE QVariant recalculate(const QVariant& ether) const; 49 | Q_INVOKABLE QString getCurrencyName(int index = -1) const; 50 | Q_INVOKABLE void loadCurrencies(); 51 | Q_INVOKABLE void setCurrencyIndex(int index); 52 | Q_INVOKABLE void setHelperIndex(int index); 53 | Q_INVOKABLE int getCurrencyIndex() const; 54 | Q_INVOKABLE double getCurrencyPrice(int index) const; 55 | Q_INVOKABLE QVariant recalculateToHelper(const QVariant& ether) const; 56 | public slots: 57 | void loadCurrenciesDone(QNetworkReply *reply); 58 | signals: 59 | void currencyChanged(); 60 | void helperIndexChanged(int index); 61 | private: 62 | const QSslConfiguration& fSSLConfig; 63 | CurrencyInfos fCurrencies; 64 | QNetworkAccessManager fNetManager; 65 | int fIndex; 66 | QTimer fTimer; 67 | 68 | int getHelperIndex() const; 69 | const QString getHelperName() const; 70 | }; 71 | 72 | } 73 | 74 | #endif // CURRENCYMODEL_H 75 | -------------------------------------------------------------------------------- /src/etherlogapp.cpp: -------------------------------------------------------------------------------- 1 | #include "etherlogapp.h" 2 | #include 3 | #include 4 | 5 | namespace Etherwall { 6 | 7 | EtherLogApp::EtherLogApp() : EtherLog() 8 | { 9 | 10 | } 11 | 12 | void EtherLogApp::saveToClipboard() const 13 | { 14 | QApplication::clipboard()->setText(getContents()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/etherlogapp.h: -------------------------------------------------------------------------------- 1 | #ifndef ETHERLOGAPP_H 2 | #define ETHERLOGAPP_H 3 | 4 | #include "etherlog.h" 5 | 6 | namespace Etherwall { 7 | 8 | class EtherLogApp: public EtherLog 9 | { 10 | Q_OBJECT 11 | public: 12 | EtherLogApp(); 13 | 14 | Q_INVOKABLE void saveToClipboard() const; 15 | }; 16 | } 17 | 18 | 19 | #endif // ETHERLOGAPP_H 20 | -------------------------------------------------------------------------------- /src/eventmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "eventmodel.h" 2 | 3 | namespace Etherwall { 4 | 5 | EventModel::EventModel(const ContractModel& contractModel, const FilterModel& filterModel) : 6 | QAbstractTableModel(0), fContractModel(contractModel), fList() 7 | { 8 | connect(&contractModel, &ContractModel::newEvent, this, &EventModel::onNewEvent); 9 | connect(&filterModel, &FilterModel::beforeLoadLogs, this, &EventModel::onBeforeLoadLogs); 10 | } 11 | 12 | QHash EventModel::roleNames() const { 13 | QHash roles; 14 | roles[Qt::DisplayRole] = "display"; 15 | roles[EventNameRole] = "name"; 16 | roles[EventContractRole] = "contract"; 17 | roles[EventAddressRole] = "address"; 18 | roles[EventDataRole] = "data"; 19 | roles[EventTopicsRole] = "topics"; 20 | roles[EventBlockHashRole] = "blockhash"; 21 | roles[EventBlockNumberRole] = "blocknumber"; 22 | roles[EventTransactionHashRole] = "transactionhash"; 23 | 24 | return roles; 25 | } 26 | 27 | int EventModel::rowCount(const QModelIndex & parent __attribute__ ((unused))) const { 28 | return fList.size(); 29 | } 30 | 31 | int EventModel::columnCount(const QModelIndex &parent) const 32 | { 33 | Q_UNUSED(parent); 34 | 35 | return 3; 36 | } 37 | 38 | QVariant EventModel::data(const QModelIndex & index, int role) const { 39 | int row = index.row(); 40 | 41 | if ( role == Qt::DisplayRole ) { 42 | switch ( index.column() ) { 43 | case 0: return fList.at(row).value(EventNameRole); 44 | case 1: return fList.at(row).contract(); 45 | case 2: return fList.at(row).blockNumber(); 46 | } 47 | 48 | return "?"; 49 | } 50 | 51 | return fList.at(row).value(role); 52 | } 53 | 54 | const QString EventModel::getName(int index) const { 55 | if ( index < 0 || index >= fList.length() ) { 56 | return QString(); 57 | } 58 | 59 | return fList.at(index).value(EventNameRole).toString(); 60 | } 61 | 62 | const QString EventModel::getContract(int index) const { 63 | if ( index < 0 || index >= fList.length() ) { 64 | return QString(); 65 | } 66 | 67 | return fList.at(index).value(EventContractRole).toString(); 68 | } 69 | 70 | const QString EventModel::getAddress(int index) const { 71 | if ( index < 0 || index >= fList.length() ) { 72 | return QString(); 73 | } 74 | 75 | return fList.at(index).address(); 76 | } 77 | 78 | const QString EventModel::getData(int index) const { 79 | if ( index < 0 || index >= fList.length() ) { 80 | return QString(); 81 | } 82 | 83 | return fList.at(index).value(EventDataRole).toString(); 84 | } 85 | 86 | const QString EventModel::getBlockNumber(int index) const { 87 | if ( index < 0 || index >= fList.length() ) { 88 | return QString(); 89 | } 90 | 91 | return fList.at(index).value(EventBlockNumberRole).toString(); 92 | } 93 | 94 | const QString EventModel::getBlockHash(int index) const { 95 | if ( index < 0 || index >= fList.length() ) { 96 | return QString(); 97 | } 98 | 99 | return fList.at(index).value(EventBlockHashRole).toString(); 100 | } 101 | 102 | const QString EventModel::getTransactionHash(int index) const { 103 | if ( index < 0 || index >= fList.length() ) { 104 | return QString(); 105 | } 106 | 107 | return fList.at(index).transactionHash(); 108 | } 109 | 110 | const QString EventModel::getTopics(int index) const { 111 | if ( index < 0 || index >= fList.length() ) { 112 | return QString(); 113 | } 114 | 115 | return fList.at(index).value(EventTopicsRole).toString(); 116 | } 117 | 118 | const QVariantList EventModel::getArgModel(int index) const { 119 | if ( index < 0 || index >= fList.length() ) { 120 | return QVariantList(); 121 | } 122 | 123 | const ContractArgs args = fList.at(index).getArguments(); 124 | const QVariantList params = fList.at(index).getParams(); 125 | QVariantList result; 126 | QVariantMap map; 127 | 128 | int i = 0; 129 | foreach ( const ContractArg arg, args ) { 130 | map["name"] = arg.name(); 131 | map["type"] = arg.type(); 132 | QString strVal = fList.at(index).paramToStr(params.at(i++)); 133 | map["value"] = strVal; 134 | result.append(map); 135 | } 136 | 137 | return result; 138 | } 139 | 140 | const QString EventModel::getParamValue(int index) const { 141 | if ( index < 0 || index >= fList.length() ) { 142 | return QString(); 143 | } 144 | 145 | const QVariant value = fList.at(index).getParams().at(index); 146 | QString strVal = fList.at(index).paramToStr(value); 147 | 148 | return strVal; 149 | } 150 | 151 | void EventModel::onNewEvent(const EventInfo& info, bool isNew) { 152 | // sort by block number descending 153 | int index = 0; 154 | while ( index < fList.length() && fList.at(index).blockNumber() > info.blockNumber() ) { 155 | index++; 156 | } 157 | 158 | beginInsertRows(QModelIndex(), index, index); 159 | fList.insert(index, info); 160 | endInsertRows(); 161 | 162 | if ( isNew ) { 163 | emit receivedEvent(info.contract(), info.signature()); 164 | } 165 | } 166 | 167 | void EventModel::onBeforeLoadLogs() { 168 | beginResetModel(); 169 | fList.clear(); 170 | endResetModel(); 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /src/eventmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENTMODEL_H 2 | #define EVENTMODEL_H 3 | 4 | #include 5 | #include 6 | #include "contractinfo.h" 7 | #include "contractmodel.h" 8 | #include "filtermodel.h" 9 | 10 | namespace Etherwall { 11 | 12 | class EventModel : public QAbstractTableModel 13 | { 14 | Q_OBJECT 15 | public: 16 | EventModel(const ContractModel& contractModel, const FilterModel& filterModel); 17 | 18 | QHash roleNames() const; 19 | int rowCount(const QModelIndex & parent __attribute__ ((unused))) const; 20 | Q_INVOKABLE virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; 21 | QVariant data(const QModelIndex & index, int role) const; 22 | Q_INVOKABLE const QString getName(int index) const; 23 | Q_INVOKABLE const QString getContract(int index) const; 24 | Q_INVOKABLE const QString getAddress(int index) const; 25 | Q_INVOKABLE const QString getData(int index) const; 26 | Q_INVOKABLE const QString getBlockNumber(int index) const; 27 | Q_INVOKABLE const QString getBlockHash(int index) const; 28 | Q_INVOKABLE const QString getTransactionHash(int index) const; 29 | Q_INVOKABLE const QString getTopics(int index) const; 30 | Q_INVOKABLE const QVariantList getArgModel(int index) const; 31 | Q_INVOKABLE const QString getParamValue(int index) const; 32 | public slots: 33 | void onNewEvent(const EventInfo& info, bool isNew); 34 | void onBeforeLoadLogs(); 35 | signals: 36 | void receivedEvent(const QString& contract, const QString& signature); 37 | private: 38 | const ContractModel& fContractModel; 39 | EventList fList; 40 | }; 41 | 42 | } 43 | 44 | #endif // EVENTMODEL_H 45 | -------------------------------------------------------------------------------- /src/filtermodel.cpp: -------------------------------------------------------------------------------- 1 | #include "filtermodel.h" 2 | #include "helpers.h" 3 | #include 4 | 5 | namespace Etherwall { 6 | 7 | FilterModel::FilterModel(NodeIPC& ipc) : QAbstractTableModel(0), fIpc(ipc), fList() 8 | { 9 | } 10 | 11 | QHash FilterModel::roleNames() const { 12 | QHash roles; 13 | roles[Qt::DisplayRole] = "display"; 14 | roles[FilterNameRole] = "name"; 15 | roles[FilterAddressRole] = "address"; 16 | roles[FilterContractRole] = "contract"; 17 | roles[FilterTopicsRole] = "topics"; 18 | roles[FilterActiveRole] = "active"; 19 | 20 | return roles; 21 | } 22 | 23 | int FilterModel::rowCount(const QModelIndex & parent __attribute__ ((unused))) const { 24 | return fList.size(); 25 | } 26 | 27 | int FilterModel::columnCount(const QModelIndex &parent) const 28 | { 29 | Q_UNUSED(parent); 30 | return 3; 31 | } 32 | 33 | QVariant FilterModel::data(const QModelIndex & index, int role) const { 34 | int row = index.row(); 35 | 36 | if ( role == Qt::DisplayRole ) { 37 | switch ( index.column() ) { 38 | case 0: return fList.at(row).value(FilterNameRole); 39 | case 1: return fList.at(row).value(FilterContractRole); 40 | case 2: return fList.at(row).value(FilterActiveRole); 41 | } 42 | 43 | return "?"; 44 | } 45 | 46 | return fList.at(row).value(role); 47 | } 48 | 49 | const QString FilterModel::getName(int index) const { 50 | if ( index < 0 || index >= fList.length() ) { 51 | return QString(); 52 | } 53 | 54 | return fList.at(index).value(FilterNameRole).toString(); 55 | } 56 | 57 | const QString FilterModel::getContract(int index) const { 58 | if ( index < 0 || index >= fList.length() ) { 59 | return QString(); 60 | } 61 | 62 | return fList.at(index).value(FilterContractRole).toString(); 63 | } 64 | 65 | const QJsonArray FilterModel::getTopics(int index) const { 66 | if ( index < 0 || index >= fList.length() ) { 67 | return QJsonArray(); 68 | } 69 | 70 | const QJsonArray topics = fList.at(index).value(FilterTopicsRole).toJsonArray(); 71 | return topics; 72 | } 73 | 74 | bool FilterModel::getActive(int index) const { 75 | if ( index < 0 || index >= fList.length() ) { 76 | return false; 77 | } 78 | 79 | return fList.at(index).value(FilterActiveRole).toBool(); 80 | } 81 | 82 | void FilterModel::addFilter(const QString& name, const QString& address, const QString& contract, const QString& topics, bool active) { 83 | QJsonParseError parseError; 84 | QJsonDocument doc = QJsonDocument::fromJson(topics.toUtf8(), &parseError); 85 | 86 | if ( parseError.error != QJsonParseError::NoError ) { 87 | EtherLog::logMsg("Error parsing topics on addfilter", LS_Error); 88 | return; 89 | } 90 | 91 | const QJsonArray topicArray = doc.array(); 92 | const FilterInfo info(name, address, contract, topicArray, active); 93 | QSettings settings; 94 | settings.beginGroup("filters" + fIpc.chainManager().networkPostfix()); 95 | settings.setValue(info.getHandle(), info.toJsonString()); 96 | settings.endGroup(); 97 | 98 | // check if it's an update 99 | for ( int i = 0; i < fList.length(); i++ ) { 100 | const FilterInfo fi = fList.at(i); 101 | if ( fi.getHandle() == info.getHandle() ) { 102 | fList[i] = info; 103 | 104 | update(i); 105 | return; 106 | } 107 | } 108 | 109 | beginInsertRows(QModelIndex(), fList.length(), fList.length()); 110 | fList.append(info); 111 | endInsertRows(); 112 | 113 | registerFilters(); 114 | loadLogs(); 115 | } 116 | 117 | void FilterModel::setFilterActive(int index, bool active) { 118 | if ( index < 0 || index >= fList.length() ) { 119 | return; 120 | } 121 | 122 | fList[index].setActive(active); 123 | const FilterInfo info = fList.at(index); 124 | 125 | QSettings settings; 126 | settings.beginGroup("filters" + fIpc.chainManager().networkPostfix()); 127 | settings.setValue(info.getHandle(), info.toJsonString()); 128 | settings.endGroup(); 129 | 130 | update(index); 131 | } 132 | 133 | void FilterModel::deleteFilter(int index) { 134 | if ( index < 0 || index >= fList.length() ) { 135 | return; 136 | } 137 | 138 | const FilterInfo info = fList.at(index); 139 | registerFilters(); 140 | QSettings settings; 141 | settings.beginGroup("filters" + fIpc.chainManager().networkPostfix()); 142 | settings.remove(info.getHandle()); 143 | settings.endGroup(); 144 | 145 | beginRemoveRows(QModelIndex(), index, index); 146 | fList.removeAt(index); 147 | endRemoveRows(); 148 | } 149 | 150 | void FilterModel::update(int index) { 151 | const QModelIndex& leftIndex = QAbstractTableModel::createIndex(index, 0); 152 | const QModelIndex& rightIndex = QAbstractTableModel::createIndex(index, 3); 153 | QVector roles(5); 154 | roles[0] = FilterNameRole; 155 | roles[1] = FilterContractRole; 156 | roles[2] = FilterTopicsRole; 157 | roles[3] = FilterActiveRole; 158 | roles[4] = Qt::DisplayRole; 159 | emit dataChanged(leftIndex, rightIndex, roles); 160 | 161 | registerFilters(); 162 | if ( fList.at(index).getActive() ) { 163 | loadLogs(); 164 | } 165 | } 166 | 167 | void FilterModel::registerFilters() const { 168 | fIpc.uninstallFilter("watchFilter"); 169 | if ( getActiveCount() > 0 ) { 170 | QJsonArray addresses; 171 | QJsonArray topics; 172 | foreach ( const FilterInfo& info, fList ) { 173 | if ( !info.getActive() ) { 174 | continue; 175 | } 176 | 177 | addresses.append(info.value(FilterAddressRole).toString()); 178 | Helpers::mergeJsonArrays(topics, info.value(FilterTopicsRole).toJsonArray()); 179 | } 180 | 181 | if ( addresses.size() > 0 ) { // ensure we don't watch everything 182 | fIpc.newEventFilter(addresses, topics, "watchFilter"); 183 | } 184 | } 185 | } 186 | 187 | int FilterModel::getActiveCount() const 188 | { 189 | int count = 0; 190 | foreach ( const FilterInfo& info, fList ) { 191 | if ( info.getActive() ) { 192 | count++; 193 | } 194 | } 195 | 196 | return count; 197 | } 198 | 199 | void FilterModel::loadLogs() const { 200 | const QSettings settings; 201 | quint64 day = settings.value("geth/logsize", 7200).toLongLong(); 202 | quint64 fromBlock = fIpc.blockNumber() > day ? fIpc.blockNumber() - day : 1; 203 | 204 | emit beforeLoadLogs(); 205 | foreach ( const FilterInfo& info, fList ) { 206 | if ( !info.value(FilterActiveRole).toBool() ) { 207 | continue; 208 | } 209 | 210 | QStringList addresses; 211 | addresses.append(info.value(FilterAddressRole).toString()); 212 | const QJsonArray infoTopics = info.value(FilterTopicsRole).toJsonArray(); 213 | info.getHandle(); 214 | fIpc.loadLogs(addresses, infoTopics, fromBlock, "watchFilter"); 215 | } 216 | } 217 | 218 | void FilterModel::reload() { 219 | beginResetModel(); 220 | QSettings settings; 221 | settings.beginGroup("filters" + fIpc.chainManager().networkPostfix()); 222 | 223 | const QStringList list = settings.allKeys(); 224 | 225 | foreach ( const QString addr, list ) { 226 | QJsonParseError parseError; 227 | const QString val = settings.value(addr).toString(); 228 | const QJsonDocument jsonDoc = QJsonDocument::fromJson(val.toUtf8(), &parseError); 229 | 230 | if ( parseError.error != QJsonParseError::NoError ) { 231 | EtherLog::logMsg("Error parsing stored filter: " + parseError.errorString(), LS_Error); 232 | } else { 233 | const FilterInfo info(jsonDoc.object()); 234 | fList.append(info); 235 | } 236 | } 237 | 238 | settings.endGroup(); 239 | 240 | registerFilters(); 241 | loadLogs(); 242 | endResetModel(); 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /src/filtermodel.h: -------------------------------------------------------------------------------- 1 | #ifndef FILTERMODEL_H 2 | #define FILTERMODEL_H 3 | 4 | #include 5 | #include 6 | #include "contractinfo.h" 7 | #include "nodeipc.h" 8 | 9 | namespace Etherwall { 10 | 11 | class FilterModel : public QAbstractTableModel 12 | { 13 | Q_OBJECT 14 | public: 15 | FilterModel(NodeIPC& ipc); 16 | 17 | QHash roleNames() const; 18 | int rowCount(const QModelIndex & parent = QModelIndex()) const; 19 | Q_INVOKABLE virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; 20 | QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 21 | 22 | Q_INVOKABLE const QString getName(int index) const; 23 | Q_INVOKABLE const QString getContract(int index) const; 24 | Q_INVOKABLE const QJsonArray getTopics(int index) const; 25 | Q_INVOKABLE bool getActive(int index) const; 26 | 27 | Q_INVOKABLE void addFilter(const QString& name, const QString& address, const QString& contract, const QString& topics, bool active); 28 | Q_INVOKABLE void setFilterActive(int index, bool active); 29 | Q_INVOKABLE void deleteFilter(int index); 30 | Q_INVOKABLE void loadLogs() const; 31 | public slots: 32 | void reload(); 33 | signals: 34 | void beforeLoadLogs() const; 35 | private: 36 | void update(int index); 37 | void registerFilters() const; 38 | NodeIPC& fIpc; 39 | EventFilters fList; 40 | 41 | int getActiveCount() const; 42 | }; 43 | 44 | } 45 | 46 | #endif // FILTERMODEL_H 47 | -------------------------------------------------------------------------------- /src/gethlogapp.cpp: -------------------------------------------------------------------------------- 1 | #include "gethlogapp.h" 2 | #include 3 | #include 4 | 5 | namespace Etherwall { 6 | 7 | GethLogApp::GethLogApp() : GethLog() 8 | { 9 | 10 | } 11 | 12 | void GethLogApp::saveToClipboard() const 13 | { 14 | QApplication::clipboard()->setText(getContents()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/gethlogapp.h: -------------------------------------------------------------------------------- 1 | #ifndef GETHLOGAPP_H 2 | #define GETHLOGAPP_H 3 | 4 | #include "gethlog.h" 5 | 6 | namespace Etherwall { 7 | 8 | class GethLogApp: public GethLog 9 | { 10 | Q_OBJECT 11 | public: 12 | GethLogApp(); 13 | 14 | Q_INVOKABLE void saveToClipboard() const; 15 | }; 16 | } 17 | 18 | #endif // GETHLOGAPP_H 19 | -------------------------------------------------------------------------------- /src/initializer.cpp: -------------------------------------------------------------------------------- 1 | #include "initializer.h" 2 | #include "etherlog.h" 3 | #include "helpers.h" 4 | #include "nodeipc.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace Etherwall { 11 | 12 | 13 | const QString Initializer::defaultGethPath() { 14 | #ifdef Q_OS_WIN32 15 | return QApplication::applicationDirPath() + "/geth.exe"; 16 | #else 17 | #ifdef Q_OS_MACX 18 | return QApplication::applicationDirPath() + "/geth"; 19 | #else 20 | return "/usr/bin/geth"; 21 | #endif 22 | #endif 23 | } 24 | 25 | Initializer::Initializer(const QString& gethPath, const QSslConfiguration& sslConfig) : 26 | QObject(0), fSSLConfig(sslConfig), fGethPath(gethPath) 27 | { 28 | connect(&fNetManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpRequestDone(QNetworkReply*))); 29 | 30 | replaceDeprecatedSettings(); 31 | } 32 | 33 | void Initializer::replaceDeprecatedSettings() const { 34 | QSettings settings; 35 | QString argStr = settings.value("geth/args", NodeIPC::sDefaultGethArgs).toString(); 36 | 37 | // check deprecated options and replace them 38 | if ( argStr.contains("--syncmode=fast") || argStr.contains("--light") || argStr.contains("--fast") ) { 39 | argStr = argStr.replace("--light", "--syncmode=light"); 40 | argStr = argStr.replace("--fast", "--syncmode=snap"); 41 | argStr = argStr.replace("--syncmode=fast", "--syncmode=snap"); 42 | settings.setValue("geth/args", argStr); 43 | qDebug() << "replaced args\n"; 44 | } 45 | 46 | // enable old personal API until we use clef 47 | if ( !argStr.contains("--rpc.enabledeprecatedpersonal") ) { 48 | argStr.append(" --rpc.enabledeprecatedpersonal"); 49 | qDebug() << "enabled personal API\n"; 50 | settings.setValue("geth/args", argStr); 51 | } 52 | } 53 | 54 | void Initializer::start() 55 | { 56 | QNetworkRequest request(QUrl("https://api.etherwall.com/api/init")); 57 | request.setSslConfiguration(fSSLConfig); 58 | request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); 59 | QJsonObject objectJson; 60 | const QByteArray data = QJsonDocument(objectJson).toJson(); 61 | 62 | EtherLog::logMsg("HTTP Post request: " + data, LS_Debug); 63 | EtherLog::logMsg("Connecting to main Etherwall server", LS_Info); 64 | 65 | fNetManager.post(request, data); 66 | } 67 | 68 | void Initializer::proceed() 69 | { 70 | emit initDone(fGethPath, fVersion, fEndpoint, fWarning); 71 | } 72 | 73 | void Initializer::httpRequestDone(QNetworkReply *reply) 74 | { 75 | QSettings settings; 76 | QString err; 77 | const auto parsed = Helpers::parseHTTPReply(reply, err); 78 | if ( !err.isEmpty() ){ 79 | emit error(err); 80 | return; 81 | } 82 | 83 | QJsonObject resObj = parsed.object(); 84 | const bool success = resObj.value("success").toBool(false); 85 | 86 | if ( !success ) { 87 | const QString error = resObj.value("error").toString("unknown error"); 88 | EtherLog::logMsg("Response error: " + error, LS_Error); 89 | emit initDone(fGethPath, "0.0.0", QString(), "Unable to connect to Etherwall server"); 90 | return; 91 | } 92 | 93 | const QString customRemoteURL = settings.value("geth/custom", false).toBool() ? settings.value("geth/remoteURL", "").toString() : ""; 94 | 95 | fVersion = resObj.value("version").toString("0.0.0"); 96 | fEndpoint = customRemoteURL.isEmpty() ? resObj.value("endpoint").toString() : customRemoteURL; 97 | fWarning = resObj.value("warning").toString(); 98 | 99 | if ( fWarning.isEmpty() ) { 100 | proceed(); 101 | } else { 102 | emit warning(fVersion, fEndpoint, fWarning); 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/initializer.h: -------------------------------------------------------------------------------- 1 | #ifndef INITIALIZER_H 2 | #define INITIALIZER_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Etherwall { 8 | 9 | class Initializer : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit Initializer(const QString& gethPath, const QSslConfiguration& sslConfig); 14 | void replaceDeprecatedSettings() const; 15 | Q_INVOKABLE void start(); 16 | Q_INVOKABLE void proceed(); 17 | static const QString defaultGethPath(); 18 | signals: 19 | void initDone(const QString& gethPath, const QString& version, const QString& endpoint, const QString& warning) const; 20 | void warning(const QString& version, const QString& endpoint, const QString& warning) const; 21 | void error(const QString& error) const; 22 | private slots: 23 | void httpRequestDone(QNetworkReply *reply); 24 | private: 25 | const QSslConfiguration& fSSLConfig; 26 | QNetworkAccessManager fNetManager; 27 | QString fGethPath; 28 | QString fVersion; 29 | QString fEndpoint; 30 | QString fWarning; 31 | }; 32 | 33 | } 34 | 35 | #endif // INITIALIZER_H 36 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file main.cpp 15 | * @author Ales Katona 16 | * @date 2017 17 | * 18 | * Main entry point 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "etherlogapp.h" 32 | #include "gethlogapp.h" 33 | #include "settings.h" 34 | #include "clipboard.h" 35 | #include "initializer.h" 36 | #include "accountmodel.h" 37 | #include "accountproxymodel.h" 38 | #include "transactionmodel.h" 39 | #include "contractmodel.h" 40 | #include "eventmodel.h" 41 | #include "currencymodel.h" 42 | #include "filtermodel.h" 43 | #include "tokenmodel.h" 44 | #include "nodemanager.h" 45 | #include "helpers.h" 46 | #include "nodews.h" 47 | #include "trezor/trezor.h" 48 | #include "platform/devicemanager.h" 49 | #include "cert.h" 50 | 51 | using namespace Etherwall; 52 | 53 | // ew-node version check 54 | #if EW_NODE_VERSION != 1000009 55 | #error "ew-node version mismatch, update git submodules" 56 | #endif 57 | 58 | int main(int argc, char *argv[]) 59 | { 60 | QApplication app(argc, argv); 61 | 62 | qmlRegisterType("AccountProxyModel", 0, 1, "AccountProxyModel"); 63 | 64 | QCoreApplication::setOrganizationName("Etherdyne"); 65 | QCoreApplication::setOrganizationDomain("etherwall.com"); 66 | QCoreApplication::setApplicationName("Etherwall"); 67 | QCoreApplication::setApplicationVersion("3.0.6"); 68 | app.setWindowIcon(QIcon(QPixmap(":/images/icon"))); 69 | 70 | QTranslator translator; 71 | translator.load("i18n/etherwall_" + QLocale::system().name()); 72 | app.installTranslator(&translator); 73 | 74 | Settings settings; 75 | 76 | const QString gethPath = settings.value("geth/path", Initializer::defaultGethPath()).toString(); 77 | const QString dataPath = settings.value("geth/datadir", NodeIPC::sDefaultDataDir).toString(); 78 | 79 | // set defaults 80 | if ( !settings.contains("geth/path") ) { 81 | settings.setValue("geth/path", gethPath); 82 | } 83 | if ( !settings.contains("geth/datadir") ) { 84 | settings.setValue("geth/datadir", dataPath); 85 | } 86 | 87 | ClipboardAdapter clipboard; 88 | EtherLogApp log; // important to be first (apart from clipboard) 89 | NodeManager nodeManager; 90 | GethLogApp gethLog; 91 | 92 | // get SSL cert for https://data.etherwall.com, no longer needed! 93 | // const QSslCertificate certificate(EtherWall_Cert.toUtf8()); 94 | QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration(); 95 | // sslConfig.addCaCertificate(certificate); 96 | 97 | Initializer initializer(gethPath, sslConfig); 98 | Trezor::TrezorDevice trezor; 99 | DeviceManager deviceManager(app); 100 | NodeWS ipc(gethLog); 101 | CurrencyModel currencyModel(sslConfig); 102 | AccountModel accountModel(ipc, currencyModel, trezor); 103 | TransactionModel transactionModel(ipc, accountModel, sslConfig); 104 | ContractModel contractModel(ipc, accountModel); 105 | FilterModel filterModel(ipc); 106 | EventModel eventModel(contractModel, filterModel); 107 | 108 | TokenModel tokenModel(&contractModel); 109 | 110 | // main connections 111 | QObject::connect(&initializer, &Initializer::initDone, &ipc, &NodeWS::start); 112 | QObject::connect(&ipc, &NodeWS::clientVersionChanged, &nodeManager, &NodeManager::onClientVersionChanged); 113 | QObject::connect(&accountModel, &AccountModel::accountsReady, &deviceManager, &DeviceManager::startProbe); 114 | QObject::connect(&contractModel, &ContractModel::tokenBalanceDone, &accountModel, &AccountModel::onTokenBalanceDone); 115 | QObject::connect(&transactionModel, &TransactionModel::confirmedTransaction, &contractModel, &ContractModel::onConfirmedTransaction); 116 | QObject::connect(&accountModel, &AccountModel::accountsReady, &filterModel, &FilterModel::reload); 117 | QObject::connect(&tokenModel, &TokenModel::selectedTokenContract, &contractModel, &ContractModel::onSelectedTokenContract); 118 | QObject::connect(&deviceManager, &DeviceManager::deviceInserted, &trezor, &Trezor::TrezorDevice::onDeviceInserted); 119 | QObject::connect(&deviceManager, &DeviceManager::deviceRemoved, &trezor, &Trezor::TrezorDevice::onDeviceRemoved); 120 | QObject::connect(&trezor, &Trezor::TrezorDevice::transactionReady, &transactionModel, &TransactionModel::onRawTransaction); 121 | 122 | // for QML only 123 | QmlHelpers qmlHelpers; 124 | 125 | QQmlApplicationEngine engine; 126 | 127 | engine.rootContext()->setContextProperty("settings", &settings); 128 | engine.rootContext()->setContextProperty("initializer", &initializer); 129 | engine.rootContext()->setContextProperty("nodeManager", &nodeManager); 130 | engine.rootContext()->setContextProperty("ipc", &ipc); 131 | engine.rootContext()->setContextProperty("trezor", &trezor); 132 | engine.rootContext()->setContextProperty("accountModel", &accountModel); 133 | engine.rootContext()->setContextProperty("transactionModel", &transactionModel); 134 | engine.rootContext()->setContextProperty("contractModel", &contractModel); 135 | engine.rootContext()->setContextProperty("filterModel", &filterModel); 136 | engine.rootContext()->setContextProperty("eventModel", &eventModel); 137 | engine.rootContext()->setContextProperty("currencyModel", ¤cyModel); 138 | engine.rootContext()->setContextProperty("clipboard", &clipboard); 139 | engine.rootContext()->setContextProperty("log", &log); 140 | engine.rootContext()->setContextProperty("geth", &gethLog); 141 | engine.rootContext()->setContextProperty("helpers", &qmlHelpers); 142 | 143 | engine.rootContext()->setContextProperty("tokenModel", &tokenModel); 144 | 145 | engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); 146 | 147 | if ( settings.contains("program/v2firstrun") ) { 148 | initializer.start(); 149 | } 150 | 151 | return app.exec(); 152 | } 153 | -------------------------------------------------------------------------------- /src/nodemanager.h: -------------------------------------------------------------------------------- 1 | #ifndef NODEMANAGER_H 2 | #define NODEMANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace Etherwall { 11 | 12 | enum NodeTypes { 13 | Geth = 0, 14 | Parity = 1 15 | }; 16 | 17 | class NodeManager : public QObject 18 | { 19 | Q_OBJECT 20 | public: 21 | explicit NodeManager(QObject *parent = nullptr); 22 | 23 | const QString cmdLineArgs() const; 24 | public slots: 25 | void onClientVersionChanged(const QString& ver); 26 | signals: 27 | void error(const QString& error) const; 28 | void newNodeVersionAvailable(const QString& nodeName, const QString& curVersion, const QString& newVersion) const; 29 | protected: 30 | void handleRelease(const QJsonDocument& reply); 31 | void handleTags(const QJsonDocument& reply); 32 | private slots: 33 | void onHttpRequestDone(QNetworkReply* reply); 34 | private: 35 | NodeTypes fNodeType; 36 | QString fNodeName; 37 | QNetworkAccessManager fNetManager; 38 | QString fLatestTag; 39 | QString fDownloadLink; 40 | QString fCurrentTag; 41 | int fLatestVersion; 42 | int fCurrentVersion; 43 | 44 | const QString tagFromFullVersion(const QString& ver) const; 45 | const QString settingsPrefix() const; 46 | void saveResults(); 47 | void loadResults(); 48 | void checkVersions() const; 49 | }; 50 | 51 | } 52 | 53 | #endif // NODEMANAGER_H 54 | -------------------------------------------------------------------------------- /src/platform/devicemanager.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICEMANAGER_H 2 | #define DEVICEMANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef Q_OS_MACX 10 | #include 11 | #include 12 | #include 13 | #endif 14 | #ifdef Q_OS_WIN32 15 | #include 16 | #include 17 | #include 18 | #endif 19 | #ifdef Q_OS_LINUX 20 | #include 21 | #include 22 | #endif 23 | 24 | namespace Etherwall { 25 | 26 | #ifdef Q_OS_WIN32 27 | class DeviceManager; 28 | 29 | class WindowsUSBFilter: public QAbstractNativeEventFilter 30 | { 31 | public: 32 | WindowsUSBFilter(DeviceManager& owner); 33 | virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); 34 | private: 35 | DeviceManager& fOwner; 36 | }; 37 | #endif 38 | 39 | class DeviceManager : public QThread 40 | { 41 | Q_OBJECT 42 | public: 43 | explicit DeviceManager(QApplication& app); 44 | virtual ~DeviceManager(); 45 | void run(); 46 | signals: 47 | void deviceInserted() const; 48 | void deviceRemoved() const; 49 | public slots: 50 | void startProbe(); 51 | private: 52 | #ifdef Q_OS_MACX 53 | IONotificationPortRef fNotifyPort; 54 | io_iterator_t fRawAddedIter; 55 | io_iterator_t fRawRemovedIter; 56 | #endif 57 | #ifdef Q_OS_WIN32 58 | WindowsUSBFilter fFilter; 59 | #endif 60 | #ifdef Q_OS_LINUX 61 | struct udev* fUdev; 62 | struct udev_monitor* fUdevMonitor; 63 | #endif 64 | }; 65 | 66 | } 67 | 68 | #endif // DEVICEMANAGER_H 69 | -------------------------------------------------------------------------------- /src/settings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file settings.cpp 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Settings QML binding implementation 19 | */ 20 | 21 | #include "settings.h" 22 | 23 | namespace Etherwall { 24 | 25 | Settings::Settings(QObject *parent) 26 | : QSettings(parent) 27 | { 28 | } 29 | 30 | bool Settings::contains(const QString& key) const 31 | { 32 | return QSettings::contains(key); 33 | } 34 | 35 | QVariant Settings::value(const QString& key, const QVariant& defaultValue) const 36 | { 37 | return QSettings::value(key, defaultValue); 38 | } 39 | 40 | bool Settings::valueBool(const QString& key, bool defaultValue) const 41 | { 42 | return QSettings::value(key, defaultValue).toBool(); 43 | } 44 | 45 | 46 | void Settings::setValue(const QString& key, const QVariant& value) 47 | { 48 | QSettings::setValue(key, value); 49 | } 50 | 51 | void Settings::remove(const QString &key) 52 | { 53 | QSettings::remove(key); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file settings.h 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Settings QML binding header 19 | */ 20 | 21 | #ifndef SETTINGS_H 22 | #define SETTINGS_H 23 | 24 | #include 25 | 26 | namespace Etherwall { 27 | 28 | class Settings: public QSettings 29 | { 30 | Q_OBJECT 31 | public: 32 | Settings(QObject *parent = 0); 33 | Q_INVOKABLE bool contains(const QString& key) const; 34 | Q_INVOKABLE QVariant value(const QString& key, const QVariant& defaultValue = QVariant()) const; 35 | Q_INVOKABLE bool valueBool(const QString& key, const bool defaultValue = false) const; 36 | Q_INVOKABLE void setValue(const QString& key, const QVariant& value); 37 | Q_INVOKABLE void remove(const QString& key); 38 | }; 39 | 40 | } 41 | 42 | #endif // SETTINGS_H 43 | -------------------------------------------------------------------------------- /src/tokenmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "tokenmodel.h" 2 | #include "contractmodel.h" 3 | #include 4 | 5 | namespace Etherwall { 6 | 7 | TokenModel::TokenModel(ContractModel* source) : 8 | QAbstractListModel(0), fContractModel(*source), fOuterIndex(0) 9 | { 10 | fFilteredContracts.setSourceModel(source); 11 | fFilteredContracts.setFilterRole(TokenRole); 12 | fFilteredContracts.setFilterRegExp(".+"); 13 | 14 | connect(source, &QAbstractListModel::modelReset, this, &TokenModel::modelReset); 15 | connect(source, &QAbstractListModel::dataChanged, this, &TokenModel::onDataChanged); 16 | connect(source, &QAbstractListModel::rowsInserted, this, &TokenModel::onRowsChanged); 17 | connect(source, &QAbstractListModel::rowsRemoved, this, &TokenModel::onRowsChanged); 18 | } 19 | 20 | QHash TokenModel::roleNames() const 21 | { 22 | QHash roles; 23 | roles[AddressRole] = "address"; 24 | roles[TokenRole] = "token"; 25 | roles[DecimalsRole] = "decimals"; 26 | 27 | return roles; 28 | } 29 | 30 | int TokenModel::rowCount(const QModelIndex &parent) const 31 | { 32 | return fFilteredContracts.rowCount(parent) + 1; 33 | } 34 | 35 | QVariant TokenModel::data(const QModelIndex &index, int role) const 36 | { 37 | if ( role != TokenRole && role != DecimalsRole && role != AddressRole ) { 38 | return QVariant("Invalid role"); 39 | } 40 | 41 | if ( index.row() == 0 ) { 42 | if ( role == TokenRole ) { 43 | return QVariant("ETH"); 44 | } else if ( role == DecimalsRole ) { 45 | return QVariant(18); 46 | } else if ( role == AddressRole ) { 47 | return QVariant("0x0000000000000000000000000000000000000000"); 48 | } 49 | } 50 | 51 | QModelIndex origIndex = fFilteredContracts.index(index.row(), index.column()); 52 | if ( index.row() > 0 ) { 53 | origIndex = fFilteredContracts.index(index.row() - 1, index.column()); 54 | } 55 | const QVariant result = fFilteredContracts.data(origIndex, role); 56 | return result; 57 | } 58 | 59 | int TokenModel::getOuterIndex() const 60 | { 61 | return fOuterIndex; 62 | } 63 | 64 | void TokenModel::selectToken(int index) 65 | { 66 | if ( index < 0 || index > fFilteredContracts.rowCount() ) { 67 | return; 68 | } 69 | 70 | fOuterIndex = index; 71 | emit outerIndexChanged(index); 72 | 73 | if ( index == 0 ) { 74 | emit selectedTokenContract(-1, true); 75 | return; 76 | } 77 | 78 | emit selectedTokenContract(mapIndex(index), true); 79 | } 80 | 81 | const QString TokenModel::getTokenAddress(int index) const 82 | { 83 | if ( index < 0 || index > fFilteredContracts.rowCount() ) { 84 | return QString("invalid"); 85 | } 86 | 87 | if ( index == 0 ) { 88 | return QString("0x000000000000000000000000000000000000000"); 89 | } 90 | 91 | int mapped = mapIndex(index); 92 | 93 | return fContractModel.getAddress(mapped); 94 | } 95 | 96 | int TokenModel::getTokenDecimals(int index) const 97 | { 98 | if ( index < 0 || index > fFilteredContracts.rowCount() ) { 99 | return -1; 100 | } 101 | 102 | if ( index == 0 ) { 103 | return 18; 104 | } 105 | 106 | int mapped = mapIndex(index); 107 | return fContractModel.getDecimals(mapped); 108 | } 109 | 110 | const QString TokenModel::getTokenTransferData(int index, const QString &toAddress, const QString& value) const 111 | { 112 | if ( index < 0 || index > fFilteredContracts.rowCount() ) { 113 | return QString(); 114 | } 115 | 116 | if ( index == 0 ) { 117 | return QString(); 118 | } 119 | 120 | int mapped = mapIndex(index); 121 | return fContractModel.encodeTransfer(mapped, toAddress, value); 122 | } 123 | 124 | void TokenModel::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) 125 | { 126 | Q_UNUSED(topLeft); 127 | Q_UNUSED(bottomRight); 128 | Q_UNUSED(roles); 129 | 130 | beginResetModel(); 131 | endResetModel(); 132 | } 133 | 134 | void TokenModel::onRowsChanged(const QModelIndex &parent, int first, int last) 135 | { 136 | Q_UNUSED(parent); 137 | Q_UNUSED(first); 138 | Q_UNUSED(last); 139 | beginResetModel(); 140 | endResetModel(); 141 | } 142 | 143 | int TokenModel::mapIndex(int index) const 144 | { 145 | index -= 1; // discount the ETH 146 | const QModelIndex modelIndex = fFilteredContracts.index(index, 0); 147 | const QModelIndex mappedIndex = fFilteredContracts.mapToSource(modelIndex); 148 | 149 | return mappedIndex.row(); 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/tokenmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef TOKENMODEL_H 2 | #define TOKENMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "contractmodel.h" 9 | 10 | namespace Etherwall { 11 | 12 | class TokenModel : public QAbstractListModel 13 | { 14 | Q_OBJECT 15 | Q_PROPERTY(int outerIndex READ getOuterIndex NOTIFY outerIndexChanged) 16 | public: 17 | TokenModel(ContractModel* source); 18 | 19 | QHash roleNames() const; 20 | int rowCount(const QModelIndex & parent = QModelIndex()) const; 21 | QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 22 | int getOuterIndex() const; 23 | 24 | Q_INVOKABLE void selectToken(int index); 25 | Q_INVOKABLE const QString getTokenAddress(int index) const; 26 | Q_INVOKABLE int getTokenDecimals(int index) const; 27 | Q_INVOKABLE const QString getTokenTransferData(int index, const QString& toAddress, const QString& value) const; 28 | signals: 29 | void selectedTokenContract(int index, bool forAccounts) const; 30 | void outerIndexChanged(int index) const; 31 | private slots: 32 | void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); 33 | void onRowsChanged(const QModelIndex &parent, int first, int last); 34 | private: 35 | QSortFilterProxyModel fFilteredContracts; 36 | ContractModel& fContractModel; 37 | int fOuterIndex; 38 | 39 | int mapIndex(int index) const; 40 | }; 41 | 42 | } 43 | 44 | #endif // TOKENMODEL_H 45 | -------------------------------------------------------------------------------- /src/transactionmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of etherwall. 3 | etherwall is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | etherwall is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with etherwall. If not, see . 13 | */ 14 | /** @file transactionmodel.h 15 | * @author Ales Katona 16 | * @date 2015 17 | * 18 | * Transaction model header 19 | */ 20 | 21 | 22 | #ifndef TRANSACTIONMODEL_H 23 | #define TRANSACTIONMODEL_H 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "types.h" 31 | #include "nodeipc.h" 32 | #include "accountmodel.h" 33 | #include "etherlog.h" 34 | 35 | namespace Etherwall { 36 | 37 | class TransactionModel : public QAbstractTableModel 38 | { 39 | Q_OBJECT 40 | Q_PROPERTY(quint64 firstBlock READ getFirstBlock NOTIFY blockNumberChanged) 41 | Q_PROPERTY(quint64 lastBlock READ getLastBlock NOTIFY blockNumberChanged) 42 | Q_PROPERTY(quint64 blockNumber READ getBlockNumber NOTIFY blockNumberChanged FINAL) 43 | Q_PROPERTY(QString gasPrice READ getGasPrice NOTIFY gasPriceChanged FINAL) 44 | Q_PROPERTY(QString gasEstimate READ getGasEstimate NOTIFY gasEstimateChanged FINAL) 45 | Q_PROPERTY(QString latestVersion READ getLatestVersion NOTIFY latestVersionChanged FINAL) 46 | public: 47 | TransactionModel(NodeIPC& ipc, const AccountModel& accountModel, const QSslConfiguration& sslConfig); 48 | quint64 getBlockNumber() const; 49 | const QString& getGasPrice() const; 50 | const QString& getLatestVersion() const; 51 | const QString& getGasEstimate() const; 52 | QHash roleNames() const; 53 | int rowCount(const QModelIndex & parent = QModelIndex()) const; 54 | Q_INVOKABLE virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; 55 | QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 56 | int containsTransaction(const QString& hash); 57 | 58 | Q_INVOKABLE void sendTransaction(const QString& password, const QString& from, const QString& to, 59 | const QString& value, quint64 nonce, const QString& gas = QString(), 60 | const QString& gasPrice = QString(), const QString& data = QString()); 61 | 62 | Q_INVOKABLE void call(const QString& from, const QString& to, 63 | const QString& value, const QString& gas, 64 | const QString& gasPrice, const QString& data, 65 | int index, const QVariantMap& userData); 66 | 67 | Q_INVOKABLE const QString estimateTotal(const QString& value, const QString& gas, const QString& gasPrice) const; 68 | Q_INVOKABLE void loadHistory(); 69 | Q_INVOKABLE const QString getHash(int index) const; 70 | Q_INVOKABLE const QString getSender(int index) const; 71 | Q_INVOKABLE const QString getReceiver(int index) const; 72 | Q_INVOKABLE double getValue(int index) const; 73 | Q_INVOKABLE const QJsonObject getJson(int index, bool decimal) const; 74 | Q_INVOKABLE const QString getMaxValue(int row, const QString& gas, const QString& gasPrice) const; 75 | Q_INVOKABLE void lookupAccountsAliases(); 76 | Q_INVOKABLE void checkVersion(bool manual = false); 77 | double getHistoryProgress() const; 78 | quint64 getFirstBlock() const; 79 | quint64 getLastBlock() const; 80 | public slots: 81 | void onRawTransaction(const Ethereum::Tx& tx); 82 | private slots: 83 | void connectToServerDone(); 84 | void getAccountsDone(const QStringList& list); 85 | void getBlockNumberDone(quint64 num); 86 | void getGasPriceDone(const QString& num); 87 | void estimateGasDone(const QString& num); 88 | void onSendTransactionDone(const QString& hash); 89 | void onSignTransactionDone(const QString& hash); 90 | void onNewTransaction(const QJsonObject& json); 91 | void newBlock(const QJsonObject& block); 92 | void syncingChanged(bool syncing); 93 | void refresh(); 94 | void loadHistoryDone(QNetworkReply* reply); 95 | void checkVersionDone(QNetworkReply *reply); 96 | void httpRequestDone(QNetworkReply *reply); 97 | signals: 98 | void error(const QString& error) const; 99 | void blockNumberChanged(quint64 num) const; 100 | void gasPriceChanged(const QString& price) const; 101 | void gasEstimateChanged(const QString& price) const; 102 | void historyChanged() const; 103 | void latestVersionChanged(const QString& version, bool manualVersionCheck) const; 104 | void latestVersionSame(const QString& version, bool manualVersionCheck) const; 105 | void receivedTransaction(const QString& toAddress) const; 106 | void confirmedTransaction(const QString& fromAddress, const QString& toAddress, const QString& hash) const; 107 | private: 108 | const QSslConfiguration fSSLConfig; 109 | NodeIPC& fIpc; 110 | const AccountModel& fAccountModel; 111 | TransactionList fTransactionList; 112 | quint64 fBlockNumber; 113 | quint64 fLastBlock; 114 | quint64 fFirstBlock; 115 | QString fGasPrice; 116 | QString fGasEstimate; 117 | TransactionInfo fQueuedTransaction; 118 | QNetworkAccessManager fNetManager; 119 | QString fLatestVersion; 120 | 121 | int getInsertIndex(const TransactionInfo& info) const; 122 | void addTransaction(const TransactionInfo& info); 123 | void storeTransaction(const TransactionInfo& info); 124 | void refreshPendingTransactions(); 125 | }; 126 | 127 | } 128 | 129 | 130 | #endif // TRANSACTIONMODEL_H 131 | -------------------------------------------------------------------------------- /src/trezor/hdpath.cpp: -------------------------------------------------------------------------------- 1 | #include "hdpath.h" 2 | #include 3 | 4 | namespace Trezor { 5 | 6 | HDPath::HDPath(const QString &fullPath) 7 | { 8 | fIsValid = false; 9 | if ( !fullPath.startsWith('m') || fullPath.endsWith('/') ) { 10 | qDebug() << "Invalid HD path: " << fullPath << "\n"; 11 | return; 12 | } 13 | 14 | QStringList segments = fullPath.split('/'); 15 | if ( segments.size() <= 1 ) { 16 | qDebug() << "Invalid HD path: " << fullPath << "\n"; 17 | return; 18 | } 19 | 20 | if ( segments.at(0) != "m" ) { 21 | qDebug() << "Invalid HD path: " << fullPath << "\n"; 22 | return; 23 | } 24 | 25 | segments.removeFirst(); 26 | foreach ( const QString segment, segments ) { 27 | quint32 num; 28 | if ( parseSegment(segment, num) ) { 29 | fSegments.append(num); 30 | } else { 31 | qDebug() << "Invalid HD path: " << fullPath << "\n"; 32 | return; 33 | } 34 | } 35 | 36 | fPath = fullPath; 37 | fIsValid = true; 38 | } 39 | 40 | bool HDPath::getSegment(int index, quint32 &value) const 41 | { 42 | if ( !fIsValid ) { 43 | return false; 44 | } 45 | 46 | if ( fSegments.isEmpty() || index >= fSegments.size() ) { 47 | return false; 48 | } 49 | 50 | value = fSegments.at(index); 51 | return true; 52 | } 53 | 54 | const QString HDPath::toString() const 55 | { 56 | return fPath; 57 | } 58 | 59 | bool HDPath::valid() const 60 | { 61 | return fIsValid; 62 | } 63 | 64 | bool HDPath::parseSegment(const QString &segment, quint32& result) const 65 | { 66 | result = 0; 67 | QString val = segment; 68 | if ( val.endsWith("'") || val.endsWith('H', Qt::CaseInsensitive) ) { 69 | result = 0x80000000; 70 | val = val.left(segment.length() - 1); 71 | } 72 | 73 | bool ok = false; 74 | result += val.toUInt(&ok, 10); 75 | if ( !ok ) { 76 | qDebug() << "invalid segment: " << segment << "\n"; 77 | return false; 78 | } 79 | 80 | return true; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/trezor/hdpath.h: -------------------------------------------------------------------------------- 1 | #ifndef HDPATH_H 2 | #define HDPATH_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Trezor { 8 | 9 | class HDPath 10 | { 11 | public: 12 | HDPath(const QString& fullPath); 13 | bool getSegment(int index, quint32& value) const; 14 | const QString toString() const; 15 | bool valid() const; 16 | private: 17 | QList fSegments; 18 | bool fIsValid; 19 | QString fPath; 20 | 21 | bool parseSegment(const QString& segment, quint32& result) const; 22 | }; 23 | 24 | } 25 | 26 | #endif // HDPATH_H 27 | -------------------------------------------------------------------------------- /src/trezor/trezor.h: -------------------------------------------------------------------------------- 1 | #ifndef TREZOR_H 2 | #define TREZOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "proto/messages.pb.h" 11 | #include "proto/messages-common.pb.h" 12 | #include "proto/messages-management.pb.h" 13 | #include "proto/messages-ethereum.pb.h" 14 | #include "wire.h" 15 | #include "hdpath.h" 16 | #include "ethereum/tx.h" 17 | 18 | using namespace hw::trezor::messages; 19 | using namespace hw::trezor::messages::common; 20 | using namespace hw::trezor::messages::management; 21 | using namespace hw::trezor::messages::ethereum; 22 | 23 | namespace Trezor { 24 | 25 | class TrezorWorker: public QThread 26 | { 27 | Q_OBJECT 28 | public: 29 | TrezorWorker(Wire::Device& device); 30 | void setRequest(const Wire::Message& request); 31 | const Wire::Message& getReply() const; 32 | const QVariant getIndex() const; 33 | protected: 34 | virtual void run(); 35 | private: 36 | Wire::Device& fDevice; 37 | Wire::Message fRequest; 38 | Wire::Message fReply; 39 | }; 40 | 41 | class MessageQueue: public QQueue 42 | { 43 | public: 44 | MessageQueue(); 45 | void lock(int type, const QVariant& index); 46 | void unlock(); 47 | void push(const Wire::Message& msg); 48 | bool pop(Wire::Message& popped); 49 | const QString toString() const; 50 | private: 51 | int fLockType; 52 | QVariant fIndex; 53 | }; 54 | 55 | class TrezorDevice: public QObject 56 | { 57 | Q_OBJECT 58 | Q_PROPERTY(QString deviceID READ getDeviceID NOTIFY initialized) 59 | Q_PROPERTY(QString version READ getVersion NOTIFY initialized) 60 | Q_PROPERTY(bool present READ isPresent NOTIFY presenceChanged) 61 | Q_PROPERTY(bool initialized READ isInitialized NOTIFY initializedChanged) 62 | Q_PROPERTY(bool busy READ getBusy NOTIFY busyChanged) 63 | public: 64 | explicit TrezorDevice(); 65 | virtual ~TrezorDevice(); 66 | 67 | bool isPresent(); 68 | bool isInitialized(); 69 | void getAddress(const HDPath& hdPath); 70 | const QString getDeviceID() const; 71 | const QString getVersion() const; 72 | void initialize(); 73 | Q_INVOKABLE void cancel(); 74 | Q_INVOKABLE void submitPin(const QString& pin); 75 | Q_INVOKABLE void submitPassphrase(const QString& pw); 76 | // all values in ether 77 | Q_INVOKABLE void signTransaction(quint32 chaindID, const QString& hdPath, const QString& from, const QString& to, 78 | const QString& valStr, quint64 nonce, 79 | const QString& gas = QString(), const QString& gasPrice = QString(), 80 | const QString& data = QString()); 81 | signals: 82 | void presenceChanged(bool present) const; 83 | void initialized(const QString& deviceID) const; 84 | void initializedChanged(bool initialized) const; 85 | void failure(const QString& error) const; 86 | void matrixRequest(int type) const; 87 | void buttonRequest(int code) const; 88 | void passphraseRequest(bool onDevice) const; 89 | void addressRetrieved(const QString& address, const QString& hdPath) const; 90 | void busyChanged(bool busy) const; 91 | void transactionReady(const Ethereum::Tx& tx) const; 92 | void deviceOutdated(const QString& minVersion, const QString& curVersion) const; 93 | void error(const QString& error) const; 94 | public slots: 95 | void onDeviceInserted(); 96 | void onDeviceRemoved(); 97 | void onDirectoryChanged(const QString& path); 98 | void checkPresence(); 99 | private slots: 100 | void workerDone(); 101 | private: 102 | Wire::Device fDevice; 103 | TrezorWorker fWorker; 104 | MessageQueue fQueue; 105 | QString fDeviceID; 106 | QString fVersion; 107 | bool fDevicePresent; 108 | Ethereum::Tx fPendingTx; 109 | 110 | bool getBusy() const; 111 | void bail(const QString& err); 112 | const Wire::Message serializeMessage(google::protobuf::Message& msg, MessageType, const QVariant& index); 113 | bool parseMessage(const Wire::Message& msg_in, google::protobuf::Message& parsed) const; 114 | void sendMessage(google::protobuf::Message& msg, MessageType type, QVariant index = QVariant()); 115 | void sendNext(); 116 | void handleResponse(const Wire::Message& msg_in); 117 | void handleFailure(const Wire::Message& msg_in); 118 | void handleMatrixRequest(const Wire::Message& msg_in); 119 | void handleButtonRequest(const Wire::Message& msg_in); 120 | void handlePassphrase(const Wire::Message& msg_in); 121 | void handlePassphraseStateRequest(const Wire::Message& msg_in); 122 | void handleFeatures(const Wire::Message& msg_in); 123 | void handleAddress(const Wire::Message& msg_in); 124 | void handleTxRequest(const Wire::Message& msg_in); 125 | }; 126 | 127 | } 128 | 129 | #endif // TREZOR_H 130 | -------------------------------------------------------------------------------- /src/trezor/wire.h: -------------------------------------------------------------------------------- 1 | #ifndef WIRE_HPP 2 | #define WIRE_HPP 3 | 4 | /* 5 | * This file is modified from the TREZOR project. 6 | * 7 | * Copyright (C) 2017 Ales Katona 8 | * 9 | * This library is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public License 20 | * along with this library. If not, see . 21 | */ 22 | 23 | #ifdef _WIN32 24 | #include 25 | #else 26 | #include 27 | #endif 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | namespace Trezor { 38 | 39 | namespace Wire { 40 | 41 | class Device 42 | { 43 | public: 44 | typedef std::uint8_t char_type; 45 | 46 | struct wire_error 47 | : public std::runtime_error 48 | { using std::runtime_error::runtime_error; }; 49 | 50 | Device(); 51 | Device(Device const&) = delete; 52 | Device &operator=(Device const&) = delete; 53 | ~Device(); 54 | 55 | void init(); 56 | bool isInitialized() const; 57 | void close(); 58 | 59 | bool isPresent(); 60 | // try writing packet that will be discarded to figure out hid version 61 | int try_hid_version(); 62 | void read_buffered(char_type *data, size_t len); 63 | 64 | void write(char_type const *data, size_t len); 65 | static const QString getDevicePath(); 66 | private: 67 | size_t read_report_from_buffer(char_type *data, size_t len); 68 | void buffer_report(); 69 | size_t write_report(char_type const *data, size_t len); 70 | 71 | typedef std::vector buffer_type; 72 | typedef std::array report_type; 73 | 74 | hid_device *hid; 75 | buffer_type read_buffer; 76 | int hid_version; 77 | 78 | libusb_context* usb; 79 | libusb_device_handle* usb_dev; 80 | int usb_max_size; 81 | 82 | enum { 83 | Trezor_V1, Trezor_V2 84 | } trezor_ver; 85 | }; 86 | 87 | class Message 88 | { 89 | public: 90 | std::uint16_t id; 91 | std::vector data; 92 | QVariant index; // for keeping track on queue side 93 | 94 | typedef Device::wire_error header_wire_error; 95 | 96 | void read_from(Device &device); 97 | void write_to(Device &device) const; 98 | }; 99 | 100 | } 101 | 102 | } 103 | 104 | #endif // WIRE_HPP 105 | -------------------------------------------------------------------------------- /tests/conversions.txt: -------------------------------------------------------------------------------- 1 | ether 4 to weihex: 0x3782dace9d900000 2 | ether 213987325409 to weihex: 0x2b36e2abaa3d84c12d2e40000 3 | ether 0 to weiHex: 0x0 4 | ether 0.1 to weiHex: 0x16345785d8a0000 5 | ether 0.000000000000000001 to weiHex: 0x1 6 | ether 8.3 to weiHex: 0x732f860653be0000 7 | --------------------------------------------------------------------------------