diff --git a/Silentdragonlite b/Silentdragonlite new file mode 100755 index 0000000..cabaf68 Binary files /dev/null and b/Silentdragonlite differ diff --git a/lib/Cargo.lock b/lib/Cargo.lock index f01b494..0c8fe51 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)", - "silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=0b09f20990195a2a44bce871cd0bb293eaf38b33)", + "silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=58839270ace26bf08d351375d0d945c2dd5527f9)", ] [[package]] @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "silentdragonlitelib" version = "0.1.0" -source = "git+https://github.com/DenioD/silentdragonlite-cli?rev=0b09f20990195a2a44bce871cd0bb293eaf38b33#0b09f20990195a2a44bce871cd0bb293eaf38b33" +source = "git+https://github.com/DenioD/silentdragonlite-cli?rev=58839270ace26bf08d351375d0d945c2dd5527f9#58839270ace26bf08d351375d0d945c2dd5527f9" dependencies = [ "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bellman 0.1.0 (git+https://github.com/DenioD/librustzcash.git?rev=caaee693c47c2ee9ecd1e1546b8fe3c714f342bc)", @@ -2481,7 +2481,7 @@ dependencies = [ "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=0b09f20990195a2a44bce871cd0bb293eaf38b33)" = "" +"checksum silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=58839270ace26bf08d351375d0d945c2dd5527f9)" = "" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585232e78a4fc18133eef9946d3080befdf68b906c51b621531c37e91787fa2b" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index ecfda16..52a181b 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -11,4 +11,4 @@ crate-type = ["staticlib"] [dependencies] libc = "0.2.58" lazy_static = "1.4.0" -silentdragonlitelib = { git = "https://github.com/DenioD/silentdragonlite-cli", rev = "0b09f20990195a2a44bce871cd0bb293eaf38b33" } +silentdragonlitelib = { git = "https://github.com/DenioD/silentdragonlite-cli", rev = "58839270ace26bf08d351375d0d945c2dd5527f9" } diff --git a/silentdragon-lite.pro b/silentdragon-lite.pro index 870d6ef..e54460a 100644 --- a/silentdragon-lite.pro +++ b/silentdragon-lite.pro @@ -93,6 +93,7 @@ HEADERS += \ lib/silentdragonlitelib.h FORMS += \ + src/encryption.ui \ src/mainwindow.ui \ src/migration.ui \ src/newseed.ui \ @@ -147,6 +148,8 @@ else:win32: librust.target = $$PWD/lib/target/x86_64-pc-windows-gnu/release/s unix: librust.commands = $(MAKE) -C $$PWD/lib else:win32: librust.commands = $(MAKE) -C $$PWD/lib winrelease +librust.depends = lib/Cargo.toml lib/src/lib.rs + librustclean.commands = "rm -rf $$PWD/lib/target" distclean.depends += librustclean diff --git a/src/controller.cpp b/src/controller.cpp index 5b58a15..3c0dff6 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -162,8 +162,6 @@ void Controller::getInfoThenRefresh(bool force) { model->setLatestBlock(curBlock); ui->blockHeight->setText(QString::number(curBlock)); - qDebug() << "Refreshing. Full update: " << doUpdate; - // Connected, so display checkmark. auto tooltip = Settings::getInstance()->getSettings().server + "\n" + QString::fromStdString(reply.dump()); QIcon i(":/icons/res/connected.gif"); @@ -185,6 +183,14 @@ void Controller::getInfoThenRefresh(bool force) { // See if recurring payments needs anything Recurring::getInstance()->processPending(main); + // Check if the wallet is locked/encrypted + zrpc->fetchWalletEncryptionStatus([=] (const json& reply) { + bool isEncrypted = reply["encrypted"].get(); + bool isLocked = reply["locked"].get(); + + model->setEncryptionStatus(isEncrypted, isLocked); + }); + if ( doUpdate ) { // Something changed, so refresh everything. refreshBalances(); @@ -273,6 +279,34 @@ void Controller::processUnspent(const json& reply, QMap* balan processFn(reply["pending_utxos"].get()); }; +void Controller::updateUIBalances() { + CAmount balT = getModel()->getBalT(); + CAmount balZ = getModel()->getBalZ(); + CAmount balVerified = getModel()->getBalVerified(); + + // Reduce the BalanceZ by the pending outgoing amount. We're adding + // here because totalPending is already negative for outgoing txns. + balZ = balZ + getModel()->getTotalPending(); + + CAmount balTotal = balT + balZ; + CAmount balAvailable = balT + balVerified; + + // Balances table + ui->balSheilded ->setText(balZ.toDecimalhushString()); + ui->balVerified ->setText(balVerified.toDecimalhushString()); + ui->balTransparent->setText(balT.toDecimalhushString()); + ui->balTotal ->setText(balTotal.toDecimalhushString()); + + ui->balSheilded ->setToolTip(balZ.toDecimalUSDString()); + ui->balVerified ->setToolTip(balVerified.toDecimalUSDString()); + ui->balTransparent->setToolTip(balT.toDecimalUSDString()); + ui->balTotal ->setToolTip(balTotal.toDecimalUSDString()); + + // Send tab + ui->txtAvailablehush->setText(balAvailable.toDecimalhushString()); + ui->txtAvailableUSD->setText(balAvailable.toDecimalUSDString()); +} + void Controller::refreshBalances() { if (!zrpc->haveConnection()) return noConnection(); @@ -283,29 +317,18 @@ void Controller::refreshBalances() { CAmount balZ = CAmount::fromqint64(reply["zbalance"].get()); CAmount balVerified = CAmount::fromqint64(reply["verified_zbalance"].get()); - CAmount balTotal = balT + balZ; - CAmount balAvailable = balT + balVerified; + model->setBalT(balT); + model->setBalZ(balZ); + model->setBalVerified(balVerified); // This is for the websockets AppDataModel::getInstance()->setBalances(balT, balZ); // This is for the datamodel + CAmount balAvailable = balT + balVerified; model->setAvailableBalance(balAvailable); - // Balances table - ui->balSheilded ->setText(balZ.toDecimalhushString()); - ui->balVerified ->setText(balVerified.toDecimalhushString()); - ui->balTransparent->setText(balT.toDecimalhushString()); - ui->balTotal ->setText(balTotal.toDecimalhushString()); - - ui->balSheilded ->setToolTip(balZ.toDecimalUSDString()); - ui->balVerified ->setToolTip(balVerified.toDecimalUSDString()); - ui->balTransparent->setToolTip(balT.toDecimalUSDString()); - ui->balTotal ->setToolTip(balTotal.toDecimalUSDString()); - - // Send tab - ui->txtAvailablehush->setText(balAvailable.toDecimalhushString()); - ui->txtAvailableUSD->setText(balAvailable.toDecimalUSDString()); + updateUIBalances(); }); // 2. Get the UTXOs @@ -414,11 +437,56 @@ void Controller::refreshTransactions() { } + // Calculate the total unspent amount that's pending. This will need to be + // shown in the UI so the user can keep track of pending funds + CAmount totalPending; + for (auto txitem : txdata) { + if (txitem.confirmations == 0) { + for (auto item: txitem.items) { + totalPending = totalPending + item.amount; + } + } + } + getModel()->setTotalPending(totalPending); + + // Update UI Balance + updateUIBalances(); + // Update model data, which updates the table view transactionsTableModel->replaceData(txdata); }); } +// If the wallet is encrpyted and locked, we need to unlock it +void Controller::unlockIfEncrypted(std::function cb, std::function error) { + auto encStatus = getModel()->getEncryptionStatus(); + if (encStatus.first && encStatus.second) { + // Wallet is encrypted and locked. Ask for the password and unlock. + QString password = QInputDialog::getText(main, main->tr("Wallet Password"), + main->tr("Your wallet is encrypted.\nPlease enter your wallet password"), QLineEdit::Password); + + if (password.isEmpty()) { + error(); + return; + } + + zrpc->unlockWallet(password, [=](json reply) { + if (isJsonSuccess(reply)) { + cb(); + } else { + QMessageBox::critical(main, main->tr("Wallet Decryption Failed"), + QString::fromStdString(reply["error"].get()), + QMessageBox::Ok + ); + error(); + } + }); + } else { + // Not locked, so just call the function + cb(); + } +} + /** * Execute a transaction with the standard UI. i.e., standard status bar message and standard error * handling @@ -444,21 +512,25 @@ void Controller::executeStandardUITransaction(Tx tx) { void Controller::executeTransaction(Tx tx, const std::function submitted, const std::function error) { - // First, create the json params - json params = json::array(); - fillTxJsonParams(params, tx); - std::cout << std::setw(2) << params << std::endl; - - zrpc->sendTransaction(QString::fromStdString(params.dump()), [=](const json& reply) { - if (reply.find("txid") == reply.end()) { - error("", "Couldn't understand Response: " + QString::fromStdString(reply.dump())); - } else { - QString txid = QString::fromStdString(reply["txid"].get()); - submitted(txid); - } - }, - [=](QString errStr) { - error("", errStr); + unlockIfEncrypted([=] () { + // First, create the json params + json params = json::array(); + fillTxJsonParams(params, tx); + std::cout << std::setw(2) << params << std::endl; + + zrpc->sendTransaction(QString::fromStdString(params.dump()), [=](const json& reply) { + if (reply.find("txid") == reply.end()) { + error("", "Couldn't understand Response: " + QString::fromStdString(reply.dump())); + } else { + QString txid = QString::fromStdString(reply["txid"].get()); + submitted(txid); + } + }, + [=](QString errStr) { + error("", errStr); + }); + }, [=]() { + error("", main->tr("Failed to unlock wallet")); }); } diff --git a/src/controller.h b/src/controller.h index d9ceceb..39b2233 100644 --- a/src/controller.h +++ b/src/controller.h @@ -37,8 +37,7 @@ public: void checkForUpdate(bool silent = true); void refreshZECPrice(); - //void getZboardTopics(std::function)> cb); - + void executeStandardUITransaction(Tx tx); void executeTransaction(Tx tx, @@ -53,11 +52,42 @@ public: void noConnection(); bool isEmbedded() { return ehushd != nullptr; } - void createNewZaddr(bool sapling, const std::function& cb) { zrpc->createNewZaddr(sapling, cb); } - void createNewTaddr(const std::function& cb) { zrpc->createNewTaddr(cb); } - - void fetchPrivKey(QString addr, const std::function& cb) { zrpc->fetchPrivKey(addr, cb); } - void fetchAllPrivKeys(const std::function cb) { zrpc->fetchAllPrivKeys(cb); } + void encryptWallet(QString password, const std::function& cb) { + zrpc->encryptWallet(password, cb); + } + + void removeWalletEncryption(QString password, const std::function& cb) { + zrpc->removeWalletEncryption(password, cb); } + + void saveWallet(const std::function& cb) { zrpc->saveWallet(cb); } + + void createNewZaddr(bool sapling, const std::function& cb) { + unlockIfEncrypted([=] () { + zrpc->createNewZaddr(sapling, cb); + }, [=](){}); + } + void createNewTaddr(const std::function& cb) { + unlockIfEncrypted([=] () { + zrpc->createNewTaddr(cb); + }, [=](){}); + } + + void fetchPrivKey(QString addr, const std::function& cb) { + unlockIfEncrypted([=] () { + zrpc->fetchPrivKey(addr, cb); + }, + [=]() { + cb({ {"error", "Failed to unlock wallet"} }); + }); + } + void fetchAllPrivKeys(const std::function cb) { + unlockIfEncrypted([=] () { + zrpc->fetchAllPrivKeys(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); } @@ -72,8 +102,11 @@ private: void processUnspent (const json& reply, QMap* newBalances, QList* newUnspentOutputs); void updateUI (bool anyUnconfirmed); + void updateUIBalances (); + + void getInfoThenRefresh (bool force); - void getInfoThenRefresh(bool force); + void unlockIfEncrypted (std::function cb, std::function error); QProcess* ehushd = nullptr; diff --git a/src/datamodel.cpp b/src/datamodel.cpp index e043466..c1c4d66 100644 --- a/src/datamodel.cpp +++ b/src/datamodel.cpp @@ -24,6 +24,7 @@ DataModel::~DataModel() { } void DataModel::setLatestBlock(int blockHeight) { + QReadLocker locker(lock); this->latestBlock = blockHeight; } diff --git a/src/datamodel.h b/src/datamodel.h index 2e1764f..4d2ac06 100644 --- a/src/datamodel.h +++ b/src/datamodel.h @@ -26,7 +26,10 @@ public: void markAddressUsed(QString address); void setLatestBlock(int blockHeight); - int getLatestBlock() { return this->latestBlock; } + int getLatestBlock() { QReadLocker locker(lock); return this->latestBlock; } + + void setEncryptionStatus(bool encrypted, bool locked) { this->isEncrypted = encrypted; this->isLocked = locked; } + QPair getEncryptionStatus() { return qMakePair(this->isEncrypted, this->isLocked); } const QList getAllZAddresses() { QReadLocker locker(lock); return *zaddresses; } const QList getAllTAddresses() { QReadLocker locker(lock); return *taddresses; } @@ -34,14 +37,29 @@ public: const QMap getAllBalances() { QReadLocker locker(lock); return *balances; } const QMap getUsedAddresses() { QReadLocker locker(lock); return *usedAddresses; } - CAmount getAvailableBalance() { return availableBalance; } - void setAvailableBalance(CAmount a) { this->availableBalance = a; } + CAmount getAvailableBalance() { QReadLocker locker(lock); return availableBalance; } + void setAvailableBalance(CAmount a) { QReadLocker locker(lock); this->availableBalance = a; } + + CAmount getBalT() { QReadLocker locker(lock); return balT; } + void setBalT(CAmount a) { QReadLocker locker(lock); this->balT = a; } + + CAmount getBalZ() { QReadLocker locker(lock); return balZ; } + void setBalZ(CAmount a) { QReadLocker locker(lock); this->balZ = a; } + + CAmount getBalVerified() { QReadLocker locker(lock); return balVerified; } + void setBalVerified(CAmount a) { QReadLocker locker(lock); this->balVerified = a; } + + CAmount getTotalPending() { QReadLocker locker(lock); return totalPending; } + void setTotalPending(CAmount a) { QReadLocker locker(lock); this->totalPending = a; } DataModel(); ~DataModel(); private: int latestBlock; + bool isEncrypted = false; + bool isLocked = false; + QList* utxos = nullptr; QMap* balances = nullptr; QMap* usedAddresses = nullptr; @@ -49,9 +67,13 @@ private: QList* taddresses = nullptr; CAmount availableBalance; + CAmount totalPending; // Outgoing pending is -ve - QReadWriteLock* lock; + CAmount balT; + CAmount balZ; + CAmount balVerified; + QReadWriteLock* lock; }; #endif // DATAMODEL_H \ No newline at end of file diff --git a/src/encryption.ui b/src/encryption.ui new file mode 100644 index 0000000..b4ab606 --- /dev/null +++ b/src/encryption.ui @@ -0,0 +1,165 @@ + + + encryptionDialog + + + + 0 + 0 + 400 + 300 + + + + Encrypt Your Wallet + + + + + + Qt::Horizontal + + + + + + + Encryption Password: + + + + + + + Confirm Password: + + + + + + + QLineEdit::Password + + + + + + + color: red; + + + Passwords don't match + + + Qt::AlignCenter + + + + + + + QLineEdit::Password + + + + + + + Qt::Horizontal + + + + + + + WARNING: If you forget your password, the only way to recover the wallet is from the seed phrase. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + txtPassword + txtConfirmPassword + + + + + buttonBox + accepted() + encryptionDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + encryptionDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/liteinterface.cpp b/src/liteinterface.cpp index 1b322fe..1dfc874 100644 --- a/src/liteinterface.cpp +++ b/src/liteinterface.cpp @@ -77,6 +77,36 @@ void LiteInterface::saveWallet(const std::function& cb) { conn->doRPCWithDefaultErrorHandling("save", "", cb); } +void LiteInterface::unlockWallet(QString password, const std::function& cb) { + if (conn == nullptr) + return; + + conn->doRPCWithDefaultErrorHandling("unlock", password, cb); +} + +void LiteInterface::fetchWalletEncryptionStatus(const std::function& cb) { + if (conn == nullptr) + return; + + conn->doRPCWithDefaultErrorHandling("encryptionstatus", "", cb); +} + +void LiteInterface::encryptWallet(QString password, const std::function& cb) { + if (conn == nullptr) + return; + + conn->doRPCWithDefaultErrorHandling("encrypt", password, cb); +} + + +void LiteInterface::removeWalletEncryption(QString password, const std::function& cb) { + if (conn == nullptr) + return; + + conn->doRPCWithDefaultErrorHandling("decrypt", password, cb); +} + + void LiteInterface::sendTransaction(QString params, const std::function& cb, const std::function& err) { if (conn == nullptr) diff --git a/src/liteinterface.h b/src/liteinterface.h index dcb8158..f318f8b 100644 --- a/src/liteinterface.h +++ b/src/liteinterface.h @@ -56,6 +56,11 @@ public: void saveWallet(const std::function& cb); + void fetchWalletEncryptionStatus(const std::function& cb); + void encryptWallet(QString password, const std::function& cb); + void unlockWallet(QString password, const std::function& cb); + void removeWalletEncryption(QString password, const std::function& cb); + //void importZPrivKey(QString addr, bool rescan, const std::function& cb); //void importTPrivKey(QString addr, bool rescan, const std::function& cb); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 32a1033..db11a78 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,6 +1,7 @@ #include "mainwindow.h" #include "addressbook.h" #include "viewalladdresses.h" +#include "ui_encryption.h" #include "ui_mainwindow.h" #include "ui_mobileappconnector.h" #include "ui_addressbook.h" @@ -22,8 +23,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { - - // Include css QString theme_name; try @@ -83,6 +82,15 @@ MainWindow::MainWindow(QWidget *parent) : payhushURI(); }); + // Wallet encryption + QObject::connect(ui->actionEncrypt_Wallet, &QAction::triggered, [=]() { + encryptWallet(); + }); + + QObject::connect(ui->actionRemove_Wallet_Encryption, &QAction::triggered, [=]() { + removeWalletEncryption(); + }); + // Export All Private Keys QObject::connect(ui->actionExport_All_Private_Keys, &QAction::triggered, this, &MainWindow::exportAllKeys); @@ -215,6 +223,108 @@ void MainWindow::closeEvent(QCloseEvent* event) { QMainWindow::closeEvent(event); } + +void MainWindow::encryptWallet() { + // Check if wallet is already encrypted + auto encStatus = rpc->getModel()->getEncryptionStatus(); + if (encStatus.first) { + QMessageBox::information(this, tr("Wallet is already encrypted"), + tr("Your wallet is already encrypted with a password.\nPlease use 'Remove Wallet Encryption' if you want to remove the wallet encryption."), + QMessageBox::Ok + ); + return; + } + + QDialog d(this); + Ui_encryptionDialog ed; + ed.setupUi(&d); + + // Handle edits on the password box + auto fnPasswordEdited = [=](const QString&) { + // Enable the OK button if the passwords match. + if (!ed.txtPassword->text().isEmpty() && + ed.txtPassword->text() == ed.txtConfirmPassword->text()) { + ed.lblPasswordMatch->setText(""); + ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + } else { + ed.lblPasswordMatch->setText(tr("Passwords don't match")); + ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + } + }; + + QObject::connect(ed.txtConfirmPassword, &QLineEdit::textChanged, fnPasswordEdited); + QObject::connect(ed.txtPassword, &QLineEdit::textChanged, fnPasswordEdited); + + ed.txtPassword->setText(""); + ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + auto fnShowError = [=](QString title, const json& res) { + QMessageBox::critical(this, title, + tr("Error was:\n") + QString::fromStdString(res.dump()), + QMessageBox::Ok + ); + }; + + if (d.exec() == QDialog::Accepted) { + rpc->encryptWallet(ed.txtPassword->text(), [=](json res) { + if (isJsonSuccess(res)) { + // Save the wallet + rpc->saveWallet([=] (json reply) { + if (isJsonSuccess(reply)) { + QMessageBox::information(this, tr("Wallet Encrypted"), + tr("Your wallet was successfully encrypted! The password will be needed to send funds or export private keys."), + QMessageBox::Ok + ); + } else { + fnShowError(tr("Wallet Encryption Failed"), reply); + } + }); + } else { + fnShowError(tr("Wallet Encryption Failed"), res); + } + }); + } +} + +void MainWindow::removeWalletEncryption() { + // Check if wallet is already encrypted + auto encStatus = rpc->getModel()->getEncryptionStatus(); + if (!encStatus.first) { + QMessageBox::information(this, tr("Wallet is not encrypted"), + tr("Your wallet is not encrypted with a password."), + QMessageBox::Ok + ); + return; + } + + QString password = QInputDialog::getText(this, tr("Wallet Password"), + tr("Please enter your wallet password"), QLineEdit::Password); + + rpc->removeWalletEncryption(password, [=] (json res) { + if (isJsonSuccess(res)) { + // Save the wallet + rpc->saveWallet([=] (json reply) { + if(isJsonSuccess(reply)) { + QMessageBox::information(this, tr("Wallet Encryption Removed"), + tr("Your wallet was successfully decrypted! You will no longer need a password to send funds or export private keys."), + QMessageBox::Ok + ); + } else { + QMessageBox::critical(this, tr("Wallet Decryption Failed"), + QString::fromStdString(reply["error"].get()), + QMessageBox::Ok + ); + } + }); + } else { + QMessageBox::critical(this, tr("Wallet Decryption Failed"), + QString::fromStdString(res["error"].get()), + QMessageBox::Ok + ); + } + }); +} + void MainWindow::setupStatusBar() { // Status Bar loadingLabel = new QLabel(); @@ -616,7 +726,7 @@ void MainWindow::exportKeys(QString addr) { if (! *(isDialogAlive.get()) ) return; if (reply.is_discarded() || !reply.is_array()) { - pui.privKeyTxt->setPlainText(tr("Error loading private keys")); + pui.privKeyTxt->setPlainText(tr("Error loading private keys: ") + QString::fromStdString(reply.dump())); pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false); return; diff --git a/src/mainwindow.h b/src/mainwindow.h index 2fc4bdf..7051085 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -96,6 +96,9 @@ private: Tx createTxFromSendPage(); bool confirmTx(Tx tx, RecurringPaymentInfo* rpi); + void encryptWallet(); + void removeWalletEncryption(); + void cancelButton(); void sendButton(); void addAddressSection(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index e19b086..eb8d799 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -85,7 +85,7 @@ - Verified + Notarized @@ -324,7 +324,7 @@ - Total verified funds available: + Total notarized funds available: @@ -392,8 +392,8 @@ 0 0 - 1162 - 344 + 1226 + 504 @@ -1088,7 +1088,7 @@ 0 0 1274 - 39 + 22 @@ -1129,6 +1129,9 @@ + + + @@ -1225,6 +1228,16 @@ File a bug... + + + Encrypt Wallet + + + + + Remove Wallet Encryption + + diff --git a/src/settings.h b/src/settings.h index 75abd31..5d1f1c2 100644 --- a/src/settings.h +++ b/src/settings.h @@ -4,6 +4,8 @@ #include "precompiled.h" #include "camount.h" +using json = nlohmann::json; + struct Config { QString server; }; @@ -119,4 +121,10 @@ private: double ZECPrice = 0.0; }; + +inline bool isJsonSuccess(const json& res) { + return res.find("result") != res.end() && + QString::fromStdString(res["result"].get()) == "success"; +} + #endif // SETTINGS_H diff --git a/src/version.h b/src/version.h index 3e7162c..58be58c 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define APP_VERSION "1.0-beta1" +#define APP_VERSION "1.0"