diff --git a/src/mainwindow.h b/src/mainwindow.h index 3a823ae..69a4d3f 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -39,6 +39,7 @@ public: void updateLabelsAutoComplete(); + QString doSendTxValidations(Tx tx); void setDefaultPayFrom(); RPC* getRPC() { return rpc; } @@ -85,9 +86,7 @@ private: void memoButtonClicked(int number, bool includeReplyTo = false); void setMemoEnabled(int number, bool enabled); - - QString doSendTxValidations(Tx tx); - + void donate(); void addressBook(); void payZcashURI(); diff --git a/src/websockets.cpp b/src/websockets.cpp index 3ef4a76..6aa66fd 100644 --- a/src/websockets.cpp +++ b/src/websockets.cpp @@ -1,5 +1,5 @@ - #include "websockets.h" + #include "rpc.h" #include "settings.h" @@ -88,6 +88,9 @@ QJsonDocument AppDataServer::processMessage(QString message, MainWindow* mainWin else if (msg.object()["command"] == "getTransactions") { return processGetTransactions(mainWindow); } + else if (msg.object()["command"] == "sendTx") { + return processSendTx(msg.object()["tx"].toObject(), mainWindow); + } else { return QJsonDocument(QJsonObject{ {"errorCode", -1}, @@ -96,6 +99,79 @@ QJsonDocument AppDataServer::processMessage(QString message, MainWindow* mainWin } } +QJsonDocument AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow) { + auto error = [=](QString reason) -> QJsonDocument { + return QJsonDocument(QJsonObject{ + {"errorCode", -1}, + {"errorMessage", "Couldn't send Tx:" + reason} + }); + }; + + // Create a Tx Object + Tx tx; + tx.fee = Settings::getMinerFee(); + + // Find a from address that has at least the sending amout + double amt = sendTx["amount"].toDouble(); + auto allBalances = mainwindow->getRPC()->getAllBalances(); + QList> bals; + for (auto i : allBalances->keys()) { + // Filter out sprout Txns + if (Settings::getInstance()->isSproutAddress(i)) + continue; + bals.append(QPair(i, allBalances->value(i))); + } + + if (bals.isEmpty()) { + return error("No sapling or transparent addresses"); + } + + std::sort(bals.begin(), bals.end(), [=](const QPaira, const QPair b) ->bool { + // If same type, sort by amount + if (a.first[0] == b.first[0]) { + return a.second > b.second; + } + else { + return a > b; + } + }); + + if (amt > bals[0].second) { + // There isn't any any address capable of sending the Tx. + return error("Amount exceeds the balance of your largest address."); + } + + tx.fromAddr = bals[0].first; + tx.toAddrs = { ToFields{ sendTx["to"].toString(), amt, sendTx["memo"].toString(), sendTx["memo"].toString().toUtf8().toHex()} }; + + // TODO: Respect the autoshield change setting + + QString validation = mainwindow->doSendTxValidations(tx); + if (!validation.isEmpty()) { + return error(validation); + } + + json params = json::array(); + mainwindow->getRPC()->fillTxJsonParams(params, tx); + std::cout << std::setw(2) << params << std::endl; + + // And send the Tx + mainwindow->getRPC()->sendZTransaction(params, [=](const json& reply) { + QString opid = QString::fromStdString(reply.get()); + + // And then start monitoring the transaction + mainwindow->getRPC()->addNewTxToWatch(tx, opid); + + // TODO: Handle the error if the computed Tx fails. + }); + + return QJsonDocument(QJsonObject{ + {"version", 1.0}, + {"command", "sendTx"}, + {"result", "success"} + }); +} + QJsonDocument AppDataServer::processGetInfo(MainWindow* mainWindow) { return QJsonDocument(QJsonObject{ {"version", 1.0}, diff --git a/src/websockets.h b/src/websockets.h index cb6d831..77f388a 100644 --- a/src/websockets.h +++ b/src/websockets.h @@ -33,6 +33,7 @@ private: class AppDataServer { public: + static QJsonDocument processSendTx(QJsonObject sendTx, MainWindow* mainwindow); static QJsonDocument processMessage(QString message, MainWindow* mainWindow); static QJsonDocument processGetInfo(MainWindow* mainWindow); static QJsonDocument processGetTransactions(MainWindow* mainWindow);