Skip to content

Commit 8c92bfd

Browse files
committed
fix: Bug #33 — wrong mint tooltip limits + silent decimal truncation
Two issues found during Gitter community testing (Apr 1 2026): 1. Tooltip showed generic wallet limits (0.00000001 to 999,999,999) instead of actual DD limits ($100-$100K for mint, $1-$100K for send). Root cause: AmountValidator was initialized with DGB satoshi ranges rather than DigiDollar consensus params. 2. Entering amounts with >2 decimal places (e.g. 9999.12345678) was silently truncated to 2 places via static_cast<CAmount>(amount*100) with no warning. Users saw 'Mint validation success' for the wrong amount. Fixes across all 4 DD widgets (mint, send, redeem, positions): - Add maxDecimals parameter to AmountValidator (default 8 for DGB backwards compat, 2 for all DD widgets) - Validator now rejects >2 decimal places at input time — users literally cannot type a third decimal digit - Update all tooltips/placeholders to show correct DD limits - Replace static_cast truncation with std::llround() as defense-in-depth - Change all DD formatDDAmount() from 'f',8 to 'f',2 (DD is cents) - Fix 'Use available balance' buttons to fill 2 decimal places Consensus params (unchanged): minMintAmount=10000 ($100), maxMintAmount=10000000 ($100K), minOutputAmount=100 ($1).
1 parent 11cca7d commit 8c92bfd

5 files changed

Lines changed: 37 additions & 31 deletions

File tree

src/qt/digidollarmintwidget.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@ void DigiDollarMintWidget::setupUI()
9797
m_mainLayout->setSpacing(0);
9898
m_mainLayout->setContentsMargins(0, 0, 0, 0);
9999

100-
// Create validators
101-
m_amountValidator = new AmountValidator(0.00000001, 999999999.99999999, this);
100+
// Create validators — DD amounts are in dollars with max 2 decimal places (cents)
101+
// Mint limits: $100 minimum, $100,000 maximum (from consensus params)
102+
m_amountValidator = new AmountValidator(100.00, 100000.00, 2, this);
102103

103104
// Create horizontal layout for mint amount and lock period side-by-side
104105
QHBoxLayout* topLayout = new QHBoxLayout();
@@ -158,8 +159,8 @@ void DigiDollarMintWidget::setupMintAmountSection()
158159
m_amountEdit = new QLineEdit(this);
159160
m_amountEdit->setObjectName("amountEdit");
160161
m_amountEdit->setValidator(m_amountValidator);
161-
m_amountEdit->setPlaceholderText("0.00000000");
162-
m_amountEdit->setToolTip(tr("The amount of DigiDollar to mint.\n\nSupported formats:\n0.00000001 (minimum)\n• Up to 8 decimal places\n• Maximum: 999,999,999.99999999"));
162+
m_amountEdit->setPlaceholderText("0.00");
163+
m_amountEdit->setToolTip(tr("The amount of DigiDollar to mint.\n\n• Minimum: $100.00\nMaximum: $100,000.00\n• Up to 2 decimal places (cents)"));
163164
m_amountEdit->setFocusPolicy(Qt::StrongFocus);
164165
m_amountEdit->setAttribute(Qt::WA_InputMethodEnabled, true);
165166
QFont monospaceFont = GUIUtil::fixedPitchFont();
@@ -759,8 +760,8 @@ void DigiDollarMintWidget::onMintClicked()
759760
return;
760761
}
761762

762-
// Convert amount from double to CAmount (cents)
763-
CAmount ddAmountCents = static_cast<CAmount>(m_mintAmount * 100);
763+
// Convert amount from double to CAmount (cents) — use llround to avoid truncation
764+
CAmount ddAmountCents = static_cast<CAmount>(std::llround(m_mintAmount * 100));
764765

765766
// Call the wallet model to mint DigiDollar
766767
WalletModel::DigiDollarMintResult result = m_walletModel->mintDigiDollar(ddAmountCents, m_selectedTier);
@@ -905,7 +906,7 @@ bool DigiDollarMintWidget::validateCollateral() const
905906

906907
QString DigiDollarMintWidget::formatDDAmount(double amount) const
907908
{
908-
return QString::number(amount, 'f', 8) + " DD";
909+
return QString::number(amount, 'f', 2) + " DD";
909910
}
910911

911912
QString DigiDollarMintWidget::formatDGBAmount(double amount) const

src/qt/digidollarpositionswidget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ QWidget* DigiDollarPositionsWidget::createHealthWidget(double health) const
955955

956956
QString DigiDollarPositionsWidget::formatDDAmount(double amount) const
957957
{
958-
return QString::number(amount, 'f', 8) + " DD";
958+
return QString::number(amount, 'f', 2) + " DD";
959959
}
960960

