Compare commits
1 Commits
master
...
fix-rpath-
Author | SHA1 | Date |
---|---|---|
dsc | 6745f49e8f | 4 years ago |
@ -1 +0,0 @@
|
||||
Subproject commit 470c4316460bb8c3e23bfa37c79c8621ef3f1b4c
|
@ -1 +1 @@
|
||||
Subproject commit a6bf6dbb8f1637ccffee1a30d2285324a3ce4d66
|
||||
Subproject commit a1404e92cb439ba0f120e7c4a579ed0b9a0372a4
|
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 955 B |
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file>assets/exec/tor</file>
|
||||
<file>tor/tor</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file>tor/tor</file>
|
||||
<file>tor/libevent-2.1.7.dylib</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -1,6 +0,0 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file>assets/exec/tor</file>
|
||||
<file>assets/exec/libevent-2.1.7.dylib</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file>assets/exec/xmrig</file>
|
||||
<file>tor/tor.exe</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -1,62 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include "broadcasttxdialog.h"
|
||||
#include "ui_broadcasttxdialog.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx)
|
||||
: QDialog(parent)
|
||||
, m_ctx(ctx)
|
||||
, ui(new Ui::BroadcastTxDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_network = new UtilsNetworking(m_ctx->network, this);
|
||||
|
||||
auto node = ctx->nodes->connection();
|
||||
m_rpc = new DaemonRpc(this, m_network, node.full);
|
||||
|
||||
connect(ui->btn_Broadcast, &QPushButton::clicked, this, &BroadcastTxDialog::broadcastTx);
|
||||
connect(ui->btn_Close, &QPushButton::clicked, this, &BroadcastTxDialog::reject);
|
||||
|
||||
connect(m_rpc, &DaemonRpc::ApiResponse, this, &BroadcastTxDialog::onApiResponse);
|
||||
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void BroadcastTxDialog::broadcastTx() {
|
||||
QString tx = ui->transaction->toPlainText();
|
||||
|
||||
QString node = [this]{
|
||||
QString node;
|
||||
if (ui->radio_useCustom->isChecked())
|
||||
node = ui->customNode->text();
|
||||
else
|
||||
node = m_ctx->nodes->connection().full;
|
||||
|
||||
if (!node.startsWith("http://"))
|
||||
node = QString("http://%1").arg(node);
|
||||
return node;
|
||||
}();
|
||||
|
||||
m_rpc->setDaemonAddress(node);
|
||||
m_rpc->sendRawTransaction(tx);
|
||||
}
|
||||
|
||||
void BroadcastTxDialog::onApiResponse(const DaemonRpc::DaemonResponse &resp) {
|
||||
if (!resp.ok) {
|
||||
QMessageBox::warning(this, "Transaction broadcast", resp.status);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp.endpoint == DaemonRpc::Endpoint::SEND_RAW_TRANSACTION) {
|
||||
QMessageBox::information(this, "Transaction broadcast", "Transaction submitted successfully.\n\n"
|
||||
"If the transaction belongs to this wallet it may take several minutes before it shows up in the history tab.");
|
||||
}
|
||||
}
|
||||
|
||||
BroadcastTxDialog::~BroadcastTxDialog() {
|
||||
delete ui;
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_BROADCASTTXDIALOG_H
|
||||
#define FEATHER_BROADCASTTXDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "appcontext.h"
|
||||
#include "utils/daemonrpc.h"
|
||||
|
||||
namespace Ui {
|
||||
class BroadcastTxDialog;
|
||||
}
|
||||
|
||||
class BroadcastTxDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BroadcastTxDialog(QWidget *parent, AppContext *ctx);
|
||||
~BroadcastTxDialog() override;
|
||||
|
||||
private slots:
|
||||
void broadcastTx();
|
||||
void onApiResponse(const DaemonRpc::DaemonResponse &resp);
|
||||
|
||||
private:
|
||||
Ui::BroadcastTxDialog *ui;
|
||||
UtilsNetworking *m_network;
|
||||
AppContext *m_ctx;
|
||||
DaemonRpc *m_rpc;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_BROADCASTTXDIALOG_H
|
@ -1,111 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BroadcastTxDialog</class>
|
||||
<widget class="QDialog" name="BroadcastTxDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>797</width>
|
||||
<height>575</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Broadcast transaction</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Transaction:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="transaction">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Paste hex encoded signed tx string here</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Node</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio_useDefault">
|
||||
<property name="text">
|
||||
<string>Use currently connected node</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio_useCustom">
|
||||
<property name="text">
|
||||
<string>Use custom node</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="customNode"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>All transactions are broadcast over Tor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_Broadcast">
|
||||
<property name="text">
|
||||
<string>Broadcast</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_Close">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,186 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include "txconfadvdialog.h"
|
||||
#include "ui_txconfadvdialog.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "qrcode/QrCode.h"
|
||||
#include "dialog/qrcodedialog.h"
|
||||
#include "utils/utils.h"
|
||||
#include "libwalletqt/PendingTransactionInfo.h"
|
||||
#include "libwalletqt/Transfer.h"
|
||||
#include "libwalletqt/Input.h"
|
||||
#include "model/ModelUtils.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
TxConfAdvDialog::TxConfAdvDialog(AppContext *ctx, const QString &description, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::TxConfAdvDialog)
|
||||
, m_ctx(ctx)
|
||||
, m_exportUnsignedMenu(new QMenu(this))
|
||||
, m_exportSignedMenu(new QMenu(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_exportUnsignedMenu->addAction("Copy to clipboard", this, &TxConfAdvDialog::unsignedCopy);
|
||||
m_exportUnsignedMenu->addAction("Show as QR code", this, &TxConfAdvDialog::unsignedQrCode);
|
||||
m_exportUnsignedMenu->addAction("Save to file", this, &TxConfAdvDialog::unsignedSaveFile);
|
||||
ui->btn_exportUnsigned->setMenu(m_exportUnsignedMenu);
|
||||
|
||||
m_exportSignedMenu->addAction("Copy to clipboard", this, &TxConfAdvDialog::signedCopy);
|
||||
m_exportSignedMenu->addAction("Save to file", this, &TxConfAdvDialog::signedSaveFile);
|
||||
ui->btn_exportSigned->setMenu(m_exportSignedMenu);
|
||||
|
||||
if (m_ctx->currentWallet->viewOnly()) {
|
||||
ui->btn_exportSigned->hide();
|
||||
ui->btn_send->hide();
|
||||
}
|
||||
|
||||
ui->label_description->setText(QString("Description: %1").arg(description));
|
||||
|
||||
connect(ui->btn_sign, &QPushButton::clicked, this, &TxConfAdvDialog::signTransaction);
|
||||
connect(ui->btn_send, &QPushButton::clicked, this, &TxConfAdvDialog::broadcastTransaction);
|
||||
connect(ui->btn_close, &QPushButton::clicked, this, &TxConfAdvDialog::closeDialog);
|
||||
|
||||
ui->inputs->setFont(ModelUtils::getMonospaceFont());
|
||||
ui->outputs->setFont(ModelUtils::getMonospaceFont());
|
||||
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::setTransaction(PendingTransaction *tx) {
|
||||
ui->btn_sign->hide();
|
||||
|
||||
m_tx = tx;
|
||||
m_tx->refresh();
|
||||
PendingTransactionInfo *ptx = m_tx->transaction(0);
|
||||
|
||||
ui->txid->setText(tx->txid().first());
|
||||
|
||||
ui->amount->setText(WalletManager::displayAmount(tx->amount()));
|
||||
ui->fee->setText(WalletManager::displayAmount(ptx->fee()));
|
||||
ui->total->setText(WalletManager::displayAmount(tx->amount() + ptx->fee()));
|
||||
|
||||
auto size_str = [this]{
|
||||
if (m_ctx->currentWallet->viewOnly()) {
|
||||
return QString("Size: %1 bytes (unsigned)").arg(QString::number(m_tx->unsignedTxToBin().size()));
|
||||
} else {
|
||||
auto size = m_tx->signedTxToHex(0).size() / 2;
|
||||
return QString("Size: %1 bytes (%2 bytes unsigned)").arg(QString::number(size), QString::number(m_tx->unsignedTxToBin().size()));
|
||||
}
|
||||
}();
|
||||
ui->label_size->setText(size_str);
|
||||
|
||||
this->setupConstructionData(ptx);
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::setUnsignedTransaction(UnsignedTransaction *utx) {
|
||||
m_utx = utx;
|
||||
m_utx->refresh();
|
||||
|
||||
ui->btn_exportUnsigned->hide();
|
||||
ui->btn_exportSigned->hide();
|
||||
ui->btn_sign->show();
|
||||
ui->btn_send->hide();
|
||||
|
||||
ui->txid->setText("n/a");
|
||||
ui->label_size->setText("Size: n/a");
|
||||
|
||||
ui->amount->setText(WalletManager::displayAmount(utx->amount(0)));
|
||||
ui->fee->setText(WalletManager::displayAmount(utx->fee(0)));
|
||||
ui->total->setText(WalletManager::displayAmount(utx->amount(0) + utx->fee(0)));
|
||||
|
||||
ConstructionInfo *ci = m_utx->constructionInfo(0);
|
||||
this->setupConstructionData(ci);
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::setupConstructionData(ConstructionInfo *ci) {
|
||||
QString inputs_str;
|
||||
auto inputs = ci->inputs();
|
||||
for (const auto& i: inputs) {
|
||||
inputs_str += QString("%1 %2\n").arg(i->pubKey(), WalletManager::displayAmount(i->amount()));
|
||||
}
|
||||
ui->inputs->setText(inputs_str);
|
||||
ui->label_inputs->setText(QString("Inputs (%1)").arg(QString::number(inputs.size())));
|
||||
|
||||
QString outputs_str;
|
||||
auto outputs = ci->outputs();
|
||||
for (const auto& o: outputs) {
|
||||
outputs_str += QString("%1 %2\n").arg(o->address(), WalletManager::displayAmount(o->amount()));
|
||||
}
|
||||
ui->outputs->setText(outputs_str);
|
||||
ui->label_outputs->setText(QString("Outputs (%1)").arg(QString::number(outputs.size())));
|
||||
|
||||
ui->label_ringSize->setText(QString("Ring size: %1").arg(QString::number(ci->minMixinCount() + 1)));
|
||||
ui->label_unlockTime->setText(QString("Unlock time: %1 (height)").arg(QString::number(ci->unlockTime())));
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::signTransaction() {
|
||||
QString defaultName = QString("%1_signed_monero_tx").arg(QString::number(QDateTime::currentSecsSinceEpoch()));
|
||||
QString fn = QFileDialog::getSaveFileName(this, "Save signed transaction to file", QDir::home().filePath(defaultName), "Transaction (*signed_monero_tx)");
|
||||
if(fn.isEmpty()) return;
|
||||
|
||||
m_utx->sign(fn) ? QMessageBox::information(this, "Sign transaction", "Transaction saved successfully")
|
||||
: QMessageBox::warning(this, "Sign transaction", "Failes to save transaction to file.");
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::unsignedSaveFile() {
|
||||
QString defaultName = QString("%1_unsigned_monero_tx").arg(QString::number(QDateTime::currentSecsSinceEpoch()));
|
||||
QString fn = QFileDialog::getSaveFileName(this, "Save transaction to file", QDir::home().filePath(defaultName), "Transaction (*unsigned_monero_tx)");
|
||||
if(fn.isEmpty()) return;
|
||||
|
||||
m_tx->saveToFile(fn) ? QMessageBox::information(this, "Transaction saved to file", "Transaction saved successfully")
|
||||
: QMessageBox::warning(this, "Save transaction", "Failed to save transaction to file.");
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::signedSaveFile() {
|
||||
QString defaultName = QString("%1_signed_monero_tx").arg(QString::number(QDateTime::currentSecsSinceEpoch()));
|
||||
QString fn = QFileDialog::getSaveFileName(this, "Save transaction to file", QDir::home().filePath(defaultName), "Transaction (*signed_monero_tx)");
|
||||
if(fn.isEmpty()) return;
|
||||
|
||||
m_tx->saveToFile(fn) ? QMessageBox::information(this, "Transaction saved to file", "Transaction saved successfully")
|
||||
: QMessageBox::warning(this, "Save transaction", "Failed to save transaction to file.");
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::unsignedQrCode() {
|
||||
if (m_tx->unsignedTxToBin().size() > 2953) {
|
||||
QMessageBox::warning(this, "Unable to show QR code", "Transaction size exceeds the maximum size for QR codes (2953 bytes).");
|
||||
return;
|
||||
}
|
||||
|
||||
QrCode qr(m_tx->unsignedTxToBin(), QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::LOW);
|
||||
auto *dialog = new QrCodeDialog(this, qr, "Unsigned Transaction");
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::unsignedCopy() {
|
||||
Utils::copyToClipboard(m_tx->unsignedTxToBase64());
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::signedCopy() {
|
||||
Utils::copyToClipboard(m_tx->signedTxToHex(0));
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::signedQrCode() {
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::broadcastTransaction() {
|
||||
if (m_tx == nullptr) return;
|
||||
m_ctx->currentWallet->commitTransactionAsync(m_tx);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void TxConfAdvDialog::closeDialog() {
|
||||
if (m_tx != nullptr)
|
||||
m_ctx->currentWallet->disposeTransaction(m_tx);
|
||||
if (m_utx != nullptr)
|
||||
m_ctx->currentWallet->disposeTransaction(m_utx);
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
TxConfAdvDialog::~TxConfAdvDialog() {
|
||||
delete ui;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_TXCONFADVDIALOG_H
|
||||
#define FEATHER_TXCONFADVDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QStandardItemModel>
|
||||
#include <QAbstractButton>
|
||||
#include <QMenu>
|
||||
|
||||
#include "libwalletqt/PendingTransaction.h"
|
||||
#include "appcontext.h"
|
||||
|
||||
namespace Ui {
|
||||
class TxConfAdvDialog;
|
||||
}
|
||||
|
||||
class TxConfAdvDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TxConfAdvDialog(AppContext *ctx, const QString &description, QWidget *parent = nullptr);
|
||||
~TxConfAdvDialog() override;
|
||||
|
||||
void setTransaction(PendingTransaction *tx);
|
||||
void setUnsignedTransaction(UnsignedTransaction *utx);
|
||||
|
||||
private:
|
||||
void setupConstructionData(ConstructionInfo *ci);
|
||||
void signTransaction();
|
||||
void broadcastTransaction();
|
||||
void closeDialog();
|
||||
|
||||
void unsignedCopy();
|
||||
void unsignedQrCode();
|
||||
void unsignedSaveFile();
|
||||
|
||||
void signedCopy();
|
||||
void signedQrCode();
|
||||
void signedSaveFile();
|
||||
|
||||
Ui::TxConfAdvDialog *ui;
|
||||
AppContext *m_ctx;
|
||||
PendingTransaction *m_tx = nullptr;
|
||||
UnsignedTransaction *m_utx = nullptr;
|
||||
QMenu *m_exportUnsignedMenu;
|
||||
QMenu *m_exportSignedMenu;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //FEATHER_TXCONFADVDIALOG_H
|
@ -1,279 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TxConfAdvDialog</class>
|
||||
<widget class="QDialog" name="TxConfAdvDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>800</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Transaction</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Transaction ID:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txid">
|
||||
<property name="text">
|
||||
<string>txid</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_amount">
|
||||
<property name="text">
|
||||
<string>Amount: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="amount">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_fee">
|
||||
<property name="text">
|
||||
<string>Fee: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="fee">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Total:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="total">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_description">
|
||||
<property name="text">
|
||||
<string>Description:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_size">
|
||||
<property name="text">
|
||||
<string>Size: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_unlockTime">
|
||||
<property name="text">
|
||||
<string>Unlock time: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_ringSize">
|
||||
<property name="text">
|
||||
<string>Ringsize:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_inputs">
|
||||
<property name="text">
|
||||
<string>Inputs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="inputs">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_outputs">
|
||||
<property name="text">
|
||||
<string>Outputs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="outputs">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QToolButton" name="btn_exportUnsigned">
|
||||
<property name="text">
|
||||
<string>Export unsigned</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btn_exportSigned">
|
||||
<property name="text">
|
||||
<string>Export signed</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_sign">
|
||||
<property name="text">
|
||||
<string>Sign</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_send">
|
||||
<property name="text">
|
||||
<string>Send</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_close">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,59 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "viewonlydialog.h"
|
||||
#include "ui_viewonlydialog.h"
|
||||
|
||||
ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::ViewOnlyDialog), m_ctx(ctx)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight()));
|
||||
ui->label_primaryAddress->setText(ctx->currentWallet->address(0, 0));
|
||||
ui->label_secretViewKey->setText(ctx->currentWallet->getSecretViewKey());
|
||||
|
||||
connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboad);
|
||||
connect(ui->btn_Save, &QPushButton::clicked, this, &ViewOnlyDialog::onWriteViewOnlyWallet);
|
||||
|
||||
ui->btn_Save->setEnabled(!m_ctx->currentWallet->viewOnly());
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void ViewOnlyDialog::onWriteViewOnlyWallet(){
|
||||
QString fn = QFileDialog::getSaveFileName(this, "Save .keys wallet file", QDir::homePath(), "Monero wallet (*.keys)");
|
||||
if(fn.isEmpty()) return;
|
||||
if(!fn.endsWith(".keys")) fn += ".keys";
|
||||
|
||||
QString passwd;
|
||||
QInputDialog passwordDialog(this);
|
||||
passwordDialog.setInputMode(QInputDialog::TextInput);
|
||||
passwordDialog.setTextEchoMode(QLineEdit::Password);
|
||||
passwordDialog.setWindowTitle("View-Only wallet password");
|
||||
passwordDialog.setLabelText("Protect this view-only wallet with a password?");
|
||||
passwordDialog.resize(300, 100);
|
||||
if((bool)passwordDialog.exec())
|
||||
passwd = passwordDialog.textValue();
|
||||
|
||||
m_ctx->currentWallet->createViewOnly(fn, passwd);
|
||||
|
||||
QMessageBox::information(this, "Information", "View-only wallet successfully written to disk.");
|
||||
}
|
||||
|
||||
void ViewOnlyDialog::copyToClipboad() {
|
||||
QString text = "";
|
||||
text += QString("Address: %1\n").arg(ui->label_primaryAddress->text());
|
||||
text += QString("Secret view key: %1\n").arg(ui->label_secretViewKey->text());
|
||||
text += QString("Restore height: %1\n").arg(ui->label_restoreHeight->text());
|
||||
Utils::copyToClipboard(text);
|
||||
}
|
||||
|
||||
ViewOnlyDialog::~ViewOnlyDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_VIEWONLYDIALOG_H
|
||||
#define FEATHER_VIEWONLYDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "appcontext.h"
|
||||
|
||||
namespace Ui {
|
||||
class ViewOnlyDialog;
|
||||
}
|
||||
|
||||
class ViewOnlyDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ViewOnlyDialog(AppContext *ctx, QWidget *parent = nullptr);
|
||||
~ViewOnlyDialog() override;
|
||||
|
||||
private slots:
|
||||
void onWriteViewOnlyWallet();
|
||||
|
||||
private:
|
||||
Ui::ViewOnlyDialog *ui;
|
||||
AppContext *m_ctx = nullptr;
|
||||
void copyToClipboad();
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_KEYSDIALOG_H
|
@ -1,139 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ViewOnlyDialog</class>
|
||||
<widget class="QDialog" name="ViewOnlyDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>659</width>
|
||||
<height>254</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>View-Only</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>Restore height</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_restoreHeight">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Primary address</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_primaryAddress">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Secret view key</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_secretViewKey">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_Copy">
|
||||
<property name="text">
|
||||
<string>Copy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_Save">
|
||||
<property name="text">
|
||||
<string>Create view-only wallet</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ViewOnlyDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ViewOnlyDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -1,14 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_GLOBALS_H
|
||||
#define FEATHER_GLOBALS_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace globals
|
||||
{
|
||||
const qreal cdiv = 1e12;
|
||||
}
|
||||
|
||||
#endif //FEATHER_GLOBALS_H
|
@ -1,53 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2014-2020, The Monero Project.
|
||||
|
||||
#include "ConstructionInfo.h"
|
||||
|
||||
#include "Input.h"
|
||||
#include "Transfer.h"
|
||||
|
||||
quint64 ConstructionInfo::unlockTime() const {
|
||||
return m_unlockTime;
|
||||
}
|
||||
|
||||
QSet<quint32> ConstructionInfo::subaddressIndices() const {
|
||||
return m_subaddressIndices;
|
||||
}
|
||||
|
||||
QVector<QString> ConstructionInfo::subaddresses() const {
|
||||
return m_subaddresses;
|
||||
}
|
||||
|
||||
quint64 ConstructionInfo::minMixinCount() const {
|
||||
return m_minMixinCount;
|
||||
}
|
||||
|
||||
QList<Input *> ConstructionInfo::inputs() const {
|
||||
return m_inputs;
|
||||
}
|
||||
|
||||
QList<Transfer *> ConstructionInfo::outputs() const {
|
||||
return m_outputs;
|
||||
}
|
||||
|
||||
ConstructionInfo::ConstructionInfo(const Monero::TransactionConstructionInfo *pimpl, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_unlockTime(pimpl->unlockTime())
|
||||
, m_minMixinCount(pimpl->minMixinCount())
|
||||
{
|
||||
for (auto const &i : pimpl->inputs())
|
||||
{
|
||||
Input *input = new Input(i.amount, QString::fromStdString(i.pubkey), this);
|
||||
m_inputs.append(input);
|
||||
}
|
||||
|
||||
for (auto const &o : pimpl->outputs())
|
||||
{
|
||||
Transfer *output = new Transfer(o.amount, QString::fromStdString(o.address), this);
|
||||
m_outputs.append(output);
|
||||
}
|
||||
for (uint32_t i : pimpl->subaddressIndices())
|
||||
{
|
||||
m_subaddressIndices.insert(i);
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2014-2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_CONSTRUCTIONINFO_H
|
||||
#define FEATHER_CONSTRUCTIONINFO_H
|
||||
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
|
||||
class Input;
|
||||
class Transfer;
|
||||
|
||||
class ConstructionInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(quint64 unlockTime READ unlockTime)
|
||||
Q_PROPERTY(QSet<quint32> subaddressIndices READ subaddressIndices)
|
||||
Q_PROPERTY(QVector<QString> subaddresses READ subaddresses)
|
||||
Q_PROPERTY(quint64 minMixinCount READ minMixinCount)
|
||||
Q_PROPERTY(QList<Input*> inputs READ inputs)
|
||||
Q_PROPERTY(QList<Transfer*> outputs READ outputs)
|
||||
|
||||
public:
|
||||
quint64 unlockTime() const;
|
||||
QSet<quint32> subaddressIndices() const;
|
||||
QVector<QString> subaddresses() const;
|
||||
quint64 minMixinCount() const;
|
||||
QList<Input*> inputs() const;
|
||||
QList<Transfer*> outputs() const;
|
||||
|
||||
private:
|
||||
explicit ConstructionInfo(const Monero::TransactionConstructionInfo *pimpl, QObject *parent = nullptr);
|
||||
|
||||
friend class PendingTransactionInfo;
|
||||
friend class UnsignedTransaction;
|
||||
quint64 m_unlockTime;
|
||||
QSet<quint32> m_subaddressIndices;
|
||||
QVector<QString> m_subaddresses;
|
||||
quint64 m_minMixinCount;
|
||||
mutable QList<Input*> m_inputs;
|
||||
mutable QList<Transfer*> m_outputs;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_CONSTRUCTIONINFO_H
|
@ -1,29 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2014-2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_INPUT_H
|
||||
#define FEATHER_INPUT_H
|
||||
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include <QObject>
|
||||
#include <utility>
|
||||
|
||||
class Input : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(quint64 amount READ amount)
|
||||
Q_PROPERTY(QString pubKey READ pubKey)
|
||||
|
||||
private:
|
||||
explicit Input(uint64_t _amount, QString _address, QObject *parent = nullptr): QObject(parent), m_amount(_amount), m_pubkey(std::move(_address)) {};
|
||||
|
||||
friend class ConstructionInfo;
|
||||
quint64 m_amount;
|
||||
QString m_pubkey;
|
||||
public:
|
||||
quint64 amount() const { return m_amount; }
|
||||
QString pubKey() const { return m_pubkey; }
|
||||
|
||||
};
|
||||
|
||||
#endif //FEATHER_INPUT_H
|
@ -1,32 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2014-2020, The Monero Project.
|
||||
|
||||
#include "PendingTransactionInfo.h"
|
||||
#include "Input.h"
|
||||
#include "Transfer.h"
|
||||
|
||||
quint64 PendingTransactionInfo::fee() const {
|
||||
return m_fee;
|
||||
}
|
||||
|
||||
quint64 PendingTransactionInfo::dust() const {
|
||||
return m_dust;
|
||||
}
|
||||
|
||||
bool PendingTransactionInfo::dustAddedToFee() const {
|
||||
return m_dustAddedToFee;
|
||||
}
|
||||
|
||||
QString PendingTransactionInfo::txKey() const {
|
||||
return m_txKey;
|
||||
}
|
||||
|
||||
PendingTransactionInfo::PendingTransactionInfo(const Monero::PendingTransactionInfo *pimpl, QObject *parent)
|
||||
: ConstructionInfo(pimpl->constructionData(), parent)
|
||||
, m_fee(pimpl->fee())
|
||||
, m_dust(pimpl->dust())
|
||||
, m_dustAddedToFee(pimpl->dustAddedToFee())
|
||||
, m_txKey(QString::fromStdString(pimpl->txKey()))
|
||||
{
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2014-2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_PENDINGTRANSACTIONINFO_H
|
||||
#define FEATHER_PENDINGTRANSACTIONINFO_H
|
||||
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include "ConstructionInfo.h"
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
|
||||
class Input;
|
||||
class Transfer;
|
||||
|
||||
class PendingTransactionInfo : public ConstructionInfo
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(quint64 fee READ fee)
|
||||
Q_PROPERTY(quint64 dust READ dust)
|
||||
Q_PROPERTY(bool dustAddedToFee READ dustAddedToFee)
|
||||
Q_PROPERTY(QString txKey READ txKey)
|
||||
Q_PROPERTY(quint64 unlockTime READ unlockTime)
|
||||
Q_PROPERTY(QSet<quint32> subaddressIndices READ subaddressIndices)
|
||||
Q_PROPERTY(QVector<QString> subaddresses READ subaddresses)
|
||||
Q_PROPERTY(quint64 minMixinCount READ minMixinCount)
|
||||
Q_PROPERTY(QList<Input*> inputs READ inputs)
|
||||
Q_PROPERTY(QList<Transfer*> outputs READ outputs)
|
||||
|
||||
public:
|
||||
quint64 fee() const;
|
||||
quint64 dust() const;
|
||||
bool dustAddedToFee() const;
|
||||
QString txKey() const;
|
||||
|
||||
private:
|
||||
explicit PendingTransactionInfo(const Monero::PendingTransactionInfo *pimpl, QObject *parent = nullptr);
|
||||
|
||||
friend class PendingTransaction;
|
||||
quint64 m_fee;
|
||||
quint64 m_dust;
|
||||
bool m_dustAddedToFee;
|
||||
QString m_txKey;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_PENDINGTRANSACTIONINFO_H
|
@ -1,89 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include "daemonrpc.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
DaemonRpc::DaemonRpc(QObject *parent, UtilsNetworking *network, QString daemonAddress)
|
||||
: QObject(parent)
|
||||
, m_network(network)
|
||||
, m_daemonAddress(std::move(daemonAddress))
|
||||
{
|
||||
}
|
||||
|
||||
void DaemonRpc::sendRawTransaction(const QString &tx_as_hex, bool do_not_relay, bool do_sanity_checks) {
|
||||
QJsonObject req;
|
||||
req["tx_as_hex"] = tx_as_hex;
|
||||
req["do_not_relay"] = do_not_relay;
|
||||
req["do_sanity_checks"] = do_sanity_checks;
|
||||
|
||||
QString url = QString("%1/send_raw_transaction").arg(m_daemonAddress);
|
||||
QNetworkReply *reply = m_network->postJson(url, req);
|
||||
connect(reply, &QNetworkReply::finished, std::bind(&DaemonRpc::onResponse, this, reply, Endpoint::SEND_RAW_TRANSACTION));
|
||||
}
|
||||
|
||||
void DaemonRpc::onResponse(QNetworkReply *reply, Endpoint endpoint) {
|
||||
const auto ok = reply->error() == QNetworkReply::NoError;
|
||||
const auto err = reply->errorString();
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
QJsonObject obj;
|
||||
if (!data.isEmpty() && Utils::validateJSON(data)) {
|
||||
auto doc = QJsonDocument::fromJson(data);
|
||||
obj = doc.object();
|
||||
}
|
||||
else if (!ok) {
|
||||
emit ApiResponse(DaemonResponse(false, endpoint, err));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
emit ApiResponse(DaemonResponse(false, endpoint, "Invalid response from daemon"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj.value("status").toString() != "OK") {
|
||||
QString failedMsg;
|
||||
switch (endpoint) {
|
||||
case SEND_RAW_TRANSACTION:
|
||||
failedMsg = this->onSendRawTransactionFailed(obj);
|
||||
break;
|
||||
default:
|
||||
failedMsg = obj.value("status").toString();
|
||||
}
|
||||
|
||||
emit ApiResponse(DaemonResponse(false, endpoint, failedMsg, obj));
|
||||
return;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
emit ApiResponse(DaemonResponse(true, endpoint, "", obj));
|
||||
}
|
||||
|
||||
QString DaemonRpc::onSendRawTransactionFailed(const QJsonObject &obj) {
|
||||
QString message = [&obj]{
|
||||
if (obj.value("double_spend").toBool())
|
||||
return "Transaction is a double spend";
|
||||
if (obj.value("fee_too_low").toBool())
|
||||
return "Fee is too low";
|
||||
if (obj.value("invalid_input").toBool())
|
||||
return "Output is invalid";
|
||||
if (obj.value("low_mixin").toBool())
|
||||
return "Mixin count is too low";
|
||||
if (obj.value("overspend").toBool())
|
||||
return "Transaction uses more money than available";
|
||||
if (obj.value("too_big").toBool())
|
||||
return "Transaction size is too big";
|
||||
return "Daemon returned an unknown error";
|
||||
}();
|
||||
|
||||
return QString("Transaction failed: %1").arg(message);
|
||||
}
|
||||
|
||||
void DaemonRpc::setDaemonAddress(const QString &daemonAddress) {
|
||||
m_daemonAddress = daemonAddress;
|
||||
}
|
||||
|
||||
void DaemonRpc::setNetwork(UtilsNetworking *network) {
|
||||
m_network = network;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_DAEMON_RPC_H
|
||||
#define FEATHER_DAEMON_RPC_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "utils/networking.h"
|
||||
|
||||
class DaemonRpc : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Endpoint {
|
||||
SEND_RAW_TRANSACTION = 0
|
||||
};
|
||||
|
||||
struct DaemonResponse {
|
||||
explicit DaemonResponse(bool ok, Endpoint endpoint, QString status, QJsonObject obj = {})
|
||||
: ok(ok), endpoint(endpoint), status(std::move(status)), obj(std::move(obj)) {};
|
||||
|
||||
bool ok;
|
||||
DaemonRpc::Endpoint endpoint;
|
||||
QString status;
|
||||
QJsonObject obj;
|
||||
};
|
||||
|
||||
explicit DaemonRpc(QObject *parent, UtilsNetworking *network, QString daemonAddress);
|
||||
|
||||
void sendRawTransaction(const QString &tx_as_hex, bool do_not_relay = false, bool do_sanity_checks = true);
|
||||
|
||||
void setDaemonAddress(const QString &daemonAddress);
|
||||
void setNetwork(UtilsNetworking *network);
|
||||
|
||||
signals:
|
||||
void ApiResponse(DaemonResponse resp);
|
||||
|
||||
private slots:
|
||||
void onResponse(QNetworkReply *reply, Endpoint endpoint);
|
||||
QString onSendRawTransactionFailed(const QJsonObject &obj);
|
||||
|
||||
private:
|
||||
UtilsNetworking *m_network;
|
||||
QString m_daemonAddress;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_DAEMON_RPC_H
|
@ -1,138 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include <QtCore>
|
||||
#include <QScreen>
|
||||
#include <QDesktopWidget>
|
||||
#include <QProcess>
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include "utils/utils.h"
|
||||
#include "utils/xmrig.h"
|
||||
|
||||
#include "appcontext.h"
|
||||
|
||||
|
||||
XmRig::XmRig(const QString &configDir, QObject *parent) : QObject(parent) {
|
||||
this->rigDir = QDir(configDir).filePath("xmrig");
|
||||
}
|
||||
|
||||
void XmRig::prepare() {
|
||||
// unpack and set process signals
|
||||
|
||||
if(!this->unpackBins()) {
|
||||
qCritical() << "failed to write XMRig to config directory";
|
||||
return;
|
||||
}
|
||||
|
||||
m_process.setProcessChannelMode(QProcess::MergedChannels);
|
||||
connect(&m_process, &QProcess::readyReadStandardOutput, this, &XmRig::handleProcessOutput);
|
||||
connect(&m_process, &QProcess::errorOccurred, this, &XmRig::handleProcessError);
|
||||
connect(&m_process, &QProcess::stateChanged, this, &XmRig::stateChanged);
|
||||
}
|
||||
|
||||
void XmRig::stop() {
|
||||
if(m_process.state() == QProcess::Running) {
|
||||
#if defined(Q_OS_WIN)
|
||||
m_process.kill(); // https://doc.qt.io/qt-5/qprocess.html#terminate
|
||||
#else
|
||||
m_process.terminate();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void XmRig::start(const QString &path,
|
||||
unsigned int threads,
|
||||
const QString &address,
|
||||
const QString &username,
|
||||
const QString &password,
|
||||
bool tor, bool tls) {
|
||||
auto state = m_process.state();
|
||||
if (state == QProcess::ProcessState::Running || state == QProcess::ProcessState::Starting) {
|
||||
emit error("Can't start XMRig, already running or starting");
|
||||
return;
|
||||
}
|
||||
|
||||
if(path.isEmpty()) {
|
||||
emit error("XmRig->Start path parameter missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Utils::fileExists(path)) {
|
||||
emit error(QString("Path to XMRig binary invalid; file does not exist: %1").arg(path));
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList arguments;
|
||||
arguments << "-o" << address;
|
||||
arguments << "-a" << "rx/0";
|
||||
arguments << "-u" << username;
|
||||
if(!password.isEmpty())
|
||||
arguments << "-p" << password;
|
||||
arguments << "--no-color";
|
||||
arguments << "-t" << QString::number(threads);
|
||||
if(tor)
|
||||
arguments << "-x" << QString("%1:%2").arg(Tor::torHost).arg(Tor::torPort);
|
||||
if(tls)
|
||||
arguments << "--tls";
|
||||
arguments << "--donate-level" << "1";
|
||||
QString cmd = QString("%1 %2").arg(path, arguments.join(" "));
|
||||
emit output(cmd.toUtf8());
|
||||
m_process.start(path, arguments);
|
||||
}
|
||||
|
||||
void XmRig::stateChanged(QProcess::ProcessState state) {
|
||||
if(state == QProcess::ProcessState::Running)
|
||||
emit output("XMRig started");
|
||||
else if (state == QProcess::ProcessState::NotRunning)
|
||||
emit output("XMRig stopped");
|
||||
}
|
||||
|
||||
void XmRig::handleProcessOutput() {
|
||||
QByteArray _output = m_process.readAllStandardOutput();
|
||||
if(_output.contains("miner") && _output.contains("speed")) {
|
||||
// detect hashrate
|
||||
auto str = Utils::barrayToString(_output);
|
||||
auto spl = str.mid(str.indexOf("speed")).split(" ");
|
||||
auto rate = spl.at(2) + "H/s";
|
||||
qDebug() << "mining hashrate: " << rate;
|
||||
emit hashrate(rate);
|
||||
}
|
||||
|
||||
emit output(_output);
|
||||
}
|
||||
|
||||
void XmRig::handleProcessError(QProcess::ProcessError err) {
|
||||
if (err == QProcess::ProcessError::Crashed)
|
||||
emit error("XMRig crashed or killed");
|
||||
else if (err == QProcess::ProcessError::FailedToStart) {
|
||||
auto path = config()->get(Config::xmrigPath).toString();
|
||||
emit error(QString("XMRig binary failed to start: %1").arg(path));
|
||||
}
|
||||
}
|
||||
|
||||
bool XmRig::unpackBins() {
|
||||
QString rigFile;
|
||||
|
||||
rigFile = ":/assets/exec/xmrig";
|
||||
if (!Utils::fileExists(rigFile))
|
||||
return false;
|
||||
|
||||
// write to disk
|
||||
QFile f(rigFile);
|
||||
QFileInfo fileInfo(f);
|
||||
this->rigPath = QDir(this->rigDir).filePath(fileInfo.fileName());
|
||||
#if defined(Q_OS_WIN)
|
||||
if(!this->rigPath.endsWith(".exe"))
|
||||
this->rigPath += ".exe";
|
||||
#endif
|
||||
qDebug() << "Writing XMRig executable to " << this->rigPath;
|
||||
f.copy(rigPath);
|
||||
f.close();
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
QFile rigBin(this->rigPath);
|
||||
rigBin.setPermissions(QFile::ExeGroup | QFile::ExeOther | QFile::ExeOther | QFile::ExeUser);
|
||||
#endif
|
||||
return true;
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_XMRIG_H
|
||||
#define FEATHER_XMRIG_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <QtCore>
|
||||
#include <QRegExp>
|
||||
#include <QtNetwork>
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "utils/childproc.h"
|
||||
|
||||
class XmRig : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit XmRig(const QString &configDir, QObject *parent = nullptr);
|
||||
void prepare();
|
||||
|
||||
void start(const QString &path, unsigned int threads, const QString &address, const QString &username, const QString &password, bool tor = false, bool tls = true);
|
||||
void stop();
|
||||
bool unpackBins();
|
||||
|
||||
QString rigDir;
|
||||
QString rigPath;
|
||||
|
||||
signals:
|
||||
void error(const QString &msg);
|
||||
void output(const QByteArray &data);
|
||||
void hashrate(const QString &rate);
|
||||
|
||||
private slots:
|
||||
void stateChanged(QProcess::ProcessState);
|
||||
void handleProcessOutput();
|
||||
void handleProcessError(QProcess::ProcessError error);
|
||||
|
||||
private:
|
||||
ChildProcess m_process;
|
||||
};
|
||||
|
||||
#endif //FEATHER_XMRIG_H
|