Skip to content

Commit

Permalink
Add memo field in UI (#1493)
Browse files Browse the repository at this point in the history
* Add memo field in UI

* add memo warrning message and fixes

* Add additional checks for memo
  • Loading branch information
levoncrypto authored Nov 29, 2024
1 parent c03c847 commit 6da96d8
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 14 deletions.
53 changes: 46 additions & 7 deletions src/qt/forms/sendcoinsentry.ui
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@
</item>
</layout>
</item>
<item row="4" column="0">
<item row="6" column="0">
<widget class="QLabel" name="messageLabel">
<property name="text">
<string>Message:</string>
Expand All @@ -231,15 +231,54 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="messageTextLabel">
<item row="6" column="1">
<widget class="QLineEdit" name="messageTextLabel">
<property name="toolTip">
<string>A message that was attached to the firo: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Firo network.</string>
<string>Optional message for this transaction</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</widget>
</item>
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayoutWarning" stretch="0,1">
<property name="spacing">
<number>0</number>
</property>
</widget>
<item>
<widget class="QLabel" name="iconMessageWarning">
<property name="toolTip">
<string></string>
</property>
<property name="text">
<string></string>
</property>
<property name="minimumWidth">
5
</property>
<property name="minimumHeight">
5
</property>
<property name="fixedWidth">
10
</property>
<property name="fixedHeight">
10
</property>
<property name="styleSheet">
<string>margin-left:-30px;margin-right:-10px;margin-top:2px;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="messageWarning">
<property name="text">
<string></string>
</property>
<property name="styleSheet">
<string>color: #FFA800; margin-left:-10px;</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0" colspan="2">
<widget class="Line" name="line">
Expand Down
13 changes: 13 additions & 0 deletions src/qt/sendcoinsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ void SendCoinsDialog::on_sendButton_clicked()
}
ctx = dialog->getUnlockContext();
}
recipient.message = entry->getValue().message;
recipients.append(recipient);
}
else
Expand Down Expand Up @@ -532,6 +533,18 @@ void SendCoinsDialog::on_sendButton_clicked()
QString questionString = tr("Are you sure you want to send?");
questionString.append(warningMessage);
questionString.append("<br /><br />%1");
bool firstMessage = true;
for (const auto& rec : recipients) {
if (!rec.message.isEmpty()) {
if (firstMessage) {
questionString.append("<hr><b>" + tr("Messages") + ":</b><br>");
firstMessage = false;
}
QString sanitizedMsg = GUIUtil::HtmlEscape(rec.message, true);
questionString.append("" + sanitizedMsg + "<br>");
}
}

double txSize;
if ((fAnonymousMode == false) && (recipients.size() == sparkAddressCount) && spark::IsSparkAllowed())
{
Expand Down
39 changes: 39 additions & 0 deletions src/qt/sendcoinsentry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "optionsmodel.h"
#include "platformstyle.h"
#include "walletmodel.h"
#include "../spark/sparkwallet.h"
#include "../wallet/wallet.h"

#include <QApplication>
Expand All @@ -29,6 +30,7 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *par
QIcon icon_;
icon_.addFile(QString::fromUtf8(":/icons/ic_warning"), QSize(), QIcon::Normal, QIcon::On);
ui->iconWarning->setPixmap(icon_.pixmap(18, 18));
ui->iconMessageWarning->setPixmap(icon_.pixmap(18, 18));

ui->addressBookButton->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
ui->pasteButton->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
Expand All @@ -55,13 +57,43 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *par
connect(ui->deleteButton, &QToolButton::clicked, this, &SendCoinsEntry::deleteClicked);
connect(ui->deleteButton_is, &QToolButton::clicked, this, &SendCoinsEntry::deleteClicked);
connect(ui->deleteButton_s, &QToolButton::clicked, this, &SendCoinsEntry::deleteClicked);
connect(ui->messageTextLabel, &QLineEdit::textChanged, this, &SendCoinsEntry::on_MemoTextChanged);

ui->messageLabel->setVisible(false);
ui->messageTextLabel->setVisible(false);
ui->iconMessageWarning->setVisible(false);
}

SendCoinsEntry::~SendCoinsEntry()
{
delete ui;
}

void SendCoinsEntry::on_MemoTextChanged(const QString &text)
{
const spark::Params* params = spark::Params::get_default();
int maxLength = params->get_memo_bytes();
bool isOverLimit = text.length() > maxLength;

if (isOverLimit) {
ui->messageWarning->setText(QString("Message exceeds %1 bytes limit").arg(maxLength));
ui->messageWarning->setVisible(true);
ui->messageTextLabel->setStyleSheet("border: 1px solid red;");
ui->iconMessageWarning->setVisible(true);
} else {
QString sanitized = text;
sanitized.remove(QRegExp("[\\x00-\\x1F\\x7F]"));
if (sanitized != text) {
ui->messageTextLabel->setText(sanitized);
return;
}
ui->messageWarning->clear();
ui->messageWarning->setVisible(false);
ui->messageTextLabel->setStyleSheet("");
ui->iconMessageWarning->setVisible(false);
}
}

void SendCoinsEntry::on_pasteButton_clicked()
{
// Paste text from clipboard into recipient field
Expand All @@ -85,6 +117,13 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
updateLabel(address);
setWarning(fAnonymousMode);

bool isSparkAddress = false;
if (model) {
isSparkAddress = model->validateSparkAddress(address);
}
ui->messageLabel->setVisible(isSparkAddress);
ui->messageTextLabel->setVisible(isSparkAddress);
}