961961
QString DigiDollarPositionsWidget::formatDGBAmount(double amount) const

src/qt/digidollarredeemwidget.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ void DigiDollarRedeemWidget::setupUI()
101101
m_mainLayout->setContentsMargins(0, 0, 0, 0);
102102

103103
// Create validators
104-
m_amountValidator = new AmountValidator(0.00000001, 999999999.99999999, this);
104+
// DD amounts are in dollars with max 2 decimal places (cents precision)
105+
m_amountValidator = new AmountValidator(1.00, 100000.00, 2, this);
105106

106107
// Setup sections
107108
setupCoinControlSection();
@@ -539,18 +540,18 @@ void DigiDollarRedeemWidget::onRedeemClicked()
539540
"Required: %2 DD\n\n"
540541
"System health is below 100%, requiring additional DD to redeem.\n"
541542
"You need %3 DD more to complete this redemption.")
542-
.arg(QString::number(ddBalance, 'f', 8))
543-
.arg(QString::number(requiredDDBurn, 'f', 8))
544-
.arg(QString::number(requiredDDBurn - ddBalance, 'f', 8));
543+
.arg(QString::number(ddBalance, 'f', 2))
544+
.arg(QString::number(requiredDDBurn, 'f', 2))
545+
.arg(QString::number(requiredDDBurn - ddBalance, 'f', 2));
545546
} else {
546547
// Normal redemption
547548
errorMsg = tr("Insufficient DigiDollars.\n\n"
548549
"You have: %1 DD\n"
549550
"Required: %2 DD\n\n"
550551
"You need %3 DD more to redeem this position.")
551-
.arg(QString::number(ddBalance, 'f', 8))
552-
.arg(QString::number(requiredDDBurn, 'f', 8))
553-
.arg(QString::number(requiredDDBurn - ddBalance, 'f', 8));
552+
.arg(QString::number(ddBalance, 'f', 2))
553+
.arg(QString::number(requiredDDBurn, 'f', 2))
554+
.arg(QString::number(requiredDDBurn - ddBalance, 'f', 2));
554555
}
555556

556557
Q_EMIT message(tr("Insufficient DigiDollar Balance"), errorMsg, QMessageBox::Warning);
@@ -569,7 +570,7 @@ void DigiDollarRedeemWidget::onRedeemClicked()
569570
"Required DD burn: %3 DD")
570571
.arg(m_selectedPositionId)
571572
.arg(formatDDAmount(m_positionDDMinted))
572-
.arg(QString::number(requiredDDBurn, 'f', 8));
573+
.arg(QString::number(requiredDDBurn, 'f', 2));
573574
} else {
574575
confirmText = tr("Close vault %1 and redeem %2?")
575576
.arg(m_selectedPositionId)
@@ -594,8 +595,8 @@ void DigiDollarRedeemWidget::onRedeemClicked()
594595
return;
595596
}
596597

597-
// Convert amount from double to CAmount (cents)
598-
CAmount amountCents = static_cast<CAmount>(amount * 100);
598+
// Convert amount from double to CAmount (cents) — use llround to avoid truncation
599+
CAmount amountCents = static_cast<CAmount>(std::llround(amount * 100));
599600

600601
// Call the wallet model to redeem DigiDollar
601602
WalletModel::DigiDollarRedeemResult result = m_walletModel->redeemDigiDollar(m_selectedPositionId, amountCents, "");
@@ -807,7 +808,7 @@ void DigiDollarRedeemWidget::loadPositionDetails()
807808
m_positionHealth = pos.find_value("health_ratio").get_real();
808809
m_redeemableAmount = m_positionDDMinted; // Can redeem full amount
809810
// Auto-fill the exact amount in the amount edit field
810-
m_amountEdit->setText(QString::number(m_positionDDMinted, 'f', 8));
811+
m_amountEdit->setText(QString::number(m_positionDDMinted, 'f', 2));
811812
break;
812813
}
813814
}
@@ -926,7 +927,7 @@ bool DigiDollarRedeemWidget::validateDDBalance() const
926927

927928
QString DigiDollarRedeemWidget::formatDDAmount(double amount) const
928929
{
929-
return QString::number(amount, 'f', 8) + " DD";
930+
return QString::number(amount, 'f', 2) + " DD";
930931
}
931932

932933
QString DigiDollarRedeemWidget::formatDGBAmount(double amount) const

src/qt/digidollarsendwidget.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <univalue.h>
2222

2323
#include <chrono>
24+
#include <cmath>
2425

2526
#include <QLabel>
2627
#include <QLineEdit>
@@ -112,7 +113,9 @@ void DigiDollarSendWidget::setupUI()
112113

