rippled
Loading...
Searching...
No Matches
STAmount.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/basics/Log.h>
21#include <xrpl/basics/contract.h>
22#include <xrpl/basics/safe_cast.h>
23#include <xrpl/beast/core/LexicalCast.h>
24#include <xrpl/protocol/Protocol.h>
25#include <xrpl/protocol/STAmount.h>
26#include <xrpl/protocol/SystemParameters.h>
27#include <xrpl/protocol/UintTypes.h>
28#include <xrpl/protocol/jss.h>
29#include <boost/algorithm/string.hpp>
30#include <boost/multiprecision/cpp_int.hpp>
31#include <boost/regex.hpp>
32
33#include <iterator>
34#include <memory>
35
36namespace ripple {
37
38namespace {
39
40// Use a static inside a function to help prevent order-of-initialzation issues
41LocalValue<bool>&
42getStaticSTAmountCanonicalizeSwitchover()
43{
44 static LocalValue<bool> r{true};
45 return r;
46}
47} // namespace
48
49bool
51{
52 return *getStaticSTAmountCanonicalizeSwitchover();
53}
54
55void
57{
58 *getStaticSTAmountCanonicalizeSwitchover() = v;
59}
60
61static const std::uint64_t tenTo14 = 100000000000000ull;
62static const std::uint64_t tenTo14m1 = tenTo14 - 1;
63static const std::uint64_t tenTo17 = tenTo14 * 1000;
64
65//------------------------------------------------------------------------------
66static std::int64_t
67getInt64Value(STAmount const& amount, bool valid, const char* error)
68{
69 if (!valid)
70 Throw<std::runtime_error>(error);
71 XRPL_ASSERT(
72 amount.exponent() == 0, "ripple::getInt64Value : exponent is zero");
73
74 auto ret = static_cast<std::int64_t>(amount.mantissa());
75
76 XRPL_ASSERT(
77 static_cast<std::uint64_t>(ret) == amount.mantissa(),
78 "ripple::getInt64Value : mantissa must roundtrip");
79
80 if (amount.negative())
81 ret = -ret;
82
83 return ret;
84}
85
86static std::int64_t
87getSNValue(STAmount const& amount)
88{
89 return getInt64Value(amount, amount.native(), "amount is not native!");
90}
91
92static std::int64_t
93getMPTValue(STAmount const& amount)
94{
95 return getInt64Value(
96 amount, amount.holds<MPTIssue>(), "amount is not MPT!");
97}
98
99static bool
100areComparable(STAmount const& v1, STAmount const& v2)
101{
102 if (v1.holds<Issue>() && v2.holds<Issue>())
103 return v1.native() == v2.native() &&
104 v1.get<Issue>().currency == v2.get<Issue>().currency;
105 if (v1.holds<MPTIssue>() && v2.holds<MPTIssue>())
106 return v1.get<MPTIssue>() == v2.get<MPTIssue>();
107 return false;
108}
109
110STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name)
111{
112 std::uint64_t value = sit.get64();
113
114 // native or MPT
115 if ((value & cIssuedCurrency) == 0)
116 {
117 if ((value & cMPToken) != 0)
118 {
119 // is MPT
120 mOffset = 0;
121 mIsNegative = (value & cPositive) == 0;
122 mValue = (value << 8) | sit.get8();
123 mAsset = sit.get192();
124 return;
125 }
126 // else is XRP
127 mAsset = xrpIssue();
128 // positive
129 if ((value & cPositive) != 0)
130 {
132 mOffset = 0;
133 mIsNegative = false;
134 return;
135 }
136
137 // negative
138 if (value == 0)
139 Throw<std::runtime_error>("negative zero is not canonical");
140
142 mOffset = 0;
143 mIsNegative = true;
144 return;
145 }
146
147 Issue issue;
148 issue.currency = sit.get160();
149
150 if (isXRP(issue.currency))
151 Throw<std::runtime_error>("invalid native currency");
152
153 issue.account = sit.get160();
154
155 if (isXRP(issue.account))
156 Throw<std::runtime_error>("invalid native account");
157
158 // 10 bits for the offset, sign and "not native" flag
159 int offset = static_cast<int>(value >> (64 - 10));
160
161 value &= ~(1023ull << (64 - 10));
162
163 if (value)
164 {
165 bool isNegative = (offset & 256) == 0;
166 offset = (offset & 255) - 97; // center the range
167
168 if (value < cMinValue || value > cMaxValue || offset < cMinOffset ||
169 offset > cMaxOffset)
170 {
171 Throw<std::runtime_error>("invalid currency value");
172 }
173
174 mAsset = issue;
175 mValue = value;
176 mOffset = offset;
177 mIsNegative = isNegative;
178 canonicalize();
179 return;
180 }
181
182 if (offset != 512)
183 Throw<std::runtime_error>("invalid currency value");
184
185 mAsset = issue;
186 mValue = 0;
187 mOffset = 0;
188 mIsNegative = false;
189 canonicalize();
190}
191
193 : STBase(name), mAsset(xrpIssue()), mOffset(0)
194{
195 set(mantissa);
196}
197
198STAmount::STAmount(SField const& name, std::uint64_t mantissa, bool negative)
199 : STBase(name)
200 , mAsset(xrpIssue())
201 , mValue(mantissa)
202 , mOffset(0)
203 , mIsNegative(negative)
204{
205 XRPL_ASSERT(
207 "ripple::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
208 "mantissa input");
209}
210
211STAmount::STAmount(SField const& name, STAmount const& from)
212 : STBase(name)
213 , mAsset(from.mAsset)
214 , mValue(from.mValue)
215 , mOffset(from.mOffset)
216 , mIsNegative(from.mIsNegative)
217{
218 XRPL_ASSERT(
220 "ripple::STAmount::STAmount(SField, STAmount) : maximum input");
221 canonicalize();
222}
223
224//------------------------------------------------------------------------------
225
226STAmount::STAmount(std::uint64_t mantissa, bool negative)
227 : mAsset(xrpIssue())
228 , mValue(mantissa)
229 , mOffset(0)
230 , mIsNegative(mantissa != 0 && negative)
231{
232 XRPL_ASSERT(
234 "ripple::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
235 "input");
236}
237
239 : mAsset(xrpIssue()), mOffset(0), mIsNegative(amount < beast::zero)
240{
241 if (mIsNegative)
242 mValue = unsafe_cast<std::uint64_t>(-amount.drops());
243 else
244 mValue = unsafe_cast<std::uint64_t>(amount.drops());
245
246 canonicalize();
247}
248
251{
252 return std::make_unique<STAmount>(sit, name);
253}
254
255STBase*
256STAmount::copy(std::size_t n, void* buf) const
257{
258 return emplace(n, buf, *this);
259}
260
261STBase*
263{
264 return emplace(n, buf, std::move(*this));
265}
266
267//------------------------------------------------------------------------------
268//
269// Conversion
270//
271//------------------------------------------------------------------------------
274{
275 if (!native())
276 Throw<std::logic_error>(
277 "Cannot return non-native STAmount as XRPAmount");
278
279 auto drops = static_cast<XRPAmount::value_type>(mValue);
280
281 if (mIsNegative)
282 drops = -drops;
283
284 return XRPAmount{drops};
285}
286
289{
290 if (native() || !holds<Issue>())
291 Throw<std::logic_error>("Cannot return non-IOU STAmount as IOUAmount");
292
293 auto mantissa = static_cast<std::int64_t>(mValue);
294 auto exponent = mOffset;
295
296 if (mIsNegative)
298
299 return {mantissa, exponent};
300}
301
304{
305 if (!holds<MPTIssue>())
306 Throw<std::logic_error>("Cannot return STAmount as MPTAmount");
307
308 auto value = static_cast<MPTAmount::value_type>(mValue);
309
310 if (mIsNegative)
311 value = -value;
312
313 return MPTAmount{value};
314}
315
318{
319 XRPL_ASSERT(
320 native() == false,
321 "ripple::STAmount::operator=(IOUAmount) : is not XRP");
322 mOffset = iou.exponent();
323 mIsNegative = iou < beast::zero;
324 if (mIsNegative)
325 mValue = static_cast<std::uint64_t>(-iou.mantissa());
326 else
327 mValue = static_cast<std::uint64_t>(iou.mantissa());
328 return *this;
329}
330
331//------------------------------------------------------------------------------
332//
333// Operators
334//
335//------------------------------------------------------------------------------
336
339{
340 *this = *this + a;
341 return *this;
342}
343
346{
347 *this = *this - a;
348 return *this;
349}
350
352operator+(STAmount const& v1, STAmount const& v2)
353{
354 if (!areComparable(v1, v2))
355 Throw<std::runtime_error>("Can't add amounts that are't comparable!");
356
357 if (v2 == beast::zero)
358 return v1;
359
360 if (v1 == beast::zero)
361 {
362 // Result must be in terms of v1 currency and issuer.
363 return {
364 v1.getFName(),
365 v1.asset(),
366 v2.mantissa(),
367 v2.exponent(),
368 v2.negative()};
369 }
370
371 if (v1.native())
372 return {v1.getFName(), getSNValue(v1) + getSNValue(v2)};
373 if (v1.holds<MPTIssue>())
374 return {v1.mAsset, v1.mpt().value() + v2.mpt().value()};
375
377 {
378 auto x = v1;
379 x = v1.iou() + v2.iou();
380 return x;
381 }
382
383 int ov1 = v1.exponent(), ov2 = v2.exponent();
384 std::int64_t vv1 = static_cast<std::int64_t>(v1.mantissa());
385 std::int64_t vv2 = static_cast<std::int64_t>(v2.mantissa());
386
387 if (v1.negative())
388 vv1 = -vv1;
389
390 if (v2.negative())
391 vv2 = -vv2;
392
393 while (ov1 < ov2)
394 {
395 vv1 /= 10;
396 ++ov1;
397 }
398
399 while (ov2 < ov1)
400 {
401 vv2 /= 10;
402 ++ov2;
403 }
404
405 // This addition cannot overflow an std::int64_t. It can overflow an
406 // STAmount and the constructor will throw.
407
408 std::int64_t fv = vv1 + vv2;
409
410 if ((fv >= -10) && (fv <= 10))
411 return {v1.getFName(), v1.asset()};
412
413 if (fv >= 0)
414 return STAmount{
415 v1.getFName(),
416 v1.asset(),
417 static_cast<std::uint64_t>(fv),
418 ov1,
419 false};
420
421 return STAmount{
422 v1.getFName(), v1.asset(), static_cast<std::uint64_t>(-fv), ov1, true};
423}
424
426operator-(STAmount const& v1, STAmount const& v2)
427{
428 return v1 + (-v2);
429}
430
431//------------------------------------------------------------------------------
432
433std::uint64_t const STAmount::uRateOne = getRate(STAmount(1), STAmount(1));
434
435void
437{
438 mAsset = asset;
439}
440
441// Convert an offer into an index amount so they sort by rate.
442// A taker will take the best, lowest, rate first.
443// (e.g. a taker will prefer pay 1 get 3 over pay 1 get 2.
444// --> offerOut: takerGets: How much the offerer is selling to the taker.
445// --> offerIn: takerPays: How much the offerer is receiving from the taker.
446// <-- uRate: normalize(offerIn/offerOut)
447// A lower rate is better for the person taking the order.
448// The taker gets more for less with a lower rate.
449// Zero is returned if the offer is worthless.
451getRate(STAmount const& offerOut, STAmount const& offerIn)
452{
453 if (offerOut == beast::zero)
454 return 0;
455 try
456 {
457 STAmount r = divide(offerIn, offerOut, noIssue());
458 if (r == beast::zero) // offer is too good
459 return 0;
460 XRPL_ASSERT(
461 (r.exponent() >= -100) && (r.exponent() <= 155),
462 "ripple::getRate : exponent inside range");
463 std::uint64_t ret = r.exponent() + 100;
464 return (ret << (64 - 8)) | r.mantissa();
465 }
466 catch (std::exception const&)
467 {
468 }
469
470 // overflow -- very bad offer
471 return 0;
472}
473
474void
476{
477 elem = Json::objectValue;
478
479 if (!native())
480 {
481 // It is an error for currency or issuer not to be specified for valid
482 // json.
483 elem[jss::value] = getText();
484 mAsset.setJson(elem);
485 }
486 else
487 {
488 elem = getText();
489 }
490}
491
492//------------------------------------------------------------------------------
493//
494// STBase
495//
496//------------------------------------------------------------------------------
497
500{
501 return STI_AMOUNT;
502}
503
506{
507 std::string ret;
508
509 ret.reserve(64);
510 ret = getText() + "/" + mAsset.getText();
511 return ret;
512}
513
516{
517 // keep full internal accuracy, but make more human friendly if posible
518 if (*this == beast::zero)
519 return "0";
520
521 std::string const raw_value(std::to_string(mValue));
522 std::string ret;
523
524 if (mIsNegative)
525 ret.append(1, '-');
526
527 bool const scientific(
528 (mOffset != 0) && ((mOffset < -25) || (mOffset > -5)));
529
530 if (native() || mAsset.holds<MPTIssue>() || scientific)
531 {
532 ret.append(raw_value);
533
534 if (scientific)
535 {
536 ret.append(1, 'e');
538 }
539
540 return ret;
541 }
542
543 XRPL_ASSERT(mOffset + 43 > 0, "ripple::STAmount::getText : minimum offset");
544
545 size_t const pad_prefix = 27;
546 size_t const pad_suffix = 23;
547
548 std::string val;
549 val.reserve(raw_value.length() + pad_prefix + pad_suffix);
550 val.append(pad_prefix, '0');
551 val.append(raw_value);
552 val.append(pad_suffix, '0');
553
554 size_t const offset(mOffset + 43);
555
556 auto pre_from(val.begin());
557 auto const pre_to(val.begin() + offset);
558
559 auto const post_from(val.begin() + offset);
560 auto post_to(val.end());
561
562 // Crop leading zeroes. Take advantage of the fact that there's always a
563 // fixed amount of leading zeroes and skip them.
564 if (std::distance(pre_from, pre_to) > pad_prefix)
565 pre_from += pad_prefix;
566
567 XRPL_ASSERT(
568 post_to >= post_from,
569 "ripple::STAmount::getText : first distance check");
570
571 pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; });
572
573 // Crop trailing zeroes. Take advantage of the fact that there's always a
574 // fixed amount of trailing zeroes and skip them.
575 if (std::distance(post_from, post_to) > pad_suffix)
576 post_to -= pad_suffix;
577
578 XRPL_ASSERT(
579 post_to >= post_from,
580 "ripple::STAmount::getText : second distance check");
581
582 post_to = std::find_if(
585 [](char c) { return c != '0'; })
586 .base();
587
588 // Assemble the output:
589 if (pre_from == pre_to)
590 ret.append(1, '0');
591 else
592 ret.append(pre_from, pre_to);
593
594 if (post_to != post_from)
595 {
596 ret.append(1, '.');
597 ret.append(post_from, post_to);
598 }
599
600 return ret;
601}
602
605{
606 Json::Value elem;
607 setJson(elem);
608 return elem;
609}
610
611void
613{
614 if (native())
615 {
616 XRPL_ASSERT(mOffset == 0, "ripple::STAmount::add : zero offset");
617
618 if (!mIsNegative)
620 else
621 s.add64(mValue);
622 }
623 else if (mAsset.holds<MPTIssue>())
624 {
625 auto u8 = static_cast<unsigned char>(cMPToken >> 56);
626 if (!mIsNegative)
627 u8 |= static_cast<unsigned char>(cPositive >> 56);
628 s.add8(u8);
629 s.add64(mValue);
631 }
632 else
633 {
634 if (*this == beast::zero)
636 else if (mIsNegative) // 512 = not native
637 s.add64(
638 mValue |
639 (static_cast<std::uint64_t>(mOffset + 512 + 97) << (64 - 10)));
640 else // 256 = positive
641 s.add64(
642 mValue |
643 (static_cast<std::uint64_t>(mOffset + 512 + 256 + 97)
644 << (64 - 10)));
647 }
648}
649
650bool
652{
653 const STAmount* v = dynamic_cast<const STAmount*>(&t);
654 return v && (*v == *this);
655}
656
657bool
659{
660 return (mValue == 0) && native();
661}
662
663//------------------------------------------------------------------------------
664
665// amount = mValue * [10 ^ mOffset]
666// Representation range is 10^80 - 10^(-80).
667//
668// On the wire:
669// - high bit is 0 for XRP, 1 for issued currency
670// - next bit is 1 for positive, 0 for negative (except 0 issued currency, which
671// is a special case of 0x8000000000000000
672// - for issued currencies, the next 8 bits are (mOffset+97).
673// The +97 is so that this value is always positive.
674// - The remaining bits are significant digits (mantissa)
675// That's 54 bits for issued currency and 62 bits for native
676// (but XRP only needs 57 bits for the max value of 10^17 drops)
677//
678// mValue is zero if the amount is zero, otherwise it's within the range
679// 10^15 to (10^16 - 1) inclusive.
680// mOffset is in the range -96 to +80.
681void
683{
684 if (native() || mAsset.holds<MPTIssue>())
685 {
686 // native and MPT currency amounts should always have an offset of zero
687 // log(2^64,10) ~ 19.2
688 if (mValue == 0 || mOffset <= -20)
689 {
690 mValue = 0;
691 mOffset = 0;
692 mIsNegative = false;
693 return;
694 }
695
697 {
698 // log(cMaxNativeN, 10) == 17
699 if (native() && mOffset > 17)
700 Throw<std::runtime_error>(
701 "Native currency amount out of range");
702 // log(maxMPTokenAmount, 10) ~ 18.96
703 if (mAsset.holds<MPTIssue>() && mOffset > 18)
704 Throw<std::runtime_error>("MPT amount out of range");
705 }
706
708 {
709 Number num(
711 auto set = [&](auto const& val) {
712 mIsNegative = val.value() < 0;
713 mValue = mIsNegative ? -val.value() : val.value();
714 };
715 if (native())
716 set(XRPAmount{num});
717 else
718 set(MPTAmount{num});
719 mOffset = 0;
720 }
721 else
722 {
723 while (mOffset < 0)
724 {
725 mValue /= 10;
726 ++mOffset;
727 }
728
729 while (mOffset > 0)
730 {
732 {
733 // N.B. do not move the overflow check to after the
734 // multiplication
735 if (native() && mValue > cMaxNativeN)
736 Throw<std::runtime_error>(
737 "Native currency amount out of range");
738 else if (!native() && mValue > maxMPTokenAmount)
739 Throw<std::runtime_error>("MPT amount out of range");
740 }
741 mValue *= 10;
742 --mOffset;
743 }
744 }
745
746 if (native() && mValue > cMaxNativeN)
747 Throw<std::runtime_error>("Native currency amount out of range");
748 else if (!native() && mValue > maxMPTokenAmount)
749 Throw<std::runtime_error>("MPT amount out of range");
750
751 return;
752 }
753
755 {
756 *this = iou();
757 return;
758 }
759
760 if (mValue == 0)
761 {
762 mOffset = -100;
763 mIsNegative = false;
764 return;
765 }
766
767 while ((mValue < cMinValue) && (mOffset > cMinOffset))
768 {
769 mValue *= 10;
770 --mOffset;
771 }
772
773 while (mValue > cMaxValue)
774 {
775 if (mOffset >= cMaxOffset)
776 Throw<std::runtime_error>("value overflow");
777
778 mValue /= 10;
779 ++mOffset;
780 }
781
782 if ((mOffset < cMinOffset) || (mValue < cMinValue))
783 {
784 mValue = 0;
785 mIsNegative = false;
786 mOffset = -100;
787 return;
788 }
789
790 if (mOffset > cMaxOffset)
791 Throw<std::runtime_error>("value overflow");
792
793 XRPL_ASSERT(
794 (mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)),
795 "ripple::STAmount::canonicalize : value inside range");
796 XRPL_ASSERT(
797 (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)),
798 "ripple::STAmount::canonicalize : offset inside range");
799 XRPL_ASSERT(
800 (mValue != 0) || (mOffset != -100),
801 "ripple::STAmount::canonicalize : value or offset set");
802}
803
804void
806{
807 if (v < 0)
808 {
809 mIsNegative = true;
810 mValue = static_cast<std::uint64_t>(-v);
811 }
812 else
813 {
814 mIsNegative = false;
815 mValue = static_cast<std::uint64_t>(v);
816 }
817}
818
819//------------------------------------------------------------------------------
820
823{
824 if (rate == 0)
825 return STAmount(noIssue());
826
827 std::uint64_t mantissa = rate & ~(255ull << (64 - 8));
828 int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
829
830 return STAmount(noIssue(), mantissa, exponent);
831}
832
833STAmount
834amountFromString(Asset const& asset, std::string const& amount)
835{
836 static boost::regex const reNumber(
837 "^" // the beginning of the string
838 "([-+]?)" // (optional) + or - character
839 "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
840 "(\\.([0-9]+))?" // (optional) period followed by any number
841 "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
842 "$",
843 boost::regex_constants::optimize);
844
845 boost::smatch match;
846
847 if (!boost::regex_match(amount, match, reNumber))
848 Throw<std::runtime_error>("Number '" + amount + "' is not valid");
849
850 // Match fields:
851 // 0 = whole input
852 // 1 = sign
853 // 2 = integer portion
854 // 3 = whole fraction (with '.')
855 // 4 = fraction (without '.')
856 // 5 = whole exponent (with 'e')
857 // 6 = exponent sign
858 // 7 = exponent number
859
860 // CHECKME: Why 32? Shouldn't this be 16?
861 if ((match[2].length() + match[4].length()) > 32)
862 Throw<std::runtime_error>("Number '" + amount + "' is overlong");
863
864 bool negative = (match[1].matched && (match[1] == "-"));
865
866 // Can't specify XRP or MPT using fractional representation
867 if ((asset.native() || asset.holds<MPTIssue>()) && match[3].matched)
868 Throw<std::runtime_error>(
869 "XRP and MPT must be specified as integral amount.");
870
871 std::uint64_t mantissa;
872 int exponent;
873
874 if (!match[4].matched) // integer only
875 {
876 mantissa =
877 beast::lexicalCastThrow<std::uint64_t>(std::string(match[2]));
878 exponent = 0;
879 }
880 else
881 {
882 // integer and fraction
883 mantissa = beast::lexicalCastThrow<std::uint64_t>(match[2] + match[4]);
884 exponent = -(match[4].length());
885 }
886
887 if (match[5].matched)
888 {
889 // we have an exponent
890 if (match[6].matched && (match[6] == "-"))
891 exponent -= beast::lexicalCastThrow<int>(std::string(match[7]));
892 else
893 exponent += beast::lexicalCastThrow<int>(std::string(match[7]));
894 }
895
896 return {asset, mantissa, exponent, negative};
897}
898
899STAmount
900amountFromJson(SField const& name, Json::Value const& v)
901{
902 STAmount::mantissa_type mantissa = 0;
903 STAmount::exponent_type exponent = 0;
904 bool negative = false;
905 Asset asset;
906
907 Json::Value value;
908 Json::Value currencyOrMPTID;
909 Json::Value issuer;
910 bool isMPT = false;
911
912 if (v.isNull())
913 {
914 Throw<std::runtime_error>(
915 "XRP may not be specified with a null Json value");
916 }
917 else if (v.isObject())
918 {
919 if (!validJSONAsset(v))
920 Throw<std::runtime_error>("Invalid Asset's Json specification");
921
922 value = v[jss::value];
923 if (v.isMember(jss::mpt_issuance_id))
924 {
925 isMPT = true;
926 currencyOrMPTID = v[jss::mpt_issuance_id];
927 }
928 else
929 {
930 currencyOrMPTID = v[jss::currency];
931 issuer = v[jss::issuer];
932 }
933 }
934 else if (v.isArray())
935 {
936 value = v.get(Json::UInt(0), 0);
937 currencyOrMPTID = v.get(Json::UInt(1), Json::nullValue);
938 issuer = v.get(Json::UInt(2), Json::nullValue);
939 }
940 else if (v.isString())
941 {
942 std::string val = v.asString();
944 boost::split(elements, val, boost::is_any_of("\t\n\r ,/"));
945
946 if (elements.size() > 3)
947 Throw<std::runtime_error>("invalid amount string");
948
949 value = elements[0];
950
951 if (elements.size() > 1)
952 currencyOrMPTID = elements[1];
953
954 if (elements.size() > 2)
955 issuer = elements[2];
956 }
957 else
958 {
959 value = v;
960 }
961
962 bool const native = !currencyOrMPTID.isString() ||
963 currencyOrMPTID.asString().empty() ||
964 (currencyOrMPTID.asString() == systemCurrencyCode());
965
966 if (native)
967 {
968 if (v.isObjectOrNull())
969 Throw<std::runtime_error>("XRP may not be specified as an object");
970 asset = xrpIssue();
971 }
972 else
973 {
974 if (isMPT)
975 {
976 // sequence (32 bits) + account (160 bits)
977 uint192 u;
978 if (!u.parseHex(currencyOrMPTID.asString()))
979 Throw<std::runtime_error>("invalid MPTokenIssuanceID");
980 asset = u;
981 }
982 else
983 {
984 Issue issue;
985 if (!to_currency(issue.currency, currencyOrMPTID.asString()))
986 Throw<std::runtime_error>("invalid currency");
987 if (!issuer.isString() ||
988 !to_issuer(issue.account, issuer.asString()))
989 Throw<std::runtime_error>("invalid issuer");
990 if (issue.native())
991 Throw<std::runtime_error>("invalid issuer");
992 asset = issue;
993 }
994 }
995
996 if (value.isInt())
997 {
998 if (value.asInt() >= 0)
999 {
1000 mantissa = value.asInt();
1001 }
1002 else
1003 {
1004 mantissa = -value.asInt();
1005 negative = true;
1006 }
1007 }
1008 else if (value.isUInt())
1009 {
1010 mantissa = v.asUInt();
1011 }
1012 else if (value.isString())
1013 {
1014 auto const ret = amountFromString(asset, value.asString());
1015
1016 mantissa = ret.mantissa();
1017 exponent = ret.exponent();
1018 negative = ret.negative();
1019 }
1020 else
1021 {
1022 Throw<std::runtime_error>("invalid amount type");
1023 }
1024
1025 return {name, asset, mantissa, exponent, negative};
1026}
1027
1028bool
1030{
1031 try
1032 {
1033 result = amountFromJson(sfGeneric, jvSource);
1034 return true;
1035 }
1036 catch (const std::exception& e)
1037 {
1038 JLOG(debugLog().warn())
1039 << "amountFromJsonNoThrow: caught: " << e.what();
1040 }
1041 return false;
1042}
1043
1044//------------------------------------------------------------------------------
1045//
1046// Operators
1047//
1048//------------------------------------------------------------------------------
1049
1050bool
1051operator==(STAmount const& lhs, STAmount const& rhs)
1052{
1053 return areComparable(lhs, rhs) && lhs.negative() == rhs.negative() &&
1054 lhs.exponent() == rhs.exponent() && lhs.mantissa() == rhs.mantissa();
1055}
1056
1057bool
1058operator<(STAmount const& lhs, STAmount const& rhs)
1059{
1060 if (!areComparable(lhs, rhs))
1061 Throw<std::runtime_error>(
1062 "Can't compare amounts that are't comparable!");
1063
1064 if (lhs.negative() != rhs.negative())
1065 return lhs.negative();
1066
1067 if (lhs.mantissa() == 0)
1068 {
1069 if (rhs.negative())
1070 return false;
1071 return rhs.mantissa() != 0;
1072 }
1073
1074 // We know that lhs is non-zero and both sides have the same sign. Since
1075 // rhs is zero (and thus not negative), lhs must, therefore, be strictly
1076 // greater than zero. So if rhs is zero, the comparison must be false.
1077 if (rhs.mantissa() == 0)
1078 return false;
1079
1080 if (lhs.exponent() > rhs.exponent())
1081 return lhs.negative();
1082 if (lhs.exponent() < rhs.exponent())
1083 return !lhs.negative();
1084 if (lhs.mantissa() > rhs.mantissa())
1085 return lhs.negative();
1086 if (lhs.mantissa() < rhs.mantissa())
1087 return !lhs.negative();
1088
1089 return false;
1090}
1091
1092STAmount
1093operator-(STAmount const& value)
1094{
1095 if (value.mantissa() == 0)
1096 return value;
1097 return STAmount(
1098 value.getFName(),
1099 value.asset(),
1100 value.mantissa(),
1101 value.exponent(),
1102 !value.negative(),
1104}
1105
1106//------------------------------------------------------------------------------
1107//
1108// Arithmetic
1109//
1110//------------------------------------------------------------------------------
1111
1112// Calculate (a * b) / c when all three values are 64-bit
1113// without loss of precision:
1114static std::uint64_t
1116 std::uint64_t multiplier,
1117 std::uint64_t multiplicand,
1118 std::uint64_t divisor)
1119{
1120 boost::multiprecision::uint128_t ret;
1121
1122 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1123 ret /= divisor;
1124
1126 {
1127 Throw<std::overflow_error>(
1128 "overflow: (" + std::to_string(multiplier) + " * " +
1129 std::to_string(multiplicand) + ") / " + std::to_string(divisor));
1130 }
1131
1132 return static_cast<uint64_t>(ret);
1133}
1134
1135static std::uint64_t
1137 std::uint64_t multiplier,
1138 std::uint64_t multiplicand,
1139 std::uint64_t divisor,
1140 std::uint64_t rounding)
1141{
1142 boost::multiprecision::uint128_t ret;
1143
1144 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1145 ret += rounding;
1146 ret /= divisor;
1147
1149 {
1150 Throw<std::overflow_error>(
1151 "overflow: ((" + std::to_string(multiplier) + " * " +
1152 std::to_string(multiplicand) + ") + " + std::to_string(rounding) +
1153 ") / " + std::to_string(divisor));
1154 }
1155
1156 return static_cast<uint64_t>(ret);
1157}
1158
1159STAmount
1160divide(STAmount const& num, STAmount const& den, Asset const& asset)
1161{
1162 if (den == beast::zero)
1163 Throw<std::runtime_error>("division by zero");
1164
1165 if (num == beast::zero)
1166 return {asset};
1167
1168 std::uint64_t numVal = num.mantissa();
1169 std::uint64_t denVal = den.mantissa();
1170 int numOffset = num.exponent();
1171 int denOffset = den.exponent();
1172
1173 if (num.native() || num.holds<MPTIssue>())
1174 {
1175 while (numVal < STAmount::cMinValue)
1176 {
1177 // Need to bring into range
1178 numVal *= 10;
1179 --numOffset;
1180 }
1181 }
1182
1183 if (den.native() || den.holds<MPTIssue>())
1184 {
1185 while (denVal < STAmount::cMinValue)
1186 {
1187 denVal *= 10;
1188 --denOffset;
1189 }
1190 }
1191
1192 // We divide the two mantissas (each is between 10^15
1193 // and 10^16). To maintain precision, we multiply the
1194 // numerator by 10^17 (the product is in the range of
1195 // 10^32 to 10^33) followed by a division, so the result
1196 // is in the range of 10^16 to 10^15.
1197 return STAmount(
1198 asset,
1199 muldiv(numVal, tenTo17, denVal) + 5,
1200 numOffset - denOffset - 17,
1201 num.negative() != den.negative());
1202}
1203
1204STAmount
1205multiply(STAmount const& v1, STAmount const& v2, Asset const& asset)
1206{
1207 if (v1 == beast::zero || v2 == beast::zero)
1208 return STAmount(asset);
1209
1210 if (v1.native() && v2.native() && asset.native())
1211 {
1212 std::uint64_t const minV = std::min(getSNValue(v1), getSNValue(v2));
1213 std::uint64_t const maxV = std::max(getSNValue(v1), getSNValue(v2));
1214
1215 if (minV > 3000000000ull) // sqrt(cMaxNative)
1216 Throw<std::runtime_error>("Native value overflow");
1217
1218 if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1219 Throw<std::runtime_error>("Native value overflow");
1220
1221 return STAmount(v1.getFName(), minV * maxV);
1222 }
1223 if (v1.holds<MPTIssue>() && v2.holds<MPTIssue>() && asset.holds<MPTIssue>())
1224 {
1225 std::uint64_t const minV = std::min(getMPTValue(v1), getMPTValue(v2));
1226 std::uint64_t const maxV = std::max(getMPTValue(v1), getMPTValue(v2));
1227
1228 if (minV > 3037000499ull) // sqrt(maxMPTokenAmount) ~ 3037000499.98
1229 Throw<std::runtime_error>("MPT value overflow");
1230
1231 if (((maxV >> 32) * minV) > 2147483648ull) // maxMPTokenAmount / 2^32
1232 Throw<std::runtime_error>("MPT value overflow");
1233
1234 return STAmount(asset, minV * maxV);
1235 }
1236
1238 {
1239 auto const r = Number{v1} * Number{v2};
1240 return STAmount{asset, r.mantissa(), r.exponent()};
1241 }
1242
1243 std::uint64_t value1 = v1.mantissa();
1244 std::uint64_t value2 = v2.mantissa();
1245 int offset1 = v1.exponent();
1246 int offset2 = v2.exponent();
1247
1248 if (v1.native() || v1.holds<MPTIssue>())
1249 {
1250 while (value1 < STAmount::cMinValue)
1251 {
1252 value1 *= 10;
1253 --offset1;
1254 }
1255 }
1256
1257 if (v2.native() || v2.holds<MPTIssue>())
1258 {
1259 while (value2 < STAmount::cMinValue)
1260 {
1261 value2 *= 10;
1262 --offset2;
1263 }
1264 }
1265
1266 // We multiply the two mantissas (each is between 10^15
1267 // and 10^16), so their product is in the 10^30 to 10^32
1268 // range. Dividing their product by 10^14 maintains the
1269 // precision, by scaling the result to 10^16 to 10^18.
1270 return STAmount(
1271 asset,
1272 muldiv(value1, value2, tenTo14) + 7,
1273 offset1 + offset2 + 14,
1274 v1.negative() != v2.negative());
1275}
1276
1277// This is the legacy version of canonicalizeRound. It's been in use
1278// for years, so it is deeply embedded in the behavior of cross-currency
1279// transactions.
1280//
1281// However in 2022 it was noticed that the rounding characteristics were
1282// surprising. When the code converts from IOU-like to XRP-like there may
1283// be a fraction of the IOU-like representation that is too small to be
1284// represented in drops. `canonicalizeRound()` currently does some unusual
1285// rounding.
1286//
1287// 1. If the fractional part is greater than or equal to 0.1, then the
1288// number of drops is rounded up.
1289//
1290// 2. However, if the fractional part is less than 0.1 (for example,
1291// 0.099999), then the number of drops is rounded down.
1292//
1293// The XRP Ledger has this rounding behavior baked in. But there are
1294// situations where this rounding behavior led to undesirable outcomes.
1295// So an alternative rounding approach was introduced. You'll see that
1296// alternative below.
1297static void
1298canonicalizeRound(bool native, std::uint64_t& value, int& offset, bool)
1299{
1300 if (native)
1301 {
1302 if (offset < 0)
1303 {
1304 int loops = 0;
1305
1306 while (offset < -1)
1307 {
1308 value /= 10;
1309 ++offset;
1310 ++loops;
1311 }
1312
1313 value += (loops >= 2) ? 9 : 10; // add before last divide
1314 value /= 10;
1315 ++offset;
1316 }
1317 }
1318 else if (value > STAmount::cMaxValue)
1319 {
1320 while (value > (10 * STAmount::cMaxValue))
1321 {
1322 value /= 10;
1323 ++offset;
1324 }
1325
1326 value += 9; // add before last divide
1327 value /= 10;
1328 ++offset;
1329 }
1330}
1331
1332// The original canonicalizeRound did not allow the rounding direction to
1333// be specified. It also ignored some of the bits that could contribute to
1334// rounding decisions. canonicalizeRoundStrict() tracks all of the bits in
1335// the value being rounded.
1336static void
1338 bool native,
1339 std::uint64_t& value,
1340 int& offset,
1341 bool roundUp)
1342{
1343 if (native)
1344 {
1345 if (offset < 0)
1346 {
1347 bool hadRemainder = false;
1348
1349 while (offset < -1)
1350 {
1351 // It would be better to use std::lldiv than to separately
1352 // compute the remainder. But std::lldiv does not support
1353 // unsigned arguments.
1354 std::uint64_t const newValue = value / 10;
1355 hadRemainder |= (value != (newValue * 10));
1356 value = newValue;
1357 ++offset;
1358 }
1359 value +=
1360 (hadRemainder && roundUp) ? 10 : 9; // Add before last divide
1361 value /= 10;
1362 ++offset;
1363 }
1364 }
1365 else if (value > STAmount::cMaxValue)
1366 {
1367 while (value > (10 * STAmount::cMaxValue))
1368 {
1369 value /= 10;
1370 ++offset;
1371 }
1372 value += 9; // add before last divide
1373 value /= 10;
1374 ++offset;
1375 }
1376}
1377
1378namespace {
1379
1380// We need a class that has an interface similar to NumberRoundModeGuard
1381// but does nothing.
1382class DontAffectNumberRoundMode
1383{
1384public:
1385 explicit DontAffectNumberRoundMode(Number::rounding_mode mode) noexcept
1386 {
1387 }
1388
1389 DontAffectNumberRoundMode(DontAffectNumberRoundMode const&) = delete;
1390
1391 DontAffectNumberRoundMode&
1392 operator=(DontAffectNumberRoundMode const&) = delete;
1393};
1394
1395} // anonymous namespace
1396
1397// Pass the canonicalizeRound function pointer as a template parameter.
1398//
1399// We might need to use NumberRoundModeGuard. Allow the caller
1400// to pass either that or a replacement as a template parameter.
1401template <
1402 void (*CanonicalizeFunc)(bool, std::uint64_t&, int&, bool),
1403 typename MightSaveRound>
1404static STAmount
1406 STAmount const& v1,
1407 STAmount const& v2,
1408 Asset const& asset,
1409 bool roundUp)
1410{
1411 if (v1 == beast::zero || v2 == beast::zero)
1412 return {asset};
1413
1414 bool const xrp = asset.native();
1415
1416 if (v1.native() && v2.native() && xrp)
1417 {
1420
1421 if (minV > 3000000000ull) // sqrt(cMaxNative)
1422 Throw<std::runtime_error>("Native value overflow");
1423
1424 if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1425 Throw<std::runtime_error>("Native value overflow");
1426
1427 return STAmount(v1.getFName(), minV * maxV);
1428 }
1429
1430 if (v1.holds<MPTIssue>() && v2.holds<MPTIssue>() && asset.holds<MPTIssue>())
1431 {
1432 std::uint64_t const minV = std::min(getMPTValue(v1), getMPTValue(v2));
1433 std::uint64_t const maxV = std::max(getMPTValue(v1), getMPTValue(v2));
1434
1435 if (minV > 3037000499ull) // sqrt(maxMPTokenAmount) ~ 3037000499.98
1436 Throw<std::runtime_error>("MPT value overflow");
1437
1438 if (((maxV >> 32) * minV) > 2147483648ull) // maxMPTokenAmount / 2^32
1439 Throw<std::runtime_error>("MPT value overflow");
1440
1441 return STAmount(asset, minV * maxV);
1442 }
1443
1444 std::uint64_t value1 = v1.mantissa(), value2 = v2.mantissa();
1445 int offset1 = v1.exponent(), offset2 = v2.exponent();
1446
1447 if (v1.native() || v1.holds<MPTIssue>())
1448 {
1449 while (value1 < STAmount::cMinValue)
1450 {
1451 value1 *= 10;
1452 --offset1;
1453 }
1454 }
1455
1456 if (v2.native() || v2.holds<MPTIssue>())
1457 {
1458 while (value2 < STAmount::cMinValue)
1459 {
1460 value2 *= 10;
1461 --offset2;
1462 }
1463 }
1464
1465 bool const resultNegative = v1.negative() != v2.negative();
1466
1467 // We multiply the two mantissas (each is between 10^15
1468 // and 10^16), so their product is in the 10^30 to 10^32
1469 // range. Dividing their product by 10^14 maintains the
1470 // precision, by scaling the result to 10^16 to 10^18.
1471 //
1472 // If the we're rounding up, we want to round up away
1473 // from zero, and if we're rounding down, truncation
1474 // is implicit.
1475 std::uint64_t amount = muldiv_round(
1476 value1, value2, tenTo14, (resultNegative != roundUp) ? tenTo14m1 : 0);
1477
1478 int offset = offset1 + offset2 + 14;
1479 if (resultNegative != roundUp)
1480 {
1481 CanonicalizeFunc(xrp, amount, offset, roundUp);
1482 }
1483 STAmount result = [&]() {
1484 // If appropriate, tell Number to round down. This gives the desired
1485 // result from STAmount::canonicalize.
1486 MightSaveRound const savedRound(Number::towards_zero);
1487 return STAmount(asset, amount, offset, resultNegative);
1488 }();
1489
1490 if (roundUp && !resultNegative && !result)
1491 {
1492 if (xrp)
1493 {
1494 // return the smallest value above zero
1495 amount = 1;
1496 offset = 0;
1497 }
1498 else
1499 {
1500 // return the smallest value above zero
1501 amount = STAmount::cMinValue;
1502 offset = STAmount::cMinOffset;
1503 }
1504 return STAmount(asset, amount, offset, resultNegative);
1505 }
1506 return result;
1507}
1508
1509STAmount
1511 STAmount const& v1,
1512 STAmount const& v2,
1513 Asset const& asset,
1514 bool roundUp)
1515{
1516 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(
1517 v1, v2, asset, roundUp);
1518}
1519
1520STAmount
1522 STAmount const& v1,
1523 STAmount const& v2,
1524 Asset const& asset,
1525 bool roundUp)
1526{
1527 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(
1528 v1, v2, asset, roundUp);
1529}
1530
1531// We might need to use NumberRoundModeGuard. Allow the caller
1532// to pass either that or a replacement as a template parameter.
1533template <typename MightSaveRound>
1534static STAmount
1536 STAmount const& num,
1537 STAmount const& den,
1538 Asset const& asset,
1539 bool roundUp)
1540{
1541 if (den == beast::zero)
1542 Throw<std::runtime_error>("division by zero");
1543
1544 if (num == beast::zero)
1545 return {asset};
1546
1547 std::uint64_t numVal = num.mantissa(), denVal = den.mantissa();
1548 int numOffset = num.exponent(), denOffset = den.exponent();
1549
1550 if (num.native() || num.holds<MPTIssue>())
1551 {
1552 while (numVal < STAmount::cMinValue)
1553 {
1554 numVal *= 10;
1555 --numOffset;
1556 }
1557 }
1558
1559 if (den.native() || den.holds<MPTIssue>())
1560 {
1561 while (denVal < STAmount::cMinValue)
1562 {
1563 denVal *= 10;
1564 --denOffset;
1565 }
1566 }
1567
1568 bool const resultNegative = (num.negative() != den.negative());
1569
1570 // We divide the two mantissas (each is between 10^15
1571 // and 10^16). To maintain precision, we multiply the
1572 // numerator by 10^17 (the product is in the range of
1573 // 10^32 to 10^33) followed by a division, so the result
1574 // is in the range of 10^16 to 10^15.
1575 //
1576 // We round away from zero if we're rounding up or
1577 // truncate if we're rounding down.
1578 std::uint64_t amount = muldiv_round(
1579 numVal, tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1580
1581 int offset = numOffset - denOffset - 17;
1582
1583 if (resultNegative != roundUp)
1585 asset.native() || asset.holds<MPTIssue>(), amount, offset, roundUp);
1586
1587 STAmount result = [&]() {
1588 // If appropriate, tell Number the rounding mode we are using.
1589 // Note that "roundUp == true" actually means "round away from zero".
1590 // Otherwise round toward zero.
1591 using enum Number::rounding_mode;
1592 MightSaveRound const savedRound(
1593 roundUp ^ resultNegative ? upward : downward);
1594 return STAmount(asset, amount, offset, resultNegative);
1595 }();
1596
1597 if (roundUp && !resultNegative && !result)
1598 {
1599 if (asset.native() || asset.holds<MPTIssue>())
1600 {
1601 // return the smallest value above zero
1602 amount = 1;
1603 offset = 0;
1604 }
1605 else
1606 {
1607 // return the smallest value above zero
1608 amount = STAmount::cMinValue;
1609 offset = STAmount::cMinOffset;
1610 }
1611 return STAmount(asset, amount, offset, resultNegative);
1612 }
1613 return result;
1614}
1615
1616STAmount
1618 STAmount const& num,
1619 STAmount const& den,
1620 Asset const& asset,
1621 bool roundUp)
1622{
1623 return divRoundImpl<DontAffectNumberRoundMode>(num, den, asset, roundUp);
1624}
1625
1626STAmount
1628 STAmount const& num,
1629 STAmount const& den,
1630 Asset const& asset,
1631 bool roundUp)
1632{
1633 return divRoundImpl<NumberRoundModeGuard>(num, den, asset, roundUp);
1634}
1635
1636} // namespace ripple
T append(T... args)
T begin(T... args)
Represents a JSON value.
Definition: json_value.h:147
bool isArray() const
Value get(UInt index, const Value &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
Definition: json_value.cpp:841
bool isObjectOrNull() const
Int asInt() const
Definition: json_value.cpp:503
bool isString() const
UInt asUInt() const
Definition: json_value.cpp:545
bool isObject() const
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
bool isUInt() const
Definition: json_value.cpp:998
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:980
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:943
bool isInt() const
Definition: json_value.cpp:992
bool native() const
Definition: Asset.h:96
void setJson(Json::Value &jv) const
Definition: Asset.cpp:41
constexpr TIss const & get() const
constexpr bool holds() const
Definition: Asset.h:119
std::string getText() const
Definition: Asset.cpp:35
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:45
int exponent() const noexcept
Definition: IOUAmount.h:165
std::int64_t mantissa() const noexcept
Definition: IOUAmount.h:171
A currency issued by an account.
Definition: Issue.h:36
AccountID account
Definition: Issue.h:39
Currency currency
Definition: Issue.h:38
bool native() const
Definition: Issue.cpp:61
constexpr value_type value() const
Returns the underlying value.
Definition: MPTAmount.h:136
MPTID const & getMptID() const
Definition: MPTIssue.cpp:43
Identifies fields.
Definition: SField.h:144
constexpr bool holds() const noexcept
Definition: STAmount.h:456
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:604
IOUAmount iou() const
Definition: STAmount.cpp:288
static const std::uint64_t cIssuedCurrency
Definition: STAmount.h:75
void canonicalize()
Definition: STAmount.cpp:682
bool mIsNegative
Definition: STAmount.h:60
STAmount & operator=(beast::Zero)
Definition: STAmount.h:531
int exponent() const noexcept
Definition: STAmount.h:443
STBase * move(std::size_t n, void *buf) override
Definition: STAmount.cpp:262
Asset const & asset() const
Definition: STAmount.h:474
constexpr TIss const & get() const
STAmount & operator+=(STAmount const &)
Definition: STAmount.cpp:338
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
Definition: STAmount.cpp:250
void setIssue(Asset const &asset)
Set the Issue for this amount.
Definition: STAmount.cpp:436
XRPAmount xrp() const
Definition: STAmount.cpp:273
void setJson(Json::Value &) const
Definition: STAmount.cpp:475
bool isDefault() const override
Definition: STAmount.cpp:658
STAmount & operator-=(STAmount const &)
Definition: STAmount.cpp:345
void add(Serializer &s) const override
Definition: STAmount.cpp:612
static const int cMaxOffset
Definition: STAmount.h:66
SerializedTypeID getSType() const override
Definition: STAmount.cpp:499
mantissa_type mValue
Definition: STAmount.h:58
STAmount const & value() const noexcept
Definition: STAmount.h:575
std::string getText() const override
Definition: STAmount.cpp:515
bool negative() const noexcept
Definition: STAmount.h:462
STBase * copy(std::size_t n, void *buf) const override
Definition: STAmount.cpp:256
static const std::uint64_t cPositive
Definition: STAmount.h:76
MPTAmount mpt() const
Definition: STAmount.cpp:303
exponent_type mOffset
Definition: STAmount.h:59
Issue const & issue() const
Definition: STAmount.h:487
static const std::uint64_t cMinValue
Definition: STAmount.h:69
static const std::uint64_t cMPToken
Definition: STAmount.h:77
static const int cMinOffset
Definition: STAmount.h:65
bool isEquivalent(const STBase &t) const override
Definition: STAmount.cpp:651
void set(std::int64_t v)
Definition: STAmount.cpp:805
std::uint64_t mantissa() const noexcept
Definition: STAmount.h:468
static const std::uint64_t cValueMask
Definition: STAmount.h:78
static const std::uint64_t cMaxNativeN
Definition: STAmount.h:74
std::string getFullText() const override
Definition: STAmount.cpp:505
STAmount(SerialIter &sit, SField const &name)
Definition: STAmount.cpp:110
bool native() const noexcept
Definition: STAmount.h:449
static const std::uint64_t cMaxValue
Definition: STAmount.h:70
static std::uint64_t const uRateOne
Definition: STAmount.h:80
A type which can be exported to a well known binary format.
Definition: STBase.h:124
SField const & getFName() const
Definition: STBase.cpp:134
static STBase * emplace(std::size_t n, void *buf, T &&val)
Definition: STBase.h:222
uint192 get192()
Definition: Serializer.h:415
uint160 get160()
Definition: Serializer.h:409
unsigned char get8()
Definition: Serializer.cpp:340
std::uint64_t get64()
Definition: Serializer.cpp:377
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:131
int add8(unsigned char i)
Definition: Serializer.cpp:143
constexpr value_type drops() const
Returns the number of drops.
Definition: XRPAmount.h:177
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:502
T distance(T... args)
T empty(T... args)
T end(T... args)
T find_if(T... args)
T make_reverse_iterator(T... args)
T max(T... args)
T min(T... args)
@ nullValue
'null' value
Definition: json_value.h:36
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
unsigned int UInt
Definition: json_forwards.h:27
TER valid(PreclaimContext const &ctx, AccountID const &src)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:118
STAmount amountFromString(Asset const &issue, std::string const &amount)
Definition: STAmount.cpp:834
static void canonicalizeRoundStrict(bool native, std::uint64_t &value, int &offset, bool roundUp)
Definition: STAmount.cpp:1337
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:87
static const std::uint64_t tenTo14
Definition: STAmount.cpp:61
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
Definition: AccountID.cpp:184
static bool areComparable(STAmount const &v1, STAmount const &v2)
Definition: STAmount.cpp:100
STAmount divRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
Definition: STAmount.cpp:1627
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:900
SerializedTypeID
Definition: SField.h:108
SField const sfGeneric
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
Definition: Protocol.h:116
STAmount amountFromQuality(std::uint64_t rate)
Definition: STAmount.cpp:822
bool getSTAmountCanonicalizeSwitchover()
Definition: STAmount.cpp:50
static std::string const & systemCurrencyCode()
static const std::uint64_t tenTo14m1
Definition: STAmount.cpp:62
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:316
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:451
static std::int64_t getSNValue(STAmount const &amount)
Definition: STAmount.cpp:87
bool validJSONAsset(Json::Value const &jv)
Definition: Asset.cpp:54
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:452
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition: Issue.h:126
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1029
static std::int64_t getMPTValue(STAmount const &amount)
Definition: STAmount.cpp:93
bool operator<(Slice const &lhs, Slice const &rhs) noexcept
Definition: Slice.h:222
void setSTAmountCanonicalizeSwitchover(bool v)
Definition: STAmount.cpp:56
static const std::uint64_t tenTo17
Definition: STAmount.cpp:63
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
Definition: STAmount.cpp:1617
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
Definition: STAmount.cpp:1115
Number operator-(Number const &x, Number const &y)
Definition: Number.h:282
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
Definition: STAmount.cpp:1510
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:621
static STAmount mulRoundImpl(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
Definition: STAmount.cpp:1405
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition: base_uint.h:584
static STAmount divRoundImpl(STAmount const &num, STAmount const &den, Asset const &asset, bool roundUp)
Definition: STAmount.cpp:1535
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
Definition: STAmount.cpp:1521
static std::int64_t getInt64Value(STAmount const &amount, bool valid, const char *error)
Definition: STAmount.cpp:67
static std::uint64_t muldiv_round(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding)
Definition: STAmount.cpp:1136
bool getSTNumberSwitchover()
Definition: IOUAmount.cpp:42
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset, bool)
Definition: STAmount.cpp:1298
T reserve(T... args)
T length(T... args)
Note, should be treated as flags that can be | and &.
Definition: STBase.h:36
T to_string(T... args)
T what(T... args)