void SendCoinsEntry::setModel(WalletModel *_model)
Expand Down
1 change: 1 addition & 0 deletions src/qt/sendcoinsentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public Q_SLOTS:
private Q_SLOTS:
void deleteClicked();
void on_payTo_textChanged(const QString &address);
void on_MemoTextChanged(const QString &text);
void on_addressBookButton_clicked();
void on_pasteButton_clicked();
void updateDisplayUnit();
Expand Down
42 changes: 38 additions & 4 deletions src/qt/transactiondesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,44 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->GetTotalSize()) + " bytes<br>";
strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";

// Message from normal firo:URI (firo:123...?message=example)
for (const PAIRTYPE(std::string, std::string)& r : wtx.vOrderForm)
if (r.first == "Message")
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
isminetype fAllFromMe = ISMINE_SPENDABLE;
bool foundSparkOutput = false;

for (const CTxIn& txin : wtx.tx->vin) {
isminetype mine = wallet->IsMine(txin, *wtx.tx);
fAllFromMe = std::min(fAllFromMe, mine);
}

bool firstMessage = true;
if (fAllFromMe) {
for (const CTxOut& txout : wtx.tx->vout) {
if (wtx.IsChange(txout)) continue;

CSparkOutputTx sparkOutput;
if (wallet->GetSparkOutputTx(txout.scriptPubKey, sparkOutput)) {
if (!sparkOutput.memo.empty()) {
foundSparkOutput = true;
if (firstMessage) {
strHTML += "<hr><b>" + tr("Messages") + ":</b><br>";
firstMessage = false;
}
strHTML += "" + GUIUtil::HtmlEscape(sparkOutput.memo, true) + "<br>";
}
}
}
}

if (!foundSparkOutput && wallet->sparkWallet) {
for (const auto& [id, meta] : wallet->sparkWallet->getMintMap()) {
if (meta.txid == rec->hash && !meta.memo.empty()) {
if (firstMessage) {
strHTML += "<hr><b>" + tr("Messages") + ":</b><br>";
firstMessage = false;
}
strHTML += "" + GUIUtil::HtmlEscape(meta.memo, true) + "<br>";
}
}
}

if (wtx.IsCoinBase())
{
Expand Down
4 changes: 2 additions & 2 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareMintSparkTransaction(std::vecto
address.decode(rcp.address.toStdString());
spark::MintedCoinData data;
data.address = address;
data.memo = "";
data.memo = rcp.message.toStdString();
data.v = rcp.amount;
outputs.push_back(data);
total += rcp.amount;
Expand Down Expand Up @@ -1481,7 +1481,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareSpendSparkTransaction(WalletMod
address.decode(rcp.address.toStdString());
spark::OutputCoinData data;
data.address = address;
data.memo = "";
data.memo = rcp.message.toStdString();
data.v = rcp.amount;
privateRecipients.push_back(std::make_pair(data, rcp.fSubtractFeeFromAmount));
} else {
Expand Down
11 changes: 11 additions & 0 deletions src/spark/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class CSparkOutputTx
{
public:
std::string address;
std::string memo;
int64_t amount;

CSparkOutputTx()
Expand All @@ -97,6 +98,7 @@ class CSparkOutputTx
void SetNull()
{
address = "";
memo = "";
amount = 0;
}

Expand All @@ -105,6 +107,15 @@ class CSparkOutputTx
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(address);
READWRITE(amount);
if (ser_action.ForRead()) {
if (!s.empty()) {
READWRITE(memo);
} else {
memo = "";
}
} else {
READWRITE(memo);
}
}
};

Expand Down
9 changes: 8 additions & 1 deletion src/spark/sparkwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,12 @@ std::vector<CRecipient> CSparkWallet::CreateSparkMintRecipients(
script.insert(script.end(), serializedCoins[i].begin(), serializedCoins[i].end());
unsigned char network = spark::GetNetworkType();
std::string addr = outputs[i].address.encode(network);
CRecipient recipient = {script, CAmount(outputs[i].v), false, addr};
std::string memo = outputs[i].memo;
const std::size_t max_memo_size = outputs[i].address.get_params()->get_memo_bytes();
if (memo.length() > max_memo_size) {
throw std::runtime_error(strprintf("Memo exceeds maximum length of %d bytes", max_memo_size));
}
CRecipient recipient = {script, CAmount(outputs[i].v), false, addr, memo};
results.emplace_back(recipient);
}

Expand Down Expand Up @@ -1093,6 +1098,7 @@ bool CSparkWallet::CreateSparkMintTransactions(
CSparkOutputTx output;
output.address = recipient.address;
output.amount = recipient.nAmount;
output.memo = recipient.memo;
walletdb.WriteSparkOutputTx(recipient.scriptPubKey, output);
break;
}
Expand Down Expand Up @@ -1530,6 +1536,7 @@ CWalletTx CSparkWallet::CreateSparkSpendTransaction(
CSparkOutputTx output;
output.address = privOutputs[i].address.encode(network);
output.amount = privOutputs[i].v;
output.memo = privOutputs[i].memo;
walletdb.WriteSparkOutputTx(script, output);
tx.vout.push_back(CTxOut(0, script));
i++;
Expand Down
1 change: 1 addition & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ struct CRecipient
CAmount nAmount;
bool fSubtractFeeFromAmount;
std::string address;
std::string memo;
};

typedef std::map<std::string, std::string> mapValue_t;
Expand Down

0 comments on commit 6da96d8

Please sign in to comment.