113114
// Create validators
114115
m_addressValidator = new DigiDollarAddressValidator(this);
115-
m_amountValidator = new AmountValidator(0.00000001, 999999999.99999999, this);
116+
// DD amounts are in dollars with max 2 decimal places (cents precision)
117+
// Send limits: $1 minimum (dust threshold), $100,000 maximum
118+
m_amountValidator = new AmountValidator(1.00, 100000.00, 2, this);
116119

117120
// Setup sections
118121
setupCoinControlSection();
@@ -255,8 +258,8 @@ void DigiDollarSendWidget::setupAmountSection()
255258
m_amountEdit = new QLineEdit(this);
256259
m_amountEdit->setObjectName("amountEdit");
257260
m_amountEdit->setValidator(m_amountValidator);
258-
m_amountEdit->setPlaceholderText("0.00000000");
259-
m_amountEdit->setToolTip(tr("The amount to send in DigiDollar.\n\nSupported formats:\n0.00000001 (minimum)\n• Up to 8 decimal places\n• Maximum: 999,999,999.99999999"));
261+
m_amountEdit->setPlaceholderText("0.00");
262+
m_amountEdit->setToolTip(tr("The amount of DigiDollar to send.\n\n• Minimum: $1.00\nMaximum: $100,000.00\n• Up to 2 decimal places (cents)"));
260263
m_amountEdit->setFocusPolicy(Qt::StrongFocus);
261264
m_amountEdit->setAttribute(Qt::WA_InputMethodEnabled, true);
262265
QFont monospaceFont = GUIUtil::fixedPitchFont();
@@ -660,7 +663,7 @@ void DigiDollarSendWidget::onUseAvailableBalanceClicked()
660663
// Users can send their ENTIRE DD balance without any deduction
661664
if (m_availableBalance > 0) {
662665
// Set amount to full available balance (fees are paid separately in DGB)
663-
m_amountEdit->setText(QString::number(m_availableBalance, 'f', 8));
666+
m_amountEdit->setText(QString::number(m_availableBalance, 'f', 2));
664667
onAmountChanged();
665668
}
666669
}
@@ -763,7 +766,7 @@ bool DigiDollarSendWidget::validateBalance() const
763766

764767
QString DigiDollarSendWidget::formatDDAmount(double amount) const
765768
{
766-
return QString::number(amount, 'f', 8) + " DD";
769+
return QString::number(amount, 'f', 2) + " DD";
767770
}
768771

769772
QString DigiDollarSendWidget::formatUSDAmount(double amount) const
@@ -916,7 +919,7 @@ void DigiDollarSendWidget::executeTransfer(const QString& address, double amount
916919
m_clearButton->setEnabled(false);
917920
m_useAvailableBalanceButton->setEnabled(false);
918921

919-
CAmount amountCents = static_cast<CAmount>(amount * 100);
922+
CAmount amountCents = static_cast<CAmount>(std::llround(amount * 100));
920923
QString note = m_noteEdit ? m_noteEdit->text().trimmed() : QString();
921924

922925
WalletModel::DigiDollarSendResult result = m_walletModel->sendDigiDollar(address, amountCents, note);
@@ -1310,8 +1313,8 @@ QString DigiDollarSendWidget::maskValue(const QString& value) const
13101313
}
13111314

13121315
// AmountValidator implementation
1313-
AmountValidator::AmountValidator(double min, double max, QObject* parent) :
1314-
QValidator(parent), m_min(min), m_max(max)
1316+
AmountValidator::AmountValidator(double min, double max, int maxDecimals, QObject* parent) :
1317+
QValidator(parent), m_min(min), m_max(max), m_maxDecimals(maxDecimals)
13151318
{
13161319
}
13171320

@@ -1334,10 +1337,10 @@ QValidator::State AmountValidator::validate(QString& input, int& pos) const
13341337
return QValidator::Invalid;
13351338
}
13361339

1337-
// Check decimal places (max 8)
1340+
// Check decimal places (max m_maxDecimals, default 8)
13381341
int decimalPos = input.indexOf('.');
13391342
if (decimalPos != -1) {
1340-
if (input.length() - decimalPos - 1 > 8) {
1343+
if (input.length() - decimalPos - 1 > m_maxDecimals) {
13411344
return QValidator::Invalid;
13421345
}
13431346
}

src/qt/digidollarsendwidget.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,14 @@ class AmountValidator : public QValidator
216216
Q_OBJECT
217217

218218
public:
219-
explicit AmountValidator(double min = 0.00000001, double max = 999999999.99999999, QObject* parent = nullptr);
219+
explicit AmountValidator(double min = 0.00000001, double max = 999999999.99999999, int maxDecimals = 8, QObject* parent = nullptr);
220220

221221
QValidator::State validate(QString& input, int& pos) const override;
222222

223223
private:
224224
double m_min;
225225
double m_max;
226+
int m_maxDecimals;
226227
};
227228

228229
/**

0 commit comments

Comments
 (0)