diff --git a/src/websockets.cpp b/src/websockets.cpp index afbbca6..852a553 100644 --- a/src/websockets.cpp +++ b/src/websockets.cpp @@ -664,6 +664,9 @@ void AppDataServer::processDecryptedMessage(QString message, MainWindow* mainWin } else if (msg.object()["command"] == "sendTx") { processSendTx(msg.object()["tx"].toObject(), mainWindow, pClient); + } + else if (msg.object()["command"] == "sendmanyTx") { + processSendManyTx(msg.object()["tx"].toObject(), mainWindow, pClient); } else { auto r = QJsonDocument(QJsonObject{ @@ -765,6 +768,107 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st pClient->sendTextMessage(encryptOutgoing(r)); } +// "sendmanyTx" command. This method will actually send money, so be careful with everything +void AppDataServer::processSendManyTx(QJsonObject sendmanyTx, MainWindow* mainwindow, std::shared_ptr pClient) { + qDebug() << "processSendManyTx with to=" << sendmanyTx["to"].toString(); + auto error = [=](QString reason) { + auto r = QJsonDocument(QJsonObject{ + {"errorCode", -1}, + {"errorMessage", "Couldn't send Tx:" + reason} + }).toJson(); + pClient->sendTextMessage(encryptOutgoing(r)); + return; + }; + + // Refuse to send if the node is still syncing + if (Settings::getInstance()->isSyncing()) { + error(QObject::tr("Node is still syncing.")); + return; + } + + // Create a Tx Object + Tx tx; + tx.fee = Settings::getMinerFee(); + + // Find a from address that has at least the sending amout + CAmount amt = CAmount::fromDecimalString(sendmanyTx["amount"].toString()); + auto allBalances = mainwindow->getRPC()->getModel()->getAllBalances(); + QList> bals; + for (auto i : allBalances.keys()) { + // Filter out sprout addresses + if (Settings::getInstance()->isSproutAddress(i)) + continue; + // Filter out balances that don't have the requisite amount + if (allBalances.value(i) < amt) + continue; + + bals.append(QPair(i, allBalances.value(i))); + } + + if (bals.isEmpty()) { + error(QObject::tr("No sapling or transparent addresses with enough balance to spend.")); + return; + } + + std::sort(bals.begin(), bals.end(), [=](const QPaira, const QPair b) -> bool { + // Sort z addresses first + return a.first > b.first; + }); + + //send to more then one Receipent + + int totalSendManyItems = sendmanyTx.size(); + for (int i=0; i < totalSendManyItems; i++) { + + amt = CAmount::fromDecimalString(sendmanyTx["amount"].toString() % QString::number(i+1)); + QString addr = sendmanyTx["to"].toString() % QString::number(i+1); + QString memo = sendmanyTx["memo"].toString() % QString::number(i+1); + + tx.fromAddr = bals[0].first; + tx.toAddrs = { ToFields{ addr, amt, memo} }; +} + // TODO: Respect the autoshield change setting + + QString validation = mainwindow->doSendTxValidations(tx); + if (!validation.isEmpty()) { + error(validation); + return; + } + + json params = json::array(); + mainwindow->getRPC()->fillTxJsonParams(params, tx); + std::cout << std::setw(2) << params << std::endl; + + // And send the Tx + mainwindow->getRPC()->executeTransaction(tx, + [=] (QString txid) { + auto r = QJsonDocument(QJsonObject{ + {"version", 1.0}, + {"command", "sendTxSubmitted"}, + {"txid", txid} + }).toJson(); + pClient->sendTextMessage(encryptOutgoing(r)); + }, + // Errored while submitting Tx + [=] (QString, QString errStr) { + auto r = QJsonDocument(QJsonObject{ + {"version", 1.0}, + {"command", "sendTxFailed"}, + {"err", errStr} + }).toJson(); + pClient->sendTextMessage(encryptOutgoing(r)); + } + ); + + auto r = QJsonDocument(QJsonObject{ + {"version", 1.0}, + {"command", "sendTx"}, + {"result", "success"} + }).toJson(); + pClient->sendTextMessage(encryptOutgoing(r)); +} + + // "getInfo" command void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr pClient) { auto connectedName = jobj["name"].toString(); diff --git a/src/websockets.h b/src/websockets.h index 6483f42..ec63502 100644 --- a/src/websockets.h +++ b/src/websockets.h @@ -101,6 +101,7 @@ public: void updateUIWithNewQRCode(MainWindow* mainwindow); void processSendTx(QJsonObject sendTx, MainWindow* mainwindow, std::shared_ptr pClient); + void processSendManyTx(QJsonObject sendmanyTx, MainWindow* mainwindow, std::shared_ptr pClient); void processMessage(QString message, MainWindow* mainWindow, std::shared_ptr pClient, AppConnectionType connType); void processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr pClient); void processDecryptedMessage(QString message, MainWindow* mainWindow, std::shared_ptr pClient);