Browse Source

History: rework

wizard_redesign
tobtoht 5 months ago
parent
commit
cc5b3c3c27
Signed by: tobtoht GPG Key ID: 1CADD27F41F45C3C
  1. 1
      .gitignore
  2. 23
      src/appcontext.cpp
  3. 2
      src/appcontext.h
  4. 226
      src/dialog/TxProofDialog.cpp
  5. 56
      src/dialog/TxProofDialog.h
  6. 301
      src/dialog/TxProofDialog.ui
  7. 29
      src/dialog/transactioninfodialog.cpp
  8. 6
      src/dialog/transactioninfodialog.h
  9. 67
      src/dialog/transactioninfodialog.ui
  10. 115
      src/dialog/verifyproofdialog.cpp
  11. 8
      src/dialog/verifyproofdialog.h
  12. 593
      src/dialog/verifyproofdialog.ui
  13. 94
      src/historywidget.cpp
  14. 2
      src/historywidget.h
  15. 9
      src/historywidget.ui
  16. 9
      src/libwalletqt/TransactionHistory.cpp
  17. 1
      src/libwalletqt/TransactionHistory.h
  18. 22
      src/mainwindow.cpp
  19. 1
      src/mainwindow.h
  20. 188
      src/model/HistoryView.cpp
  21. 44
      src/model/HistoryView.h
  22. 2
      src/model/ModelUtils.cpp
  23. 47
      src/model/TransactionHistoryModel.cpp
  24. 7
      src/model/TransactionHistoryModel.h
  25. 4
      src/model/TransactionHistoryProxyModel.cpp
  26. 1
      src/model/TransactionHistoryProxyModel.h
  27. 11
      src/settings.cpp
  28. 2
      src/settings.h
  29. 14
      src/settings.ui
  30. 4
      src/utils/config.cpp
  31. 4
      src/utils/config.h
  32. 68
      src/widgets/txproofwidget.cpp
  33. 33
      src/widgets/txproofwidget.h
  34. 110
      src/widgets/txproofwidget.ui

1
.gitignore

