From 443a07e676e13e3f6cec455d30130b8153bffedf Mon Sep 17 00:00:00 2001 From: Duke Date: Sat, 21 Jan 2023 23:22:51 -0500 Subject: [PATCH] SilentDragonX Add support to SD for DragonX. Currently there is no UI for switching between coins and SD does not render data for multiple coins at one time. Everything works based on the name of the binary that is used to start the wallet. If the binary is named "silentdragonx" then the code will connect to the DragonX full node instead of the Hush full node. SDX has it's own log file and stores data in it's own files, so it is possible to run SD and SDX at the same time. Currently the images, icons and translations still need to be customized for DragonX. To compile run ./build-sdx.sh and then run ./silentdragonx --- .gitignore | 4 +- README.md | 11 +++ build-sdx.sh | 20 +++++ build.sh | 2 +- silentdragonx.pro | 168 ++++++++++++++++++++++++++++++++++++ src/addressbook.cpp | 4 + src/connection.cpp | 78 ++++++++++++++--- src/createhushconfdialog.ui | 2 +- src/main.cpp | 24 +++++- src/mainwindow.cpp | 75 ++++++++++------ src/mainwindow.ui | 26 ++---- src/requestdialog.cpp | 13 ++- src/requestdialog.ui | 2 +- src/rpc.cpp | 41 ++++++--- src/senttxstore.cpp | 5 ++ src/settings.cpp | 29 ++++++- src/settings.ui | 4 +- src/txtablemodel.cpp | 19 ++-- 18 files changed, 438 insertions(+), 89 deletions(-) create mode 100755 build-sdx.sh create mode 100644 silentdragonx.pro diff --git a/.gitignore b/.gitignore index 4a21c30..248a400 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ docs/website/public hushd IDEWorkspaceChecks.plist hush-cli -hushd +dragonxd *.mak Makefile Makefile.* @@ -18,7 +18,7 @@ res/libsodium.a res/libsodium.a res/libsodium/libsodium* silentdragon -silentdragon +silentdragonx silentdragon.pro.user *.sln src/precompiled.h.cpp diff --git a/README.md b/README.md index 958d1ad..d43fe20 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,17 @@ make ./SilentDragon.app/Contents/MacOS/SilentDragon ``` +### Building SilentDragonX + + +``` +git clone https://git.hush.is/hush/SilentDragon +cd SilentDragon +./build-sdx.sh +``` + +The binary will be called `silentdragonx` + ### Emulating the embedded node In binary releases, SilentDragon will use node binaries in the current directory to sync a node from scratch. diff --git a/build-sdx.sh b/build-sdx.sh new file mode 100755 index 0000000..d1ebf38 --- /dev/null +++ b/build-sdx.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2018-2023 The Hush Developers +# Released under the GPLv3 + +# This builds a binary called "silentdragonx" + +set -e + +if [ -e dragonxd ]; then + echo "Found dragonxd binary" +else + echo "dragonxd could not be found!" + echo "Either copy the binary to this dir or make a symlink." + echo "This command will create a symlink to it if this repo is in the same directory as your hush3.git: " + echo "ln -s ../hush3/src/dragonxd" + exit 1 +fi + +# Use a modified QT project file with same build.sh +SDCONF=silentdragonx.pro ./build.sh diff --git a/build.sh b/build.sh index 7cb8668..04c5cb6 100755 --- a/build.sh +++ b/build.sh @@ -17,7 +17,7 @@ fi VERSION=$(cat src/version.h |cut -d\" -f2) echo "Compiling SilentDragon $VERSION with $JOBS threads..." -CONF=silentdragon.pro +CONF=${SDCONF:-silentdragon.pro} if ! command -v qmake &> /dev/null then diff --git a/silentdragonx.pro b/silentdragonx.pro new file mode 100644 index 0000000..c611772 --- /dev/null +++ b/silentdragonx.pro @@ -0,0 +1,168 @@ +# Copyright 2018-2023 The Hush Developers +# Released under the GPLv3 + +QT += core gui network + +CONFIG += precompile_header + +PRECOMPILED_HEADER = src/precompiled.h + +QT += widgets +QT += websockets + +TARGET = silentdragonx + +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += \ + QT_DEPRECATED_WARNINGS + +INCLUDEPATH += src/3rdparty/ +INCLUDEPATH += src/ + +mac: LIBS+= -Wl,-dead_strip +mac: LIBS+= -Wl,-dead_strip_dylibs +mac: LIBS+= -Wl,-bind_at_load + +RESOURCES = application.qrc + +MOC_DIR = bin +OBJECTS_DIR = bin +UI_DIR = src + +CONFIG += c++14 + +SOURCES += \ + src/main.cpp \ + src/mainwindow.cpp \ + src/rpc.cpp \ + src/balancestablemodel.cpp \ + src/3rdparty/qrcode/BitBuffer.cpp \ + src/3rdparty/qrcode/QrCode.cpp \ + src/3rdparty/qrcode/QrSegment.cpp \ + src/settings.cpp \ + src/sendtab.cpp \ + src/senttxstore.cpp \ + src/txtablemodel.cpp \ + src/peerstablemodel.cpp \ + src/bannedpeerstablemodel.cpp \ + src/qrcodelabel.cpp \ + src/connection.cpp \ + src/fillediconlabel.cpp \ + src/addressbook.cpp \ + src/logger.cpp \ + src/addresscombo.cpp \ + src/validateaddress.cpp \ + src/websockets.cpp \ + src/mobileappconnector.cpp \ + src/recurring.cpp \ + src/requestdialog.cpp \ + src/memoedit.cpp \ + src/viewalladdresses.cpp + +HEADERS += \ + src/guiconstants.h \ + src/mainwindow.h \ + src/precompiled.h \ + src/rpc.h \ + src/balancestablemodel.h \ + src/3rdparty/qrcode/BitBuffer.hpp \ + src/3rdparty/qrcode/QrCode.hpp \ + src/3rdparty/qrcode/QrSegment.hpp \ + src/settings.h \ + src/txtablemodel.h \ + src/peerstablemodel.h \ + src/bannedpeerstablemodel.h \ + src/senttxstore.h \ + src/qrcodelabel.h \ + src/connection.h \ + src/fillediconlabel.h \ + src/addressbook.h \ + src/logger.h \ + src/addresscombo.h \ + src/validateaddress.h \ + src/websockets.h \ + src/mobileappconnector.h \ + src/recurring.h \ + src/requestdialog.h \ + src/memoedit.h \ + src/viewalladdresses.h + +FORMS += \ + src/mainwindow.ui \ + src/qrcode.ui \ + src/rescandialog.ui \ + src/settings.ui \ + src/about.ui \ + src/confirm.ui \ + src/privkey.ui \ + src/viewkey.ui \ + src/memodialog.ui \ + src/viewalladdresses.ui \ + src/validateaddress.ui \ + src/viewalladdresses.ui \ + src/connection.ui \ + src/addressbook.ui \ + src/viewalladdresses.ui \ + src/mobileappconnector.ui \ + src/createhushconfdialog.ui \ + src/recurringdialog.ui \ + src/newrecurring.ui \ + src/requestdialog.ui + + +TRANSLATIONS = res-drgx/silentdragon_be.ts \ + res-drgx/silentdragon_bg.ts \ + res-drgx/silentdragon_de.ts \ + res-drgx/silentdragon_es.ts \ + res-drgx/silentdragon_fi.ts \ + res-drgx/silentdragon_fil.ts \ + res-drgx/silentdragon_fr.ts \ + res-drgx/silentdragon_hr.ts \ + res-drgx/silentdragon_id.ts \ + res-drgx/silentdragon_it.ts \ + res-drgx/silentdragon_nl.ts \ + res-drgx/silentdragon_pl.ts \ + res-drgx/silentdragon_pt.ts \ + res-drgx/silentdragon_ro.ts \ + res-drgx/silentdragon_ru.ts \ + res-drgx/silentdragon_sr.ts \ + res-drgx/silentdragon_tr.ts \ + res-drgx/silentdragon_uk.ts \ + res-drgx/silentdragon_zh.ts + +include(singleapplication/singleapplication.pri) +DEFINES += QAPPLICATION_CLASS=QApplication _FORTIFY_SOURCE=2 + +QMAKE_INFO_PLIST = res/Info.plist + +win32: RC_ICONS = res/icon.ico +ICON = res/logo.icns + +libsodium.target = $$PWD/res/libsodium.a +libsodium.commands = res/libsodium/buildlibsodium.sh + +QMAKE_EXTRA_TARGETS += libsodium +QMAKE_CLEAN += res/libsodium.a + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/res/ -llibsodium +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/res/ -llibsodiumd +else:unix: LIBS += -L$$PWD/res/ -lsodium + +INCLUDEPATH += $$PWD/res +DEPENDPATH += $$PWD/res + +win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/res/liblibsodium.a +else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/res/liblibsodium.a +else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/res/libsodium.lib +else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/res/libsodiumd.lib +else:unix: PRE_TARGETDEPS += $$PWD/res/libsodium.a diff --git a/src/addressbook.cpp b/src/addressbook.cpp index 64bc38e..c61e302 100644 --- a/src/addressbook.cpp +++ b/src/addressbook.cpp @@ -7,6 +7,7 @@ #include "mainwindow.h" #include "rpc.h" +extern bool isdragonx; AddressBookModel::AddressBookModel(QTableView *parent) : QAbstractTableModel(parent) { @@ -293,6 +294,9 @@ void AddressBook::writeToStorage() { QString AddressBook::writeableFile() { auto filename = QStringLiteral("addresslabels.dat"); + if (isdragonx) { + filename = QStringLiteral("addresslabels-drgx.dat"); + } auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); if (!dir.exists()) diff --git a/src/connection.cpp b/src/connection.cpp index b826496..ac536a6 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2022 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "connection.h" #include "mainwindow.h" @@ -9,6 +9,8 @@ #include "precompiled.h" #include "version.h" +extern bool isdragonx; + ConnectionLoader::ConnectionLoader(MainWindow* main, RPC* rpc) { qDebug() << __func__; this->main = main; @@ -92,11 +94,23 @@ void ConnectionLoader::doAutoConnect(bool tryEhushdStart) { "with SilentDragon\n\n." "Please remove the following line from your HUSH3.conf and restart SilentDragon\n" "daemon=1"); + if (isdragonx) { + explanation = QString() % QObject::tr("You have dragonxd set to start as a daemon, which can cause problems " + "with SilentDragonX\n\n." + "Please remove the following line from your DRAGONX.conf and restart SilentDragonX\n" + "daemon=1"); + } } else { explanation = QString() % QObject::tr("Couldn't start the embedded hushd.\n\n" "Please try restarting.\n\nIf you previously started hushd with custom arguments, you might need to reset HUSH3.conf.\n\n" "If all else fails, please run hushd manually.") % (ehushd ? QObject::tr("The process returned") + ":\n\n" % ehushd->errorString() : QString("")); + if(isdragonx) { + explanation = QString() % QObject::tr("Couldn't start the embedded dragonxd.\n\n" + "Please try restarting.\n\nIf you previously started hushd with custom arguments, you might need to reset DRAGONX.conf.\n\n" + "If all else fails, please run dragonxd manually.") % + (ehushd ? QObject::tr("The process returned") + ":\n\n" % ehushd->errorString() : QString("")); + } } this->showError(explanation); @@ -106,6 +120,11 @@ void ConnectionLoader::doAutoConnect(bool tryEhushdStart) { main->logger->write("Not using embedded and couldn't connect to hushd"); QString explanation = QString() % QObject::tr("Couldn't connect to hushd configured in HUSH3.conf.\n\n" "Not starting embedded hushd because --no-embedded was passed"); + if(isdragonx) { + main->logger->write("Not using embedded and couldn't connect to dragonxd"); + QString explanation = QString() % QObject::tr("Couldn't connect to dragonxd configured in DRAGONX.conf.\n\n" + "Not starting embedded dragonxd because --no-embedded was passed"); + } this->showError(explanation); } }); @@ -189,9 +208,9 @@ void ConnectionLoader::createHushConf() { QFile file(confLocation); if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { - main->logger->write("Could not create HUSH3.conf, returning"); + QString explanation = QString() % (isdragonx ? QObject::tr("Could not create DRAGONX.conf.") : QObject::tr("Could not create HUSH3.conf.") ); + main->logger->write(explanation); - QString explanation = QString() % QObject::tr("Could not create HUSH3.conf."); this->showError(explanation); return; } @@ -346,23 +365,27 @@ bool ConnectionLoader::startEmbeddedHushd() { #ifdef Q_OS_WIN64 auto hushdProgram = appPath.absoluteFilePath("hushd.exe"); + // params for DRGX are handled below #else auto hushdProgram = appPath.absoluteFilePath("hushd"); + if (isdragonx) { + hushdProgram = appPath.absoluteFilePath("dragonxd"); + } #endif //if (!QFile(hushdProgram).exists()) { if (!QFile::exists(hushdProgram)) { - qDebug() << "Can't find hushd at " << hushdProgram; - main->logger->write("Can't find hushd at " + hushdProgram); + qDebug() << "Can't find binary at " << hushdProgram; + main->logger->write("Can't find binary at " + hushdProgram); return false; } else { - qDebug() << "Found hushd at " << hushdProgram; - main->logger->write("Found hushd at " + hushdProgram); + qDebug() << "Found binary at " << hushdProgram; + main->logger->write("Found binary at " + hushdProgram); } ehushd = std::shared_ptr(new QProcess(main)); QObject::connect(ehushd.get(), &QProcess::started, [=] () { - qDebug() << "Embedded hushd started via " << hushdProgram; + qDebug() << "Embedded binary started via " << hushdProgram; }); QObject::connect(ehushd.get(), QOverload::of(&QProcess::finished), @@ -396,6 +419,10 @@ bool ConnectionLoader::startEmbeddedHushd() { qDebug() << "No ASN map file found"; } */ + if(isdragonx) { + // dragonxd bash script cannot be used on windows, so specify exact chain params + params += " -ac_name=DRAGONX -ac_algo=randomx -ac_halving=3500000 -ac_reward=300000000 -ac_blocktime=36 -ac_private=1 -addnode=176.126.87.241 "; + } QStringList arguments = params.split(" "); @@ -557,6 +584,21 @@ void ConnectionLoader::showError(QString explanation) { } QString ConnectionLoader::locateHushConfFile() { + + // HSC's have no legacy locations + if (isdragonx) { + auto ticker = "DRAGONX"; +#ifdef Q_OS_LINUX + auto confLocation = QStandardPaths::locate(QStandardPaths::HomeLocation, QString(".hush/") + ticker + "/" + ticker + ".conf"); +#elif defined(Q_OS_DARWIN) + auto confLocation = QStandardPaths::locate(QStandardPaths::HomeLocation, "Library/Application Support/Hush/HUSH3/HUSH3.conf"); +#else + auto confLocation = QStandardPaths::locate(QStandardPaths::AppDataLocation, "../../Hush/HUSH3/HUSH3.conf"); +#endif + qDebug() << "found conf at " << confLocation; + return QDir::cleanPath(confLocation); + } + #ifdef Q_OS_LINUX auto confLocation = QStandardPaths::locate(QStandardPaths::HomeLocation, ".hush/HUSH3/HUSH3.conf"); if(!QFile(confLocation).exists()) { @@ -585,10 +627,19 @@ QString ConnectionLoader::locateHushConfFile() { QString ConnectionLoader::hushConfWritableLocation() { #ifdef Q_OS_LINUX auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".hush/HUSH3/HUSH3.conf"); + if(isdragonx) { + confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".hush/DRAGONX/DRAGONX.conf"); + } #elif defined(Q_OS_DARWIN) auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath("Library/Application Support/Hush/HUSH3/HUSH3.conf"); + if(isdragonx) { + confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath("Library/Application Support/Hush/DRAGONX/DRAGONX.conf"); + } #else auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("../../Hush/HUSH3/HUSH3.conf"); + if(isdragonx) { + confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("../../Hush/DRAGONX/DRAGONX.conf"); + } #endif main->logger->write("HUSH3.conf writeable location at " + QDir::cleanPath(confLocation)); @@ -663,7 +714,8 @@ bool ConnectionLoader::verifyParams() { } /** - * Try to automatically detect a HUSH3/HUSH3.conf file in the correct location and load parameters + * Try to automatically detect a HUSH3/HUSH3.conf file + or DRAGONX/DRAGONX.conf in the correct location and load parameters */ std::shared_ptr ConnectionLoader::autoDetectHushConf() { auto confLocation = locateHushConfFile(); @@ -728,7 +780,13 @@ std::shared_ptr ConnectionLoader::autoDetectHushConf() { } // If rpcport is not in the file, and it was not set by the testnet=1 flag, then go to default - if (hushconf->port.isEmpty()) hushconf->port = "18031"; + if (hushconf->port.isEmpty()) { + if(isdragonx) { + hushconf->port = "21769"; + } else { + hushconf->port = "18031"; + } + } file.close(); // Save to Qsettings diff --git a/src/createhushconfdialog.ui b/src/createhushconfdialog.ui index 9306a67..07ff088 100644 --- a/src/createhushconfdialog.ui +++ b/src/createhushconfdialog.ui @@ -11,7 +11,7 @@ - Configure HUSH3.conf + Configuration diff --git a/src/main.cpp b/src/main.cpp index c4f4c57..ca3c873 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,8 @@ #include "settings.h" #include "version.h" +bool isdragonx = 0; + class SignalHandler { public: @@ -140,6 +142,14 @@ public: ~Application() {} int main(int argc, char *argv[]) { + fprintf(stderr,"%s: argv0 = %s\n", __func__, argv[0]); + QString binaryName(argv[0]); + QStringList pathParts = binaryName.split(QLatin1Char('/')); + qDebug() << pathParts; + + isdragonx = binaryName.endsWith("dragonx") || binaryName.endsWith("dragonx.exe"); + qDebug() << "isdragonx=" << isdragonx; + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); @@ -173,14 +183,18 @@ public: } QCoreApplication::setOrganizationName("Hush"); - QCoreApplication::setApplicationName("SilentDragon"); + QCoreApplication::setApplicationName(isdragonx ? "SilentDragonX" : "SilentDragon"); QString locale = QLocale::system().name(); locale.truncate(locale.lastIndexOf('_')); // Get the language code qDebug() << "Loading locale " << locale; QTranslator translator; - translator.load(QString(":/translations/res/silentdragon_") + locale); + if(isdragonx) { + translator.load(QString(":/translations/res-drgx/silentdragon_") + locale); + } else { + translator.load(QString(":/translations/res/silentdragon_") + locale); + } a.installTranslator(&translator); QIcon icon(":/icons/res/icon.ico"); @@ -218,7 +232,11 @@ public: } w = new MainWindow(); - w->setWindowTitle("SilentDragon v" + QString(APP_VERSION)); + if(isdragonx) { + w->setWindowTitle("SilentDragonX v" + QString(APP_VERSION)); + } else { + w->setWindowTitle("SilentDragon v" + QString(APP_VERSION)); + } // If there was a payment URI on the command line, pay it if (parser.positionalArguments().length() > 0) { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 84ff2f3..021e1cd 100755 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -24,6 +24,8 @@ #include "requestdialog.h" #include "websockets.h" +extern bool isdragonx; + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) @@ -42,7 +44,7 @@ MainWindow::MainWindow(QWidget *parent) : this->slot_change_theme(theme_name); ui->setupUi(this); - logger = new Logger(this, QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("SilentDragon.log")); + logger = new Logger(this, QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath(isdragonx ? "SilentDragonX.log" : "SilentDragon.log")); // Status Bar setupStatusBar(); @@ -52,7 +54,6 @@ MainWindow::MainWindow(QWidget *parent) : // Set up actions QObject::connect(ui->actionExit, &QAction::triggered, this, &MainWindow::close); - QObject::connect(ui->actionDonate, &QAction::triggered, this, &MainWindow::donate); QObject::connect(ui->actionTelegram, &QAction::triggered, this, &MainWindow::telegram); QObject::connect(ui->actionReportBug, &QAction::triggered, this, &MainWindow::reportbug); QObject::connect(ui->actionWebsite, &QAction::triggered, this, &MainWindow::website); @@ -527,7 +528,7 @@ void MainWindow::setupSettingsModal() { settings.rpcuser->setReadOnly(true); settings.rpcpassword->setReadOnly(true); } else { - settings.confMsg->setText("No local HUSH3.conf found. Please configure connection manually."); + settings.confMsg->setText("No " % hushConfLocation % " found. Please configure connection manually."); settings.hostname->setEnabled(true); settings.port->setEnabled(true); settings.rpcuser->setEnabled(true); @@ -789,33 +790,26 @@ void MainWindow::addressBook() { void MainWindow::telegram() { QString url = "https://hush.is/tg"; + if (isdragonx) { + url = "https://dragonx.is/tg"; + } QDesktopServices::openUrl(QUrl(url)); } void MainWindow::reportbug() { + // dragonx doesn't have it's own support, for now QString url = "https://hush.is/tg_support"; QDesktopServices::openUrl(QUrl(url)); } void MainWindow::website() { QString url = "https://hush.is"; + if (isdragonx) { + url = "https://dragonx.is"; + } QDesktopServices::openUrl(QUrl(url)); } -void MainWindow::donate() { - removeExtraAddresses(); - - ui->Address1->setText(Settings::getDonationAddr()); - ui->Address1->setCursorPosition(0); - ui->Amount1->setText("0.00"); - ui->MemoTxt1->setText(tr("Some feedback about SilentDragon or Hush...")); - - ui->statusBar->showMessage(tr("Send Duke some private and shielded feedback about ") % Settings::getTokenName() % tr(" or SilentDragon")); - - // And switch to the send tab. - ui->tabWidget->setCurrentIndex(1); -} - // Validate an address void MainWindow::validateAddress() { // Make sure everything is up and running @@ -940,6 +934,10 @@ void MainWindow::payHushURI(QString uri, QString myAddr) { if (uri.isEmpty()) { uri = QInputDialog::getText(this, tr("Paste HUSH URI"), "HUSH URI" + QString(" ").repeated(180)); + if(isdragonx) { + uri = QInputDialog::getText(this, tr("Paste DRGX URI"), + "DRGX URI" + QString(" ").repeated(180)); + } } // If there's no URI, just exit @@ -950,8 +948,13 @@ void MainWindow::payHushURI(QString uri, QString myAddr) { qDebug() << "Received URI " << uri; PaymentURI paymentInfo = Settings::parseURI(uri); if (!paymentInfo.error.isEmpty()) { - QMessageBox::critical(this, tr("Error paying Hush URI"), + if(isdragonx) { + QMessageBox::critical(this, tr("Error paying DragonX URI"), + tr("URI should be of the form 'drgx:?amt=x&memo=y") + "\n" + paymentInfo.error); + } else { + QMessageBox::critical(this, tr("Error paying Hush URI"), tr("URI should be of the form 'hush:?amt=x&memo=y") + "\n" + paymentInfo.error); + } return; } @@ -1404,6 +1407,29 @@ void MainWindow::setupBalancesTab() { }); } + menu.addAction(tr("Shield mining funds to default zaddr"), [=] () { + auto defaultZaddr = rpc->getDefaultSaplingAddress(); + QJsonArray params = QJsonArray {addr, defaultZaddr }; + qDebug() << "Calling shieldCoinbase with params=" << params; + rpc->shieldCoinbase(params, [=](const QJsonValue& reply) { + QString shieldingValue = reply.toObject()["shieldingValue"].toString(); + QString opid = reply.toObject()["opid"].toString(); + auto remainingUTXOs = reply.toObject()["remainingUTXOs"].toInt(); + qDebug() << "ShieldCoinbase reply=" << reply; + // By default we shield 50 blocks at a time + if(remainingUTXOs > 0) { + //TODO: more utxos to shield + } + ui->statusBar->showMessage(tr("Shielded") + shieldingValue + " HUSH in Mining funds to " + addr + " in opid " + opid, 3 * 1000); + }, [=](QString errStr) { + //error("", errStr); + qDebug() << "z_shieldcoinbase pooped:" << errStr; + if(errStr == "Could not find any coinbase funds to shield.") { + ui->statusBar->showMessage("No mining funds found to shield!"); + } + }); + }); + menu.addAction(tr("View on block explorer"), [=] () { QString url; auto explorer = Settings::getInstance()->getExplorer(); @@ -1435,6 +1461,7 @@ void MainWindow::setupBalancesTab() { //TODO: should this be kept? menu.addAction(tr("Convert Address"), [=] () { QString url; + // HUSH3 can be used for all HSC's since they all have the same address format url = "https://dexstats.info/addressconverter.php?fromcoin=HUSH3&address=" + addr; QDesktopServices::openUrl(QUrl(url)); }); @@ -1609,23 +1636,23 @@ void MainWindow::setupPeersTab() { }); /* - //grep 'BAN THRESHOLD EXCEEDED' ~/.komodo/HUSH3/debug.log + //grep 'BAN THRESHOLD EXCEEDED' ~/.hush/HUSH3/debug.log //grep Disconnected ... QFile debuglog = ""; #ifdef Q_OS_LINUX - debuglog = "~/.komodo/HUSH3/debug.log"; + debuglog = "~/.hush/HUSH3/debug.log"; #elif defined(Q_OS_DARWIN) - debuglog = "~/Library/Application Support/Komodo/HUSH3/debug.log"; + debuglog = "~/Library/Application Support/Hush/HUSH3/debug.log"; #elif defined(Q_OS_WIN64) // "C:/Users//AppData/Roaming/", // TODO: get current username - debuglog = "C:/Users//AppData/Roaming/Komodo/HUSH3/debug.log"; + debuglog = "C:/Users//AppData/Roaming/Hush/HUSH3/debug.log"; #else // Bless Your Heart, You Like Danger! // There are open bounties to port HUSH softtware to OpenBSD and friends: // git.hush.is/hush/tasks - debuglog = "~/.komodo/HUSH3/debug.log"; + debuglog = "~/.hush/HUSH3/debug.log"; #endif // Q_OS_LINUX if(debuglog.exists()) { @@ -1801,7 +1828,7 @@ void MainWindow::setupTransactionsTab() { */ // Payment Request - if (!memo.isEmpty() && memo.startsWith("hush:")) { + if (!memo.isEmpty() && memo.startsWith(isdragonx ? "drgx:" : "hush:")) { menu.addAction(tr("View Payment Request"), [=] () { RequestDialog::showPaymentConfirmation(this, memo); }); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 092ccdc..008acf1 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1061,7 +1061,7 @@ - <html><head/><body><p align="center"><span style=" font-weight:600;">Hush Market Information</span></p></body></html> + <html><head/><body><p align="center"><span style=" font-weight:600;">Market Information</span></p></body></html> @@ -1132,7 +1132,7 @@ - hushd + Node info @@ -1609,7 +1609,6 @@ &Help - @@ -1660,19 +1659,14 @@ Ctrl+P - - - &Send Duke Feedback - - - &Hush Telegram + &Telegram - &Hush Website + &Website @@ -1690,14 +1684,6 @@ &Export all private keys - - - &z-board.net - - - Ctrl+A, Ctrl+Z - - Address &book @@ -1718,7 +1704,7 @@ - Pay HUSH &URI... + Pay URI... @@ -1731,7 +1717,7 @@ - Request HUSH... + Request funds... diff --git a/src/requestdialog.cpp b/src/requestdialog.cpp index 2d37d41..10e26bc 100644 --- a/src/requestdialog.cpp +++ b/src/requestdialog.cpp @@ -7,8 +7,8 @@ #include "mainwindow.h" #include "rpc.h" #include "settings.h" - #include "precompiled.h" +extern bool isdragonx; RequestDialog::RequestDialog(QWidget *parent) : QDialog(parent), @@ -49,8 +49,13 @@ void RequestDialog::setupDialog(MainWindow* main, QDialog* d, Ui_RequestDialog* void RequestDialog::showPaymentConfirmation(MainWindow* main, QString paymentURI) { PaymentURI payInfo = Settings::parseURI(paymentURI); if (!payInfo.error.isEmpty()) { - QMessageBox::critical(main, tr("Error paying HUSH URI"), + if(isdragonx) { + QMessageBox::critical(main, tr("Error paying DRAGONX URI"), + tr("URI should be of the form 'drgx:?amt=x&memo=y") + "\n" + payInfo.error); + } else { + QMessageBox::critical(main, tr("Error paying HUSH URI"), tr("URI should be of the form 'hush:?amt=x&memo=y") + "\n" + payInfo.error); + } return; } @@ -126,11 +131,11 @@ void RequestDialog::showRequestZcash(MainWindow* main) { if (d.exec() == QDialog::Accepted) { // Construct a Hush Payment URI with the data and pay it immediately. - QString memoURI = "hush:" + req.cmbMyAddress->currentText() + QString memoURI = (isdragonx ? "drgx:" : "hush:" ) + req.cmbMyAddress->currentText() + "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble()) + "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText()); - QString sendURI = "hush:" + AddressBook::addressFromAddressLabel(req.txtFrom->text()) + QString sendURI = (isdragonx ? "drgx:" : "hush:" ) + AddressBook::addressFromAddressLabel(req.txtFrom->text()) + "?amt=0.0001" + "&memo=" + QUrl::toPercentEncoding(memoURI); diff --git a/src/requestdialog.ui b/src/requestdialog.ui index bd3139a..35f395b 100644 --- a/src/requestdialog.ui +++ b/src/requestdialog.ui @@ -216,7 +216,7 @@ - Request payment from a Sapling address. You'll send a HUSH 0.0001 transaction to the address with a HUSH payment URI. The memo will be included in the transaction when the address pays you. + Request payment from a zaddr. You'll send a 0.0001 transaction to the address with a payment URI. The memo will be included in the transaction when the address pays you. true diff --git a/src/rpc.cpp b/src/rpc.cpp index 5a1b5cc..42c0117 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -7,6 +7,8 @@ #include "version.h" #include "websockets.h" +extern bool isdragonx; + RPC::RPC(MainWindow* main) { auto cl = new ConnectionLoader(main, this); @@ -729,6 +731,10 @@ void RPC::getInfoThenRefresh(bool force) { int blocks_until_halving= 2020000 - curBlock; char halving_days[8]; int blocktime = 75; // seconds + if(isdragonx) { + blocks_until_halving= 3500000 - curBlock; + blocktime = 60; + } sprintf(halving_days, "%.2f", (double) (blocks_until_halving * blocktime) / (60*60*24) ); QString ntzhash = reply["notarizedhash"].toString(); QString ntztxid = reply["notarizedtxid"].toString(); @@ -776,7 +782,11 @@ void RPC::getInfoThenRefresh(bool force) { qint64 solrate = reply.toInt(); //TODO: format decimal - ui->solrate->setText(QString::number((double)solrate / 1000000) % " MegaSol/s"); + if(isdragonx) { + ui->solrate->setText(QString::number((double)solrate) % " Hash/s"); + } else { + ui->solrate->setText(QString::number((double)solrate / 1000000) % " MegaSol/s"); + } }); // Get network info @@ -833,14 +843,18 @@ void RPC::getInfoThenRefresh(bool force) { ui->heightLabel->setText(QObject::tr("Block height")); } - auto ticker_price = s->get_price(ticker); QString extra = ""; - if(ticker_price > 0 && ticker != "BTC") { - extra = QString::number( s->getBTCPrice() ) % "sat"; - } QString price = ""; - if (ticker_price > 0) { - price = QString(", ") % "HUSH" % "=" % QString::number( (double)ticker_price,'f',8) % " " % ticker % " " % extra; + + // No price data for dragonx for now + if (!isdragonx) { + auto ticker_price = s->get_price(ticker); + if(ticker_price > 0 && ticker != "BTC") { + extra = QString::number( s->getBTCPrice() ) % "sat"; + } + if (ticker_price > 0) { + price = QString(", ") % "HUSH" % "=" % QString::number( (double)ticker_price,'f',8) % " " % ticker % " " % extra; + } } // Update the status bar @@ -857,14 +871,13 @@ void RPC::getInfoThenRefresh(bool force) { auto hushPrice = Settings::getUSDFormat(1); QString tooltip; if (connections > 0) { - tooltip = QObject::tr("Connected to hushd"); - } - else { - tooltip = QObject::tr("hushd has no peer connections! Network issues?"); + tooltip = QObject::tr("Connected"); + } else { + tooltip = QObject::tr("No peer connections! Network issues?"); } tooltip = tooltip % "(v" % QString::number(Settings::getInstance()->getHushdVersion()) % ")"; - if (!hushPrice.isEmpty()) { + if (!isdragonx && !hushPrice.isEmpty()) { tooltip = "1 HUSH = " % hushPrice % "\n" % tooltip; } main->statusLabel->setToolTip(tooltip); @@ -1363,6 +1376,10 @@ void RPC::refreshPrice() { if (conn == nullptr) return noConnection(); + if (isdragonx) { + return; + } + auto s = Settings::getInstance(); if (s->getAllowFetchPrices() == false) { diff --git a/src/senttxstore.cpp b/src/senttxstore.cpp index e9f8505..407552d 100644 --- a/src/senttxstore.cpp +++ b/src/senttxstore.cpp @@ -3,9 +3,14 @@ #include "senttxstore.h" #include "settings.h" +extern bool isdragonx; + /// Get the location of the app data file to be written. QString SentTxStore::writeableFile() { auto filename = QStringLiteral("senttxstore.dat"); + if (isdragonx) { + filename = QStringLiteral("senttxstore-drgx.dat"); + } auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); if (!dir.exists()) diff --git a/src/settings.cpp b/src/settings.cpp index e3fd871..38947c6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -3,6 +3,8 @@ #include "mainwindow.h" #include "settings.h" +extern bool isdragonx; + Settings* Settings::instance = nullptr; Settings* Settings::init() { @@ -39,6 +41,10 @@ Explorer Settings::getExplorer() { //TODO: make it easy for people to use other explorers QString explorer = "https://explorer.hush.is"; + if(isdragonx) { + explorer = "https://explorer.dragonx.is"; + } + auto txExplorerUrl = s.value("explorer/txExplorerUrl", explorer + "/tx/").toString(); auto addressExplorerUrl = s.value("explorer/addressExplorerUrl", explorer + "/address/").toString(); @@ -328,6 +334,9 @@ QString Settings::getHUSHUSDDisplayFormat(double bal) { const QString Settings::txidStatusMessage = QString(QObject::tr("Transaction submitted (right click to copy) txid:")); QString Settings::getTokenName() { + if (isdragonx) { + return "DRGX"; + } if (Settings::getInstance()->isTestnet()) { return "TUSH"; } else { @@ -449,12 +458,26 @@ QString Settings::paymentURIPretty(PaymentURI uri) { PaymentURI Settings::parseURI(QString uri) { PaymentURI ans; - if (!uri.startsWith("hush:")) { - ans.error = "Not a HUSH payment URI"; - return ans; + auto proto=""; + if (isdragonx) { + proto ="drgx:"; + if (!uri.startsWith(proto % QString(":"))) { + ans.error = "Not a DRGX payment URI"; + return ans; + } + } else { + proto = "hush:"; + if (!uri.startsWith(proto % QString(":"))) { + ans.error = "Not a HUSH payment URI"; + return ans; + } } + uri = uri.right(uri.length() - QString("hush:").length()); + if(isdragonx) { + uri = uri.right(uri.length() - QString("drgx:").length()); + } QRegExp re("([a-zA-Z0-9]+)"); int pos; diff --git a/src/settings.ui b/src/settings.ui index e1cc096..5fd4fda 100644 --- a/src/settings.ui +++ b/src/settings.ui @@ -588,14 +588,14 @@ - Connect to the internet to fetch HUSH prices + Connect to the internet to fetch prices - Fetch HUSH prices + Fetch prices diff --git a/src/txtablemodel.cpp b/src/txtablemodel.cpp index f43e4ef..b1803c8 100644 --- a/src/txtablemodel.cpp +++ b/src/txtablemodel.cpp @@ -5,6 +5,8 @@ #include "rpc.h" #include "guiconstants.h" +extern bool isdragonx; + TxTableModel::TxTableModel(QObject *parent) : QAbstractTableModel(parent) { headers << QObject::tr("Type") << QObject::tr("Address") << QObject::tr("Date/Time") << QObject::tr("Amount"); @@ -195,14 +197,19 @@ int TxTableModel::columnCount(const QModelIndex&) const if (!dat.memo.isEmpty()) { // If the memo is a Payment URI, then show a payment request icon - if (dat.memo.startsWith("hush:")) { + if(isdragonx) { + if (dat.memo.startsWith("drgx:")) { + QIcon icon(":/icons/res-drgx/paymentreq.gif"); + return QVariant(icon.pixmap(16, 16)); + } + } else if (dat.memo.startsWith("hush:")) { QIcon icon(":/icons/res/paymentreq.gif"); return QVariant(icon.pixmap(16, 16)); - } else { - // Return the info pixmap to indicate memo - QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); - return QVariant(icon.pixmap(16, 16)); - } + } + + // Return the info pixmap to indicate memo + QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); + return QVariant(icon.pixmap(16, 16)); } else { // TODO: Add appropriate icons for types of txs instead of empty pixmap //qDebug() << "Type = " +getType(index.row()) + "Address = " +getAddr(index.row()) + "From Address = " +getFromAddr(index.row());