@@ -40,6 +40,12 @@ class STAmount final : public STBase, public CountedObject<STAmount>
4040 exponent_type mOffset ;
4141 bool mIsNegative ;
4242
43+ // The Enforce integer setting is not stored or serialized. If set, it is
44+ // used during automatic conversions to Number. If not set, the default
45+ // behavior is used. It can also be overridden when coverting by using
46+ // toNumber().
47+ std::optional<Number::EnforceInteger> enforceConversion_;
48+
4349public:
4450 using value_type = STAmount;
4551
@@ -135,16 +141,46 @@ class STAmount final : public STBase, public CountedObject<STAmount>
135141 STAmount (A const & asset, int mantissa, int exponent = 0 );
136142
137143 template <AssetType A>
138- STAmount (A const & asset, Number const & number)
144+ STAmount (
145+ A const & asset,
146+ Number const & number,
147+ std::optional<Number::EnforceInteger> enforce = std::nullopt )
139148 : STAmount(asset, number.mantissa(), number.exponent())
140149 {
150+ enforceConversion_ = enforce;
151+ if (!enforce)
152+ {
153+ // Use the default conversion behavior
154+ [[maybe_unused]]
155+ Number const n = *this ;
156+ }
157+ else if (enforce == Number::strong)
158+ {
159+ // Throw if it's not valid
160+ if (!validNumber ())
161+ {
162+ Throw<std::overflow_error>(
163+ " STAmount::STAmount integer Number lost precision" );
164+ }
165+ }
141166 }
142167
143168 // Legacy support for new-style amounts
144169 STAmount (IOUAmount const & amount, Issue const & issue);
145170 STAmount (XRPAmount const & amount);
146171 STAmount (MPTAmount const & amount, MPTIssue const & mptIssue);
147172 operator Number () const ;
173+ Number
174+ toNumber (Number::EnforceInteger enforce) const ;
175+
176+ void
177+ setIntegerEnforcement (std::optional<Number::EnforceInteger> enforce);
178+
179+ std::optional<Number::EnforceInteger>
180+ integerEnforcement () const noexcept ;
181+
182+ bool
183+ validNumber () const noexcept ;
148184
149185 // --------------------------------------------------------------------------
150186 //
@@ -155,6 +191,9 @@ class STAmount final : public STBase, public CountedObject<STAmount>
155191 int
156192 exponent () const noexcept ;
157193
194+ bool
195+ integral () const noexcept ;
196+
158197 bool
159198 native () const noexcept ;
160199
@@ -435,6 +474,12 @@ STAmount::exponent() const noexcept
435474 return mOffset ;
436475}
437476
477+ inline bool
478+ STAmount::integral () const noexcept
479+ {
480+ return mAsset .integral ();
481+ }
482+
438483inline bool
439484STAmount::native () const noexcept
440485{
@@ -510,13 +555,26 @@ inline STAmount::operator bool() const noexcept
510555
511556inline STAmount::operator Number () const
512557{
558+ if (enforceConversion_)
559+ return toNumber (*enforceConversion_);
513560 if (native ())
514561 return xrp ();
515562 if (mAsset .holds <MPTIssue>())
516563 return mpt ();
517564 return iou ();
518565}
519566
567+ inline Number
568+ STAmount::toNumber (Number::EnforceInteger enforce) const
569+ {
570+ if (native ())
571+ return xrp ().toNumber (enforce);
572+ if (mAsset .holds <MPTIssue>())
573+ return mpt ().toNumber (enforce);
574+ // It doesn't make sense to enforce limits on IOUs
575+ return iou ();
576+ }
577+
520578inline STAmount&
521579STAmount::operator =(beast::Zero)
522580{
@@ -538,6 +596,11 @@ STAmount::operator=(Number const& number)
538596 mValue = mIsNegative ? -number.mantissa () : number.mantissa ();
539597 mOffset = number.exponent ();
540598 canonicalize ();
599+
600+ // Convert it back to a Number to check that it's valid
601+ [[maybe_unused]]
602+ Number n = *this ;
603+
541604 return *this ;
542605}
543606
@@ -553,7 +616,7 @@ STAmount::clear()
553616{
554617 // The -100 is used to allow 0 to sort less than a small positive values
555618 // which have a negative exponent.
556- mOffset = native () ? 0 : -100 ;
619+ mOffset = integral () ? 0 : -100 ;
557620 mValue = 0 ;
558621 mIsNegative = false ;
559622}
0 commit comments