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() + "/" + to_string(mIssue.currency);
554 
555  if (!mIsNative)
556  {
557  ret += "/";
558 
559  if (isXRP(*this))
560  ret += "0";
561  else if (mIssue.account == noAccount())
562  ret += "1";
563  else
564  ret += to_string(mIssue.account);
565  }
566 
567  return ret;
568 }
569 
572 {
573  // keep full internal accuracy, but make more human friendly if posible
574  if (*this == beast::zero)
575  return "0";
576 
577  std::string const raw_value(std::to_string(mValue));
578  std::string ret;
579 
580  if (mIsNegative)
581  ret.append(1, '-');
582 
583  bool const scientific(
584  (mOffset != 0) && ((mOffset < -25) || (mOffset > -5)));
585 
586  if (mIsNative || scientific)
587  {
588  ret.append(raw_value);
589 
590  if (scientific)
591  {
592  ret.append(1, 'e');
594  }
595 
596  return ret;
597  }
598 
599  assert(mOffset + 43 > 0);
600 
601  size_t const pad_prefix = 27;
602  size_t const pad_suffix = 23;
603 
604  std::string val;
605  val.reserve(raw_value.length() + pad_prefix + pad_suffix);
606  val.append(pad_prefix, '0');
607  val.append(raw_value);
608  val.append(pad_suffix, '0');
609 
610  size_t const offset(mOffset + 43);
611 
612  auto pre_from(val.begin());
613  auto const pre_to(val.begin() + offset);
614 
615  auto const post_from(val.begin() + offset);
616  auto post_to(val.end());
617 
618  // Crop leading zeroes. Take advantage of the fact that there's always a
619  // fixed amount of leading zeroes and skip them.
620  if (std::distance(pre_from, pre_to) > pad_prefix)
621  pre_from += pad_prefix;
622 
623  assert(post_to >= post_from);
624 
625  pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; });
626 
627  // Crop trailing zeroes. Take advantage of the fact that there's always a
628  // fixed amount of trailing zeroes and skip them.
629  if (std::distance(post_from, post_to) > pad_suffix)
630  post_to -= pad_suffix;
631 
632  assert(post_to >= post_from);
633 
634  post_to = std::find_if(
636  std::make_reverse_iterator(post_from),
637  [](char c) { return c != '0'; })
638  .base();
639 
640  // Assemble the output:
641  if (pre_from == pre_to)
642  ret.append(1, '0');
643  else
644  ret.append(pre_from, pre_to);
645 
646  if (post_to != post_from)
647  {
648  ret.append(1, '.');
649  ret.append(post_from, post_to);
650  }
651 
652  return ret;
653 }
654 
656 {
657  Json::Value elem;
658  setJson(elem);
659  return elem;
660 }
661 
662 void
664 {
665  if (mIsNative)
666  {
667  assert(mOffset == 0);
668 
669  if (!mIsNegative)
670  s.add64(mValue | cPosNative);
671  else
672  s.add64(mValue);
673  }
674  else
675  {
676  if (*this == beast::zero)
677  s.add64(cNotNative);
678  else if (mIsNegative) // 512 = not native
679  s.add64(
680  mValue |
681  (static_cast<std::uint64_t>(mOffset + 512 + 97) << (64 - 10)));
682  else // 256 = positive
683  s.add64(
684  mValue |
685  (static_cast<std::uint64_t>(mOffset + 512 + 256 + 97)
686  << (64 - 10)));
687 
690  }
691 }
692 
693 bool
695 {
696  const STAmount* v = dynamic_cast<const STAmount*>(&t);
697  return v && (*v == *this);
698 }
699 
700 bool
702 {
703  return (mValue == 0) && mIsNative;
704 }
705 
706 //------------------------------------------------------------------------------
707 
708 // amount = mValue * [10 ^ mOffset]
709 // Representation range is 10^80 - 10^(-80).
710 //
711 // On the wire:
712 // - high bit is 0 for XRP, 1 for issued currency
713 // - next bit is 1 for positive, 0 for negative (except 0 issued currency, which
714 // is a special case of 0x8000000000000000
715 // - for issued currencies, the next 8 bits are (mOffset+97).
716 // The +97 is so that this value is always positive.
717 // - The remaining bits are significant digits (mantissa)
718 // That's 54 bits for issued currency and 62 bits for native
719 // (but XRP only needs 57 bits for the max value of 10^17 drops)
720 //
721 // mValue is zero if the amount is zero, otherwise it's within the range
722 // 10^15 to (10^16 - 1) inclusive.
723 // mOffset is in the range -96 to +80.
724 void
726 {
727  if (isXRP(*this))
728  {
729  // native currency amounts should always have an offset of zero
730  mIsNative = true;
731 
732  // log(2^64,10) ~ 19.2
733  if (mValue == 0 || mOffset <= -20)
734  {
735  mValue = 0;
736  mOffset = 0;
737  mIsNegative = false;
738  return;
739  }
740 
742  {
743  // log(cMaxNativeN, 10) == 17
744  if (mOffset > 17)
745  Throw<std::runtime_error>(
746  "Native currency amount out of range");
747  }
748 
750  {
751  Number num(
753  XRPAmount xrp{num};
754  mIsNegative = xrp.drops() < 0;
755  mValue = mIsNegative ? -xrp.drops() : xrp.drops();
756  mOffset = 0;
757  }
758  else
759  {
760  while (mOffset < 0)
761  {
762  mValue /= 10;
763  ++mOffset;
764  }
765 
766  while (mOffset > 0)
767  {
769  {
770  // N.B. do not move the overflow check to after the
771  // multiplication
772  if (mValue > cMaxNativeN)
773  Throw<std::runtime_error>(
774  "Native currency amount out of range");
775  }
776  mValue *= 10;
777  --mOffset;
778  }
779  }
780 
781  if (mValue > cMaxNativeN)
782  Throw<std::runtime_error>("Native currency amount out of range");
783 
784  return;
785  }
786 
787  mIsNative = false;
788 
789  if (getSTNumberSwitchover())
790  {
791  *this = iou();
792  return;
793  }
794 
795  if (mValue == 0)
796  {
797  mOffset = -100;
798  mIsNegative = false;
799  return;
800  }
801 
802  while ((mValue < cMinValue) && (mOffset > cMinOffset))
803  {
804  mValue *= 10;
805  --mOffset;
806  }
807 
808  while (mValue > cMaxValue)
809  {
810  if (mOffset >= cMaxOffset)
811  Throw<std::runtime_error>("value overflow");
812 
813  mValue /= 10;
814  ++mOffset;
815  }
816 
817  if ((mOffset < cMinOffset) || (mValue < cMinValue))
818  {
819  mValue = 0;
820  mIsNegative = false;
821  mOffset = -100;
822  return;
823  }
824 
825  if (mOffset > cMaxOffset)
826  Throw<std::runtime_error>("value overflow");
827 
828  assert((mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)));
829  assert(
830  (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)));
831  assert((mValue != 0) || (mOffset != -100));
832 }
833 
834 void
836 {
837  if (v < 0)
838  {
839  mIsNegative = true;
840  mValue = static_cast<std::uint64_t>(-v);
841  }
842  else
843  {
844  mIsNegative = false;
845  mValue = static_cast<std::uint64_t>(v);
846  }
847 }
848 
849 //------------------------------------------------------------------------------
850 
851 STAmount
853 {
854  if (rate == 0)
855  return STAmount(noIssue());
856 
857  std::uint64_t mantissa = rate & ~(255ull << (64 - 8));
858  int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
859 
860  return STAmount(noIssue(), mantissa, exponent);
861 }
862 
863 STAmount
864 amountFromString(Issue const& issue, std::string const& amount)
865 {
866  static boost::regex const reNumber(
867  "^" // the beginning of the string
868  "([-+]?)" // (optional) + or - character
869  "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
870  "(\\.([0-9]+))?" // (optional) period followed by any number
871  "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
872  "$",
873  boost::regex_constants::optimize);
874 
875  boost::smatch match;
876 
877  if (!boost::regex_match(amount, match, reNumber))
878  Throw<std::runtime_error>("Number '" + amount + "' is not valid");
879 
880  // Match fields:
881  // 0 = whole input
882  // 1 = sign
883  // 2 = integer portion
884  // 3 = whole fraction (with '.')
885  // 4 = fraction (without '.')
886  // 5 = whole exponent (with 'e')
887  // 6 = exponent sign
888  // 7 = exponent number
889 
890  // CHECKME: Why 32? Shouldn't this be 16?
891  if ((match[2].length() + match[4].length()) > 32)
892  Throw<std::runtime_error>("Number '" + amount + "' is overlong");
893 
894  bool negative = (match[1].matched && (match[1] == "-"));
895 
896  // Can't specify XRP using fractional representation
897  if (isXRP(issue) && match[3].matched)
898  Throw<std::runtime_error>("XRP must be specified in integral drops.");
899 
900  std::uint64_t mantissa;
901  int exponent;
902 
903  if (!match[4].matched) // integer only
904  {
905  mantissa =
906  beast::lexicalCastThrow<std::uint64_t>(std::string(match[2]));
907  exponent = 0;
908  }
909  else
910  {
911  // integer and fraction
912  mantissa = beast::lexicalCastThrow<std::uint64_t>(match[2] + match[4]);
913  exponent = -(match[4].length());
914  }
915 
916  if (match[5].matched)
917  {
918  // we have an exponent
919  if (match[6].matched && (match[6] == "-"))
920  exponent -= beast::lexicalCastThrow<int>(std::string(match[7]));
921  else
922  exponent += beast::lexicalCastThrow<int>(std::string(match[7]));
923  }
924 
925  return {issue, mantissa, exponent, negative};
926 }
927 
928 STAmount
929 amountFromJson(SField const& name, Json::Value const& v)
930 {
931  STAmount::mantissa_type mantissa = 0;
932  STAmount::exponent_type exponent = 0;
933  bool negative = false;
934  Issue issue;
935 
936  Json::Value value;
937  Json::Value currency;
938  Json::Value issuer;
939 
940  if (v.isNull())
941  {
942  Throw<std::runtime_error>(
943  "XRP may not be specified with a null Json value");
944  }
945  else if (v.isObject())
946  {
947  value = v[jss::value];
948  currency = v[jss::currency];
949  issuer = v[jss::issuer];
950  }
951  else if (v.isArray())
952  {
953  value = v.get(Json::UInt(0), 0);
954  currency = v.get(Json::UInt(1), Json::nullValue);
955  issuer = v.get(Json::UInt(2), Json::nullValue);
956  }
957  else if (v.isString())
958  {
959  std::string val = v.asString();
960  std::vector<std::string> elements;
961  boost::split(elements, val, boost::is_any_of("\t\n\r ,/"));
962 
963  if (elements.size() > 3)
964  Throw<std::runtime_error>("invalid amount string");
965 
966  value = elements[0];
967 
968  if (elements.size() > 1)
969  currency = elements[1];
970 
971  if (elements.size() > 2)
972  issuer = elements[2];
973  }
974  else
975  {
976  value = v;
977  }
978 
979  bool const native = !currency.isString() || currency.asString().empty() ||
980  (currency.asString() == systemCurrencyCode());
981 
982  if (native)
983  {
984  if (v.isObjectOrNull())
985  Throw<std::runtime_error>("XRP may not be specified as an object");
986  issue = xrpIssue();
987  }
988  else
989  {
990  // non-XRP
991  if (!to_currency(issue.currency, currency.asString()))
992  Throw<std::runtime_error>("invalid currency");
993 
994  if (!issuer.isString() || !to_issuer(issue.account, issuer.asString()))
995  Throw<std::runtime_error>("invalid issuer");
996 
997  if (isXRP(issue.currency))
998  Throw<std::runtime_error>("invalid issuer");
999  }
1000 
1001  if (value.isInt())
1002  {
1003  if (value.asInt() >= 0)
1004  {
1005  mantissa = value.asInt();
1006  }
1007  else
1008  {
1009  mantissa = -value.asInt();
1010  negative = true;
1011  }
1012  }
1013  else if (value.isUInt())
1014  {
1015  mantissa = v.asUInt();
1016  }
1017  else if (value.isString())
1018  {
1019  auto const ret = amountFromString(issue, value.asString());
1020 
1021  mantissa = ret.mantissa();
1022  exponent = ret.exponent();
1023  negative = ret.negative();
1024  }
1025  else
1026  {
1027  Throw<std::runtime_error>("invalid amount type");
1028  }
1029 
1030  return {name, issue, mantissa, exponent, native, negative};
1031 }
1032 
1033 bool
1034 amountFromJsonNoThrow(STAmount& result, Json::Value const& jvSource)
1035 {
1036  try
1037  {
1038  result = amountFromJson(sfGeneric, jvSource);
1039  return true;
1040  }
1041  catch (const std::exception& e)
1042  {
1043  JLOG(debugLog().warn())
1044  << "amountFromJsonNoThrow: caught: " << e.what();
1045  }
1046  return false;
1047 }
1048 
1049 //------------------------------------------------------------------------------
1050 //
1051 // Operators
1052 //
1053 //------------------------------------------------------------------------------
1054 
1055 bool
1056 operator==(STAmount const& lhs, STAmount const& rhs)
1057 {
1058  return areComparable(lhs, rhs) && lhs.negative() == rhs.negative() &&
1059  lhs.exponent() == rhs.exponent() && lhs.mantissa() == rhs.mantissa();
1060 }
1061 
1062 bool
1063 operator<(STAmount const& lhs, STAmount const& rhs)
1064 {
1065  if (!areComparable(lhs, rhs))
1066  Throw<std::runtime_error>(
1067  "Can't compare amounts that are't comparable!");
1068 
1069  if (lhs.negative() != rhs.negative())
1070  return lhs.negative();
1071 
1072  if (lhs.mantissa() == 0)
1073  {
1074  if (rhs.negative())
1075  return false;
1076  return rhs.mantissa() != 0;
1077  }
1078 
1079  // We know that lhs is non-zero and both sides have the same sign. Since
1080  // rhs is zero (and thus not negative), lhs must, therefore, be strictly
1081  // greater than zero. So if rhs is zero, the comparison must be false.
1082  if (rhs.mantissa() == 0)
1083  return false;
1084 
1085  if (lhs.exponent() > rhs.exponent())
1086  return lhs.negative();
1087  if (lhs.exponent() < rhs.exponent())
1088  return !lhs.negative();
1089  if (lhs.mantissa() > rhs.mantissa())
1090  return lhs.negative();
1091  if (lhs.mantissa() < rhs.mantissa())
1092  return !lhs.negative();
1093 
1094  return false;
1095 }
1096 
1097 STAmount
1098 operator-(STAmount const& value)
1099 {
1100  if (value.mantissa() == 0)
1101  return value;
1102  return STAmount(
1103  value.getFName(),
1104  value.issue(),
1105  value.mantissa(),
1106  value.exponent(),
1107  value.native(),
1108  !value.negative(),
1110 }
1111 
1112 //------------------------------------------------------------------------------
1113 //
1114 // Arithmetic
1115 //
1116 //------------------------------------------------------------------------------
1117 
1118 // Calculate (a * b) / c when all three values are 64-bit
1119 // without loss of precision:
1120 static std::uint64_t
1122  std::uint64_t multiplier,
1123  std::uint64_t multiplicand,
1124  std::uint64_t divisor)
1125 {
1126  boost::multiprecision::uint128_t ret;
1127 
1128  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1129  ret /= divisor;
1130 
1132  {
1133  Throw<std::overflow_error>(
1134  "overflow: (" + std::to_string(multiplier) + " * " +
1135  std::to_string(multiplicand) + ") / " + std::to_string(divisor));
1136  }
1137 
1138  return static_cast<uint64_t>(ret);
1139 }
1140 
1141 static std::uint64_t
1143  std::uint64_t multiplier,
1144  std::uint64_t multiplicand,
1145  std::uint64_t divisor,
1146  std::uint64_t rounding)
1147 {
1148  boost::multiprecision::uint128_t ret;
1149 
1150  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1151  ret += rounding;
1152  ret /= divisor;
1153 
1155  {
1156  Throw<std::overflow_error>(
1157  "overflow: ((" + std::to_string(multiplier) + " * " +
1158  std::to_string(multiplicand) + ") + " + std::to_string(rounding) +
1159  ") / " + std::to_string(divisor));
1160  }
1161 
1162  return static_cast<uint64_t>(ret);
1163 }
1164 
1165 STAmount
1166 divide(STAmount const& num, STAmount const& den, Issue const& issue)
1167 {
1168  if (den == beast::zero)
1169  Throw<std::runtime_error>("division by zero");
1170 
1171  if (num == beast::zero)
1172  return {issue};
1173 
1174  std::uint64_t numVal = num.mantissa();
1175  std::uint64_t denVal = den.mantissa();
1176  int numOffset = num.exponent();
1177  int denOffset = den.exponent();
1178 
1179  if (num.native())
1180  {
1181  while (numVal < STAmount::cMinValue)
1182  {
1183  // Need to bring into range
1184  numVal *= 10;
1185  --numOffset;
1186  }
1187  }
1188 
1189  if (den.native())
1190  {
1191  while (denVal < STAmount::cMinValue)
1192  {
1193  denVal *= 10;
1194  --denOffset;
1195  }
1196  }
1197 
1198  // We divide the two mantissas (each is between 10^15
1199  // and 10^16). To maintain precision, we multiply the
1200  // numerator by 10^17 (the product is in the range of
1201  // 10^32 to 10^33) followed by a division, so the result
1202  // is in the range of 10^16 to 10^15.
1203  return STAmount(
1204  issue,
1205  muldiv(numVal, tenTo17, denVal) + 5,
1206  numOffset - denOffset - 17,
1207  num.negative() != den.negative());
1208 }
1209 
1210 STAmount
1211 multiply(STAmount const& v1, STAmount const& v2, Issue const& issue)
1212 {
1213  if (v1 == beast::zero || v2 == beast::zero)
1214  return STAmount(issue);
1215 
1216  if (v1.native() && v2.native() && isXRP(issue))
1217  {
1218  std::uint64_t const minV =
1219  getSNValue(v1) < getSNValue(v2) ? getSNValue(v1) : getSNValue(v2);
1220  std::uint64_t const maxV =
1221  getSNValue(v1) < getSNValue(v2) ? getSNValue(v2) : getSNValue(v1);
1222 
1223  if (minV > 3000000000ull) // sqrt(cMaxNative)
1224  Throw<std::runtime_error>("Native value overflow");
1225 
1226  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1227  Throw<std::runtime_error>("Native value overflow");
1228 
1229  return STAmount(v1.getFName(), minV * maxV);
1230  }
1231 
1232  if (getSTNumberSwitchover())
1233  return {IOUAmount{Number{v1} * Number{v2}}, issue};
1234 
1235  std::uint64_t value1 = v1.mantissa();
1236  std::uint64_t value2 = v2.mantissa();
1237  int offset1 = v1.exponent();
1238  int offset2 = v2.exponent();
1239 
1240  if (v1.native())
1241  {
1242  while (value1 < STAmount::cMinValue)
1243  {
1244  value1 *= 10;
1245  --offset1;
1246  }
1247  }
1248 
1249  if (v2.native())
1250  {
1251  while (value2 < STAmount::cMinValue)
1252  {
1253  value2 *= 10;
1254  --offset2;
1255  }
1256  }
1257 
1258  // We multiply the two mantissas (each is between 10^15
1259  // and 10^16), so their product is in the 10^30 to 10^32
1260  // range. Dividing their product by 10^14 maintains the
1261  // precision, by scaling the result to 10^16 to 10^18.
1262  return STAmount(
1263  issue,
1264  muldiv(value1, value2, tenTo14) + 7,
1265  offset1 + offset2 + 14,
1266  v1.negative() != v2.negative());
1267 }
1268 
1269 static void
1270 canonicalizeRound(bool native, std::uint64_t& value, int& offset)
1271 {
1272  if (native)
1273  {
1274  if (offset < 0)
1275  {
1276  int loops = 0;
1277 
1278  while (offset < -1)
1279  {
1280  value /= 10;
1281  ++offset;
1282  ++loops;
1283  }
1284 
1285  value += (loops >= 2) ? 9 : 10; // add before last divide
1286  value /= 10;
1287  ++offset;
1288  }
1289  }
1290  else if (value > STAmount::cMaxValue)
1291  {
1292  while (value > (10 * STAmount::cMaxValue))
1293  {
1294  value /= 10;
1295  ++offset;
1296  }
1297 
1298  value += 9; // add before last divide
1299  value /= 10;
1300  ++offset;
1301  }
1302 }
1303 
1304 STAmount
1306  STAmount const& v1,
1307  STAmount const& v2,
1308  Issue const& issue,
1309  bool roundUp)
1310 {
1311  if (v1 == beast::zero || v2 == beast::zero)
1312  return {issue};
1313 
1314  bool const xrp = isXRP(issue);
1315 
1316  if (v1.native() && v2.native() && xrp)
1317  {
1318  std::uint64_t minV =
1319  (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v1) : getSNValue(v2);
1320  std::uint64_t maxV =
1321  (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v2) : getSNValue(v1);
1322 
1323  if (minV > 3000000000ull) // sqrt(cMaxNative)
1324  Throw<std::runtime_error>("Native value overflow");
1325 
1326  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1327  Throw<std::runtime_error>("Native value overflow");
1328 
1329  return STAmount(v1.getFName(), minV * maxV);
1330  }
1331 
1332  std::uint64_t value1 = v1.mantissa(), value2 = v2.mantissa();
1333  int offset1 = v1.exponent(), offset2 = v2.exponent();
1334 
1335  if (v1.native())
1336  {
1337  while (value1 < STAmount::cMinValue)
1338  {
1339  value1 *= 10;
1340  --offset1;
1341  }
1342  }
1343 
1344  if (v2.native())
1345  {
1346  while (value2 < STAmount::cMinValue)
1347  {
1348  value2 *= 10;
1349  --offset2;
1350  }
1351  }
1352 
1353  bool const resultNegative = v1.negative() != v2.negative();
1354 
1355  // We multiply the two mantissas (each is between 10^15
1356  // and 10^16), so their product is in the 10^30 to 10^32
1357  // range. Dividing their product by 10^14 maintains the
1358  // precision, by scaling the result to 10^16 to 10^18.
1359  //
1360  // If the we're rounding up, we want to round up away
1361  // from zero, and if we're rounding down, truncation
1362  // is implicit.
1363  std::uint64_t amount = muldiv_round(
1364  value1, value2, tenTo14, (resultNegative != roundUp) ? tenTo14m1 : 0);
1365 
1366  int offset = offset1 + offset2 + 14;
1367  if (resultNegative != roundUp)
1368  canonicalizeRound(xrp, amount, offset);
1369  STAmount result(issue, amount, offset, resultNegative);
1370 
1371  if (roundUp && !resultNegative && !result)
1372  {
1373  if (xrp)
1374  {
1375  // return the smallest value above zero
1376  amount = 1;
1377  offset = 0;
1378  }
1379  else
1380  {
1381  // return the smallest value above zero
1382  amount = STAmount::cMinValue;
1383  offset = STAmount::cMinOffset;
1384  }
1385  return STAmount(issue, amount, offset, resultNegative);
1386  }
1387  return result;
1388 }
1389 
1390 STAmount
1392  STAmount const& num,
1393  STAmount const& den,
1394  Issue const& issue,
1395  bool roundUp)
1396 {
1397  if (den == beast::zero)
1398  Throw<std::runtime_error>("division by zero");
1399 
1400  if (num == beast::zero)
1401  return {issue};
1402 
1403  std::uint64_t numVal = num.mantissa(), denVal = den.mantissa();
1404  int numOffset = num.exponent(), denOffset = den.exponent();
1405 
1406  if (num.native())
1407  {
1408  while (numVal < STAmount::cMinValue)
1409  {
1410  numVal *= 10;
1411  --numOffset;
1412  }
1413  }
1414 
1415  if (den.native())
1416  {
1417  while (denVal < STAmount::cMinValue)
1418  {
1419  denVal *= 10;
1420  --denOffset;
1421  }
1422  }
1423 
1424  bool const resultNegative = (num.negative() != den.negative());
1425 
1426  // We divide the two mantissas (each is between 10^15
1427  // and 10^16). To maintain precision, we multiply the
1428  // numerator by 10^17 (the product is in the range of
1429  // 10^32 to 10^33) followed by a division, so the result
1430  // is in the range of 10^16 to 10^15.
1431  //
1432  // We round away from zero if we're rounding up or
1433  // truncate if we're rounding down.
1434  std::uint64_t amount = muldiv_round(
1435  numVal, tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1436 
1437  int offset = numOffset - denOffset - 17;
1438 
1439  if (resultNegative != roundUp)
1440  canonicalizeRound(isXRP(issue), amount, offset);
1441 
1442  STAmount result(issue, amount, offset, resultNegative);
1443  if (roundUp && !resultNegative && !result)
1444  {
1445  if (isXRP(issue))
1446  {
1447  // return the smallest value above zero
1448  amount = 1;
1449  offset = 0;
1450  }
1451  else
1452  {
1453  // return the smallest value above zero
1454  amount = STAmount::cMinValue;
1455  offset = STAmount::cMinOffset;
1456  }
1457  return STAmount(issue, amount, offset, resultNegative);
1458  }
1459  return result;
1460 }
1461 
1462 } // 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:1142
ripple::amountFromJsonNoThrow
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1034
ripple::IOUAmount::exponent
int exponent() const noexcept
Definition: IOUAmount.h:163
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
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:835
ripple::JsonOptions
JsonOptions
Definition: STBase.h:34
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:327
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:63
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:571
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:655
ripple::SerializedTypeID
SerializedTypeID
Definition: SField.h:52
ripple::operator-
Number operator-(Number const &x, Number const &y)
Definition: Number.h:277
ripple::STAmount::mValue
mantissa_type mValue
Definition: STAmount.h:54
iterator
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
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:103
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::debugLog
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:452
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:334
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:1305
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::divRound
STAmount divRound(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1391
ripple::SerialIter::get160
uint160 get160()
Definition: Serializer.h:370
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:532
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:1121
ripple::STAmount
Definition: STAmount.h:45
ripple::getSTAmountCanonicalizeSwitchover
bool getSTAmountCanonicalizeSwitchover()
Definition: STAmount.cpp:49
ripple::amountFromJson
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:929
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::canonicalizeRound
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset)
Definition: STAmount.cpp:1270
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:852
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:694
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:864
ripple::STAmount::isDefault
bool isDefault() const override
Definition: STAmount.cpp:701
ripple::STAmount::unchecked
Definition: STAmount.h:80
ripple::getSTNumberSwitchover
bool getSTNumberSwitchover()
Definition: IOUAmount.cpp:42
ripple::SField
Identifies fields.
Definition: SField.h:112
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:725
ripple::STAmount::add
void add(Serializer &s) const override
Definition: STAmount.cpp:663
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:95
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::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:175
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:38
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::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