From 58c80aaf819acc0ccc06fc611cf826d9a4ac9335 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 31 Oct 2019 09:47:34 -0700 Subject: [PATCH 1/6] Refresh wallet after encryption status change. Fixes #11 --- src/mainwindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6143aeb..e7cb1ed 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -275,6 +275,9 @@ void MainWindow::encryptWallet() { fnShowError(tr("Wallet Encryption Failed"), reply); } }); + + // And then refresh the UI + rpc->refresh(true); } else { fnShowError(tr("Wallet Encryption Failed"), res); } @@ -312,6 +315,9 @@ void MainWindow::removeWalletEncryption() { ); } }); + + // And then refresh the UI + rpc->refresh(true); } else { QMessageBox::critical(this, tr("Wallet Decryption Failed"), QString::fromStdString(res["error"].get()), From 0a99730fbadce32d1b54263a976a6c049bb761f6 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 31 Oct 2019 09:55:48 -0700 Subject: [PATCH 2/6] Handle blank passwords/cancel. Fixes #10 --- src/controller.cpp | 3 +++ src/mainwindow.cpp | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/controller.cpp b/src/controller.cpp index 392043c..9c46529 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -462,6 +462,9 @@ void Controller::unlockIfEncrypted(std::function cb, std::functionunlockWallet(password, [=](json reply) { if (isJsonSuccess(reply)) { cb(); + + // Refresh the wallet so the encryption status is now in sync. + refresh(true); } else { QMessageBox::critical(main, main->tr("Wallet Decryption Failed"), QString::fromStdString(reply["error"].get()), diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e7cb1ed..02eb930 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -296,8 +296,22 @@ void MainWindow::removeWalletEncryption() { return; } + bool ok; QString password = QInputDialog::getText(this, tr("Wallet Password"), - tr("Please enter your wallet password"), QLineEdit::Password); + tr("Please enter your wallet password"), QLineEdit::Password, "", &ok); + + // If cancel was pressed, just return + if (!ok) { + return; + } + + if (password.isEmpty()) { + QMessageBox::critical(this, tr("Wallet Decryption Failed"), + tr("Please enter a password to decrypt your wallet!"), + QMessageBox::Ok + ); + return; + } rpc->removeWalletEncryption(password, [=] (json res) { if (isJsonSuccess(res)) { From 07a07009e63f0ff23728f377f64f4b69bc70986d Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 31 Oct 2019 10:03:09 -0700 Subject: [PATCH 3/6] Handle insufficient funds Fixes #12 --- src/sendtab.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sendtab.cpp b/src/sendtab.cpp index 7a2e458..6c8023d 100644 --- a/src/sendtab.cpp +++ b/src/sendtab.cpp @@ -614,6 +614,7 @@ void MainWindow::sendButton() { Tx tx = createTxFromSendPage(); QString error = doSendTxValidations(tx); + if (!error.isEmpty()) { // Something went wrong, so show an error and exit QMessageBox msg(QMessageBox::Critical, tr("Transaction Error"), error, @@ -707,6 +708,9 @@ void MainWindow::sendButton() { } QString MainWindow::doSendTxValidations(Tx tx) { + // Check to see if we have enough verified funds to send the Tx. + + CAmount total; for (auto toAddr : tx.toAddrs) { if (!Settings::isValidAddress(toAddr.addr)) { QString addr = (toAddr.addr.length() > 100 ? toAddr.addr.left(100) + "..." : toAddr.addr); @@ -718,6 +722,16 @@ QString MainWindow::doSendTxValidations(Tx tx) { if (toAddr.amount.toqint64() < 0) { return QString(tr("Amount for address '%1' is invalid!").arg(toAddr.addr)); } + + total = total + toAddr.amount; + } + total = total + tx.fee; + + auto available = rpc->getModel()->getAvailableBalance(); + + if (available < total) { + return tr("Not enough available funds to send this transaction\n\nHave: %1\nNeed: %2\n\nNote: Funds need 5 confirmations before they can be spent") + .arg(available.toDecimalZECString(), total.toDecimalZECString()); } return ""; From a9707ba2780514423124c4115cccfe4c761d38f3 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 31 Oct 2019 10:58:41 -0700 Subject: [PATCH 4/6] Remove unnecessary logging --- src/connection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/connection.cpp b/src/connection.cpp index 585a0be..a2a882d 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -173,7 +173,7 @@ void Executor::run() { QString reply = litelib_process_response(resp); - qDebug() << "RPC Reply=" << reply; + //qDebug() << "RPC Reply=" << reply; auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); if (parsed.is_discarded() || parsed.is_null()) { emit handleError(reply); @@ -212,7 +212,7 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio return; } - qDebug() << "Doing RPC: " << cmd; + //qDebug() << "Doing RPC: " << cmd; // Create a runner. auto runner = new Executor(cmd, args); From 54c3971bed4400f014c9b4d4ee9e186502f64d00 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 31 Oct 2019 10:58:54 -0700 Subject: [PATCH 5/6] Export seed menu item --- lib/Cargo.lock | 6 ++-- src/controller.h | 10 ++++++ src/liteinterface.cpp | 7 ++++ src/liteinterface.h | 1 + src/mainwindow.cpp | 77 +++++++++++++++++++++++++++++-------------- src/mainwindow.h | 2 +- src/mainwindow.ui | 6 ++-- src/settings.h | 6 ++++ 8 files changed, 83 insertions(+), 32 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 6f0ae92..f4d311b 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1051,7 +1051,7 @@ version = "0.1.0" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "zecwalletlitelib 0.1.0 (git+https://github.com/adityapk00/zecwallet-light-cli?rev=50d331b0cfe1b3c4b81e33fd6febb4b24264627a)", + "zecwalletlitelib 0.1.0 (git+https://github.com/adityapk00/zecwallet-light-cli?rev=3e1c61a4b0589be1ff7590cf4ddf025a9160c631)", ] [[package]] @@ -2266,7 +2266,7 @@ dependencies = [ [[package]] name = "zecwalletlitelib" version = "0.1.0" -source = "git+https://github.com/adityapk00/zecwallet-light-cli?rev=50d331b0cfe1b3c4b81e33fd6febb4b24264627a#50d331b0cfe1b3c4b81e33fd6febb4b24264627a" +source = "git+https://github.com/adityapk00/zecwallet-light-cli?rev=3e1c61a4b0589be1ff7590cf4ddf025a9160c631#3e1c61a4b0589be1ff7590cf4ddf025a9160c631" dependencies = [ "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bellman 0.1.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)", @@ -2562,4 +2562,4 @@ dependencies = [ "checksum zcash_client_backend 0.0.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)" = "" "checksum zcash_primitives 0.0.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)" = "" "checksum zcash_proofs 0.0.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)" = "" -"checksum zecwalletlitelib 0.1.0 (git+https://github.com/adityapk00/zecwallet-light-cli?rev=50d331b0cfe1b3c4b81e33fd6febb4b24264627a)" = "" +"checksum zecwalletlitelib 0.1.0 (git+https://github.com/adityapk00/zecwallet-light-cli?rev=3e1c61a4b0589be1ff7590cf4ddf025a9160c631)" = "" diff --git a/src/controller.h b/src/controller.h index c2eb326..1394fad 100644 --- a/src/controller.h +++ b/src/controller.h @@ -81,6 +81,7 @@ public: cb({ {"error", "Failed to unlock wallet"} }); }); } + void fetchAllPrivKeys(const std::function cb) { unlockIfEncrypted([=] () { zrpc->fetchAllPrivKeys(cb); @@ -90,6 +91,15 @@ public: }); } + void fetchSeed(const std::function cb) { + unlockIfEncrypted([=] () { + zrpc->fetchSeed(cb); + }, + [=]() { + cb({ {"error", "Failed to unlock wallet"} }); + }); + } + // void importZPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importZPrivKey(addr, rescan, cb); } // void importTPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importTPrivKey(addr, rescan, cb); } diff --git a/src/liteinterface.cpp b/src/liteinterface.cpp index 88628a9..30f1a0b 100644 --- a/src/liteinterface.cpp +++ b/src/liteinterface.cpp @@ -56,6 +56,13 @@ void LiteInterface::fetchPrivKey(QString addr, const std::function& conn->doRPCWithDefaultErrorHandling("export", addr, cb); } +void LiteInterface::fetchSeed(const std::function& cb) { + if (conn == nullptr) + return; + + conn->doRPCWithDefaultErrorHandling("seed", "", cb); +} + void LiteInterface::fetchBalance(const std::function& cb) { if (conn == nullptr) return; diff --git a/src/liteinterface.h b/src/liteinterface.h index da04641..203967f 100644 --- a/src/liteinterface.h +++ b/src/liteinterface.h @@ -52,6 +52,7 @@ public: void fetchPrivKey(QString addr, const std::function& cb); void fetchAllPrivKeys(const std::function); + void fetchSeed(const std::function&); void saveWallet(const std::function& cb); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 02eb930..8384e49 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -91,7 +91,7 @@ MainWindow::MainWindow(QWidget *parent) : QObject::connect(ui->actionExport_All_Private_Keys, &QAction::triggered, this, &MainWindow::exportAllKeys); // Backup wallet.dat - QObject::connect(ui->actionBackup_wallet_dat, &QAction::triggered, this, &MainWindow::backupWalletDat); + QObject::connect(ui->actionExport_Seed, &QAction::triggered, this, &MainWindow::exportSeed); // Export transactions QObject::connect(ui->actionExport_transactions, &QAction::triggered, this, &MainWindow::exportTransactions); @@ -648,36 +648,60 @@ void MainWindow::exportTransactions() { } /** - * Backup the wallet.dat file. This is kind of a hack, since it has to read from the filesystem rather than an RPC call - * This might fail for various reasons - Remote zcashd, non-standard locations, custom params passed to zcashd, many others + * Export the seed phrase. */ -void MainWindow::backupWalletDat() { +void MainWindow::exportSeed() { if (!rpc->getConnection()) return; - // QDir zcashdir(rpc->getConnection()->config->zcashDir); - // QString backupDefaultName = "zcash-wallet-backup-" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".dat"; - - // if (Settings::getInstance()->isTestnet()) { - // zcashdir.cd("testnet3"); - // backupDefaultName = "testnet-" + backupDefaultName; - // } + QDialog d(this); + Ui_PrivKey pui; + pui.setupUi(&d); - // QFile wallet(zcashdir.filePath("wallet.dat")); - // if (!wallet.exists()) { - // QMessageBox::critical(this, tr("No wallet.dat"), tr("Couldn't find the wallet.dat on this computer") + "\n" + - // tr("You need to back it up from the machine zcashd is running on"), QMessageBox::Ok); - // return; - // } - - // QUrl backupName = QFileDialog::getSaveFileUrl(this, tr("Backup wallet.dat"), backupDefaultName, "Data file (*.dat)"); - // if (backupName.isEmpty()) - // return; + // Make the window big by default + auto ps = this->geometry(); + QMargins margin = QMargins() + 50; + d.setGeometry(ps.marginsRemoved(margin)); - // if (!wallet.copy(backupName.toLocalFile())) { - // QMessageBox::critical(this, tr("Couldn't backup"), tr("Couldn't backup the wallet.dat file.") + - // tr("You need to back it up manually."), QMessageBox::Ok); - // } + Settings::saveRestore(&d); + + pui.privKeyTxt->setPlainText(tr("This might take several minutes. Loading...")); + pui.privKeyTxt->setReadOnly(true); + pui.privKeyTxt->setLineWrapMode(QPlainTextEdit::LineWrapMode::NoWrap); + + pui.helpLbl->setText(tr("This is your wallet seed. Please back it up carefully and safely.")); + + // Disable the save button until it finishes loading + pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false); + pui.buttonBox->button(QDialogButtonBox::Ok)->setVisible(false); + + // Wire up save button + QObject::connect(pui.buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, [=] () { + QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), + "zcash-seed.txt"); + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + QMessageBox::information(this, tr("Unable to open file"), file.errorString()); + return; + } + QTextStream out(&file); + out << pui.privKeyTxt->toPlainText(); + }); + + rpc->fetchSeed([=](json reply) { + if (isJsonError(reply)) { + pui.privKeyTxt->setPlainText(tr("Error loading wallet seed: ") + QString::fromStdString(reply["error"])); + pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false); + + return; + } + + pui.privKeyTxt->setPlainText(QString::fromStdString(reply.dump())); + pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true); + }); + + + d.exec(); } void MainWindow::exportAllKeys() { @@ -685,6 +709,9 @@ void MainWindow::exportAllKeys() { } void MainWindow::exportKeys(QString addr) { + if (!rpc->getConnection()) + return; + bool allKeys = addr.isEmpty() ? true : false; QDialog d(this); diff --git a/src/mainwindow.h b/src/mainwindow.h index f1f0426..6d3393d 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -120,7 +120,7 @@ private: void importPrivKey(); void exportAllKeys(); void exportKeys(QString addr = ""); - void backupWalletDat(); + void exportSeed(); void exportTransactions(); void doImport(QList* keys); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 690f3d9..b66cf15 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1099,7 +1099,7 @@ - + @@ -1178,9 +1178,9 @@ Ctrl+B - + - &Backup wallet.dat + &Export seed phrase diff --git a/src/settings.h b/src/settings.h index 94a1e8c..d60619d 100644 --- a/src/settings.h +++ b/src/settings.h @@ -127,4 +127,10 @@ inline bool isJsonSuccess(const json& res) { QString::fromStdString(res["result"].get()) == "success"; } +inline bool isJsonError(const json& res) { + return res.find("result") != res.end() && + QString::fromStdString(res["result"].get()) == "error"; +} + + #endif // SETTINGS_H From 0d5ea2f5a511567e7f527b8cd7b17cce2804ffaa Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 31 Oct 2019 12:09:20 -0700 Subject: [PATCH 6/6] Point URLs to zecwallet-lite --- src/controller.cpp | 4 ++-- src/mainwindow.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controller.cpp b/src/controller.cpp index 9c46529..004b545 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -531,7 +531,7 @@ void Controller::checkForUpdate(bool silent) { if (!zrpc->haveConnection()) return noConnection(); - QUrl cmcURL("https://api.github.com/repos/ZcashFoundation/zecwallet/releases"); + QUrl cmcURL("https://api.github.com/repos/adityapk00/zecwallet-lite/releases"); QNetworkRequest req; req.setUrl(cmcURL); @@ -579,7 +579,7 @@ void Controller::checkForUpdate(bool silent) { .arg(currentVersion.toString()), QMessageBox::Yes, QMessageBox::Cancel); if (ans == QMessageBox::Yes) { - QDesktopServices::openUrl(QUrl("https://github.com/ZcashFoundation/zecwallet/releases")); + QDesktopServices::openUrl(QUrl("https://github.com/adityapk00/zecwallet-lite/releases")); } else { // If the user selects cancel, don't bother them again for this version s.setValue("update/lastversion", maxVersion.toString()); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 8384e49..4fdd3db 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -54,7 +54,7 @@ MainWindow::MainWindow(QWidget *parent) : // File a bug QObject::connect(ui->actionFile_a_bug, &QAction::triggered, [=]() { - QDesktopServices::openUrl(QUrl("https://github.com/zcashfoundation/zecwallet/issues/new")); + QDesktopServices::openUrl(QUrl("https://github.com/adityapk00/zecwallet-lite/issues/new")); }); // Set up check for updates action