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