1- // Copyright (c) 2024 The Bitcoin Core developers
1+ // Copyright (c) 2024-2025 The Bitcoin Core developers
22// Distributed under the MIT software license, see the accompanying
33// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44
77#include < QRegExp>
88#include < QStringList>
99
10-
11- BitcoinAmount::BitcoinAmount (QObject *parent) : QObject(parent)
10+ BitcoinAmount::BitcoinAmount (QObject* parent)
11+ : QObject(parent)
1212{
13- m_unit = Unit::BTC;
14- }
15-
16- int BitcoinAmount::decimals (Unit unit)
17- {
18- switch (unit) {
19- case Unit::BTC: return 8 ;
20- case Unit::SAT: return 0 ;
21- } // no default case, so the compiler can warn about missing cases
22- assert (false );
2313}
2414
2515QString BitcoinAmount::sanitize (const QString &text)
@@ -43,6 +33,30 @@ QString BitcoinAmount::sanitize(const QString &text)
4333 return result;
4434}
4535
36+ qint64 BitcoinAmount::satoshi () const
37+ {
38+ return m_satoshi;
39+ }
40+
41+ void BitcoinAmount::setSatoshi (qint64 new_amount)
42+ {
43+ m_isSet = true ;
44+ if (m_satoshi != new_amount) {
45+ m_satoshi = new_amount;
46+ Q_EMIT amountChanged ();
47+ }
48+ }
49+
50+ void BitcoinAmount::clear ()
51+ {
52+ if (!m_isSet && m_satoshi == 0 ) {
53+ return ;
54+ }
55+ m_satoshi = 0 ;
56+ m_isSet = false ;
57+ Q_EMIT amountChanged ();
58+ }
59+
4660BitcoinAmount::Unit BitcoinAmount::unit () const
4761{
4862 return m_unit;
@@ -58,97 +72,82 @@ QString BitcoinAmount::unitLabel() const
5872{
5973 switch (m_unit) {
6074 case Unit::BTC: return " ₿" ;
61- case Unit::SAT: return " Sat " ;
75+ case Unit::SAT: return " sat " ;
6276 }
6377 assert (false );
6478}
6579
66- QString BitcoinAmount::amount () const
80+ void BitcoinAmount::flipUnit ()
6781{
68- return m_amount;
82+ if (m_unit == Unit::BTC) {
83+ m_unit = Unit::SAT;
84+ } else {
85+ m_unit = Unit::BTC;
86+ }
87+ Q_EMIT unitChanged ();
88+ Q_EMIT amountChanged ();
6989}
7090
71- QString BitcoinAmount::satoshiAmount () const
91+ QString BitcoinAmount::satsToBtc (qint64 sat)
7292{
73- return toSatoshis (m_amount) ;
74- }
93+ const bool negative = sat < 0 ;
94+ qint64 absSat = negative ? -sat : sat;
7595
76- void BitcoinAmount::setAmount (const QString& new_amount)
77- {
78- m_amount = sanitize (new_amount);
79- Q_EMIT amountChanged ();
96+ const qint64 wholePart = absSat / COIN;
97+ const qint64 fracInt = absSat % COIN;
98+ QString fracPart = QString (" %1" ).arg (fracInt, 8 , 10 , QLatin1Char (' 0' ));
99+
100+ QString result = QString::number (wholePart) + ' .' + fracPart;
101+ if (negative) {
102+ result.prepend (' -' );
103+ }
104+ return result;
80105}
81106
82- QString BitcoinAmount::toSatoshis ( const QString& text ) const
107+ QString BitcoinAmount::toDisplay ( ) const
83108{
109+ if (!m_isSet) {
110+ return " " ;
111+ }
84112 if (m_unit == Unit::SAT) {
85- return text ;
113+ return QString::number (m_satoshi) ;
86114 } else {
87- return convert (text, m_unit );
115+ return satsToBtc (m_satoshi );
88116 }
89117}
90118
91- long long BitcoinAmount::toSatoshis ( QString& amount, const Unit unit )
119+ qint64 BitcoinAmount::btcToSats ( const QString& btcSanitized )
92120{
93- int num_decimals = decimals (unit);
94-
95- QStringList parts = amount.remove (' ' ).split (" ." );
121+ if (btcSanitized.isEmpty () || btcSanitized == " ." ) return 0 ;
96122
97- QString whole = parts[ 0 ] ;
98- QString decimals ;
123+ QString cleaned = btcSanitized ;
124+ if (cleaned. startsWith ( ' . ' )) cleaned. prepend ( ' 0 ' ) ;
99125
100- if (parts.size () > 1 )
101- {
102- decimals = parts[1 ];
126+ QStringList parts = cleaned.split (' .' );
127+ const qint64 whole = parts[0 ].isEmpty () ? 0 : parts[0 ].toLongLong ();
128+ qint64 frac = 0 ;
129+ if (parts.size () == 2 ) {
130+ frac = parts[1 ].leftJustified (8 , ' 0' ).toLongLong ();
103131 }
104- QString str = whole + decimals.leftJustified (num_decimals, ' 0' , true );
105132
106- return str. toLongLong () ;
133+ return whole * COIN + frac ;
107134}
108135
109- QString BitcoinAmount::convert (const QString& amount, Unit unit) const
136+ void BitcoinAmount::fromDisplay (const QString& text)
110137{
111- if (amount == " " ) {
112- return amount;
113- }
114-
115- QString result = amount;
116- int decimalPosition = result.indexOf (" ." );
117-
118- if (decimalPosition == -1 ) {
119- decimalPosition = result.length ();
120- result.append (" ." );
138+ if (text.trimmed ().isEmpty ()) {
139+ clear ();
140+ return ;
121141 }
122142
123- if (unit == Unit::BTC) {
124- int numDigitsAfterDecimal = result.length () - decimalPosition - 1 ;
125- if (numDigitsAfterDecimal < 8 ) {
126- result.append (QString (8 - numDigitsAfterDecimal, ' 0' ));
127- }
128- result.remove (decimalPosition, 1 );
129-
130- while (result.startsWith (' 0' ) && result.length () > 1 ) {
131- result.remove (0 , 1 );
132- }
133- } else if (unit == Unit::SAT) {
134- result.remove (decimalPosition, 1 );
135- int newDecimalPosition = decimalPosition - 8 ;
136- if (newDecimalPosition < 1 ) {
137- result = QString (" 0" ).repeated (-newDecimalPosition) + result;
138- newDecimalPosition = 0 ;
139- }
140- result.insert (newDecimalPosition, " ." );
141-
142- while (result.endsWith (' 0' ) && result.contains (' .' )) {
143- result.chop (1 );
144- }
145- if (result.endsWith (' .' )) {
146- result.chop (1 );
147- }
148- if (result.startsWith (' .' )) {
149- result.insert (0 , " 0" );
150- }
143+ qint64 newSat = 0 ;
144+ if (m_unit == Unit::BTC) {
145+ QString sanitized = sanitize (text);
146+ newSat = btcToSats (sanitized);
147+ } else {
148+ QString digitsOnly = text;
149+ digitsOnly.remove (QRegExp (" [^0-9]" ));
150+ newSat = digitsOnly.trimmed ().isEmpty () ? 0 : digitsOnly.toLongLong ();
151151 }
152-
153- return result;
152+ setSatoshi (newSat);
154153}
0 commit comments