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