├── .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 | [](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 | [](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 |
--------------------------------------------------------------------------------