From b5ca3d635e4069fd32c34ca6682a36ea893f9bdf Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 24 Jul 2019 13:11:54 -0700 Subject: [PATCH 01/14] Fix header resizing on tx table --- src/mainwindow.cpp | 5 +++++ src/rpc.cpp | 3 +-- src/settings.cpp | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 71848c5..fed98a6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -177,6 +177,11 @@ void MainWindow::restoreSavedStates() { ui->balancesTable->horizontalHeader()->restoreState(s.value("baltablegeometry").toByteArray()); ui->transactionsTable->horizontalHeader()->restoreState(s.value("tratablegeometry").toByteArray()); + + // Explicitly set the tx table resize headers, since some previous values may have made them + // non-expandable. + ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive); + ui->transactionsTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch); } void MainWindow::doClose() { diff --git a/src/rpc.cpp b/src/rpc.cpp index c38be5b..35a073b 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -27,8 +27,7 @@ RPC::RPC(MainWindow* main) { // Setup transactions table model transactionsTableModel = new TxTableModel(ui->transactionsTable); main->ui->transactionsTable->setModel(transactionsTableModel); - main->ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); - + // Set up timer to refresh Price priceTimer = new QTimer(main); QObject::connect(priceTimer, &QTimer::timeout, [=]() { diff --git a/src/settings.cpp b/src/settings.cpp index 66bdef7..fec889f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -178,6 +178,7 @@ void Settings::saveRestore(QDialog* d) { void Settings::saveRestoreTableHeader(QTableView* table, QDialog* d, QString tablename) { table->horizontalHeader()->restoreState(QSettings().value(tablename).toByteArray()); + table->horizontalHeader()->setStretchLastSection(true); QObject::connect(d, &QDialog::finished, [=](auto) { QSettings().setValue(tablename, table->horizontalHeader()->saveState()); From 64c4e82f58dc6bda827c8284d28806924abd0e97 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 24 Jul 2019 10:58:46 -0700 Subject: [PATCH 02/14] 0.7.6 --- README.md | 6 +++--- src/version.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 316245b..cfa7f9e 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,14 @@ Head over to the releases page and grab the latest installers or binary. https:/ If you are on Debian/Ubuntu, please download the `.deb` package and install it. ``` -sudo dpkg -i linux-deb-zecwallet-v0.7.5.deb +sudo dpkg -i linux-deb-zecwallet-v0.7.6.deb sudo apt install -f ``` Or you can download and run the binaries directly. ``` -tar -xvf zecwallet-v0.7.5.tar.gz -./zecwallet-v0.7.5/zecwallet +tar -xvf zecwallet-v0.7.6.tar.gz +./zecwallet-v0.7.6/zecwallet ``` ### Windows diff --git a/src/version.h b/src/version.h index 1cc7722..ce09c51 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define APP_VERSION "0.7.5" +#define APP_VERSION "0.7.6" From c4a691381d4e2751e1cd77eebb76e207a7f2e236 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Sat, 27 Jul 2019 08:00:11 -0700 Subject: [PATCH 03/14] Keep existing address selected in recieve dropdown --- src/mainwindow.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ae03159..2220875 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1258,6 +1258,9 @@ std::function MainWindow::addZAddrsToComboList(bool sapling) { return [=] (bool checked) { if (checked && this->rpc->getAllZAddresses() != nullptr) { auto addrs = this->rpc->getAllZAddresses(); + + // Save the current address, so we can update it later + auto zaddr = ui->listReceiveAddresses->currentText(); ui->listReceiveAddresses->clear(); std::for_each(addrs->begin(), addrs->end(), [=] (auto addr) { @@ -1269,6 +1272,10 @@ std::function MainWindow::addZAddrsToComboList(bool sapling) { } } }); + + if (!zaddr.isEmpty() && Settings::isZAddress(zaddr)) { + ui->listReceiveAddresses->setCurrentText(zaddr); + } // If z-addrs are empty, then create a new one. if (addrs->isEmpty()) { @@ -1461,6 +1468,10 @@ void MainWindow::setupReceiveTab() { void MainWindow::updateTAddrCombo(bool checked) { if (checked) { auto utxos = this->rpc->getUTXOs(); + + // Save the current address so we can restore it later + auto currentTaddr = ui->listReceiveAddresses->currentText(); + ui->listReceiveAddresses->clear(); // Maintain a set of addresses so we don't duplicate any, because we'll be adding @@ -1502,6 +1513,16 @@ void MainWindow::updateTAddrCombo(bool checked) { ui->listReceiveAddresses->addItem(addr, 0); } } + + // 4. Add the previously selected t-address + if (!currentTaddr.isEmpty() && Settings::isTAddress(currentTaddr)) { + // Make sure the current taddr is in the list + if (!addrs.contains(currentTaddr)) { + auto bal = rpc->getAllBalances()->value(currentTaddr); + ui->listReceiveAddresses->addItem(currentTaddr, bal); + } + ui->listReceiveAddresses->setCurrentText(currentTaddr); + } } }; From df1cbe6570ecba9b7d0bc1e257e8eca060576ce0 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 24 Jul 2019 10:32:38 -0700 Subject: [PATCH 04/14] Add num of skipper taddrs --- src/mainwindow.cpp | 10 ++++++++++ src/precompiled.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2220875..cbb41d7 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1523,6 +1523,16 @@ void MainWindow::updateTAddrCombo(bool checked) { } ui->listReceiveAddresses->setCurrentText(currentTaddr); } + + // 5. Add a last, disabled item if there are remaining items + if (allTaddrs->size() > addrs.size()) { + auto num = QString::number(allTaddrs->size() - addrs.size()); + ui->listReceiveAddresses->addItem("-- " + num + " more --", 0); + + QStandardItemModel* model = qobject_cast(ui->listReceiveAddresses->model()); + QStandardItem* item = model->findItems("--", Qt::MatchStartsWith)[0]; + item->setFlags(item->flags() & ~Qt::ItemIsEnabled); + } } }; diff --git a/src/precompiled.h b/src/precompiled.h index 5745182..79c4c8b 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include From 1219651f7690bab9f8495f13c29b9233278a8e14 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 24 Jul 2019 10:23:59 -0700 Subject: [PATCH 05/14] 171 - Validate address --- src/mainwindow.cpp | 49 +++++++++++++++++++++++- src/mainwindow.h | 2 + src/mainwindow.ui | 6 +++ src/rpc.cpp | 12 ++++++ src/rpc.h | 2 +- src/validateaddress.cpp | 37 ++++++++++++++++++ src/validateaddress.h | 23 +++++++++++ src/validateaddress.ui | 85 +++++++++++++++++++++++++++++++++++++++++ zec-qt-wallet.pro | 7 +++- 9 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 src/validateaddress.cpp create mode 100644 src/validateaddress.h create mode 100644 src/validateaddress.ui diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index cbb41d7..f330ee2 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,6 +1,7 @@ #include "mainwindow.h" #include "addressbook.h" #include "viewalladdresses.h" +#include "validateaddress.h" #include "ui_mainwindow.h" #include "ui_mobileappconnector.h" #include "ui_addressbook.h" @@ -11,6 +12,7 @@ #include "ui_turnstile.h" #include "ui_turnstileprogress.h" #include "ui_viewalladdresses.h" +#include "ui_validateaddress.h" #include "rpc.h" #include "balancestablemodel.h" #include "settings.h" @@ -83,6 +85,9 @@ MainWindow::MainWindow(QWidget *parent) : // z-Board.net QObject::connect(ui->actionz_board_net, &QAction::triggered, this, &MainWindow::postToZBoard); + // Validate Address + QObject::connect(ui->actionValidate_Address, &QAction::triggered, this, &MainWindow::validateAddress); + // Connect mobile app QObject::connect(ui->actionConnect_Mobile_App, &QAction::triggered, this, [=] () { if (rpc->getConnection() == nullptr) @@ -644,6 +649,48 @@ void MainWindow::donate() { ui->tabWidget->setCurrentIndex(1); } +/** + * Validate an address + */ +void MainWindow::validateAddress() { + // Make sure everything is up and running + if (!getRPC() || !getRPC()->getConnection()) + return; + + // First thing is ask the user for an address + bool ok; + auto address = QInputDialog::getText(this, tr("Enter Address to validate"), + tr("Transparent or Shielded Address:") + QString(" ").repeated(140), // Pad the label so the dialog box is wide enough + QLineEdit::Normal, "", &ok); + if (!ok) + return; + + getRPC()->validateAddress(address, [=] (json props) { + QDialog d(this); + Ui_ValidateAddress va; + va.setupUi(&d); + Settings::saveRestore(&d); + Settings::saveRestoreTableHeader(va.tblProps, &d, "validateaddressprops"); + va.tblProps->horizontalHeader()->setStretchLastSection(true); + + va.lblAddress->setText(address); + + QList> propsList; + for (auto it = props.begin(); it != props.end(); it++) { + + propsList.append( + QPair( + QString::fromStdString(it.key()), QString::fromStdString(it.value().dump())) + ); + } + + ValidateAddressesModel model(va.tblProps, propsList); + va.tblProps->setModel(&model); + + d.exec(); + }); + +} void MainWindow::postToZBoard() { QDialog d(this); @@ -1233,7 +1280,6 @@ void MainWindow::setupTransactionsTab() { } void MainWindow::addNewZaddr(bool sapling) { - rpc->newZaddr(sapling, [=] (json reply) { QString addr = QString::fromStdString(reply.get()); // Make sure the RPC class reloads the z-addrs for future use @@ -1325,6 +1371,7 @@ void MainWindow::setupReceiveTab() { viewaddrs.setupUi(&d); Settings::saveRestore(&d); Settings::saveRestoreTableHeader(viewaddrs.tblAddresses, &d, "viewalladdressestable"); + viewaddrs.tblAddresses->horizontalHeader()->setStretchLastSection(true); ViewAllAddressesModel model(viewaddrs.tblAddresses, *getRPC()->getAllTAddresses(), getRPC()); viewaddrs.tblAddresses->setModel(&model); diff --git a/src/mainwindow.h b/src/mainwindow.h index 40ca4ee..5343d28 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -58,6 +58,8 @@ public: void balancesReady(); void payZcashURI(QString uri = "", QString myAddr = ""); + void validateAddress(); + void updateLabels(); void updateTAddrCombo(bool checked); void updateFromCombo(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index aa9599a..b148265 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1084,6 +1084,7 @@ &Apps + @@ -1202,6 +1203,11 @@ File a bug... + + + Validate Address + + diff --git a/src/rpc.cpp b/src/rpc.cpp index 5a79623..c38be5b 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -219,6 +219,18 @@ void RPC::importTPrivKey(QString addr, bool rescan, const std::functiondoRPCWithDefaultErrorHandling(payload, cb); } +void RPC::validateAddress(QString address, const std::function& cb) { + QString method = address.startsWith("z") ? "z_validateaddress" : "validateaddress"; + + json payload = { + {"jsonrpc", "1.0"}, + {"id", "someid"}, + {"method", method.toStdString() }, + {"params", { address.toStdString() } }, + }; + + conn->doRPCWithDefaultErrorHandling(payload, cb); +} void RPC::getBalance(const std::function& cb) { json payload = { diff --git a/src/rpc.h b/src/rpc.h index a4e54ea..9064b17 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -84,6 +84,7 @@ public: void getTPrivKey(QString addr, const std::function& cb); void importZPrivKey(QString addr, bool rescan, const std::function& cb); void importTPrivKey(QString addr, bool rescan, const std::function& cb); + void validateAddress(QString address, const std::function& cb); void shutdownZcashd(); void noConnection(); @@ -121,7 +122,6 @@ private: void getZAddresses (const std::function& cb); void getTAddresses (const std::function& cb); - Connection* conn = nullptr; QProcess* ezcashd = nullptr; diff --git a/src/validateaddress.cpp b/src/validateaddress.cpp new file mode 100644 index 0000000..d82e82e --- /dev/null +++ b/src/validateaddress.cpp @@ -0,0 +1,37 @@ +#include "validateaddress.h" + + +ValidateAddressesModel::ValidateAddressesModel(QTableView *parent, QList> props) + : QAbstractTableModel(parent) { + headers << tr("Property") << tr("Value"); + this->props = props; +} + + +int ValidateAddressesModel::rowCount(const QModelIndex&) const { + return props.size(); +} + +int ValidateAddressesModel::columnCount(const QModelIndex&) const { + return headers.size(); +} + +QVariant ValidateAddressesModel::data(const QModelIndex &index, int role) const { + QPair p = props.at(index.row()); + if (role == Qt::DisplayRole) { + switch(index.column()) { + case 0: return p.first; + case 1: return p.second; + } + } + return QVariant(); +} + + +QVariant ValidateAddressesModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + return headers.at(section); + } + + return QVariant(); +} diff --git a/src/validateaddress.h b/src/validateaddress.h new file mode 100644 index 0000000..19db4cb --- /dev/null +++ b/src/validateaddress.h @@ -0,0 +1,23 @@ +#ifndef VALIDATEADDRESS_H +#define VALIDATEADDRESS_H + +#include "precompiled.h" + +class ValidateAddressesModel : public QAbstractTableModel { + +public: + ValidateAddressesModel(QTableView* parent, QList> props); + ~ValidateAddressesModel() = default; + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + +private: + QList> props; + QStringList headers; +}; + + +#endif // VALIDATEADDRESS_H diff --git a/src/validateaddress.ui b/src/validateaddress.ui new file mode 100644 index 0000000..20caebb --- /dev/null +++ b/src/validateaddress.ui @@ -0,0 +1,85 @@ + + + ValidateAddress + + + + 0 + 0 + 400 + 300 + + + + Validate Address + + + + + + TextLabel + + + + + + + Address: + + + + + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + ValidateAddress + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ValidateAddress + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/zec-qt-wallet.pro b/zec-qt-wallet.pro index 493e303..755ce22 100644 --- a/zec-qt-wallet.pro +++ b/zec-qt-wallet.pro @@ -53,6 +53,7 @@ SOURCES += \ src/addressbook.cpp \ src/logger.cpp \ src/addresscombo.cpp \ + src/validateaddress.cpp \ src/websockets.cpp \ src/mobileappconnector.cpp \ src/recurring.cpp \ @@ -78,13 +79,14 @@ HEADERS += \ src/fillediconlabel.h \ src/addressbook.h \ src/logger.h \ - src/addresscombo.h \ + src/addresscombo.h \ + src/validateaddress.h \ src/websockets.h \ src/mobileappconnector.h \ src/recurring.h \ src/requestdialog.h \ src/memoedit.h \ - src/viewalladdresses.h + src/viewalladdresses.h FORMS += \ src/mainwindow.ui \ @@ -97,6 +99,7 @@ FORMS += \ src/turnstileprogress.ui \ src/privkey.ui \ src/memodialog.ui \ + src/validateaddress.ui \ src/viewalladdresses.ui \ src/connection.ui \ src/zboard.ui \ From 141e70a873ccd2b4cde398b98c93e743903636c5 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 24 Jul 2019 13:11:54 -0700 Subject: [PATCH 06/14] Fix header resizing on tx table --- src/mainwindow.cpp | 5 +++++ src/rpc.cpp | 3 +-- src/settings.cpp | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f330ee2..7334cf3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -177,6 +177,11 @@ void MainWindow::restoreSavedStates() { ui->balancesTable->horizontalHeader()->restoreState(s.value("baltablegeometry").toByteArray()); ui->transactionsTable->horizontalHeader()->restoreState(s.value("tratablegeometry").toByteArray()); + + // Explicitly set the tx table resize headers, since some previous values may have made them + // non-expandable. + ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive); + ui->transactionsTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch); } void MainWindow::doClose() { diff --git a/src/rpc.cpp b/src/rpc.cpp index c38be5b..35a073b 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -27,8 +27,7 @@ RPC::RPC(MainWindow* main) { // Setup transactions table model transactionsTableModel = new TxTableModel(ui->transactionsTable); main->ui->transactionsTable->setModel(transactionsTableModel); - main->ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); - + // Set up timer to refresh Price priceTimer = new QTimer(main); QObject::connect(priceTimer, &QTimer::timeout, [=]() { diff --git a/src/settings.cpp b/src/settings.cpp index 66bdef7..fec889f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -178,6 +178,7 @@ void Settings::saveRestore(QDialog* d) { void Settings::saveRestoreTableHeader(QTableView* table, QDialog* d, QString tablename) { table->horizontalHeader()->restoreState(QSettings().value(tablename).toByteArray()); + table->horizontalHeader()->setStretchLastSection(true); QObject::connect(d, &QDialog::finished, [=](auto) { QSettings().setValue(tablename, table->horizontalHeader()->saveState()); From 48b4ddc47038d865683d157de5ac4412f0a55be0 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 24 Jul 2019 10:58:46 -0700 Subject: [PATCH 07/14] 0.7.6 --- README.md | 6 +++--- src/version.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 316245b..cfa7f9e 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,14 @@ Head over to the releases page and grab the latest installers or binary. https:/ If you are on Debian/Ubuntu, please download the `.deb` package and install it. ``` -sudo dpkg -i linux-deb-zecwallet-v0.7.5.deb +sudo dpkg -i linux-deb-zecwallet-v0.7.6.deb sudo apt install -f ``` Or you can download and run the binaries directly. ``` -tar -xvf zecwallet-v0.7.5.tar.gz -./zecwallet-v0.7.5/zecwallet +tar -xvf zecwallet-v0.7.6.tar.gz +./zecwallet-v0.7.6/zecwallet ``` ### Windows diff --git a/src/version.h b/src/version.h index 1cc7722..ce09c51 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define APP_VERSION "0.7.5" +#define APP_VERSION "0.7.6" From 9b6995aa5e9e7a82fe5cf42f2d2207b9e3bcbd65 Mon Sep 17 00:00:00 2001 From: "Tom Bradshaw (presstab)" Date: Sun, 28 Jul 2019 12:23:19 -0600 Subject: [PATCH 08/14] Use enum for column numbers in txtablemodel for better clarity. (#172) --- src/txtablemodel.cpp | 26 +++++++++++++------------- src/txtablemodel.h | 9 +++++++++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/txtablemodel.cpp b/src/txtablemodel.cpp index b083b3c..e2d3651 100644 --- a/src/txtablemodel.cpp +++ b/src/txtablemodel.cpp @@ -104,9 +104,9 @@ void TxTableModel::updateAllData() { QVariant TxTableModel::data(const QModelIndex &index, int role) const { - // Align column 4,5 (confirmations, amount) right + // Align numeric columns (confirmations, amount) right if (role == Qt::TextAlignmentRole && - (index.column() == 3 || index.column() == 4)) + (index.column() == Column::Confirmations || index.column() == Column::Amount)) return QVariant(Qt::AlignRight | Qt::AlignVCenter); auto dat = modeldata->at(index.row()); @@ -125,23 +125,23 @@ void TxTableModel::updateAllData() { if (role == Qt::DisplayRole) { switch (index.column()) { - case 0: return dat.type; - case 1: { + case Column::Type: return dat.type; + case Column::Address: { auto addr = dat.address; if (addr.trimmed().isEmpty()) return "(Shielded)"; else return addr; } - case 2: return QDateTime::fromMSecsSinceEpoch(dat.datetime * (qint64)1000).toLocalTime().toString(); - case 3: return QString::number(dat.confirmations); - case 4: return Settings::getZECDisplayFormat(dat.amount); + case Column::Time: return QDateTime::fromMSecsSinceEpoch(dat.datetime * (qint64)1000).toLocalTime().toString(); + case Column::Confirmations: return QString::number(dat.confirmations); + case Column::Amount: return Settings::getZECDisplayFormat(dat.amount); } } if (role == Qt::ToolTipRole) { switch (index.column()) { - case 0: { + case Column::Type: { if (dat.memo.startsWith("zcash:")) { return Settings::paymentURIPretty(Settings::parseURI(dat.memo)); } else { @@ -149,16 +149,16 @@ void TxTableModel::updateAllData() { (dat.memo.isEmpty() ? "" : " tx memo: \"" + dat.memo + "\""); } } - case 1: { + case Column::Address: { auto addr = modeldata->at(index.row()).address; if (addr.trimmed().isEmpty()) return "(Shielded)"; else return addr; } - case 2: return QDateTime::fromMSecsSinceEpoch(modeldata->at(index.row()).datetime * (qint64)1000).toLocalTime().toString(); - case 3: return QString("%1 Network Confirmations").arg(QString::number(dat.confirmations)); - case 4: return Settings::getInstance()->getUSDFromZecAmount(modeldata->at(index.row()).amount); + case Column::Time: return QDateTime::fromMSecsSinceEpoch(modeldata->at(index.row()).datetime * (qint64)1000).toLocalTime().toString(); + case Column::Confirmations: return QString("%1 Network Confirmations").arg(QString::number(dat.confirmations)); + case Column::Amount: return Settings::getInstance()->getUSDFromZecAmount(modeldata->at(index.row()).amount); } } @@ -187,7 +187,7 @@ void TxTableModel::updateAllData() { QVariant TxTableModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role == Qt::TextAlignmentRole && (section == 3 || section == 4)) + if (role == Qt::TextAlignmentRole && (section == Column::Confirmations || section == Column::Amount)) return QVariant(Qt::AlignRight | Qt::AlignVCenter); if (role == Qt::FontRole) { diff --git a/src/txtablemodel.h b/src/txtablemodel.h index 9c09a2c..f295bc5 100644 --- a/src/txtablemodel.h +++ b/src/txtablemodel.h @@ -11,6 +11,15 @@ public: TxTableModel(QObject* parent); ~TxTableModel(); + enum Column + { + Type = 0, + Address = 1, + Time = 2, + Confirmations = 3, + Amount = 4 + }; + void addTData (const QList& data); void addZSentData(const QList& data); void addZRecvData(const QList& data); From b792679a93f21195a16e043d95abf95e8f966fe1 Mon Sep 17 00:00:00 2001 From: Arjun <37590483+denverbdr@users.noreply.github.com> Date: Sun, 28 Jul 2019 11:23:30 -0700 Subject: [PATCH 09/14] Zaddr fix (#173) * Use isZAddress instead of hardcoded "z" * Make last col in Tx table resizable --- src/mainwindow.cpp | 2 +- src/rpc.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7334cf3..ea7f52a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -181,7 +181,7 @@ void MainWindow::restoreSavedStates() { // Explicitly set the tx table resize headers, since some previous values may have made them // non-expandable. ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive); - ui->transactionsTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch); + ui->transactionsTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Interactive); } void MainWindow::doClose() { diff --git a/src/rpc.cpp b/src/rpc.cpp index 35a073b..ec5bd8d 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -219,7 +219,7 @@ void RPC::importTPrivKey(QString addr, bool rescan, const std::function& cb) { - QString method = address.startsWith("z") ? "z_validateaddress" : "validateaddress"; + QString method = Settings::isZAddress(address) ? "z_validateaddress" : "validateaddress"; json payload = { {"jsonrpc", "1.0"}, From 14568118429d086b91084921d4e7065d0bc7c845 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 31 Jul 2019 14:31:10 -0700 Subject: [PATCH 10/14] Handle case where private keys are multiline --- src/mainwindow.cpp | 12 +++++++++++- src/settings.cpp | 10 ++++++++++ src/settings.h | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ea7f52a..25b9d30 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -830,7 +830,7 @@ void MainWindow::doImport(QList* keys) { keys->pop_front(); bool rescan = keys->isEmpty(); - if (key.startsWith("S") || + if (key.startsWith("SK") || key.startsWith("secret")) { // Z key rpc->importZPrivKey(key, rescan, [=] (auto) { this->doImport(keys); }); } else { @@ -954,6 +954,16 @@ void MainWindow::importPrivKey() { return key.trimmed().split(" ")[0]; }); + // Special case. + // Sometimes, when importing from a paperwallet or such, the key is split by newlines, and might have + // been pasted like that. So check to see if the whole thing is one big private key + if (Settings::getInstance()->isValidSaplingPrivateKey(keys->join(""))) { + auto multiline = keys; + keys = new QList(); + keys->append(multiline->join("")); + delete multiline; + } + // Start the import. The function takes ownership of keys QTimer::singleShot(1, [=]() {doImport(keys);}); diff --git a/src/settings.cpp b/src/settings.cpp index fec889f..72e2b1b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -328,6 +328,16 @@ QString Settings::getZboardAddr() { } } +bool Settings::isValidSaplingPrivateKey(QString pk) { + if (isTestnet()) { + QRegExp zspkey("^secret-extended-key-test[0-9a-z]{278}$", Qt::CaseInsensitive); + return zspkey.exactMatch(pk); + } else { + QRegExp zspkey("^secret-extended-key-main[0-9a-z]{278}$", Qt::CaseInsensitive); + return zspkey.exactMatch(pk); + } +} + bool Settings::isValidAddress(QString addr) { QRegExp zcexp("^z[a-z0-9]{94}$", Qt::CaseInsensitive); QRegExp zsexp("^z[a-z0-9]{77}$", Qt::CaseInsensitive); diff --git a/src/settings.h b/src/settings.h index 612fe4b..4250644 100644 --- a/src/settings.h +++ b/src/settings.h @@ -37,6 +37,8 @@ public: bool isSaplingAddress(QString addr); bool isSproutAddress(QString addr); + bool isValidSaplingPrivateKey(QString pk); + bool isSyncing(); void setSyncing(bool syncing); From 07d398a7117db2000d57f7433c729427083d3a59 Mon Sep 17 00:00:00 2001 From: Arjun Date: Tue, 30 Jul 2019 10:43:56 -0700 Subject: [PATCH 11/14] Add empty amount check --- src/sendtab.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sendtab.cpp b/src/sendtab.cpp index eedfce0..7487d60 100644 --- a/src/sendtab.cpp +++ b/src/sendtab.cpp @@ -512,7 +512,12 @@ Tx MainWindow::createTxFromSendPage() { // If address is sprout, then we can't send change to sapling, because of turnstile. sendChangeToSapling = sendChangeToSapling && !Settings::getInstance()->isSproutAddress(addr); - double amt = ui->sendToWidgets->findChild(QString("Amount") % QString::number(i+1))->text().trimmed().toDouble(); + QString amtStr = ui->sendToWidgets->findChild(QString("Amount") % QString::number(i+1))->text().trimmed(); + if (amtStr.isEmpty()) { + amtStr = "-1";; // The user didn't specify an amount + } + + double amt = amtStr.toDouble(); totalAmt += amt; QString memo = ui->sendToWidgets->findChild(QString("MemoTxt") % QString::number(i+1))->text().trimmed(); @@ -521,8 +526,7 @@ Tx MainWindow::createTxFromSendPage() { if (Settings::getInstance()->getAllowCustomFees()) { tx.fee = ui->minerFeeAmt->text().toDouble(); - } - else { + } else { tx.fee = Settings::getMinerFee(); } @@ -731,6 +735,8 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) { // Send button clicked void MainWindow::sendButton() { + // Create a Tx from the values on the send tab. Note that this Tx object + // might not be valid yet. Tx tx = createTxFromSendPage(); QString error = doSendTxValidations(tx); @@ -810,7 +816,7 @@ QString MainWindow::doSendTxValidations(Tx tx) { // This technically shouldn't be possible, but issue #62 seems to have discovered a bug // somewhere, so just add a check to make sure. if (toAddr.amount < 0) { - return QString(tr("Amount '%1' is invalid!").arg(toAddr.amount)); + return QString(tr("Amount for address '%1' is invalid!").arg(toAddr.addr)); } } From 918408cc6e5fed280a9b3193fac65d6cf5506a1e Mon Sep 17 00:00:00 2001 From: Arjun Date: Thu, 8 Aug 2019 11:40:15 -0700 Subject: [PATCH 12/14] Move to standard UI transaction --- src/mainwindow.cpp | 15 +-------------- src/rpc.cpp | 23 +++++++++++++++++++++++ src/rpc.h | 2 ++ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 25b9d30..ee2fb32 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -796,20 +796,7 @@ void MainWindow::postToZBoard() { tx.fee = Settings::getMinerFee(); // And send the Tx - rpc->executeTransaction(tx, [=] (QString opid) { - ui->statusBar->showMessage(tr("Computing Tx: ") % opid); - }, - [=] (QString /*opid*/, QString txid) { - ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid); - }, - [=] (QString opid, QString errStr) { - ui->statusBar->showMessage(QObject::tr(" Tx ") % opid % QObject::tr(" failed"), 15 * 1000); - - if (!opid.isEmpty()) - errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr; - - QMessageBox::critical(this, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok); - }); + rpc->executeStandardUITransaction(tx); } } diff --git a/src/rpc.cpp b/src/rpc.cpp index ec5bd8d..cdf992c 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -962,6 +962,29 @@ void RPC::addNewTxToWatch(const QString& newOpid, WatchedTx wtx) { watchTxStatus(); } +/** + * Execute a transaction with the standard UI. i.e., standard status bar message and standard error + * handling + */ +void RPC::executeStandardUITransaction(Tx tx) { + executeTransaction(tx, + [=] (QString opid) { + ui->statusBar->showMessage(QObject::tr("Computing Tx: ") % opid); + }, + [=] (QString, QString txid) { + ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid); + }, + [=] (QString opid, QString errStr) { + ui->statusBar->showMessage(QObject::tr(" Tx ") % opid % QObject::tr(" failed"), 15 * 1000); + + if (!opid.isEmpty()) + errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr; + + QMessageBox::critical(main, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok); + } + ); +} + // Execute a transaction! void RPC::executeTransaction(Tx tx, diff --git a/src/rpc.h b/src/rpc.h index 9064b17..a6474fe 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -58,6 +58,8 @@ public: void refreshZECPrice(); void getZboardTopics(std::function)> cb); + void executeStandardUITransaction(Tx tx); + void executeTransaction(Tx tx, const std::function submitted, const std::function computed, From 208d37580d7cad1eb3e786b5bdabb34d3f2bd005 Mon Sep 17 00:00:00 2001 From: Arjun Date: Thu, 8 Aug 2019 11:49:12 -0700 Subject: [PATCH 13/14] Fix donation address warning --- src/mainwindow.cpp | 7 +++---- src/settings.cpp | 11 +++-------- src/settings.h | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ee2fb32..1af77d8 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -642,8 +642,7 @@ void MainWindow::donate() { // Set up a donation to me :) clearSendForm(); - ui->Address1->setText(Settings::getDonationAddr( - Settings::getInstance()->isSaplingAddress(ui->inputsCombo->currentText()))); + ui->Address1->setText(Settings::getDonationAddr()); ui->Address1->setCursorPosition(0); ui->Amount1->setText("0.01"); ui->MemoTxt1->setText(tr("Thanks for supporting ZecWallet!")); @@ -715,12 +714,12 @@ void MainWindow::postToZBoard() { QMap topics; // Insert the main topic automatically - topics.insert("#Main_Area", Settings::getInstance()->isTestnet() ? Settings::getDonationAddr(true) : Settings::getZboardAddr()); + topics.insert("#Main_Area", Settings::getInstance()->isTestnet() ? Settings::getDonationAddr() : Settings::getZboardAddr()); zb.topicsList->addItem(topics.firstKey()); // Then call the API to get topics, and if it returns successfully, then add the rest of the topics rpc->getZboardTopics([&](QMap topicsMap) { for (auto t : topicsMap.keys()) { - topics.insert(t, Settings::getInstance()->isTestnet() ? Settings::getDonationAddr(true) : topicsMap[t]); + topics.insert(t, Settings::getInstance()->isTestnet() ? Settings::getDonationAddr() : topicsMap[t]); zb.topicsList->addItem(t); } }); diff --git a/src/settings.cpp b/src/settings.cpp index 72e2b1b..4682700 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -251,17 +251,12 @@ QString Settings::getTokenName() { } } -QString Settings::getDonationAddr(bool sapling) { +QString Settings::getDonationAddr() { if (Settings::getInstance()->isTestnet()) - if (sapling) return "ztestsapling1wn6889vznyu42wzmkakl2effhllhpe4azhu696edg2x6me4kfsnmqwpglaxzs7tmqsq7kudemp5"; - else - return "ztn6fYKBii4Fp4vbGhkPgrtLU4XjXp4ZBMZgShtopmDGbn1L2JLTYbBp2b7SSkNr9F3rQeNZ9idmoR7s4JCVUZ7iiM5byhF"; else - if (sapling) return "zs1gv64eu0v2wx7raxqxlmj354y9ycznwaau9kduljzczxztvs4qcl00kn2sjxtejvrxnkucw5xx9u"; - else - return "zcEgrceTwvoiFdEvPWcsJHAMrpLsprMF6aRJiQa3fan5ZphyXLPuHghnEPrEPRoEVzUy65GnMVyCTRdkT6BYBepnXh6NBYs"; + } bool Settings::addToZcashConf(QString confLocation, QString line) { @@ -321,7 +316,7 @@ double Settings::getZboardAmount() { QString Settings::getZboardAddr() { if (Settings::getInstance()->isTestnet()) { - return getDonationAddr(true); + return getDonationAddr(); } else { return "zs10m00rvkhfm4f7n23e4sxsx275r7ptnggx39ygl0vy46j9mdll5c97gl6dxgpk0njuptg2mn9w5s"; diff --git a/src/settings.h b/src/settings.h index 4250644..a0fbff5 100644 --- a/src/settings.h +++ b/src/settings.h @@ -103,7 +103,7 @@ public: static QString getZECUSDDisplayFormat(double bal); static QString getTokenName(); - static QString getDonationAddr(bool sapling); + static QString getDonationAddr(); static double getMinerFee(); static double getZboardAmount(); From 76c4f1d4e39374a8ada43b08f2a564fac3fbac8b Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Mon, 26 Aug 2019 10:28:16 -0700 Subject: [PATCH 14/14] #177 - Remove zboard --- src/mainwindow.cpp | 3 ++- src/mainwindow.ui | 8 -------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1af77d8..92116dd 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -82,8 +82,9 @@ MainWindow::MainWindow(QWidget *parent) : // Export transactions QObject::connect(ui->actionExport_transactions, &QAction::triggered, this, &MainWindow::exportTransactions); + // Z-board seems to have been abandoned // z-Board.net - QObject::connect(ui->actionz_board_net, &QAction::triggered, this, &MainWindow::postToZBoard); + // QObject::connect(ui->actionz_board_net, &QAction::triggered, this, &MainWindow::postToZBoard); // Validate Address QObject::connect(ui->actionValidate_Address, &QAction::triggered, this, &MainWindow::validateAddress); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index b148265..44287c1 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1149,14 +1149,6 @@ &Export all private keys - - - &z-board.net - - - Ctrl+A, Ctrl+Z - - Address &book