diff --git a/src/bitpaywalletclient/bpwalletclient.cpp b/src/bitpaywalletclient/bpwalletclient.cpp index 31cef631..9b31eaf7 100644 --- a/src/bitpaywalletclient/bpwalletclient.cpp +++ b/src/bitpaywalletclient/bpwalletclient.cpp @@ -325,7 +325,7 @@ bool BitPayWalletClient::GetNewAddress(std::string& newAddress,std::string& keyp bool BitPayWalletClient::GetLastKnownAddress(std::string& address, std::string& keypath) { std::unique_lock lock(this->cs_client); - + if (lastKnownAddressJson.size() == 0) return false; @@ -349,7 +349,7 @@ bool BitPayWalletClient::GetLastKnownAddress(std::string& address, std::string& } -bool BitPayWalletClient::CreatePaymentProposal(const std::string& address, uint64_t amount, uint64_t feeperkb, UniValue& paymentProposalOut, std::string& errorOut) +bool BitPayWalletClient::CreatePaymentProposal(bool dryRun, const std::string& address, uint64_t amount, uint64_t feeperkb, UniValue& paymentProposalOut, std::string& errorOut) { //form request UniValue outputs(UniValue::VARR); @@ -367,6 +367,7 @@ bool BitPayWalletClient::CreatePaymentProposal(const std::string& address, uint6 UniValue jsonArgs(UniValue::VOBJ); jsonArgs.push_back(Pair("feePerKb", feeperkb)); jsonArgs.push_back(Pair("payProUrl", false)); + jsonArgs.push_back(Pair("dryRun", dryRun)); jsonArgs.push_back(Pair("type", "simple")); jsonArgs.push_back(Pair("version", "1.0.0")); jsonArgs.push_back(Pair("outputs", outputs)); @@ -415,14 +416,6 @@ bool BitPayWalletClient::CreatePaymentProposal(const std::string& address, uint6 DBB::LogPrint("Could not unlock funds\n", httpStatusCode); return false; } - paymentProposalOut.read(response); - - if (!PublishTxProposal(paymentProposalOut, errorOut)) { - DBB::LogPrint("Publish tx proposal failed (%s)\n", errorOut.c_str()); - return false; - } - - return true; } else { //unknown error DBB::LogPrint("Uknown error during CreatePaymentProposal\n"); @@ -439,7 +432,7 @@ bool BitPayWalletClient::CreatePaymentProposal(const std::string& address, uint6 if (!paymentProposalOut.isObject()) return false; - if (!PublishTxProposal(paymentProposalOut, errorOut)) + if (!dryRun && !PublishTxProposal(paymentProposalOut, errorOut)) return false; return true; @@ -585,7 +578,7 @@ bool BitPayWalletClient::GetFeeLevels() return false; long httpStatusCode = 0; - if (!SendRequest("get", "/v1/feelevels/?network=livenet&r="+std::to_string(CheapRandom()), "{}", response, httpStatusCode)) + if (!SendRequest("get", "/v1/feelevels/?network="+std::string(testnet ? "testnet" : "livenet")+"&r="+std::to_string(CheapRandom()), "{}", response, httpStatusCode)) return false; if (httpStatusCode != 200) @@ -598,7 +591,7 @@ bool BitPayWalletClient::GetFeeLevels() int64_t BitPayWalletClient::GetFeeForPriority(int prio) { std::unique_lock lock(this->cs_client); - + std::string keyField = ""; if (prio == 1) keyField = "normal"; @@ -793,7 +786,7 @@ void BitPayWalletClient::ParseTxProposal(const UniValue& txProposal, UniValue& c txin->script_sig = cstr_new_sz(script->len); if (!noScriptPubKey) cstr_append_buf(txin->script_sig, script->str, script->len); - + vector_add(tx->vin, txin); cstr_free(script, true); } @@ -1227,7 +1220,7 @@ void BitPayWalletClient::SaveLocalData() uint32_t lastKnownAddressLength = lastKnownAddressJson.size(); fwrite(&lastKnownAddressLength, 1, sizeof(lastKnownAddressLength), writeFile); fwrite(&lastKnownAddressJson.front(), 1, lastKnownAddressLength, writeFile); - + fwrite(&walletJoined, 1, sizeof(walletJoined), writeFile); } fclose(writeFile); @@ -1270,7 +1263,7 @@ void BitPayWalletClient::LoadLocalData() return; } else lastKnownAddressJson = ""; - + if (fread(&walletJoined, 1, sizeof(walletJoined), fh) != sizeof(walletJoined)) return; diff --git a/src/bitpaywalletclient/bpwalletclient.h b/src/bitpaywalletclient/bpwalletclient.h index fd0bb54f..a8b31986 100644 --- a/src/bitpaywalletclient/bpwalletclient.h +++ b/src/bitpaywalletclient/bpwalletclient.h @@ -99,7 +99,7 @@ class BitPayWalletClient //!Return the last (disk) cached known address for receiving coins bool GetLastKnownAddress(std::string& address, std::string& keypath); - bool CreatePaymentProposal(const std::string& address, uint64_t amount, uint64_t feeperkb, UniValue& paymentProposalOut, std::string& errorOut); + bool CreatePaymentProposal(bool dryRun, const std::string& address, uint64_t amount, uint64_t feeperkb, UniValue& paymentProposalOut, std::string& errorOut); bool PublishTxProposal(const UniValue& paymentProposal, std::string& errorOut); @@ -157,7 +157,7 @@ class BitPayWalletClient //!returns true in case of an available xpub/request key bool IsSeeded(); - + //!whether or not a Copay wallet was joined with the xpub/request key bool walletJoined; diff --git a/src/qt/dbb_gui.cpp b/src/qt/dbb_gui.cpp index daa606eb..8897add6 100644 --- a/src/qt/dbb_gui.cpp +++ b/src/qt/dbb_gui.cpp @@ -255,6 +255,9 @@ DBBDaemonGui::DBBDaemonGui(const QString& uri, QWidget* parent) : QMainWindow(pa connect(ui->upgradeFirmware, SIGNAL(clicked()), this, SLOT(upgradeFirmwareButton())); connect(ui->openSettings, SIGNAL(clicked()), this, SLOT(showSettings())); connect(ui->pairDeviceButton, SIGNAL(clicked()), this, SLOT(pairSmartphone())); + connect(ui->sendAmount, &QLineEdit::editingFinished, this, &DBBDaemonGui::displayFee); + connect(ui->sendToAddress, &QLineEdit::editingFinished, this, &DBBDaemonGui::displayFee); + connect(ui->feeLevel, static_cast(&QComboBox::currentIndexChanged), this, &DBBDaemonGui::displayFee); ui->upgradeFirmware->setVisible(true); ui->keypathLabel->setVisible(false);//hide keypath label for now (only tooptip) connect(ui->tableWidget, SIGNAL(doubleClicked(QModelIndex)),this,SLOT(historyShowTx(QModelIndex))); @@ -269,7 +272,7 @@ DBBDaemonGui::DBBDaemonGui(const QString& uri, QWidget* parent) : QMainWindow(pa } else ui->qrCodeButton->setEnabled(false); - + connect(ui->qrCodeButton, SIGNAL(clicked()),this,SLOT(showQrCodeScanner())); #else ui->qrCodeButton->setVisible(false); @@ -914,7 +917,7 @@ void DBBDaemonGui::showSetPasswordInfo() void DBBDaemonGui::setPasswordProvided(const QString& newPassword, const QString& repeatPassword) { std::string command = "{\"password\" : \"" + newPassword.toStdString() + "\"}"; - + if (repeatPassword.toStdString() != sessionPassword) { showModalInfo(tr("Incorrect old password"), DBB_PROCESS_INFOLAYER_CONFIRM_WITH_BUTTON); return; @@ -935,7 +938,7 @@ void DBBDaemonGui::setPasswordProvided(const QString& newPassword, const QString void DBBDaemonGui::setDeviceNamePasswordProvided(const QString& newPassword, const QString& newName) { tempNewDeviceName = newName; - + std::string command = "{\"password\" : \"" + newPassword.toStdString() + "\"}"; showModalInfo(tr("Saving Password")); if (executeCommandWrapper(command, DBB_PROCESS_INFOLAYER_STYLE_NO_INFO, [this](const std::string& cmdOut, dbb_cmd_execution_status_t status) { @@ -1067,7 +1070,7 @@ void DBBDaemonGui::ledClicked(dbb_led_blink_mode_t mode) command = "{\"led\" : \"blink\"}"; else if (mode == DBB_LED_BLINK_MODE_ABORT) command = "{\"led\" : \"abort\"}"; - else + else return; executeCommandWrapper(command, DBB_PROCESS_INFOLAYER_STYLE_NO_INFO, [this](const std::string& cmdOut, dbb_cmd_execution_status_t status) { UniValue jsonOut; @@ -1739,7 +1742,7 @@ void DBBDaemonGui::parseResponse(const UniValue& response, dbb_cmd_execution_sta //enable UI passwordAccepted(); - + if (!cachedWalletAvailableState) { if (sdcard.isBool() && !sdcard.isTrue()) @@ -2168,6 +2171,53 @@ void DBBDaemonGui::updateReceivingAddress(DBBWallet *wallet, const std::string & ui->keypathLabel->setText(QString::fromStdString(info)); } +void DBBDaemonGui::displayFee() { + if (!singleWallet->client.IsSeeded()) + return; + + int64_t amount = 0; + if (this->ui->sendAmount->text().size() == 0 || this->ui->sendToAddress->text().size() == 0) { + emit this->ui->infoDisplay->setText(""); + return; + } + if (!DBB::ParseMoney(this->ui->sendAmount->text().toStdString(), amount)) { + emit this->ui->infoDisplay->setText("Invalid amount"); + return; + } + + emit this->ui->infoDisplay->setText(""); + DBBNetThread* thread = DBBNetThread::DetachThread(); + thread->currentThread = std::thread([this, thread, amount]() { + UniValue proposalOut; + std::string errorOut; + + int64_t feeperkb = singleWallet->client.GetFeeForPriority(this->ui->feeLevel->currentIndex()); + if (feeperkb == 0) { + emit changeNetLoading(false); + emit shouldShowAlert("Error", tr("Could not estimate fees. Make sure you are online.")); + } else { + bool dryRun = true; + if (!singleWallet->client.CreatePaymentProposal(dryRun, this->ui->sendToAddress->text().toStdString(), amount, feeperkb, proposalOut, errorOut)) { + emit changeNetLoading(false); + emit this->ui->infoDisplay->setText(QString::fromStdString(errorOut)); + } + else + { + emit changeNetLoading(false); + std::string display = ""; + UniValue fee = find_value(proposalOut, "fee"); + if (fee.isNum()) { + display = "Fee: " + DBB::formatMoney(fee.get_int64()); + } + emit this->ui->infoDisplay->setText(QString::fromStdString(display)); + } + } + + thread->completed(); + }); + setNetLoading(true); +} + void DBBDaemonGui::createTxProposalPressed() { if (!singleWallet->client.IsSeeded()) @@ -2187,13 +2237,14 @@ void DBBDaemonGui::createTxProposalPressed() UniValue proposalOut; std::string errorOut; - int64_t fee = singleWallet->client.GetFeeForPriority(this->ui->feeLevel->currentIndex()); - if (fee == 0) { + int64_t feeperkb = singleWallet->client.GetFeeForPriority(this->ui->feeLevel->currentIndex()); + if (feeperkb == 0) { emit changeNetLoading(false); emit shouldHideModalInfo(); emit shouldShowAlert("Error", tr("Could not estimate fees. Make sure you are online.")); } else { - if (!singleWallet->client.CreatePaymentProposal(this->ui->sendToAddress->text().toStdString(), amount, fee, proposalOut, errorOut)) { + bool dryRun = false; + if (!singleWallet->client.CreatePaymentProposal(dryRun, this->ui->sendToAddress->text().toStdString(), amount, feeperkb, proposalOut, errorOut)) { emit changeNetLoading(false); emit shouldHideModalInfo(); emit shouldShowAlert("Error", QString::fromStdString(errorOut)); @@ -2365,7 +2416,7 @@ void DBBDaemonGui::updateUIStateMultisigWallets(bool joined) this->ui->multisigBalanceKey->setVisible(joined); this->ui->multisigBalance->setVisible(joined); this->ui->multisigLine->setVisible(joined); - this->ui->proposalsLabel->setVisible(joined); + this->ui->proposalsLabel->setVisible(joined); if (!joined) this->ui->noProposalsAvailable->setVisible(false); } @@ -2395,7 +2446,7 @@ void DBBDaemonGui::SingleWalletUpdateWallets(bool showLoading) } if (!singleWallet->client.IsSeeded()) return; - + if (this->ui->balanceLabel->text() == "?") { this->ui->balanceLabel->setText("Loading..."); this->ui->singleWalletBalance->setText("Loading..."); @@ -2430,7 +2481,7 @@ void DBBDaemonGui::updateUIMultisigWallets(const UniValue& walletResponse) // the encrypted name is in a JSON string conforming to the SJCL library format, see: // https://bitwiseshiftleft.github.io/sjcl/demo/ //this->ui->multisigWalletName->setText("Name: " + QString::fromStdString(vMultisigWallets[0]->walletRemoteName)); - + updateUIStateMultisigWallets(vMultisigWallets[0]->client.walletJoined); } @@ -2505,10 +2556,10 @@ void DBBDaemonGui::updateTransactionTable(DBBWallet *wallet, bool historyAvailab QStandardItem *item = new QStandardItem(QString::fromStdString(addressUV.get_str())); item->setToolTip(tr("Double-click for more details")); item->setFont(font); - item->setTextAlignment(Qt::AlignCenter); + item->setTextAlignment(Qt::AlignCenter); transactionTableModel->setItem(cnt, 2, item); } - + UniValue timeUV = find_value(obj, "time"); UniValue confirmsUV = find_value(obj, "confirmations"); if (timeUV.isNum()) @@ -2526,12 +2577,12 @@ void DBBDaemonGui::updateTransactionTable(DBBWallet *wallet, bool historyAvailab tooltip = "0"; iconName = ":/icons/confirm0"; } - + QDateTime timestamp; timestamp.setTime_t(timeUV.get_int64()); QStandardItem *item = new QStandardItem(QIcon(iconName), timestamp.toString(Qt::SystemLocaleShortDate)); item->setToolTip(tooltip + tr(" confirmations")); - item->setTextAlignment(Qt::AlignCenter); + item->setTextAlignment(Qt::AlignCenter); item->setFont(font); transactionTableModel->setItem(cnt, 3, item); } @@ -2545,7 +2596,7 @@ void DBBDaemonGui::updateTransactionTable(DBBWallet *wallet, bool historyAvailab cnt++; } - + ui->tableWidget->setModel(transactionTableModel); ui->tableWidget->setColumnHidden(0, true); @@ -3096,7 +3147,7 @@ void DBBDaemonGui::updateSettings() vMultisigWallets[0]->setSocks5ProxyURL(configData->getSocks5ProxyURL()); singleWallet->setBackendURL(configData->getBWSBackendURL()); singleWallet->setSocks5ProxyURL(configData->getSocks5ProxyURL()); - + if (comServer) { comServer->setURL(configData->getComServerURL()); diff --git a/src/qt/dbb_gui.h b/src/qt/dbb_gui.h index c66a5d54..b578c088 100644 --- a/src/qt/dbb_gui.h +++ b/src/qt/dbb_gui.h @@ -205,7 +205,7 @@ public slots: #endif void createMenuBar(); - + //== Plug / Unplug == //! gets called when the device was sucessfully unlocked (password accepted) void deviceIsReadyToInteract(); @@ -361,6 +361,8 @@ private slots: void getXPub(const std::string& keypath, dbb_response_type_t response_type = DBB_RESPONSE_TYPE_XPUB_VERIFY, dbb_address_style_t address_type = DBB_ADDRESS_STYLE_P2PKH); //!gets called when a new address is available void updateReceivingAddress(DBBWallet *wallet, const std::string &newAddress, const std::string &keypath); + //!display fee calculated based on a payment proposal based on the UI values. + void displayFee(); //!check the UI values and create a payment proposal from them, sign and post them void createTxProposalPressed(); //!Report about a submitted payment proposal diff --git a/src/qt/ui/overview.ui b/src/qt/ui/overview.ui index 71e651e5..911d7a47 100644 --- a/src/qt/ui/overview.ui +++ b/src/qt/ui/overview.ui @@ -241,7 +241,7 @@ background-color: rgba(240,240,240,255); QAbstractItemView::ScrollPerPixel - true + false true @@ -1249,17 +1249,17 @@ background-color: rgba(240,240,240,255); - - - Qt::Horizontal - - + + - 40 - 20 + 105 + 0 - + + + + @@ -1732,6 +1732,11 @@ background-color: rgba(0,0,0, 0%) QWidget
modalview.h
+ + ClickableLabel + QWidget +
clickablelabel.h
+