sweepprivkeydialog.cpp raw

   1  // Copyright (c) 2026-present The Limenka Knots developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <qt/sweepprivkeydialog.h>
   6  #include <qt/forms/ui_sweepprivkeydialog.h>
   7  
   8  #include <qt/guiutil.h>
   9  #include <qt/walletmodel.h>
  10  
  11  #include <interfaces/node.h>
  12  #include <interfaces/wallet.h>
  13  #include <univalue.h>
  14  
  15  #include <QMessageBox>
  16  #include <QUrl>
  17  
  18  SweepPrivKeyDialog::SweepPrivKeyDialog(QWidget *parent) :
  19      QDialog(parent, GUIUtil::dialog_flags),
  20      ui(new Ui::SweepPrivKeyDialog)
  21  {
  22      ui->setupUi(this);
  23      ui->privkeyEdit->setUndoRedoEnabled(false);
  24      connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::close);
  25      connect(this, &SweepPrivKeyDialog::sweepComplete, this, &SweepPrivKeyDialog::handleResult);
  26  }
  27  
  28  SweepPrivKeyDialog::~SweepPrivKeyDialog()
  29  {
  30      if (m_sweep_thread.joinable()) {
  31          m_sweep_thread.join();
  32      }
  33      ui->privkeyEdit->setPlainText(QString(ui->privkeyEdit->toPlainText().size(), '\0'));
  34      delete ui;
  35  }
  36  
  37  void SweepPrivKeyDialog::setModel(WalletModel *_model)
  38  {
  39      this->model = _model;
  40      if (!_model) return;
  41  
  42      ui->walletSelector->clear();
  43      const std::string current_name = _model->getWalletName().toStdString();
  44      for (auto& wallet : _model->node().walletLoader().getWallets()) {
  45          const std::string name = wallet->getWalletName();
  46          ui->walletSelector->addItem(name.empty() ? tr("[default wallet]") : QString::fromStdString(name),
  47                                      QString::fromStdString(name));
  48          if (name == current_name) {
  49              ui->walletSelector->setCurrentIndex(ui->walletSelector->count() - 1);
  50          }
  51      }
  52      const bool multi = ui->walletSelector->count() > 1;
  53      ui->walletSelector->setVisible(multi);
  54      ui->walletLabel->setVisible(multi);
  55  }
  56  
  57  void SweepPrivKeyDialog::reject()
  58  {
  59      on_clearButton_clicked();
  60      QDialog::reject();
  61  }
  62  
  63  void SweepPrivKeyDialog::on_sweepButton_clicked()
  64  {
  65      if (!model) return;
  66  
  67      QString keyText = ui->privkeyEdit->toPlainText().trimmed();
  68      if (keyText.isEmpty()) {
  69          ui->statusLabel->setText(tr("Please enter at least one private key."));
  70          return;
  71      }
  72  
  73      QStringList keyLines = keyText.split('\n', Qt::SkipEmptyParts);
  74      UniValue privkeys(UniValue::VARR);
  75      for (const QString& line : keyLines) {
  76          QString trimmed = line.trimmed();
  77          if (!trimmed.isEmpty()) {
  78              privkeys.push_back(trimmed.toStdString());
  79              trimmed.fill('\0');
  80          }
  81      }
  82      keyText.fill('\0');
  83  
  84      if (privkeys.empty()) {
  85          ui->statusLabel->setText(tr("Please enter at least one private key."));
  86          return;
  87      }
  88  
  89      UniValue options(UniValue::VOBJ);
  90      options.pushKV("privkeys", privkeys);
  91  
  92      QString label = ui->labelEdit->text().trimmed();
  93      if (!label.isEmpty()) {
  94          options.pushKV("label", label.toStdString());
  95      }
  96  
  97      UniValue params(UniValue::VARR);
  98      params.push_back(options);
  99  
 100      const QString selectedName = ui->walletSelector->currentData().toString();
 101      QByteArray encodedName = QUrl::toPercentEncoding(selectedName);
 102      std::string uri = "/wallet/" + std::string(encodedName.constData(), encodedName.length());
 103  
 104      ui->sweepButton->setEnabled(false);
 105      ui->closeButton->setEnabled(false);
 106      ui->statusLabel->setText(tr("Sweeping..."));
 107  
 108      if (m_sweep_thread.joinable()) {
 109          m_sweep_thread.join();
 110      }
 111  
 112      const QString sweep_failed = tr("Sweep failed");
 113      WalletModel* m = model;
 114      m_sweep_thread = std::thread([this, m, params, uri, sweep_failed]() {
 115          try {
 116              UniValue result = m->node().executeRpc("sweepprivkeys", params, uri);
 117              QString txid = QString::fromStdString(result.get_str());
 118              Q_EMIT sweepComplete(true, txid);
 119          } catch (const UniValue& e) {
 120              QString errorMsg;
 121              if (e.isObject() && e.exists("message")) {
 122                  errorMsg = QString::fromStdString(e["message"].get_str());
 123              } else {
 124                  errorMsg = sweep_failed;
 125              }
 126              Q_EMIT sweepComplete(false, errorMsg);
 127          } catch (const std::exception&) {
 128              Q_EMIT sweepComplete(false, sweep_failed);
 129          }
 130      });
 131  }
 132  
 133  void SweepPrivKeyDialog::handleResult(bool success, const QString& message)
 134  {
 135      if (m_sweep_thread.joinable()) {
 136          m_sweep_thread.join();
 137      }
 138  
 139      if (success) {
 140          ui->statusLabel->setText(tr("Success! Transaction ID: %1").arg(message));
 141          QMessageBox::information(this, tr("Sweep Successful"),
 142              tr("Coins swept successfully.\n\nTransaction ID:\n%1").arg(message));
 143          on_clearButton_clicked();
 144      } else {
 145          ui->statusLabel->setText(tr("Error: %1").arg(message));
 146      }
 147  
 148      ui->sweepButton->setEnabled(true);
 149      ui->closeButton->setEnabled(true);
 150  }
 151  
 152  void SweepPrivKeyDialog::on_clearButton_clicked()
 153  {
 154      ui->privkeyEdit->setPlainText(QString(ui->privkeyEdit->toPlainText().size(), '\0'));
 155      ui->privkeyEdit->clear();
 156      ui->labelEdit->clear();
 157      ui->statusLabel->clear();
 158  }
 159