@ -13,3 +13,4 @@ feather.cbp
src/tor/*
!src/tor/.gitkeep
src/config-feather.h
src/assets/exec/*

23
src/appcontext.cpp

@ -19,7 +19,6 @@ Prices *AppContext::prices = nullptr;
WalletKeysFilesModel *AppContext::wallets = nullptr;
TxFiatHistory *AppContext::txFiatHistory = nullptr;
double AppContext::balance = 0;
QMap<QString, QString> AppContext::txDescriptionCache;
QMap<QString, QString> AppContext::txCache;
AppContext::AppContext(QCommandLineParser *cmdargs) {
@ -303,6 +302,13 @@ void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) {
}
}
void AppContext::onAmountPrecisionChanged(int precision) {
if (!this->currentWallet) return;
auto *model = this->currentWallet->transactionHistoryModel();
if (!model) return;
model->amountPrecision = precision;
}
void AppContext::onWalletOpened(Wallet *wallet) {
auto state = wallet->status();
if (state != Wallet::Status_Ok) {
@ -770,21 +776,28 @@ void AppContext::onTransactionCreated(PendingTransaction *tx, const QVector<QStr
}
void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
if (status) {
for (const auto &entry: txid) {
this->currentWallet->setUserNote(entry, this->tmpTxDescription);
}
this->tmpTxDescription = "";
}
// Store wallet immediately so we don't risk losing tx key if wallet crashes
this->currentWallet->store();
this->updateBalance();
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
emit transactionCommitted(status, tx, txid);
this->updateBalance();
// this tx was a donation to Feather, stop our nagging
if(this->donationSending) {
this->donationSending = false;
config()->set(Config::donateBeg, -1);
}
emit transactionCommitted(status, tx, txid);
}
void AppContext::storeWallet() {

2
src/appcontext.h

@ -85,7 +85,6 @@ public:
static Prices *prices;
static WalletKeysFilesModel *wallets;
static double balance;
static QMap<QString, QString> txDescriptionCache;
static QMap<QString, QString> txCache;
static TxFiatHistory *txFiatHistory;
@ -119,6 +118,7 @@ public slots:
void onOpenAliasResolve(const QString &openAlias);
void onSetRestoreHeight(quint64 height);
void onPreferredFiatCurrencyChanged(const QString &symbol);
void onAmountPrecisionChanged(int precision);
private slots:
void onWSNodes(const QJsonArray &nodes);

226
src/dialog/TxProofDialog.cpp

@ -0,0 +1,226 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project.
#include "TxProofDialog.h"
#include "ui_TxProofDialog.h"
#include <QMessageBox>
#include "libwalletqt/Transfer.h"
#include "utils/utils.h"
TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txInfo)
: QDialog(parent)
, ui(new Ui::TxProofDialog)
, m_wallet(wallet)
{
ui->setupUi(this);
m_txid = txInfo->hash();
m_txKey = m_wallet->getTxKey(m_txid);
m_direction = txInfo->direction();
for (auto const &t: txInfo->transfers()) {
m_OutDestinations.push_back(t->address());
}
for (auto const &s: txInfo->subaddrIndex()) {
m_InDestinations.push_back(wallet->address(txInfo->subaddrAccount(), s));
}
// Due to some logic in core we can't create OutProofs
// for churn transactions that sweep from and send to the same address
for (auto const &address : m_InDestinations) {
m_OutDestinations.removeAll(address);
}
connect(ui->radio_SpendProof, &QRadioButton::toggled, this, &TxProofDialog::selectSpendProof);
connect(ui->radio_OutProof, &QRadioButton::toggled, this, &TxProofDialog::selectOutProof);
connect(ui->radio_InProof, &QRadioButton::toggled, this, &TxProofDialog::selectInProof);
connect(ui->btn_getFormattedProof, &QPushButton::pressed, this, &TxProofDialog::getFormattedProof);
connect(ui->btn_getSignature, &QPushButton::pressed, this, &TxProofDialog::getSignature);
ui->radio_SpendProof->setChecked(true);
ui->label_txid->setText(m_txid);
ui->group_summary->hide(); // todo
this->adjustSize();
}
void TxProofDialog::setTxId(const QString &txid) {
ui->label_txid->setText(txid);
}
void TxProofDialog::selectSpendProof() {
m_mode = Mode::SpendProof;
this->resetFrames();
if (m_direction == TransactionInfo::Direction_In) {
this->showWarning("Your wallet did not construct this transaction. Creating a SpendProof is not possible.");
return;
}
ui->frame_message->show();
ui->label_summary->setText("This proof shows you created a transaction with the txid shown above.");
}
void TxProofDialog::selectOutProof() {
m_mode = Mode::OutProof;
this->resetFrames();
if (m_OutDestinations.empty()) {
this->showWarning("This transaction did not spend any outputs owned by this wallet. Creating an OutProof is not possible.");
return;
}
if (m_txKey.isEmpty()) {
this->showWarning("No transaction key stored for this transaction. Creating an OutProof is not possible.");
return;
}
this->selectTxProof();
ui->combo_address->addItems(m_OutDestinations);
ui->label_summary->setText("This proof shows you paid x XMR to the address selected above.");
}
void TxProofDialog::selectInProof() {
m_mode = Mode::InProof;
this->resetFrames();
if (m_InDestinations.empty()) {
this->showWarning("Your wallet did not receive any outputs in this transaction.");
return;
}
this->selectTxProof();
ui->combo_address->addItems(m_InDestinations);
ui->label_summary->setText("This proof shows you received x XMR to the address selected above.");
}
void TxProofDialog::selectTxProof() {
ui->frame_txKeyWarning->hide();
ui->frame_message->show();
ui->frame_address->show();
ui->combo_address->clear();
}
void TxProofDialog::resetFrames() {
ui->frame_txKeyWarning->hide();
ui->frame_message->hide();
ui->frame_address->hide();
this->toggleButtons(true);
}
void TxProofDialog::toggleButtons(bool enabled) {
ui->btn_getFormattedProof->setEnabled(enabled);
ui->btn_getSignature->setEnabled(enabled);
}
void TxProofDialog::showWarning(const QString &message) {
this->toggleButtons(false);
ui->frame_txKeyWarning->show();
ui->label_txKeyWarning->setText(message);
}
void TxProofDialog::getFormattedProof() {
QString message = ui->message->toPlainText();
QString address = ui->combo_address->currentText();
QString nettype = Utils::QtEnumToString(m_wallet->nettype()).toLower();
nettype = nettype.replace(0, 1, nettype[0].toUpper()); // Capitalize first letter
TxProof proof = this->getProof();
if (!proof.error.isEmpty()) {
QMessageBox::warning(this, "Get formatted proof", QString("Failed to get proof signature: %1").arg(proof.error));
return;
}
QStringList signatureSplit;
for (int i = 0; i < proof.proof.length(); i += 64) {
signatureSplit.append(proof.proof.mid(i, 64));
}
QString signature = signatureSplit.join('\n');
QString formattedProof = [this, nettype, message, address, signature]{
switch (m_mode) {
case Mode::SpendProof: {
return QString("-----BEGIN SPENDPROOF-----\n"
"Network: Monero %1\n"
"Txid: %2\n"
"\n"
"%3\n"
"-----BEGIN SPENDPROOF SIGNATURE-----\n"
"\n"
"%4\n"
"-----END SPENDPROOF SIGNATURE-----").arg(nettype, m_txid, message, signature);
}
case Mode::OutProof: {
return QString("-----BEGIN OUTPROOF-----\n"
"Network: Monero %1\n"
"Txid: %2\n"
"Address: %3\n"
"\n"
"%4\n"
"-----BEGIN OUTPROOF SIGNATURE-----\n"
"\n"
"%5\n"
"-----END OUTPROOF SIGNATURE-----").arg(nettype, m_txid, address, message, signature);
}
case Mode::InProof: {
return QString("-----BEGIN INPROOF-----\n"
"Network: Monero %1\n"
"Txid: %2\n"
"Address: %3\n"
"\n"
"%4\n"
"-----BEGIN INPROOF SIGNATURE-----\n"
"\n"
"%5\n"
"-----END INPROOF SIGNATURE-----").arg(nettype, m_txid, address, message, signature);
}
default:
return QString("");
}
}();
Utils::copyToClipboard(formattedProof);
QMessageBox::information(this, "Get formatted proof", "Formatted proof copied to clipboard");
}
void TxProofDialog::getSignature() {
TxProof proof = this->getProof();
if (!proof.error.isEmpty()) {
QMessageBox::warning(this, "Get proof signature", QString("Failed to get proof signature: %1").arg(proof.error));
return;
}
Utils::copyToClipboard(proof.proof);
QMessageBox::information(this, "Get proof singature", "Proof signature copied to clipboard");
}
TxProof TxProofDialog::getProof() {
QString message = ui->message->toPlainText();
QString address = ui->combo_address->currentText();
TxProof proof = [this, message, address]{
switch (m_mode) {
case Mode::SpendProof: {
return m_wallet->getSpendProof(m_txid, message);
}
case Mode::OutProof:
case Mode::InProof: { // Todo: split this into separate functions
return m_wallet->getTxProof(m_txid, address, message);
}
}
}();
return proof;
}
TxProofDialog::~TxProofDialog() {
delete ui;
}

56
src/dialog/TxProofDialog.h

@ -0,0 +1,56 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project.
#ifndef FEATHER_TXPROOFDIALOG_H
#define FEATHER_TXPROOFDIALOG_H
#include <QDialog>
#include "libwalletqt/Wallet.h"
#include "libwalletqt/TransactionInfo.h"
namespace Ui {
class TxProofDialog;
}
class TxProofDialog : public QDialog
{
Q_OBJECT
public:
explicit TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txid);
~TxProofDialog() override;
void setTxId(const QString &txid);
private slots:
void selectSpendProof();
void selectOutProof();
void selectInProof();
void selectTxProof();
private:
enum Mode {
SpendProof = 0,
OutProof,
InProof
};
void getFormattedProof();
void getSignature();
TxProof getProof();
void resetFrames();
void toggleButtons(bool enabled);
void showWarning(const QString &message);
QStringList m_OutDestinations;
QStringList m_InDestinations;
QString m_txid;
QString m_txKey;
Mode m_mode;
TransactionInfo::Direction m_direction;
Ui::TxProofDialog *ui;
Wallet *m_wallet;
};
#endif //FEATHER_TXPROOFDIALOG_H

301
src/dialog/TxProofDialog.ui

@ -0,0 +1,301 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TxProofDialog</class>
<widget class="QDialog" name="TxProofDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>542</width>
<height>827</height>
</rect>
</property>
<property name="windowTitle">
<string>Create Tx Proof</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="group_proofType">
<property name="title">
<string>Select proof type:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QRadioButton" name="radio_SpendProof">
<property name="text">
<string>Prove authorship of a transaction (SpendProof)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radio_OutProof">
<property name="text">
<string>Prove a payment to an address (OutProof)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radio_InProof">
<property name="text">
<string>Prove ownership of an output (InProof)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Txid:</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QLabel" name="label_txid">
<property name="text">
<string>txid</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QFrame" name="frame_txKeyWarning">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label_txKeyWarning">
<property name="text">
<string>No transaction key stored for this transaction. Creating an OutProof is not possible.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_message">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Message: (optional)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QPlainTextEdit" name="message"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_address">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="combo_address"/>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="group_summary">
<property name="title">
<string>Summary:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_summary">
<property name="text">
<string>This proof shows I paid x XMR to ADDR.</string>
</property>
</widget>
</item>
</layout>
</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_getFormattedProof">
<property name="text">
<string>Get Formatted Proof</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_getSignature">
<property name="text">
<string>Get Signature</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

29
src/dialog/transactioninfodialog.cpp

@ -20,21 +20,18 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
{
ui->setupUi(this);
m_txProofWidget = new TxProofWidget(this, wallet, txInfo);
ui->label_txid->setText(QString(txInfo->hash()));
if (txInfo->direction() == TransactionInfo::Direction_In) {
ui->frameTxKey->hide();
} else {
QString txKey = m_wallet->getTxKey(txInfo->hash());
if (txKey.isEmpty()) {
ui->btn_CopyTxKey->setEnabled(false);
ui->btn_CopyTxKey->setToolTip("Transaction key unknown");
}
m_txKey = txKey;
m_txid = txInfo->hash();
ui->label_txid->setText(m_txid);
QString txKey = m_wallet->getTxKey(txInfo->hash());
if (txKey.isEmpty()) {
ui->btn_CopyTxKey->setEnabled(false);
ui->btn_CopyTxKey->setToolTip("Transaction key unknown");
}
m_txKey = txKey;
connect(ui->btn_CopyTxKey, &QPushButton::pressed, this, &TransactionInfoDialog::copyTxKey);
connect(ui->btn_createTxProof, &QPushButton::pressed, this, &TransactionInfoDialog::createTxProof);
QString blockHeight = QString::number(txInfo->blockHeight());
if (blockHeight == "0")
@ -66,7 +63,7 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
ui->frameDestinations->hide();
}
ui->txProofWidget->addWidget(m_txProofWidget);
m_txProofDialog = new TxProofDialog(this, m_wallet, txInfo);
this->adjustSize();
}
@ -75,6 +72,10 @@ void TransactionInfoDialog::copyTxKey() {
Utils::copyToClipboard(m_txKey);
}
void TransactionInfoDialog::createTxProof() {
m_txProofDialog->show();
}
TransactionInfoDialog::~TransactionInfoDialog() {
delete ui;
}

6
src/dialog/transactioninfodialog.h

@ -10,7 +10,7 @@
#include "libwalletqt/Coins.h"
#include "libwalletqt/TransactionInfo.h"
#include "libwalletqt/Wallet.h"
#include "widgets/txproofwidget.h"
#include "dialog/TxProofDialog.h"
namespace Ui {
class TransactionInfoDialog;
@ -26,13 +26,15 @@ public:
private:
void copyTxKey();
void createTxProof();
Ui::TransactionInfoDialog *ui;
TxProofDialog *m_txProofDialog;
TransactionInfo *m_txInfo;
Wallet *m_wallet;
TxProofWidget *m_txProofWidget;
QString m_txKey;
QString m_txid;
};
#endif //FEATHER_TRANSACTIONINFODIALOG_H

67
src/dialog/transactioninfodialog.ui

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>829</width>
<height>570</height>
<height>493</height>
</rect>
</property>
<property name="windowTitle">
@ -187,16 +187,47 @@
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>15</height>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="btn_CopyTxKey">
<property name="text">
<string>Copy Transaction Key</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_createTxProof">
<property name="text">
<string>Create Transaction Proof</string>
</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>
</layout>
</item>
<item>
<widget class="QFrame" name="frameTxKey">
<property name="frameShape">
@ -218,39 +249,9 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="btn_CopyTxKey">
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Transaction Key</string>
</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>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="txProofWidget"/>
</item>
</layout>
</widget>
<resources/>

115
src/dialog/verifyproofdialog.cpp

@ -5,6 +5,7 @@
#include "ui_verifyproofdialog.h"
#include "libwalletqt/WalletManager.h"
#include "utils/utils.h"
#include <QMessageBox>
@ -15,25 +16,34 @@ VerifyProofDialog::VerifyProofDialog(Wallet *wallet, QWidget *parent)
{
ui->setupUi(this);
m_success = QPixmap(":/assets/images/confirmed.png").scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_failure = QPixmap(":/assets/images/expired.png").scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation);
ui->frame_status->hide();
connect(ui->input_formattedProof, &QPlainTextEdit::textChanged, [this]{
ui->frame_status->hide();
});
connect(ui->btn_verify, &QPushButton::clicked, this, &VerifyProofDialog::checkProof);
connect(ui->btn_verifyFormattedProof, &QPushButton::clicked, this, &VerifyProofDialog::checkFormattedProof);
connect(ui->btn_clear, &QPushButton::clicked, [this]{
switch (ui->tabWidget->currentIndex()) {
case 0:
ui->lineEdit_spendTxID->clear();
ui->lineEdit_spendMessage->clear();
ui->input_SpendMessage->clear();
ui->input_SpendProof->clear();
break;
case 1:
ui->lineEdit_outTxID->clear();
ui->lineEdit_outAddress->clear();
ui->lineEdit_outMessage->clear();
ui->input_OutMessage->clear();
ui->input_OutProof->clear();
break;
case 2:
ui->lineEdit_inTxID->clear();
ui->lineEdit_inAddress->clear();
ui->lineEdit_inMessage->clear();
ui->input_inMessage->clear();
ui->input_InProof->clear();
break;
}
@ -48,7 +58,7 @@ VerifyProofDialog::~VerifyProofDialog()
void VerifyProofDialog::checkProof() {
switch (ui->tabWidget->currentIndex()) {
case 0:
this->checkSpendProof();
this->checkSpendProof(ui->lineEdit_spendTxID->text(), ui->input_SpendMessage->toPlainText(), ui->input_SpendProof->toPlainText());
break;
case 1:
this->checkOutProof();
@ -59,40 +69,105 @@ void VerifyProofDialog::checkProof() {
}
}
void VerifyProofDialog::checkSpendProof() {
auto r = m_wallet->checkSpendProof(ui->lineEdit_spendTxID->text(), ui->lineEdit_spendMessage->text(), ui->input_SpendProof->toPlainText());
void VerifyProofDialog::checkTxProof(const QString &txId, const QString &address, const QString &message,
const QString &signature) {
TxProofResult r = m_wallet->checkTxProof(txId, address, message, signature);
if (!r.success) {
this->proofStatus(false, m_wallet->errorString());
return;
}
if (!r.good) {
this->proofStatus(false, "Proof is invalid");
return;
}
this->proofStatus(true, QString("Proof is valid.\n\nThis address received %1 XMR, with %2 confirmation(s)").arg(WalletManager::displayAmount(r.received), QString::number(r.confirmations)));
}
void VerifyProofDialog::checkSpendProof(const QString &txId, const QString &message, const QString &signature) {
auto r = m_wallet->checkSpendProof(txId, message, signature);
if (!r.first) {
QMessageBox::information(this, "Information", m_wallet->errorString());
this->proofStatus(false, m_wallet->errorString());
return;
}
r.second ? QMessageBox::information(this, "Information", "Proof is valid")
: QMessageBox::warning(this, "Warning", "Proof is invalid");
r.second ? this->proofStatus(true, "Proof is valid")
: this->proofStatus(false, "Proof is invalid");
}
void VerifyProofDialog::checkOutProof() {
this->checkTxProof(ui->lineEdit_outTxID->text(), ui->lineEdit_outAddress->text(), ui->lineEdit_outMessage->text(), ui->input_OutProof->toPlainText());
this->checkTxProof(ui->lineEdit_outTxID->text(), ui->lineEdit_outAddress->text(), ui->input_OutMessage->toPlainText(), ui->input_OutProof->toPlainText());
}
void VerifyProofDialog::checkInProof() {
this->checkTxProof(ui->lineEdit_inTxID->text(), ui->lineEdit_inAddress->text(), ui->lineEdit_inMessage->text(), ui->input_InProof->toPlainText());
this->checkTxProof(ui->lineEdit_inTxID->text(), ui->lineEdit_inAddress->text(), ui->input_inMessage->toPlainText(), ui->input_InProof->toPlainText());
}
void VerifyProofDialog::checkTxProof(const QString &txId, const QString &address, const QString &message,
const QString &signature) {
TxProofResult r = m_wallet->checkTxProof(txId, address, message, signature);
void VerifyProofDialog::checkFormattedProof() {
QRegularExpression proof("-----BEGIN (?<type>\\w+)-----\\n"
"Network: (?<coin>\\w+) (?<network>\\w+)\\n"
"Txid: (?<txid>[0-9a-f]{64})\\n"
"(Address: (?<address>\\w+)\\n)?"
"\\n?"
"(?<message>.*?)\\n"
"-----BEGIN \\1 SIGNATURE-----\\n"
"\\n?"
"(?<signature>.*?)\\n"
"-----END \\1 SIGNATURE-----",
QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption);
QString formattedProof = ui->input_formattedProof->toPlainText();
QRegularExpressionMatch match = proof.match(formattedProof);
if (!match.hasMatch()) {
this->proofStatus(false, "Unable to parse proof");
return;
}
if (!r.success) {
QMessageBox::information(this, "Information", m_wallet->errorString());
QString type = match.captured("type").toLower();
QString coin = match.captured("coin").toLower();
QString network = match.captured("network").toLower();
QString txid = match.captured("txid");
QString address = match.captured("address");
QString message = match.captured("message");
QString signature = match.captured("signature").remove('\n');
QStringList validTypes = {"inproof", "spendproof", "outproof"};
if (!validTypes.contains(type)) {
this->proofStatus(false, QString("Unknown proof type: %1").arg(type));
return;
}
if (!r.good) {
QMessageBox::warning(this, "Warning", "Proof is invalid");
if (coin != "monero") {
this->proofStatus(false, QString("Can't verify proof for coin: %1").arg(coin));
return;
}
QString walletNetwork = Utils::QtEnumToString(m_wallet->nettype()).toLower();
if (network != walletNetwork) {
this->proofStatus(false, QString("Can't verify proof for %1 network when %2 wallet is opened").arg(network, walletNetwork));
return;
}
QString msg = QString("This address received %1 monero, with %2 confirmation(s)").arg(WalletManager::displayAmount(r.received), QString::number(r.confirmations));
QMessageBox::information(this, "Information", QString("Proof is valid.\n\n%1").arg(msg));
if (type == "outproof" || type == "inproof") {
this->checkTxProof(txid, address, message, signature);
}
if (type == "spendproof") {
this->checkSpendProof(txid, message, signature);
}
}
void VerifyProofDialog::proofStatus(bool success, const QString &message) {
if (ui->tabWidget_proofFormat->currentIndex() == 0) {
ui->frame_status->show();
ui->label_icon->setPixmap(success ? m_success : m_failure);
ui->label_status->setText(message);
}
else {
success ? QMessageBox::information(this, "Information", message)
: QMessageBox::warning(this, "Warning", message);
}
}

8
src/dialog/verifyproofdialog.h

@ -5,6 +5,7 @@
#define FEATHER_VERIFYPROOFDIALOG_H
#include <QDialog>
#include <QIcon>
#include "libwalletqt/Wallet.h"
namespace Ui {
@ -24,9 +25,14 @@ private slots:
private:
void checkTxProof(const QString &txId, const QString &address, const QString &message, const QString &signature);
void checkSpendProof();
void checkSpendProof(const QString &txId, const QString &message, const QString &signature);
void checkOutProof();
void checkInProof();
void checkFormattedProof();
void proofStatus(bool success, const QString &message);
QPixmap m_success;
QPixmap m_failure;
Ui::VerifyProofDialog *ui;
Wallet *m_wallet;

593
src/dialog/verifyproofdialog.ui

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1123</width>
<height>413</height>
<width>770</width>
<height>587</height>
</rect>
</property>
<property name="windowTitle">
@ -15,298 +15,411 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Select proof to verify:</string>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<widget class="QTabWidget" name="tabWidget_proofFormat">
<property name="currentIndex">
<number>2</number>
<number>0</number>
</property>
<widget class="QWidget" name="SpendProof">
<widget class="QWidget" name="tab_formatted">
<attribute name="title">
<string>SpendProof</string>
<string>Formatted</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="label_16">
<property name="text">
<string>A SpendProof proves authorship of a transaction.</string>
<string>Paste formatted proof here:</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Message:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_spendTxID"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Transaction ID:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_spendMessage">
<property name="placeholderText">
<string>Optional message against which the signature is signed</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>SpendProof:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="input_SpendProof">
<property name="overwriteMode">
<bool>false</bool>
</property>
<property name="placeholderText">
<string>SpendProof..</string>
</property>
</widget>
</item>
</layout>
<widget class="QPlainTextEdit" name="input_formattedProof"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<widget class="QFrame" name="frame_status">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="OutProof">
<attribute name="title">
<string>OutProof</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>An OutProof shows the prover sent an output to an address.</string>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_icon">
<property name="text">
<string>icon</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_status">
<property name="text">
<string>Proof is valid</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>OutProof:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_outTxID"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_outAddress">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Address of recipient</string>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Transaction ID:</string>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</widget>
</spacer>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<item>
<widget class="QPushButton" name="btn_verifyFormattedProof">
<property name="text">
<string>Message:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_outMessage">
<property name="placeholderText">
<string>Optional message against which the signature is signed</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPlainTextEdit" name="input_OutProof">
<property name="placeholderText">
<string>OutProof..</string>
<string>Verify</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="InProof">
<widget class="QWidget" name="tab_manual">
<attribute name="title">
<string>InProof</string>
<string>Manual</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="label_11">
<widget class="QLabel" name="label">
<property name="text">
<string>An InProof proves ownership of an output.</string>
<string>Select proof to verify:</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>InProof:</string>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="SpendProof">
<attribute name="title">
<string>SpendProof</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>A SpendProof proves authorship of a transaction.</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Message:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_spendTxID"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Transaction ID:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>SpendProof:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="input_SpendProof">
<property name="overwriteMode">
<bool>false</bool>
</property>
<property name="placeholderText">
<string>SpendProof..</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPlainTextEdit" name="input_SpendMessage">
<property name="placeholderText">
<string>Optional message against which the signature is signed</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="OutProof">
<attribute name="title">
<string>OutProof</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>An OutProof shows the prover sent an output to an address.</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>OutProof:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_outTxID"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_outAddress">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Address of recipient</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Transaction ID:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Message:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPlainTextEdit" name="input_OutProof">
<property name="placeholderText">
<string>OutProof..</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPlainTextEdit" name="input_OutMessage">
<property name="placeholderText">
<string>Optional message against which the signature is signed</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="InProof">
<attribute name="title">
<string>InProof</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>An InProof proves ownership of an output.</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>InProof:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Transaction ID:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_inAddress">
<property name="placeholderText">
<string>Output owner's address</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPlainTextEdit" name="input_InProof">
<property name="placeholderText">
<string>InProof..</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_inTxID">
<property name="placeholderText">
<string>Transaction that created the output</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="input_inMessage">
<property name="placeholderText">
<string>Optional message against which the signature is signed</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Message:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Transaction ID:</string>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</widget>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<item>
<widget class="QPushButton" name="btn_clear">
<property name="text">
<string>Address:</string>
<string>Clear</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_inAddress">
<property name="placeholderText">
<string>Output owner's address</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_inTxID">
<property name="placeholderText">
<string>Transaction that created the output</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_15">
<item>
<widget class="QPushButton" name="btn_verify">
<property name="text">
<string>Message:</string>