Browse Source

wip

pull/14/head
Aditya Kulkarni 5 years ago
parent
commit
12d6c64583
  1. 10
      src/addresscombo.cpp
  2. 5
      src/addresscombo.h
  3. 13
      src/balancestablemodel.cpp
  4. 5
      src/balancestablemodel.h
  5. 61
      src/camount.cpp
  6. 47
      src/camount.h
  7. 50
      src/controller.cpp
  8. 11
      src/controller.h
  9. 4
      src/datamodel.cpp
  10. 9
      src/datamodel.h
  11. 3
      src/liteinterface.h
  12. 10
      src/mainwindow.cpp
  13. 4
      src/mainwindow.h
  14. 12
      src/requestdialog.cpp
  15. 114
      src/sendtab.cpp
  16. 68
      src/settings.cpp
  17. 12
      src/settings.h
  18. 18
      src/txtablemodel.cpp
  19. 3
      src/viewalladdresses.cpp
  20. 20
      src/websockets.cpp
  21. 15
      src/websockets.h
  22. 6
      zecwallet-lite.pro

10
src/addresscombo.cpp

@ -24,16 +24,16 @@ void AddressCombo::setCurrentText(const QString& text) {
}
}
void AddressCombo::addItem(const QString& text, double bal) {
void AddressCombo::addItem(const QString& text, CAmount bal) {
QString txt = AddressBook::addLabelToAddress(text);
if (bal > 0)
txt = txt % "(" % Settings::getZECDisplayFormat(bal) % ")";
if (bal.toqint64() > 0)
txt = txt % "(" % bal.toDecimalZECString() % ")";
QComboBox::addItem(txt);
}
void AddressCombo::insertItem(int index, const QString& text, double bal) {
void AddressCombo::insertItem(int index, const QString& text, CAmount bal) {
QString txt = AddressBook::addLabelToAddress(text) %
"(" % Settings::getZECDisplayFormat(bal) % ")";
"(" % bal.toDecimalZECString() % ")";
QComboBox::insertItem(index, txt);
}

5
src/addresscombo.h

@ -1,6 +1,7 @@
#ifndef ADDRESSCOMBO_H
#define ADDRESSCOMBO_H
#include "camount.h"
#include "precompiled.h"
class AddressCombo : public QComboBox
@ -12,8 +13,8 @@ public:
QString itemText(int i);
QString currentText();
void addItem(const QString& itemText, double bal);
void insertItem(int index, const QString& text, double bal = 0.0);
void addItem(const QString& itemText, CAmount bal);
void insertItem(int index, const QString& text, CAmount bal = CAmount::fromqint64(0));
public slots:
void setCurrentText(const QString& itemText);

13
src/balancestablemodel.cpp

@ -1,6 +1,7 @@
#include "balancestablemodel.h"
#include "addressbook.h"
#include "settings.h"
#include "camount.h"
BalancesTableModel::BalancesTableModel(QObject *parent)
@ -8,7 +9,7 @@ BalancesTableModel::BalancesTableModel(QObject *parent)
}
void BalancesTableModel::setNewData(const QList<QString> zaddrs, const QList<QString> taddrs,
const QMap<QString, qint64> balances, const QList<UnspentOutput> outputs)
const QMap<QString, CAmount> balances, const QList<UnspentOutput> outputs)
{
loading = false;
@ -22,7 +23,7 @@ void BalancesTableModel::setNewData(const QList<QString> zaddrs, const QList<QSt
// Process the address balances into a list
delete modeldata;
modeldata = new QList<std::tuple<QString, qint64>>();
modeldata = new QList<std::tuple<QString, CAmount>>();
std::for_each(balances.keyBegin(), balances.keyEnd(), [=] (auto keyIt) {
modeldata->push_back(std::make_tuple(keyIt, balances.value(keyIt)));
});
@ -30,13 +31,13 @@ void BalancesTableModel::setNewData(const QList<QString> zaddrs, const QList<QSt
// Add all addresses that have no balances as well
for (auto zaddr: zaddrs) {
if (!balances.contains(zaddr)) {
modeldata->push_back(std::make_tuple(zaddr, 0));
modeldata->push_back(std::make_tuple(zaddr, CAmount::fromqint64(0)));
}
}
for (auto taddr: taddrs) {
if (!balances.contains(taddr)) {
modeldata->push_back(std::make_tuple(taddr, 0));
modeldata->push_back(std::make_tuple(taddr, CAmount::fromqint64(0)));
}
}
@ -101,14 +102,14 @@ QVariant BalancesTableModel::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
switch (index.column()) {
case 0: return AddressBook::addLabelToAddress(std::get<0>(modeldata->at(index.row())));
case 1: return Settings::getZECDisplayFormat(std::get<1>(modeldata->at(index.row())));
case 1: return std::get<1>(modeldata->at(index.row())).toDecimalZECString();
}
}
if(role == Qt::ToolTipRole) {
switch (index.column()) {
case 0: return AddressBook::addLabelToAddress(std::get<0>(modeldata->at(index.row())));
case 1: return Settings::getUSDFromZecAmount(std::get<1>(modeldata->at(index.row())));
case 1: return std::get<1>(modeldata->at(index.row())).toDecimalZECString();
}
}

5
src/balancestablemodel.h

@ -3,6 +3,7 @@
#include "precompiled.h"
#include "datamodel.h"
#include "camount.h"
class BalancesTableModel : public QAbstractTableModel
{
@ -10,7 +11,7 @@ public:
BalancesTableModel(QObject* parent);
~BalancesTableModel();
void setNewData(const QList<QString> zaddrs, const QList<QString> taddrs, const QMap<QString, qint64> balances, const QList<UnspentOutput> outputs);
void setNewData(const QList<QString> zaddrs, const QList<QString> taddrs, const QMap<QString, CAmount> balances, const QList<UnspentOutput> outputs);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
@ -18,7 +19,7 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QList<std::tuple<QString, qint64>>* modeldata = nullptr;
QList<std::tuple<QString, CAmount>>* modeldata = nullptr;
QList<UnspentOutput>* unspentOutputs = nullptr;
bool loading = true;

61
src/camount.cpp

@ -0,0 +1,61 @@
#include "camount.h"
#include "settings.h"
#include "precompiled.h"
const int NUMPLACES = 8;
const qint64 COIN = 100000000;
double CAmount::toDecimalDouble() const {
return static_cast<double>(this->amount) / COIN;
}
QString CAmount::toDecimalString() const {
if (amount < 0) {
CAmount negative(-1 * this->amount);
return "-" + negative.toDecimalString();
}
int wholePart = amount / COIN;
int decimalPart = amount % COIN;
QString r = QString::number(wholePart);
if (decimalPart > 0) {
QString decimalPartStr = QString::number(decimalPart);
QString leadingZeros = QString("0").repeated(NUMPLACES - decimalPartStr.length());
r = r + "." + leadingZeros + decimalPartStr;
}
return r;
}
QString CAmount::toDecimalUSDString() const {
double dblAmount = static_cast<double>(this->amount) / COIN;
double price = Settings::getInstance()->getZECPrice();
return "$" + QLocale(QLocale::English).toString(dblAmount*price, 'f', 2);
}
QString CAmount::toDecimalZECString() const {
return this->toDecimalString() % " " % Settings::getTokenName();
}
QString CAmount::toDecimalZECUSDString() const {
auto usdString = this->toDecimalUSDString();
if (!usdString.isEmpty())
return this->toDecimalZECString() % " (" % usdString % ")";
else
return this->toDecimalZECString();
}
CAmount CAmount::fromDecimalString(QString decimalString) {
auto amtParts = decimalString.split(".");
qint64 r = amtParts[0].toULongLong() * COIN;
if (amtParts.length() == 2) {
auto trailingZeros = QString("0").repeated(NUMPLACES - amtParts[1].length());
r += QString(amtParts[1] + trailingZeros).toULongLong();
}
return CAmount(r);
}

47
src/camount.h

@ -0,0 +1,47 @@
#ifndef CAMOUNT_H
#define CAMOUNT_H
class CAmount {
private:
CAmount(qint64 amount) {
this->amount = amount;
}
qint64 amount;
public:
static CAmount fromDecimalString(QString decimalString);
static CAmount fromqint64(qint64 a) {
return CAmount(a);
}
CAmount() : amount(0) {};
CAmount(const CAmount&) = default;
~CAmount() = default;
double toDecimalDouble() const;
QString toDecimalString() const;
QString toDecimalUSDString() const;
QString toDecimalZECString() const;
QString toDecimalZECUSDString() const;
qint64 toqint64() const { return amount; };
CAmount operator+ (const CAmount& other) const {
return CAmount(this->amount + other.amount);
}
CAmount operator- (const CAmount& other) const {
return CAmount(this->amount - other.amount);
}
bool operator< (const CAmount& other) const {
return this->amount < other.amount;
}
bool operator> (const CAmount& other) const {
return this->amount > other.amount;
}
};
#endif // CAMOUNT_H

50
src/controller.cpp

@ -3,6 +3,7 @@
#include "addressbook.h"
#include "settings.h"
#include "version.h"
#include "camount.h"
#include "websockets.h"
using json = nlohmann::json;
@ -91,18 +92,12 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx) {
// Construct the JSON params
json rec = json::object();
rec["address"] = toAddr.addr.toStdString();
rec["amount"] = toAddr.amount;
rec["amount"] = toAddr.amount.toqint64();
if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.trimmed().isEmpty())
rec["memo"] = toAddr.memo.toStdString();
allRecepients.push_back(rec);
}
// // Add fees if custom fees are allowed.
// if (Settings::getInstance()->getAllowCustomFees()) {
// params.push_back(1); // minconf
// params.push_back(tx.fee);
// }
}
@ -115,7 +110,7 @@ void Controller::noConnection() {
main->ui->statusBar->showMessage(QObject::tr("No Connection"), 1000);
// Clear balances table.
QMap<QString, qint64> emptyBalances;
QMap<QString, CAmount> emptyBalances;
QList<UnspentOutput> emptyOutputs;
QList<QString> emptyAddresses;
balancesTableModel->setNewData(emptyAddresses, emptyAddresses, emptyBalances, emptyOutputs);
@ -254,20 +249,21 @@ void Controller::updateUI(bool anyUnconfirmed) {
};
// Function to process reply of the listunspent and z_listunspent API calls, used below.
void Controller::processUnspent(const json& reply, QMap<QString, qint64>* balancesMap, QList<UnspentOutput>* unspentOutputs) {
void Controller::processUnspent(const json& reply, QMap<QString, CAmount>* balancesMap, QList<UnspentOutput>* unspentOutputs) {
auto processFn = [=](const json& array) {
for (auto& it : array) {
QString qsAddr = QString::fromStdString(it["address"]);
int block = it["created_in_block"].get<json::number_unsigned_t>();
QString txid = QString::fromStdString(it["created_in_txid"]);
QString amount = Settings::getDecimalString(it["value"].get<json::number_unsigned_t>());
CAmount amount = CAmount::fromqint64(it["value"].get<json::number_unsigned_t>());
bool spendable = it["unconfirmed_spent"].is_null() && it["spent"].is_null(); // TODO: Wait for 4 confirmations
bool pending = !it["unconfirmed_spent"].is_null();
unspentOutputs->push_back(UnspentOutput{ qsAddr, txid, amount, block, spendable, pending });
if (spendable) {
(*balancesMap)[qsAddr] = (*balancesMap)[qsAddr] + it["value"].get<json::number_unsigned_t>();
(*balancesMap)[qsAddr] = (*balancesMap)[qsAddr] +
CAmount::fromqint64(it["value"].get<json::number_unsigned_t>());
}
}
};
@ -284,26 +280,26 @@ void Controller::refreshBalances() {
// 1. Get the Balances
zrpc->fetchBalance([=] (json reply) {
auto balT = reply["tbalance"].get<json::number_unsigned_t>();
auto balZ = reply["zbalance"].get<json::number_unsigned_t>();
auto balTotal = balT + balZ;
CAmount balT = CAmount::fromqint64(reply["tbalance"].get<json::number_unsigned_t>());
CAmount balZ = CAmount::fromqint64(reply["zbalance"].get<json::number_unsigned_t>());
CAmount balTotal = balT + balZ;
AppDataModel::getInstance()->setBalances(balT, balZ);
ui->balSheilded ->setText(Settings::getZECDisplayFormat(balZ));
ui->balTransparent->setText(Settings::getZECDisplayFormat(balT));
ui->balTotal ->setText(Settings::getZECDisplayFormat(balTotal));
ui->balSheilded ->setText(balZ.toDecimalZECString());
ui->balTransparent->setText(balT.toDecimalZECString());
ui->balTotal ->setText(balTotal.toDecimalZECString());
ui->balSheilded ->setToolTip(Settings::getZECDisplayFormat(balZ));
ui->balTransparent->setToolTip(Settings::getZECDisplayFormat(balT));
ui->balTotal ->setToolTip(Settings::getZECDisplayFormat(balTotal));
auto price = Settings::getInstance()->getZECPrice();
ui->balSheilded ->setToolTip(balZ.toDecimalZECUSDString());
ui->balTransparent->setToolTip(balT.toDecimalZECUSDString());
ui->balTotal ->setToolTip(balTotal.toDecimalZECUSDString());
});
// 2. Get the UTXOs
// First, create a new UTXO list. It will be replacing the existing list when everything is processed.
auto newUnspentOutputs = new QList<UnspentOutput>();
auto newBalances = new QMap<QString, qint64>();
auto newBalances = new QMap<QString, CAmount>();
// Call the Transparent and Z unspent APIs serially and then, once they're done, update the UI
zrpc->fetchUnspent([=] (json reply) {
@ -334,7 +330,7 @@ void Controller::refreshTransactions() {
for (auto& it : reply.get<json::array_t>()) {
QString address;
qint64 total_amount = 0;
CAmount total_amount = CAmount::fromqint64(0);
QList<TransactionItemDetail> items;
// First, check if there's outgoing metadata
@ -342,7 +338,9 @@ void Controller::refreshTransactions() {
for (auto o: it["outgoing_metadata"].get<json::array_t>()) {
QString address = QString::fromStdString(o["address"]);
qint64 amount = -1 * o["value"].get<json::number_unsigned_t>(); // Sent items are -ve
// Sent items are -ve
CAmount amount = CAmount::fromqint64(-1 * o["value"].get<json::number_unsigned_t>());
QString memo;
if (!o["memo"].is_null()) {
@ -350,7 +348,7 @@ void Controller::refreshTransactions() {
}
items.push_back(TransactionItemDetail{address, amount, memo});
total_amount += amount;
total_amount = total_amount + amount;
}
if (items.length() == 1) {
@ -374,7 +372,7 @@ void Controller::refreshTransactions() {
items.push_back(TransactionItemDetail{
address,
it["amount"].get<json::number_integer_t>(),
CAmount::fromqint64(it["amount"].get<json::number_integer_t>()),
""
});

11
src/controller.h

@ -3,6 +3,7 @@
#include "precompiled.h"
#include "camount.h"
#include "datamodel.h"
#include "balancestablemodel.h"
#include "txtablemodel.h"
@ -20,14 +21,6 @@ struct WatchedTx {
std::function<void(QString, QString)> error;
};
struct MigrationStatus {
bool available; // Whether the underlying zcashd supports migration?
bool enabled;
QString saplingAddress;
double unmigrated;
double migrated;
QList<QString> txids;
};
class Controller
{
@ -78,7 +71,7 @@ private:
void refreshTransactions();
void processUnspent (const json& reply, QMap<QString, qint64>* newBalances, QList<UnspentOutput>* newUnspentOutputs);
void processUnspent (const json& reply, QMap<QString, CAmount>* newBalances, QList<UnspentOutput>* newUnspentOutputs);
void updateUI (bool anyUnconfirmed);
void getInfoThenRefresh(bool force);

4
src/datamodel.cpp

@ -7,7 +7,7 @@ DataModel::DataModel() {
QWriteLocker locker(lock);
utxos = new QList<UnspentOutput>();
balances = new QMap<QString, qint64>();
balances = new QMap<QString, CAmount>();
usedAddresses = new QMap<QString, bool>();
zaddresses = new QList<QString>();
taddresses = new QList<QString>();
@ -44,7 +44,7 @@ void DataModel::replaceTaddresses(QList<QString>* newT) {
taddresses = newT;
}
void DataModel::replaceBalances(QMap<QString, qint64>* newBalances) {
void DataModel::replaceBalances(QMap<QString, CAmount>* newBalances) {
QWriteLocker locker(lock);
Q_ASSERT(newBalances);

9
src/datamodel.h

@ -1,13 +1,14 @@
#ifndef DATAMODEL_H
#define DATAMODEL_H
#include "camount.h"
#include "precompiled.h"
struct UnspentOutput {
QString address;
QString txid;
QString amount;
CAmount amount;
int blockCreated;
bool spendable;
bool pending;
@ -19,7 +20,7 @@ class DataModel {
public:
void replaceZaddresses(QList<QString>* newZ);
void replaceTaddresses(QList<QString>* newZ);
void replaceBalances(QMap<QString, qint64>* newBalances);
void replaceBalances(QMap<QString, CAmount>* newBalances);
void replaceUTXOs(QList<UnspentOutput>* utxos);
void markAddressUsed(QString address);
@ -30,7 +31,7 @@ public:
const QList<QString> getAllZAddresses() { QReadLocker locker(lock); return *zaddresses; }
const QList<QString> getAllTAddresses() { QReadLocker locker(lock); return *taddresses; }
const QList<UnspentOutput> getUTXOs() { QReadLocker locker(lock); return *utxos; }
const QMap<QString, qint64> getAllBalances() { QReadLocker locker(lock); return *balances; }
const QMap<QString, CAmount> getAllBalances() { QReadLocker locker(lock); return *balances; }
const QMap<QString, bool> getUsedAddresses() { QReadLocker locker(lock); return *usedAddresses; }
@ -40,7 +41,7 @@ private:
int latestBlock;
QList<UnspentOutput>* utxos = nullptr;
QMap<QString, qint64>* balances = nullptr;
QMap<QString, CAmount>* balances = nullptr;
QMap<QString, bool>* usedAddresses = nullptr;
QList<QString>* zaddresses = nullptr;
QList<QString>* taddresses = nullptr;

3
src/liteinterface.h

@ -3,6 +3,7 @@
#include "precompiled.h"
#include "camount.h"
#include "connection.h"
using json = nlohmann::json;
@ -11,7 +12,7 @@ using json = nlohmann::json;
// into a struct with address, amount, memo
struct TransactionItemDetail {
QString address;
qint64 amount;
CAmount amount;
QString memo;
};

10
src/mainwindow.cpp

@ -438,7 +438,7 @@ void MainWindow::payZcashURI(QString uri, QString myAddr) {
ui->Address1->setText(paymentInfo.addr);
ui->Address1->setCursorPosition(0);
ui->Amount1->setText(Settings::getDecimalString(paymentInfo.amt.toDouble()));
ui->Amount1->setText(paymentInfo.amt);
ui->MemoTxt1->setText(paymentInfo.memo);
// And switch to the send tab.
@ -982,7 +982,7 @@ void MainWindow::setupReceiveTab() {
}
ui->rcvLabel->setText(label);
ui->rcvBal->setText(Settings::getZECUSDDisplayFormat(rpc->getModel()->getAllBalances().value(addr)));
ui->rcvBal->setText(rpc->getModel()->getAllBalances().value(addr).toDecimalZECUSDString());
ui->txtReceive->setPlainText(addr);
ui->qrcodeDisplay->setQrcodeString(addr);
if (rpc->getModel()->getUsedAddresses().value(addr, false)) {
@ -1073,7 +1073,7 @@ void MainWindow::updateTAddrCombo(bool checked) {
// If the address is in the address book, add it.
if (labels.contains(taddr) && !addrs.contains(taddr)) {
addrs.insert(taddr);
ui->listReceiveAddresses->addItem(taddr, 0);
ui->listReceiveAddresses->addItem(taddr, CAmount::fromqint64(0));
}
});
@ -1084,7 +1084,7 @@ void MainWindow::updateTAddrCombo(bool checked) {
if (!addrs.contains(addr)) {
addrs.insert(addr);
// Balance is zero since it has not been previously added
ui->listReceiveAddresses->addItem(addr, 0);
ui->listReceiveAddresses->addItem(addr, CAmount::fromqint64(0));
}
}
@ -1101,7 +1101,7 @@ void MainWindow::updateTAddrCombo(bool checked) {
// 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);
ui->listReceiveAddresses->addItem("-- " + num + " more --", CAmount::fromqint64(0));
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(ui->listReceiveAddresses->model());
QStandardItem* item = model->findItems("--", Qt::MatchStartsWith)[0];

4
src/mainwindow.h

@ -17,7 +17,7 @@ using json = nlohmann::json;
// Struct used to hold destination info when sending a Tx.
struct ToFields {
QString addr;
qint64 amount;
CAmount amount;
QString memo;
};
@ -25,7 +25,7 @@ struct ToFields {
struct Tx {
QString fromAddr;
QList<ToFields> toAddrs;
qint64 fee;
CAmount fee;
};
namespace Ui {

12
src/requestdialog.cpp

@ -73,7 +73,8 @@ void RequestDialog::showPaymentConfirmation(MainWindow* main, QString paymentURI
req.txtFrom->setText(payInfo.addr);
req.txtMemo->setPlainText(payInfo.memo);
req.txtAmount->setText(payInfo.amt);
req.txtAmountUSD->setText(Settings::getUSDFromZecAmount(req.txtAmount->text().toDouble()));
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
req.txtAmountUSD->setText(amount.toDecimalUSDString());
req.buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Pay"));
@ -112,9 +113,11 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
// Amount textbox
req.txtAmount->setValidator(main->getAmountValidator());
QObject::connect(req.txtAmount, &QLineEdit::textChanged, [=] (auto text) {
req.txtAmountUSD->setText(Settings::getUSDFromZecAmount(text.toDouble()));
CAmount amount = CAmount::fromDecimalString(text);
req.txtAmountUSD->setText(amount.toDecimalUSDString());
});
req.txtAmountUSD->setText(Settings::getUSDFromZecAmount(req.txtAmount->text().toDouble()));
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
req.txtAmountUSD->setText(amount.toDecimalUSDString());
req.txtMemo->setAcceptButton(req.buttonBox->button(QDialogButtonBox::Ok));
req.txtMemo->setLenDisplayLabel(req.lblMemoLen);
@ -124,8 +127,9 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
if (d.exec() == QDialog::Accepted) {
// Construct a zcash Payment URI with the data and pay it immediately.
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
QString memoURI = "zcash:" + req.cmbMyAddress->currentText()
+ "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble())
+ "?amt=" + amount.toDecimalString()
+ "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
QString sendURI = "zcash:" + AddressBook::addressFromAddressLabel(req.txtFrom->text())

114
src/sendtab.cpp

@ -61,15 +61,17 @@ void MainWindow::setupSendTab() {
// Fee amount changed
ui->minerFeeAmt->setReadOnly(true);
QObject::connect(ui->minerFeeAmt, &QLineEdit::textChanged, [=](auto txt) {
ui->lblMinerFeeUSD->setText(Settings::getUSDFromZecAmount(txt.toDouble()));
CAmount fee = CAmount::fromDecimalString(txt);
ui->lblMinerFeeUSD->setText(fee.toDecimalUSDString());
});
ui->minerFeeAmt->setText(Settings::getDecimalString(Settings::getMinerFee()));
ui->minerFeeAmt->setText(Settings::getMinerFee().toDecimalString());
// Set up focus enter to set fees
QObject::connect(ui->tabWidget, &QTabWidget::currentChanged, [=] (int pos) {
if (pos == 1) {
QString txt = ui->minerFeeAmt->text();
ui->lblMinerFeeUSD->setText(Settings::getUSDFromZecAmount(txt.toDouble()));
QString feeUSD = CAmount::fromDecimalString(txt).toDecimalUSDString();
ui->lblMinerFeeUSD->setText(feeUSD);
}
});
@ -167,67 +169,15 @@ void MainWindow::updateLabelsAutoComplete() {
}
void MainWindow::setDefaultPayFrom() {
auto findMax = [=] (QString startsWith) {
double max_amt = 0;
int idx = -1;
for (int i=0; i < ui->inputsCombo->count(); i++) {
auto addr = ui->inputsCombo->itemText(i);
if (addr.startsWith(startsWith)) {
auto amt = rpc->getModel()->getAllBalances().value(addr);
if (max_amt < amt) {
max_amt = amt;
idx = i;
}
}
}
return idx;
};
// By default, select the z-address with the most balance from the inputs combo
auto maxZ = findMax("z");
if (maxZ >= 0) {
ui->inputsCombo->setCurrentIndex(maxZ);
} else {
auto maxT = findMax("t");
maxT = maxT >= 0 ? maxT : 0;
ui->inputsCombo->setCurrentIndex(maxT);
}
};
void MainWindow::updateFromCombo() {
if (!rpc)
return;
auto lastFromAddr = ui->inputsCombo->currentText();
ui->inputsCombo->clear();
auto i = rpc->getModel()->getAllBalances().constBegin();
// Add all the addresses into the inputs combo box
while (i != rpc->getModel()->getAllBalances().constEnd()) {
ui->inputsCombo->addItem(i.key(), i.value());
if (i.key() == lastFromAddr) ui->inputsCombo->setCurrentText(i.key());
++i;
}
if (lastFromAddr.isEmpty()) {
setDefaultPayFrom();
}
else {
ui->inputsCombo->setCurrentText(lastFromAddr);
}
// delete
}
void MainWindow::inputComboTextChanged(int index) {
auto addr = ui->inputsCombo->itemText(index);
auto bal = rpc->getModel()->getAllBalances().value(addr);
auto balFmt = Settings::getZECDisplayFormat(bal);
ui->sendAddressBalance->setText(balFmt);
ui->sendAddressBalanceUSD->setText(Settings::getUSDFromZecAmount(bal));
// delete
}
@ -340,7 +290,8 @@ void MainWindow::addressChanged(int itemNumber, const QString& text) {
void MainWindow::amountChanged(int item, const QString& text) {
auto usd = ui->sendToWidgets->findChild<QLabel*>(QString("AmtUSD") % QString::number(item));
usd->setText(Settings::getUSDFromZecAmount(text.toDouble()));
CAmount amt = CAmount::fromDecimalString(text);
usd->setText(amt.toDecimalUSDString());
// If there is a recurring payment, update the info there as well
if (sendTxRecurringInfo != nullptr) {
@ -434,7 +385,7 @@ void MainWindow::clearSendForm() {
setMemoEnabled(1, false);
// Reset the fee
ui->minerFeeAmt->setText(Settings::getDecimalString(Settings::getMinerFee()));
ui->minerFeeAmt->setText(Settings::getMinerFee().toDecimalString());
// Start the deletion after the first item, since we want to keep 1 send field there all there
for (int i=1; i < totalItems; i++) {
@ -461,24 +412,24 @@ void MainWindow::maxAmountChecked(int checked) {
if (rpc == nullptr) return;
// Calculate maximum amount
double sumAllAmounts = 0.0;
CAmount sumAllAmounts = CAmount::fromqint64(0);
// Calculate all other amounts
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
// Start counting the sum skipping the first one, because the MAX button is on the first one, and we don't
// want to include it in the sum.
for (int i=1; i < totalItems; i++) {
auto amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1));
sumAllAmounts += amt->text().toDouble();
sumAllAmounts = sumAllAmounts + CAmount::fromDecimalString(amt->text());
}
sumAllAmounts += Settings::getMinerFee();
sumAllAmounts = sumAllAmounts + Settings::getMinerFee();
auto addr = ui->inputsCombo->currentText();
auto maxamount = rpc->getModel()->getAllBalances().value(addr) - sumAllAmounts;
maxamount = (maxamount < 0) ? 0 : maxamount;
maxamount = (maxamount.toqint64() < 0) ? CAmount::fromqint64(0) : maxamount;
ui->Amount1->setText(Settings::getDecimalString(maxamount));
ui->Amount1->setText(maxamount.toDecimalString());
} else if (checked == Qt::Unchecked) {
// Just remove the readonly part, don't change the content
ui->Amount1->setReadOnly(false);
@ -494,7 +445,7 @@ Tx MainWindow::createTxFromSendPage() {
// For each addr/amt in the sendTo tab
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
qint64 totalAmt = 0;
CAmount totalAmt = CAmount::fromqint64(0);
for (int i=0; i < totalItems; i++) {
QString addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") % QString::number(i+1))->text().trimmed();
// Remove label if it exists
@ -506,15 +457,15 @@ Tx MainWindow::createTxFromSendPage() {
}
bool ok;
qint64 amt;
CAmount amt;
// Make sure it parses
amtStr.toDouble(&ok);
if (!ok) {
amt = -1;
amt = CAmount::fromqint64(-1);
} else {
amt = Settings::getAmountFromUserDecimalStr(amtStr);
totalAmt += amt;
amt = CAmount::fromDecimalString(amtStr);
totalAmt = totalAmt + amt;
}
QString memo = ui->sendToWidgets->findChild<QLabel*>(QString("MemoTxt") % QString::number(i+1))->text().trimmed();
@ -587,7 +538,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
// For each addr/amt/memo, construct the JSON and also build the confirm dialog box
int row = 0;
double totalSpending = 0;
CAmount totalSpending = CAmount::fromqint64(0);
for (int i=0; i < tx.toAddrs.size(); i++) {
auto toAddr = tx.toAddrs[i];
@ -605,15 +556,15 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
// Amount (ZEC)
auto Amt = new QLabel(confirm.sendToAddrs);
Amt->setObjectName(QString("Amt") % QString::number(i + 1));
Amt->setText(Settings::getZECDisplayFormat(toAddr.amount));
Amt->setText(toAddr.amount.toDecimalZECString());
Amt->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(Amt, row, 1, 1, 1);
totalSpending += toAddr.amount;
totalSpending = totalSpending + toAddr.amount;
// Amount (USD)
auto AmtUSD = new QLabel(confirm.sendToAddrs);
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(Settings::getUSDFromZecAmount(toAddr.amount));
AmtUSD->setText(toAddr.amount.toDecimalUSDString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
@ -655,8 +606,8 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
minerFee->setObjectName(QStringLiteral("minerFee"));
minerFee->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
confirm.gridLayout->addWidget(minerFee, row, 1, 1, 1);
minerFee->setText(Settings::getZECDisplayFormat(tx.fee));
totalSpending += tx.fee;
minerFee->setText(tx.fee.toDecimalZECString());
totalSpending = totalSpending + tx.fee;
auto minerFeeUSD = new QLabel(confirm.sendToAddrs);
QSizePolicy sizePolicy1(QSizePolicy::Minimum, QSizePolicy::Preferred);
@ -664,7 +615,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
minerFeeUSD->setObjectName(QStringLiteral("minerFeeUSD"));
minerFeeUSD->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
confirm.gridLayout->addWidget(minerFeeUSD, row, 2, 1, 1);
minerFeeUSD->setText(Settings::getUSDFromZecAmount(tx.fee));
minerFeeUSD->setText(tx.fee.toDecimalUSDString());
}
// Recurring payment info, show only if there is exactly one destination address
@ -683,9 +634,9 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
confirm.sendFrom->setText(fnSplitAddressForWrap(tx.fromAddr));
confirm.sendFrom->setFont(fixedFont);
QString tooltip = tr("Current balance : ") +
Settings::getZECUSDDisplayFormat(rpc->getModel()->getAllBalances().value(tx.fromAddr));
rpc->getModel()->getAllBalances().value(tx.fromAddr).toDecimalZECUSDString();
tooltip += "\n" + tr("Balance after this Tx: ") +
Settings::getZECUSDDisplayFormat(rpc->getModel()->getAllBalances().value(tx.fromAddr) - totalSpending);
(rpc->getModel()->getAllBalances().value(tx.fromAddr) - totalSpending).toDecimalZECUSDString();
confirm.sendFrom->setToolTip(tooltip);
// Show the dialog and submit it if the user confirms
@ -769,13 +720,12 @@ 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) {
if (toAddr.amount.toqint64() < 0) {
return QString(tr("Amount for address '%1' is invalid!").arg(toAddr.addr));
}
}
return QString();
return "";
}
void MainWindow::cancelButton() {

68
src/settings.cpp

@ -1,5 +1,6 @@
#include "mainwindow.h"
#include "settings.h"
#include "camount.h"
Settings* Settings::instance = nullptr;
@ -178,66 +179,6 @@ void Settings::openTxInExplorer(QString txid) {
}
QString Settings::getUSDFormat(double usdAmt) {
return "$" + QLocale(QLocale::English).toString(usdAmt, 'f', 2);
}
QString Settings::getUSDFromZecAmount(qint64 bal) {
return getUSDFormat(bal * Settings::getInstance()->getZECPrice());
}
QString Settings::getDecimalString(qint64 amt) {
if (amt < 0) {
return "-" + Settings::getDecimalString(-1 * amt);
}
// Zcash has 8 decimal places
int places = Settings::getNumberOfDecimalPlaces();
qint64 divider = QString("1" + QString("0").repeated(places)).toULongLong();
int wholePart = amt / divider;
int decimalPart = amt % divider;
QString r = QString::number(wholePart);
if (decimalPart > 0) {
QString decimalPartStr = QString::number(decimalPart);
QString leadingZeros = QString("0").repeated(places - decimalPartStr.length());
r = r + "." + leadingZeros + decimalPartStr;
}
return r;
}
qint64 Settings::getAmountFromUserDecimalStr(QString amt) {
int places = Settings::getNumberOfDecimalPlaces();
qint64 divider = QString("1" + QString("0").repeated(places)).toULongLong();
auto amtParts = amt.split(".");
qint64 r = amtParts[0].toULongLong() * divider;
if (amtParts.length() == 2) {
auto trailingZeros = QString("0").repeated(places - amtParts[1].length());
r += QString(amtParts[1] + trailingZeros).toULongLong();
}
return r;
}
QString Settings::getZECDisplayFormat(qint64 bal) {
// This is idiotic. Why doesn't QString have a way to do this?
return getDecimalString(bal) % " " % Settings::getTokenName();
}
QString Settings::getZECUSDDisplayFormat(qint64 bal) {
auto usdFormat = getUSDFromZecAmount(bal);
if (!usdFormat.isEmpty())
return getZECDisplayFormat(bal) % " (" % usdFormat % ")";
else
return getZECDisplayFormat(bal);
}
const QString Settings::txidStatusMessage = QString(QObject::tr("Tx submitted (right click to copy) txid:"));
QString Settings::getTokenName() {
@ -256,8 +197,8 @@ QString Settings::getDonationAddr() {
}
double Settings::getMinerFee() {
return 10000;
CAmount Settings::getMinerFee() {
return CAmount::fromqint64(10000);
}
bool Settings::isValidSaplingPrivateKey(QString pk) {
@ -282,7 +223,8 @@ bool Settings::isValidAddress(QString addr) {
// Get a pretty string representation of this Payment URI
QString Settings::paymentURIPretty(PaymentURI uri) {
return QString() + "Payment Request\n" + "Pay: " + uri.addr + "\nAmount: " + getZECDisplayFormat(uri.amt.toDouble())
CAmount amount = CAmount::fromDecimalString(uri.amt);
return QString() + "Payment Request\n" + "Pay: " + uri.addr + "\nAmount: " + amount.toDecimalZECString()
+ "\nMemo:" + QUrl::fromPercentEncoding(uri.memo.toUtf8());
}

12
src/settings.h

@ -2,6 +2,7 @@
#define SETTINGS_H
#include "precompiled.h"
#include "camount.h"
struct Config {
QString server;
@ -80,20 +81,11 @@ public:
static bool isZAddress(QString addr);
static bool isTAddress(QString addr);
static QString getDecimalString(qint64 zecamt);
static QString getUSDFormat(double usdAmt);
static QString getUSDFromZecAmount(qint64 zecamt);
static QString getZECDisplayFormat(qint64 zecamt);
static QString getZECUSDDisplayFormat(qint64 bal);
static qint64 getAmountFromUserDecimalStr(QString amt);
static QString getTokenName();
static QString getDonationAddr();
static QString getDefaultServer();
static double getMinerFee();
static CAmount getMinerFee();
static int getMaxMobileAppTxns() { return 30; }

18
src/txtablemodel.cpp

@ -105,11 +105,11 @@ bool TxTableModel::exportToCsv(QString fileName) const {
case Column::Confirmations: return QString::number(dat.confirmations);
case Column::Amount: {
// Sum up all the amounts
qint64 total = 0;
CAmount total = CAmount::fromqint64(0);
for (int i=0; i < dat.items.length(); i++) {
total += dat.items[i].amount;
total = total + dat.items[i].amount;
}
return Settings::getZECDisplayFormat(total);
return total.toDecimalZECString();
}
}
}
@ -141,11 +141,11 @@ bool TxTableModel::exportToCsv(QString fileName) const {
case Column::Confirmations: return QString("%1 Network Confirmations").arg(QString::number(dat.confirmations));
case Column::Amount: {
// Sum up all the amounts
qint64 total = 0;
CAmount total = CAmount::fromqint64(0);
for (int i=0; i < dat.items.length(); i++) {
total += dat.items[i].amount;
total = total + dat.items[i].amount;
}
return Settings::getInstance()->getUSDFromZecAmount(total);
return total.toDecimalUSDString();
}
}
}
@ -237,9 +237,9 @@ QString TxTableModel::getType(int row) const {
QString TxTableModel::getAmt(int row) const {
auto dat = modeldata->at(row);
qint64 total = 0;
CAmount total = CAmount::fromqint64(0);
for (int i=0; i < dat.items.length(); i++) {
total += dat.items[i].amount;
total = total + dat.items[i].amount;
}
return Settings::getDecimalString(total);
return total.toDecimalString();
}

3
src/viewalladdresses.cpp

@ -1,4 +1,5 @@
#include "viewalladdresses.h"
#include "camount.h"
#include "settings.h"
ViewAllAddressesModel::ViewAllAddressesModel(QTableView *parent, QList<QString> taddrs, Controller* rpc)
@ -22,7 +23,7 @@ QVariant ViewAllAddressesModel::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) {
switch(index.column()) {
case 0: return address;
case 1: return rpc->getModel()->getAllBalances().value(address, 0.0);
case 1: return rpc->getModel()->getAllBalances().value(address, CAmount::fromqint64(0)).toDecimalString();
}
}
return QVariant();

20
src/websockets.cpp

@ -658,9 +658,9 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st
tx.fee = Settings::getMinerFee();
// Find a from address that has at least the sending amout
qint64 amt = Settings::getAmountFromUserDecimalStr(sendTx["amount"].toString());
CAmount amt = CAmount::fromDecimalString(sendTx["amount"].toString());
auto allBalances = mainwindow->getRPC()->getModel()->getAllBalances();
QList<QPair<QString, double>> bals;
QList<QPair<QString, CAmount>> bals;
for (auto i : allBalances.keys()) {
// Filter out sprout addresses
if (Settings::getInstance()->isSproutAddress(i))
@ -669,7 +669,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st
if (allBalances.value(i) < amt)
continue;
bals.append(QPair<QString, double>(i, allBalances.value(i)));
bals.append(QPair<QString, CAmount>(i, allBalances.value(i)));
}
if (bals.isEmpty()) {
@ -677,7 +677,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st
return;
}
std::sort(bals.begin(), bals.end(), [=](const QPair<QString, double>a, const QPair<QString, double> b) -> bool {
std::sort(bals.begin(), bals.end(), [=](const QPair<QString, CAmount>a, const QPair<QString, CAmount> b) -> bool {
// Sort z addresses first
return a.first > b.first;
});
@ -736,8 +736,8 @@ void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std
}
// Max spendable safely from a z address and from any address
double maxZSpendable = 0;
double maxSpendable = 0;
CAmount maxZSpendable = CAmount::fromqint64(0);
CAmount maxSpendable = CAmount::fromqint64(0);
for (auto a : mainWindow->getRPC()->getModel()->getAllBalances().keys()) {
if (Settings::getInstance()->isSaplingAddress(a)) {
if (mainWindow->getRPC()->getModel()->getAllBalances().value(a) > maxZSpendable) {
@ -751,14 +751,14 @@ void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std
setConnectedName(connectedName);
auto r = QJsonDocument(QJsonObject{
auto r = QJsonDocument(QJsonObject {
{"version", 1.0},
{"command", "getInfo"},
{"saplingAddress", mainWindow->getRPC()->getDefaultSaplingAddress()},
{"tAddress", mainWindow->getRPC()->getDefaultTAddress()},
{"balance", AppDataModel::getInstance()->getTotalBalance()},
{"maxspendable", maxSpendable},
{"maxzspendable", maxZSpendable},
{"balance", AppDataModel::getInstance()->getTotalBalance().toDecimalDouble()},
{"maxspendable", maxSpendable.toDecimalDouble()},
{"maxzspendable", maxZSpendable.toDecimalDouble()},
{"tokenName", Settings::getTokenName()},
{"zecprice", Settings::getInstance()->getZECPrice()},
{"serverversion", QString(APP_VERSION)}

15
src/websockets.h

@ -3,6 +3,7 @@
#include "precompiled.h"
#include "camount.h"
#include "mainwindow.h"
#include "ui_mobileappconnector.h"
@ -151,11 +152,11 @@ public:
return instance;
}
double getTBalance() { return balTransparent; }
double getZBalance() { return balShielded; }
double getTotalBalance() { return balTotal; }
CAmount getTBalance() { return balTransparent; }
CAmount getZBalance() { return balShielded; }
CAmount getTotalBalance() { return balTotal; }
void setBalances(double transparent, double shielded) {
void setBalances(CAmount transparent, CAmount shielded) {
balTransparent = transparent;
balShielded = shielded;
balTotal = balTransparent + balShielded;
@ -164,9 +165,9 @@ public:
private:
AppDataModel() = default; // Private, for singleton
double balTransparent;
double balShielded;
double balTotal;
CAmount balTransparent;
CAmount balShielded;
CAmount balTotal;
QString saplingAddress;

6
zecwallet-lite.pro

@ -60,7 +60,8 @@ SOURCES += \
src/viewalladdresses.cpp \
src/datamodel.cpp \
src/controller.cpp \
src/liteinterface.cpp
src/liteinterface.cpp \
src/camount.cpp
HEADERS += \
src/firsttimewizard.h \
@ -88,6 +89,7 @@ HEADERS += \
src/datamodel.h \
src/controller.h \
src/liteinterface.h \
src/camount.h \
lib/zecwalletlitelib.h
FORMS += \
@ -110,7 +112,7 @@ FORMS += \
src/recurringdialog.ui \
src/newrecurring.ui \
src/requestdialog.ui \
src/recurringmultiple.ui
src/recurringmultiple.ui
TRANSLATIONS = res/zec_qt_wallet_es.ts \

Loading…
Cancel
Save