mirror of
https://github.com/feather-wallet/feather.git
synced 2024-12-22 19:49:28 +00:00
Offline transaction signing
This commit is contained in:
parent
44a2fc30dc
commit
216b2e0c5e
35 changed files with 1334 additions and 52 deletions
|
@ -30,7 +30,7 @@ if(DEBUG)
|
|||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
endif()
|
||||
|
||||
set(MONERO_HEAD "f6587d7943a19c55a5b78af1a89b22c130513b73")
|
||||
set(MONERO_HEAD "c2b7b50fdea2e66a593f9c9109ebd742f69ad9d1")
|
||||
set(BUILD_GUI_DEPS ON)
|
||||
set(ARCH "x86-64")
|
||||
set(BUILD_64 ON)
|
||||
|
|
2
monero
2
monero
|
@ -1 +1 @@
|
|||
Subproject commit f6587d7943a19c55a5b78af1a89b22c130513b73
|
||||
Subproject commit c2b7b50fdea2e66a593f9c9109ebd742f69ad9d1
|
62
src/dialog/broadcasttxdialog.cpp
Normal file
62
src/dialog/broadcasttxdialog.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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;
|
||||
}
|
35
src/dialog/broadcasttxdialog.h
Normal file
35
src/dialog/broadcasttxdialog.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
// 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
|
111
src/dialog/broadcasttxdialog.ui
Normal file
111
src/dialog/broadcasttxdialog.ui
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?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>
|
|
@ -9,15 +9,14 @@
|
|||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
QrCodeDialog::QrCodeDialog(QWidget *parent, const QString &text, const QString &title)
|
||||
QrCodeDialog::QrCodeDialog(QWidget *parent, const QrCode &qrCode, const QString &title)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::QrCodeDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->setWindowTitle(title);
|
||||
|
||||
m_qrc = new QrCode(text, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::HIGH);
|
||||
m_pixmap = m_qrc->toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio);
|
||||
m_pixmap = qrCode.toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio);
|
||||
ui->QrCode->setPixmap(m_pixmap);
|
||||
|
||||
connect(ui->btn_CopyImage, &QPushButton::clicked, this, &QrCodeDialog::copyImage);
|
||||
|
@ -32,7 +31,11 @@ QrCodeDialog::QrCodeDialog(QWidget *parent, const QString &text, const QString &
|
|||
QrCodeDialog::~QrCodeDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete m_qrc;
|
||||
}
|
||||
|
||||
void QrCodeDialog::setQrCode(const QrCode &qrCode) {
|
||||
m_pixmap = qrCode.toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio);
|
||||
ui->QrCode->setPixmap(m_pixmap);
|
||||
}
|
||||
|
||||
void QrCodeDialog::copyImage() {
|
||||
|
|
|
@ -16,15 +16,15 @@ class QrCodeDialog : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QrCodeDialog(QWidget *parent, const QString &text, const QString &title = "Qr Code");
|
||||
explicit QrCodeDialog(QWidget *parent, const QrCode &qrCode, const QString &title = "Qr Code");
|
||||
~QrCodeDialog() override;
|
||||
void setQrCode(const QrCode &qrCode);
|
||||
|
||||
private:
|
||||
void copyImage();
|
||||
void saveImage();
|
||||
|
||||
Ui::QrCodeDialog *ui;
|
||||
QrCode *m_qrc;
|
||||
QPixmap m_pixmap;
|
||||
};
|
||||
|
||||
|
|
186
src/dialog/txconfadvdialog.cpp
Normal file
186
src/dialog/txconfadvdialog.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
// 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;
|
||||
}
|
54
src/dialog/txconfadvdialog.h
Normal file
54
src/dialog/txconfadvdialog.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
// 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
|
279
src/dialog/txconfadvdialog.ui
Normal file
279
src/dialog/txconfadvdialog.ui
Normal file
|
@ -0,0 +1,279 @@
|
|||
<?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>
|
|
@ -6,12 +6,15 @@
|
|||
#include "appcontext.h"
|
||||
#include "utils/config.h"
|
||||
#include "model/ModelUtils.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "txconfadvdialog.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
TxConfDialog::TxConfDialog(PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent)
|
||||
TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::TxConfDialog)
|
||||
, m_ctx(ctx)
|
||||
, m_tx(tx)
|
||||
, m_address(address)
|
||||
, m_description(description)
|
||||
|
@ -43,29 +46,16 @@ TxConfDialog::TxConfDialog(PendingTransaction *tx, const QString &address, const
|
|||
ui->label_address->setFont(ModelUtils::getMonospaceFont());
|
||||
ui->label_address->setToolTip(address);
|
||||
|
||||
connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::showAdvanced);
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Send");
|
||||
|
||||
connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::setShowAdvanced);
|
||||
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void TxConfDialog::showAdvanced() {
|
||||
const auto amount = m_tx->amount() / AppContext::cdiv;
|
||||
const auto fee = m_tx->fee() / AppContext::cdiv;
|
||||
|
||||
QString body = QString("Address: %2\n").arg(m_address.left(60));
|
||||
body += m_address.mid(60) + "\n";
|
||||
if(!m_description.isEmpty())
|
||||
body = QString("%1Description: %2\n").arg(body, m_description);
|
||||
body = QString("%1Amount: %2 XMR\n").arg(body, QString::number(amount));
|
||||
body = QString("%1Fee: %2 XMR\n").arg(body, QString::number(fee));
|
||||
body = QString("%1Ringsize: %2").arg(body, QString::number(m_mixin + 1));
|
||||
|
||||
auto subaddrIndices = m_tx->subaddrIndices();
|
||||
for (int i = 0; i < subaddrIndices.count(); ++i){
|
||||
body = QString("%1\nSpending address index: %2").arg(body, QString::number(subaddrIndices.at(i).toInt()));
|
||||
}
|
||||
|
||||
QMessageBox::information(this, "Transaction information", body);
|
||||
void TxConfDialog::setShowAdvanced() {
|
||||
this->showAdvanced = true;
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
TxConfDialog::~TxConfDialog() {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QDialog>
|
||||
#include "libwalletqt/PendingTransaction.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "appcontext.h"
|
||||
|
||||
namespace Ui {
|
||||
class TxConfDialog;
|
||||
|
@ -17,13 +18,18 @@ class TxConfDialog : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TxConfDialog(PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent = nullptr);
|
||||
explicit TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent = nullptr);
|
||||
~TxConfDialog() override;
|
||||
|
||||
bool showAdvanced = false;
|
||||
|
||||
private:
|
||||
void showAdvanced();
|
||||
void setShowAdvanced();
|
||||
void saveToFile();
|
||||
void copyToClipboard();
|
||||
|
||||
Ui::TxConfDialog *ui;
|
||||
AppContext *m_ctx;
|
||||
PendingTransaction *m_tx;
|
||||
QString m_address;
|
||||
QString m_description;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>655</width>
|
||||
<width>844</width>
|
||||
<height>248</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
|
53
src/libwalletqt/ConstructionInfo.cpp
Normal file
53
src/libwalletqt/ConstructionInfo.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
// 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);
|
||||
}
|
||||
}
|
46
src/libwalletqt/ConstructionInfo.h
Normal file
46
src/libwalletqt/ConstructionInfo.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
// 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
|
29
src/libwalletqt/Input.h
Normal file
29
src/libwalletqt/Input.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// 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
|
|
@ -16,10 +16,12 @@ QString PendingTransaction::errorString() const
|
|||
|
||||
bool PendingTransaction::commit()
|
||||
{
|
||||
// Save transaction to file if fileName is set.
|
||||
if(!m_fileName.isEmpty())
|
||||
return m_pimpl->commit(m_fileName.toStdString());
|
||||
return m_pimpl->commit(m_fileName.toStdString());
|
||||
return m_pimpl->commit();
|
||||
}
|
||||
|
||||
bool PendingTransaction::saveToFile(const QString &fileName)
|
||||
{
|
||||
return m_pimpl->commit(fileName.toStdString());
|
||||
}
|
||||
|
||||
quint64 PendingTransaction::amount() const
|
||||
|
@ -37,7 +39,6 @@ quint64 PendingTransaction::fee() const
|
|||
return m_pimpl->fee();
|
||||
}
|
||||
|
||||
|
||||
QStringList PendingTransaction::txid() const
|
||||
{
|
||||
QStringList list;
|
||||
|
@ -63,9 +64,33 @@ QList<QVariant> PendingTransaction::subaddrIndices() const
|
|||
return result;
|
||||
}
|
||||
|
||||
void PendingTransaction::setFilename(const QString &fileName)
|
||||
QByteArray PendingTransaction::unsignedTxToBin() const {
|
||||
return QByteArray::fromStdString(m_pimpl->unsignedTxToBin());
|
||||
}
|
||||
|
||||
QString PendingTransaction::unsignedTxToBase64() const
|
||||
{
|
||||
m_fileName = fileName;
|
||||
return QString::fromStdString(m_pimpl->unsignedTxToBase64());
|
||||
}
|
||||
|
||||
QString PendingTransaction::signedTxToHex(int index) const
|
||||
{
|
||||
return QString::fromStdString(m_pimpl->signedTxToHex(index));
|
||||
}
|
||||
|
||||
PendingTransactionInfo * PendingTransaction::transaction(int index) const {
|
||||
return m_pending_tx_info[index];
|
||||
}
|
||||
|
||||
void PendingTransaction::refresh()
|
||||
{
|
||||
qDeleteAll(m_pending_tx_info);
|
||||
m_pending_tx_info.clear();
|
||||
|
||||
m_pimpl->refresh();
|
||||
for (const auto i : m_pimpl->getAll()) {
|
||||
m_pending_tx_info.append(new PendingTransactionInfo(i, this));
|
||||
}
|
||||
}
|
||||
|
||||
PendingTransaction::PendingTransaction(Monero::PendingTransaction *pt, QObject *parent)
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <QVariant>
|
||||
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include "PendingTransactionInfo.h"
|
||||
|
||||
|
||||
//namespace Monero {
|
||||
//class PendingTransaction;
|
||||
|
@ -30,7 +32,7 @@ public:
|
|||
enum Status {
|
||||
Status_Ok = Monero::PendingTransaction::Status_Ok,
|
||||
Status_Error = Monero::PendingTransaction::Status_Error,
|
||||
Status_Critical = Monero::PendingTransaction::Status_Critical
|
||||
Status_Critical = Monero::PendingTransaction::Status_Critical
|
||||
};
|
||||
Q_ENUM(Status)
|
||||
|
||||
|
@ -45,21 +47,27 @@ public:
|
|||
Status status() const;
|
||||
QString errorString() const;
|
||||
Q_INVOKABLE bool commit();
|
||||
bool saveToFile(const QString &fileName);
|
||||
quint64 amount() const;
|
||||
quint64 dust() const;
|
||||
quint64 fee() const;
|
||||
QStringList txid() const;
|
||||
quint64 txCount() const;
|
||||
QList<QVariant> subaddrIndices() const;
|
||||
Q_INVOKABLE void setFilename(const QString &fileName);
|
||||
QByteArray unsignedTxToBin() const;
|
||||
QString unsignedTxToBase64() const;
|
||||
QString signedTxToHex(int index) const;
|
||||
void refresh();
|
||||
|
||||
PendingTransactionInfo * transaction(int index) const;
|
||||
|
||||
private:
|
||||
explicit PendingTransaction(Monero::PendingTransaction * pt, QObject *parent = 0);
|
||||
explicit PendingTransaction(Monero::PendingTransaction * pt, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
friend class Wallet;
|
||||
Monero::PendingTransaction * m_pimpl;
|
||||
QString m_fileName;
|
||||
mutable QList<PendingTransactionInfo*> m_pending_tx_info;
|
||||
};
|
||||
|
||||
#endif // PENDINGTRANSACTION_H
|
||||
|
|
32
src/libwalletqt/PendingTransactionInfo.cpp
Normal file
32
src/libwalletqt/PendingTransactionInfo.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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()))
|
||||
{
|
||||
|
||||
}
|
46
src/libwalletqt/PendingTransactionInfo.h
Normal file
46
src/libwalletqt/PendingTransactionInfo.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
// 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
|
|
@ -17,6 +17,7 @@ private:
|
|||
explicit Transfer(uint64_t _amount, QString _address, QObject *parent = 0): QObject(parent), m_amount(_amount), m_address(std::move(_address)) {};
|
||||
private:
|
||||
friend class TransactionInfo;
|
||||
friend class ConstructionInfo;
|
||||
quint64 m_amount;
|
||||
QString m_address;
|
||||
public:
|
||||
|
|
|
@ -83,6 +83,21 @@ void UnsignedTransaction::setFilename(const QString &fileName)
|
|||
m_fileName = fileName;
|
||||
}
|
||||
|
||||
ConstructionInfo * UnsignedTransaction::constructionInfo(int index) const {
|
||||
return m_construction_info[index];
|
||||
}
|
||||
|
||||
void UnsignedTransaction::refresh()
|
||||
{
|
||||
qDeleteAll(m_construction_info);
|
||||
m_construction_info.clear();
|
||||
|
||||
m_pimpl->refresh();
|
||||
for (const auto i : m_pimpl->getAll()) {
|
||||
m_construction_info.append(new ConstructionInfo(i, this));
|
||||
}
|
||||
}
|
||||
|
||||
UnsignedTransaction::UnsignedTransaction(Monero::UnsignedTransaction *pt, Monero::Wallet *walletImpl, QObject *parent)
|
||||
: QObject(parent), m_pimpl(pt), m_walletImpl(walletImpl)
|
||||
{
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
#include <QObject>
|
||||
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include "libwalletqt/PendingTransactionInfo.h"
|
||||
|
||||
class UnsignedTransaction : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Status status READ status)
|
||||
Q_PROPERTY(QString errorString READ errorString)
|
||||
// Q_PROPERTY(QList<qulonglong> amount READ amount)
|
||||
// Q_PROPERTY(QList<qulonglong> fee READ fee)
|
||||
Q_PROPERTY(quint64 txCount READ txCount)
|
||||
Q_PROPERTY(QString confirmationMessage READ confirmationMessage)
|
||||
Q_PROPERTY(QStringList recipientAddress READ recipientAddress)
|
||||
|
@ -41,15 +40,19 @@ public:
|
|||
quint64 minMixinCount() const;
|
||||
Q_INVOKABLE bool sign(const QString &fileName) const;
|
||||
Q_INVOKABLE void setFilename(const QString &fileName);
|
||||
void refresh();
|
||||
|
||||
ConstructionInfo * constructionInfo(int index) const;
|
||||
|
||||
private:
|
||||
explicit UnsignedTransaction(Monero::UnsignedTransaction * pt, Monero::Wallet *walletImpl, QObject *parent = 0);
|
||||
explicit UnsignedTransaction(Monero::UnsignedTransaction * pt, Monero::Wallet *walletImpl, QObject *parent = nullptr);
|
||||
~UnsignedTransaction();
|
||||
private:
|
||||
friend class Wallet;
|
||||
Monero::UnsignedTransaction * m_pimpl;
|
||||
QString m_fileName;
|
||||
Monero::Wallet * m_walletImpl;
|
||||
mutable QList<ConstructionInfo*> m_construction_info;
|
||||
};
|
||||
|
||||
#endif // UNSIGNEDTRANSACTION_H
|
||||
|
|
|
@ -529,7 +529,7 @@ void Wallet::createTransactionSingleAsync(const QString &key_image, const QStrin
|
|||
{
|
||||
m_scheduler.run([this, key_image, dst_addr, outputs, priority] {
|
||||
PendingTransaction *tx = createTransactionSingle(key_image, dst_addr, outputs, priority);
|
||||
emit transactionCreated(tx, dst_addr, "", 0); // todo: return true mixincount
|
||||
emit transactionCreated(tx, dst_addr, "", 10); // todo: return true mixincount
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -556,6 +556,21 @@ UnsignedTransaction * Wallet::loadTxFile(const QString &fileName)
|
|||
return result;
|
||||
}
|
||||
|
||||
UnsignedTransaction * Wallet::loadTxFromBase64Str(const QString &unsigned_tx)
|
||||
{
|
||||
Monero::UnsignedTransaction * ptImpl = m_walletImpl->loadUnsignedTxFromBase64Str(unsigned_tx.toStdString());
|
||||
UnsignedTransaction * result = new UnsignedTransaction(ptImpl, m_walletImpl, this);
|
||||
return result;
|
||||
}
|
||||
|
||||
PendingTransaction * Wallet::loadSignedTxFile(const QString &fileName)
|
||||
{
|
||||
qDebug() << "Tying to load " << fileName;
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->loadSignedTx(fileName.toStdString());
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl, this);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Wallet::submitTxFile(const QString &fileName) const
|
||||
{
|
||||
qDebug() << "Trying to submit " << fileName;
|
||||
|
|
|
@ -250,6 +250,12 @@ public:
|
|||
//! Sign a transfer from file
|
||||
Q_INVOKABLE UnsignedTransaction * loadTxFile(const QString &fileName);
|
||||
|
||||
//! Load an unsigned transaction from a base64 encoded string
|
||||
Q_INVOKABLE UnsignedTransaction * loadTxFromBase64Str(const QString &unsigned_tx);
|
||||
|
||||
//! Load a signed transaction from file
|
||||
Q_INVOKABLE PendingTransaction * loadSignedTxFile(const QString &fileName);
|
||||
|
||||
//! Submit a transfer from file
|
||||
Q_INVOKABLE bool submitTxFile(const QString &fileName) const;
|
||||
|
||||
|
|
|
@ -13,12 +13,15 @@
|
|||
#include "widgets/ccswidget.h"
|
||||
#include "widgets/redditwidget.h"
|
||||
#include "dialog/txconfdialog.h"
|
||||
#include "dialog/txconfadvdialog.h"
|
||||
#include "dialog/debuginfodialog.h"
|
||||
#include "dialog/walletinfodialog.h"
|
||||
#include "dialog/torinfodialog.h"
|
||||
#include "dialog/viewonlydialog.h"
|
||||
#include "dialog/broadcasttxdialog.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/config.h"
|
||||
#include "utils/daemonrpc.h"
|
||||
#include "components.h"
|
||||
#include "calcwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
@ -474,6 +477,10 @@ void MainWindow::initMenu() {
|
|||
// Tools
|
||||
connect(ui->actionSignVerify, &QAction::triggered, this, &MainWindow::menuSignVerifyClicked);
|
||||
connect(ui->actionVerifyTxProof, &QAction::triggered, this, &MainWindow::menuVerifyTxProof);
|
||||
connect(ui->actionLoadUnsignedTxFromFile, &QAction::triggered, this, &MainWindow::loadUnsignedTx);
|
||||
connect(ui->actionLoadUnsignedTxFromClipboard, &QAction::triggered, this, &MainWindow::loadUnsignedTxFromClipboard);
|
||||
connect(ui->actionLoadSignedTxFromFile, &QAction::triggered, this, &MainWindow::loadSignedTx);
|
||||
connect(ui->actionLoadSignedTxFromText, &QAction::triggered, this, &MainWindow::loadSignedTxFromText);
|
||||
|
||||
// About screen
|
||||
connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::menuAboutClicked);
|
||||
|
@ -702,15 +709,26 @@ void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QStrin
|
|||
} else {
|
||||
const auto &description = m_ctx->tmpTxDescription;
|
||||
|
||||
auto *dialog = new TxConfDialog(tx, address, description, mixin, this);
|
||||
auto *dialog = new TxConfDialog(m_ctx, tx, address, description, mixin, this);
|
||||
switch (dialog->exec()) {
|
||||
case QDialog::Rejected:
|
||||
m_ctx->onCancelTransaction(tx, address);
|
||||
{
|
||||
if (!dialog->showAdvanced)
|
||||
m_ctx->onCancelTransaction(tx, address);
|
||||
break;
|
||||
}
|
||||
case QDialog::Accepted:
|
||||
m_ctx->currentWallet->commitTransactionAsync(tx);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dialog->showAdvanced) {
|
||||
auto *dialog_adv = new TxConfAdvDialog(m_ctx, description, this);
|
||||
dialog_adv->setTransaction(tx);
|
||||
dialog_adv->exec();
|
||||
dialog_adv->deleteLater();
|
||||
}
|
||||
dialog->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1157,6 +1175,64 @@ void MainWindow::cleanupBeforeClose() {
|
|||
this->saveGeo();
|
||||
}
|
||||
|
||||
void MainWindow::loadUnsignedTx() {
|
||||
QString fn = QFileDialog::getOpenFileName(this, "Select transaction to load", QDir::homePath(), "Transaction (*unsigned_monero_tx)");
|
||||
if (fn.isEmpty()) return;
|
||||
UnsignedTransaction *tx = m_ctx->currentWallet->loadTxFile(fn);
|
||||
auto err = m_ctx->currentWallet->errorString();
|
||||
if (!err.isEmpty()) {
|
||||
QMessageBox::warning(this, "Load transaction from file", QString("Failed to load transaction.\n\n%1").arg(err));
|
||||
return;
|
||||
}
|
||||
|
||||
this->createUnsignedTxDialog(tx);
|
||||
}
|
||||
|
||||
void MainWindow::loadUnsignedTxFromClipboard() {
|
||||
QString unsigned_tx = Utils::copyFromClipboard();
|
||||
if (unsigned_tx.isEmpty()) {
|
||||
QMessageBox::warning(this, "Load unsigned transaction from clipboard", "Clipboard is empty");
|
||||
return;
|
||||
}
|
||||
UnsignedTransaction *tx = m_ctx->currentWallet->loadTxFromBase64Str(unsigned_tx);
|
||||
auto err = m_ctx->currentWallet->errorString();
|
||||
if (!err.isEmpty()) {
|
||||
QMessageBox::warning(this, "Load unsigned transaction from clipboard", QString("Failed to load transaction.\n\n%1").arg(err));
|
||||
return;
|
||||
}
|
||||
|
||||
this->createUnsignedTxDialog(tx);
|
||||
}
|
||||
|
||||
void MainWindow::loadSignedTx() {
|
||||
QString fn = QFileDialog::getOpenFileName(this, "Select transaction to load", QDir::homePath(), "Transaction (*signed_monero_tx)");
|
||||
if (fn.isEmpty()) return;
|
||||
PendingTransaction *tx = m_ctx->currentWallet->loadSignedTxFile(fn);
|
||||
auto err = m_ctx->currentWallet->errorString();
|
||||
if (!err.isEmpty()) {
|
||||
QMessageBox::warning(this, "Load signed transaction from file", err);
|
||||
return;
|
||||
}
|
||||
|
||||
auto *dialog = new TxConfAdvDialog(m_ctx, "", this);
|
||||
dialog->setTransaction(tx);
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::loadSignedTxFromText() {
|
||||
auto dialog = new BroadcastTxDialog(this, m_ctx);
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::createUnsignedTxDialog(UnsignedTransaction *tx) {
|
||||
auto *dialog = new TxConfAdvDialog(m_ctx, "", this);
|
||||
dialog->setUnsignedTransaction(tx);
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
delete ui;
|
||||
}
|
||||
|
|
|
@ -101,10 +101,15 @@ public slots:
|
|||
void onAddContact(const QString &address, const QString &name);
|
||||
void showRestoreHeightDialog();
|
||||
|
||||
// offline tx signing
|
||||
void exportKeyImages();
|
||||
void importKeyImages();
|
||||
void exportOutputs();
|
||||
void importOutputs();
|
||||
void loadUnsignedTx();
|
||||
void loadUnsignedTxFromClipboard();
|
||||
void loadSignedTx();
|
||||
void loadSignedTxFromText();
|
||||
|
||||
// libwalletqt
|
||||
void onBalanceUpdated(double balance, double unlocked, const QString &balance_str, const QString &unlocked_str);
|
||||
|
@ -136,6 +141,7 @@ private:
|
|||
void showDebugInfo();
|
||||
void showNodeExhaustedMessage();
|
||||
void showWSNodeExhaustedMessage();
|
||||
void createUnsignedTxDialog(UnsignedTransaction *tx);
|
||||
|
||||
WalletWizard *createWizard(WalletWizard::Page startPage);
|
||||
|
||||
|
|
|
@ -375,9 +375,26 @@
|
|||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuLoad_transaction">
|
||||
<property name="title">
|
||||
<string>Load unsigned transaction</string>
|
||||
</property>
|
||||
<addaction name="actionLoadUnsignedTxFromFile"/>
|
||||
<addaction name="actionLoadUnsignedTxFromClipboard"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuLoad_signed_transaction">
|
||||
<property name="title">
|
||||
<string>Broadcast transaction</string>
|
||||
</property>
|
||||
<addaction name="actionLoadSignedTxFromFile"/>
|
||||
<addaction name="actionLoadSignedTxFromText"/>
|
||||
</widget>
|
||||
<addaction name="actionSignVerify"/>
|
||||
<addaction name="actionVerifyTxProof"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuLoad_transaction"/>
|
||||
<addaction name="menuLoad_signed_transaction"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionCalculator"/>
|
||||
<addaction name="actionCreateDesktopEntry"/>
|
||||
</widget>
|
||||
|
@ -611,6 +628,36 @@
|
|||
<string>Show XMRig</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImportTransaction">
|
||||
<property name="text">
|
||||
<string>Transaction</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSubmitTransaction">
|
||||
<property name="text">
|
||||
<string>Submit transaction file</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoadUnsignedTxFromFile">
|
||||
<property name="text">
|
||||
<string>From file</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoadSignedTxFromFile">
|
||||
<property name="text">
|
||||
<string>From file</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoadUnsignedTxFromClipboard">
|
||||
<property name="text">
|
||||
<string>From clipboard</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoadSignedTxFromText">
|
||||
<property name="text">
|
||||
<string>From text</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
|
|
@ -141,7 +141,8 @@ void ReceiveWidget::setQrCode(const QString &address){
|
|||
void ReceiveWidget::showQrCodeDialog() {
|
||||
QModelIndex index = ui->addresses->currentIndex();
|
||||
QString address = index.model()->data(index.siblingAtColumn(SubaddressModel::Address), Qt::UserRole).toString();
|
||||
auto *dialog = new QrCodeDialog(this, address, "Address");
|
||||
QrCode qr(address, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::HIGH);
|
||||
auto *dialog = new QrCodeDialog(this, qr, "Address");
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
|
||||
#include <QMessageBox>
|
||||
#include "sendwidget.h"
|
||||
#include "widgets/ccswidget.h"
|
||||
|
|
89
src/utils/daemonrpc.cpp
Normal file
89
src/utils/daemonrpc.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
// 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;
|
||||
}
|
49
src/utils/daemonrpc.h
Normal file
49
src/utils/daemonrpc.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
// 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
|
|
@ -68,7 +68,7 @@ QByteArray Utils::fileOpenQRC(const QString &path) {
|
|||
bool Utils::fileWrite(const QString &path, const QString &data) {
|
||||
QFile file(path);
|
||||
if(file.open(QIODevice::WriteOnly)){
|
||||
QTextStream out(&file); out << data << endl;
|
||||
QTextStream out(&file); out << data << Qt::endl;
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
@ -362,6 +362,15 @@ void Utils::copyToClipboard(const QString &string){
|
|||
#endif
|
||||
}
|
||||
|
||||
QString Utils::copyFromClipboard() {
|
||||
QClipboard * clipboard = QApplication::clipboard();
|
||||
if (!clipboard) {
|
||||
qWarning() << "Unable to access clipboard";
|
||||
return "";
|
||||
}
|
||||
return clipboard->text();
|
||||
}
|
||||
|
||||
QString Utils::blockExplorerLink(const QString &blockExplorer, NetworkType::Type nettype, const QString &txid) {
|
||||
if (blockExplorer == "exploremonero.com") {
|
||||
if (nettype == NetworkType::MAINNET) {
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
static QStandardItem *qStandardItem(const QString &text);
|
||||
static QStandardItem *qStandardItem(const QString &text, QFont &font);
|
||||
static void copyToClipboard(const QString &string);
|
||||
static QString copyFromClipboard();
|
||||
static QString blockExplorerLink(const QString &blockExplorer, NetworkType::Type nettype, const QString &txid);
|
||||
static QString getUnixAccountName();
|
||||
static QString xdgDesktopEntry();
|
||||
|
|
|
@ -41,7 +41,6 @@ void XmrToApi::getOrderStatus(const QString &uuid) {
|
|||
void XmrToApi::onResponse(QNetworkReply *reply, Endpoint endpoint) {
|
||||
const auto ok = reply->error() == QNetworkReply::NoError;
|
||||
const auto err = reply->errorString();
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
QJsonObject obj;
|
||||
|
@ -64,6 +63,7 @@ void XmrToApi::onResponse(QNetworkReply *reply, Endpoint endpoint) {
|
|||
return;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
emit ApiResponse(XmrToResponse(true, endpoint, "", obj));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue