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 
21 #include <ripple/protocol/STAmount.h>
22 #include <ripple/basics/contract.h>
23 #include <ripple/basics/Log.h>
24 #include <ripple/basics/safe_cast.h>
25 #include <ripple/protocol/jss.h>
26 #include <ripple/protocol/SystemParameters.h>
27 #include <ripple/protocol/UintTypes.h>
28 #include <ripple/beast/core/LexicalCast.h>
29 #include <boost/regex.hpp>
30 #include <boost/algorithm/string.hpp>
31 #include <boost/multiprecision/cpp_int.hpp>
32 #include <iterator>
33 #include <memory>
34 #include <iostream>
35 
36 namespace ripple {
37 
38 static const std::uint64_t tenTo14 = 100000000000000ull;
39 static const std::uint64_t tenTo14m1 = tenTo14 - 1;
40 static const std::uint64_t tenTo17 = tenTo14 * 1000;
41 
42 //------------------------------------------------------------------------------
43 static
45 getSNValue (STAmount const& amount)
46 {
47  if (!amount.native ())
48  Throw<std::runtime_error> ("amount is not native!");
49 
50  auto ret = static_cast<std::int64_t>(amount.mantissa ());
51 
52  assert (static_cast<std::uint64_t>(ret) == amount.mantissa ());
53 
54  if (amount.negative ())
55  ret = -ret;
56 
57  return ret;
58 }
59 
60 static
61 bool
62 areComparable (STAmount const& v1, STAmount const& v2)
63 {
64  return v1.native() == v2.native() &&
65  v1.issue().currency == v2.issue().currency;
66 }
67 
69  : STBase(name)
70 {
71  std::uint64_t value = sit.get64 ();
72 
73  // native
74  if ((value & cNotNative) == 0)
75  {
76  // positive
77  if ((value & cPosNative) != 0)
78  {
79  mValue = value & ~cPosNative;
80  mOffset = 0;
81  mIsNative = true;
82  mIsNegative = false;
83  return;
84  }
85 
86  // negative
87  if (value == 0)
88  Throw<std::runtime_error> ("negative zero is not canonical");
89 
90  mValue = value;
91  mOffset = 0;
92  mIsNative = true;
93  mIsNegative = true;
94  return;
95  }
96 
97  Issue issue;
98  issue.currency = sit.get160();
99 
100  if (isXRP (issue.currency))
101  Throw<std::runtime_error> ("invalid native currency");
102 
103  issue.account = sit.get160();
104 
105  if (isXRP (issue.account))
106  Throw<std::runtime_error> ("invalid native account");
107 
108  // 10 bits for the offset, sign and "not native" flag
109  int offset = static_cast<int>(value >> (64 - 10));
110 
111  value &= ~ (1023ull << (64 - 10));
112 
113  if (value)
114  {
115  bool isNegative = (offset & 256) == 0;
116  offset = (offset & 255) - 97; // center the range
117 
118  if (value < cMinValue ||
119  value > cMaxValue ||
120  offset < cMinOffset ||
121  offset > cMaxOffset)
122  {
123  Throw<std::runtime_error> ("invalid currency value");
124  }
125 
126  mIssue = issue;
127  mValue = value;
128  mOffset = offset;
129  mIsNegative = isNegative;
130  canonicalize();
131  return;
132  }
133 
134  if (offset != 512)
135  Throw<std::runtime_error> ("invalid currency value");
136 
137  mIssue = issue;
138  mValue = 0;
139  mOffset = 0;
140  mIsNegative = false;
141  canonicalize();
142 }
143 
144 STAmount::STAmount (SField const& name, Issue const& issue,
145  mantissa_type mantissa, exponent_type exponent,
146  bool native, bool negative, unchecked)
147  : STBase (name)
148  , mIssue (issue)
149  , mValue (mantissa)
150  , mOffset (exponent)
151  , mIsNative (native)
152  , mIsNegative (negative)
153 {
154 }
155 
156 STAmount::STAmount (Issue const& issue,
157  mantissa_type mantissa, exponent_type exponent,
158  bool native, bool negative, unchecked)
159  : mIssue (issue)
160  , mValue (mantissa)
161  , mOffset (exponent)
162  , mIsNative (native)
163  , mIsNegative (negative)
164 {
165 }
166 
167 
168 STAmount::STAmount (SField const& name, Issue const& issue,
169  mantissa_type mantissa, exponent_type exponent,
170  bool native, bool negative)
171  : STBase (name)
172  , mIssue (issue)
173  , mValue (mantissa)
174  , mOffset (exponent)
175  , mIsNative (native)
176  , mIsNegative (negative)
177 {
178  canonicalize();
179 }
180 
181 STAmount::STAmount (SField const& name, std::int64_t mantissa)
182  : STBase (name)
183  , mOffset (0)
184  , mIsNative (true)
185 {
186  set (mantissa);
187 }
188 
190  std::uint64_t mantissa, bool negative)
191  : STBase (name)
192  , mValue (mantissa)
193  , mOffset (0)
194  , mIsNative (true)
195  , mIsNegative (negative)
196 {
198 }
199 
200 STAmount::STAmount (SField const& name, Issue const& issue,
201  std::uint64_t mantissa, int exponent, bool negative)
202  : STBase (name)
203  , mIssue (issue)
204  , mValue (mantissa)
205  , mOffset (exponent)
206  , mIsNegative (negative)
207 {
209  canonicalize ();
210 }
211 
212 //------------------------------------------------------------------------------
213 
214 STAmount::STAmount (std::uint64_t mantissa, bool negative)
215  : mValue (mantissa)
216  , mOffset (0)
217  , mIsNative (true)
218  , mIsNegative (mantissa != 0 && negative)
219 {
221 }
222 
223 STAmount::STAmount (Issue const& issue,
224  std::uint64_t mantissa, int exponent, bool negative)
225  : mIssue (issue)
226  , mValue (mantissa)
227  , mOffset (exponent)
228  , mIsNegative (negative)
229 {
230  canonicalize ();
231 }
232 
233 STAmount::STAmount (Issue const& issue,
234  std::int64_t mantissa, int exponent)
235  : mIssue (issue)
236  , mOffset (exponent)
237 {
238  set (mantissa);
239  canonicalize ();
240 }
241 
242 STAmount::STAmount (Issue const& issue,
243  std::uint32_t mantissa, int exponent, bool negative)
244  : STAmount (issue, safe_cast<std::uint64_t>(mantissa), exponent, negative)
245 {
246 }
247 
248 STAmount::STAmount (Issue const& issue,
249  int mantissa, int exponent)
250  : STAmount (issue, safe_cast<std::int64_t>(mantissa), exponent)
251 {
252 }
253 
254 // Legacy support for new-style amounts
255 STAmount::STAmount (IOUAmount const& amount, Issue const& issue)
256  : mIssue (issue)
257  , mOffset (amount.exponent ())
258  , mIsNative (false)
259  , mIsNegative (amount < beast::zero)
260 {
261  if (mIsNegative)
262  mValue = static_cast<std::uint64_t> (-amount.mantissa ());
263  else
264  mValue = static_cast<std::uint64_t> (amount.mantissa ());
265 
266  canonicalize ();
267 }
268 
270  : mOffset (0)
271  , mIsNative (true)
272  , mIsNegative (amount < beast::zero)
273 {
274  if (mIsNegative)
275  mValue = unsafe_cast<std::uint64_t> (-amount.drops ());
276  else
277  mValue = unsafe_cast<std::uint64_t> (amount.drops ());
278 
279  canonicalize ();
280 }
281 
284 {
285  return std::make_unique<STAmount>(sit, name);
286 }
287 
288 //------------------------------------------------------------------------------
289 //
290 // Conversion
291 //
292 //------------------------------------------------------------------------------
293 XRPAmount
295 {
296  if (!mIsNative)
297  Throw<std::logic_error> (
298  "Cannot return non-native STAmount as XRPAmount");
299 
300  auto drops = static_cast<XRPAmount::value_type> (mValue);
301 
302  if (mIsNegative)
303  drops = -drops;
304 
305  return XRPAmount{ drops };
306 }
307 
308 IOUAmount
310 {
311  if (mIsNative)
312  Throw<std::logic_error> ("Cannot return native STAmount as IOUAmount");
313 
314  auto mantissa = static_cast<std::int64_t> (mValue);
315  auto exponent = mOffset;
316 
317  if (mIsNegative)
318  mantissa = -mantissa;
319 
320  return { mantissa, exponent };
321 }
322 
323 //------------------------------------------------------------------------------
324 //
325 // Operators
326 //
327 //------------------------------------------------------------------------------
328 
330 {
331  *this = *this + a;
332  return *this;
333 }
334 
336 {
337  *this = *this - a;
338  return *this;
339 }
340 
341 STAmount operator+ (STAmount const& v1, STAmount const& v2)
342 {
343  if (!areComparable (v1, v2))
344  Throw<std::runtime_error> ("Can't add amounts that are't comparable!");
345 
346  if (v2 == beast::zero)
347  return v1;
348 
349  if (v1 == beast::zero)
350  {
351  // Result must be in terms of v1 currency and issuer.
352  return { v1.getFName (), v1.issue (),
353  v2.mantissa (), v2.exponent (), v2.negative () };
354  }
355 
356  if (v1.native ())
357  return { v1.getFName (), getSNValue (v1) + getSNValue (v2) };
358 
359  int ov1 = v1.exponent (), ov2 = v2.exponent ();
360  std::int64_t vv1 = static_cast<std::int64_t>(v1.mantissa ());
361  std::int64_t vv2 = static_cast<std::int64_t>(v2.mantissa ());
362 
363  if (v1.negative ())
364  vv1 = -vv1;
365 
366  if (v2.negative ())
367  vv2 = -vv2;
368 
369  while (ov1 < ov2)
370  {
371  vv1 /= 10;
372  ++ov1;
373  }
374 
375  while (ov2 < ov1)
376  {
377  vv2 /= 10;
378  ++ov2;
379  }
380 
381  // This addition cannot overflow an std::int64_t. It can overflow an
382  // STAmount and the constructor will throw.
383 
384  std::int64_t fv = vv1 + vv2;
385 
386  if ((fv >= -10) && (fv <= 10))
387  return { v1.getFName (), v1.issue () };
388 
389  if (fv >= 0)
390  return STAmount { v1.getFName (), v1.issue (),
391  static_cast<std::uint64_t>(fv), ov1, false };
392 
393  return STAmount { v1.getFName (), v1.issue (),
394  static_cast<std::uint64_t>(-fv), ov1, true };
395 }
396 
397 STAmount operator- (STAmount const& v1, STAmount const& v2)
398 {
399  return v1 + (-v2);
400 }
401 
402 //------------------------------------------------------------------------------
403 
404 std::uint64_t const STAmount::uRateOne = getRate (STAmount (1), STAmount (1));
405 
406 void
407 STAmount::setIssue (Issue const& issue)
408 {
409  mIssue = std::move(issue);
410  mIsNative = isXRP (*this);
411 }
412 
413 // Convert an offer into an index amount so they sort by rate.
414 // A taker will take the best, lowest, rate first.
415 // (e.g. a taker will prefer pay 1 get 3 over pay 1 get 2.
416 // --> offerOut: takerGets: How much the offerer is selling to the taker.
417 // --> offerIn: takerPays: How much the offerer is receiving from the taker.
418 // <-- uRate: normalize(offerIn/offerOut)
419 // A lower rate is better for the person taking the order.
420 // The taker gets more for less with a lower rate.
421 // Zero is returned if the offer is worthless.
423 getRate (STAmount const& offerOut, STAmount const& offerIn)
424 {
425  if (offerOut == beast::zero)
426  return 0;
427  try
428  {
429  STAmount r = divide (offerIn, offerOut, noIssue());
430  if (r == beast::zero) // offer is too good
431  return 0;
432  assert ((r.exponent() >= -100) && (r.exponent() <= 155));
433  std::uint64_t ret = r.exponent() + 100;
434  return (ret << (64 - 8)) | r.mantissa();
435  }
436  catch (std::exception const&)
437  {
438  }
439 
440  // overflow -- very bad offer
441  return 0;
442 }
443 
444 void STAmount::setJson (Json::Value& elem) const
445 {
446  elem = Json::objectValue;
447 
448  if (!mIsNative)
449  {
450  // It is an error for currency or issuer not to be specified for valid
451  // json.
452  elem[jss::value] = getText ();
453  elem[jss::currency] = to_string (mIssue.currency);
454  elem[jss::issuer] = to_string (mIssue.account);
455  }
456  else
457  {
458  elem = getText ();
459  }
460 }
461 
462 //------------------------------------------------------------------------------
463 //
464 // STBase
465 //
466 //------------------------------------------------------------------------------
467 
470 {
471  std::string ret;
472 
473  ret.reserve(64);
474  ret = getText () + "/" + to_string (mIssue.currency);
475 
476  if (!mIsNative)
477  {
478  ret += "/";
479 
480  if (isXRP (*this))
481  ret += "0";
482  else if (mIssue.account == noAccount())
483  ret += "1";
484  else
485  ret += to_string (mIssue.account);
486  }
487 
488  return ret;
489 }
490 
493 {
494  // keep full internal accuracy, but make more human friendly if posible
495  if (*this == beast::zero)
496  return "0";
497 
498  std::string const raw_value (std::to_string (mValue));
499  std::string ret;
500 
501  if (mIsNegative)
502  ret.append (1, '-');
503 
504  bool const scientific ((mOffset != 0) && ((mOffset < -25) || (mOffset > -5)));
505 
506  if (mIsNative || scientific)
507  {
508  ret.append (raw_value);
509 
510  if (scientific)
511  {
512  ret.append (1, 'e');
513  ret.append (std::to_string (mOffset));
514  }
515 
516  return ret;
517  }
518 
519  assert (mOffset + 43 > 0);
520 
521  size_t const pad_prefix = 27;
522  size_t const pad_suffix = 23;
523 
524  std::string val;
525  val.reserve (raw_value.length () + pad_prefix + pad_suffix);
526  val.append (pad_prefix, '0');
527  val.append (raw_value);
528  val.append (pad_suffix, '0');
529 
530  size_t const offset (mOffset + 43);
531 
532  auto pre_from (val.begin ());
533  auto const pre_to (val.begin () + offset);
534 
535  auto const post_from (val.begin () + offset);
536  auto post_to (val.end ());
537 
538  // Crop leading zeroes. Take advantage of the fact that there's always a
539  // fixed amount of leading zeroes and skip them.
540  if (std::distance (pre_from, pre_to) > pad_prefix)
541  pre_from += pad_prefix;
542 
543  assert (post_to >= post_from);
544 
545  pre_from = std::find_if (pre_from, pre_to,
546  [](char c)
547  {
548  return c != '0';
549  });
550 
551  // Crop trailing zeroes. Take advantage of the fact that there's always a
552  // fixed amount of trailing zeroes and skip them.
553  if (std::distance (post_from, post_to) > pad_suffix)
554  post_to -= pad_suffix;
555 
556  assert (post_to >= post_from);
557 
558  post_to = std::find_if(
559  std::make_reverse_iterator (post_to),
560  std::make_reverse_iterator (post_from),
561  [](char c)
562  {
563  return c != '0';
564  }).base();
565 
566  // Assemble the output:
567  if (pre_from == pre_to)
568  ret.append (1, '0');
569  else
570  ret.append(pre_from, pre_to);
571 
572  if (post_to != post_from)
573  {
574  ret.append (1, '.');
575  ret.append (post_from, post_to);
576  }
577 
578  return ret;
579 }
580 
583 {
584  Json::Value elem;
585  setJson (elem);
586  return elem;
587 }
588 
589 void
591 {
592  if (mIsNative)
593  {
594  assert (mOffset == 0);
595 
596  if (!mIsNegative)
597  s.add64 (mValue | cPosNative);
598  else
599  s.add64 (mValue);
600  }
601  else
602  {
603  if (*this == beast::zero)
604  s.add64 (cNotNative);
605  else if (mIsNegative) // 512 = not native
606  s.add64 (mValue | (static_cast<std::uint64_t>(mOffset + 512 + 97) << (64 - 10)));
607  else // 256 = positive
608  s.add64 (mValue | (static_cast<std::uint64_t>(mOffset + 512 + 256 + 97) << (64 - 10)));
609 
610  s.add160 (mIssue.currency);
611  s.add160 (mIssue.account);
612  }
613 }
614 
615 bool
617 {
618  const STAmount* v = dynamic_cast<const STAmount*> (&t);
619  return v && (*v == *this);
620 }
621 
622 //------------------------------------------------------------------------------
623 
624 // amount = mValue * [10 ^ mOffset]
625 // Representation range is 10^80 - 10^(-80).
626 //
627 // On the wire:
628 // - high bit is 0 for XRP, 1 for issued currency
629 // - next bit is 1 for positive, 0 for negative (except 0 issued currency, which
630 // is a special case of 0x8000000000000000
631 // - for issued currencies, the next 8 bits are (mOffset+97).
632 // The +97 is so that this value is always positive.
633 // - The remaining bits are significant digits (mantissa)
634 // That's 54 bits for issued currency and 62 bits for native
635 // (but XRP only needs 57 bits for the max value of 10^17 drops)
636 //
637 // mValue is zero if the amount is zero, otherwise it's within the range
638 // 10^15 to (10^16 - 1) inclusive.
639 // mOffset is in the range -96 to +80.
641 {
642  if (isXRP (*this))
643  {
644  // native currency amounts should always have an offset of zero
645  mIsNative = true;
646 
647  if (mValue == 0)
648  {
649  mOffset = 0;
650  mIsNegative = false;
651  return;
652  }
653 
654  while (mOffset < 0)
655  {
656  mValue /= 10;
657  ++mOffset;
658  }
659 
660  while (mOffset > 0)
661  {
662  mValue *= 10;
663  --mOffset;
664  }
665 
666  if (mValue > cMaxNativeN)
667  Throw<std::runtime_error> ("Native currency amount out of range");
668 
669  return;
670  }
671 
672  mIsNative = false;
673 
674  if (mValue == 0)
675  {
676  mOffset = -100;
677  mIsNegative = false;
678  return;
679  }
680 
681  while ((mValue < cMinValue) && (mOffset > cMinOffset))
682  {
683  mValue *= 10;
684  --mOffset;
685  }
686 
687  while (mValue > cMaxValue)
688  {
689  if (mOffset >= cMaxOffset)
690  Throw<std::runtime_error> ("value overflow");
691 
692  mValue /= 10;
693  ++mOffset;
694  }
695 
696  if ((mOffset < cMinOffset) || (mValue < cMinValue))
697  {
698  mValue = 0;
699  mIsNegative = false;
700  mOffset = -100;
701  return;
702  }
703 
704  if (mOffset > cMaxOffset)
705  Throw<std::runtime_error> ("value overflow");
706 
707  assert ((mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)));
708  assert ((mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)));
709  assert ((mValue != 0) || (mOffset != -100));
710 }
711 
713 {
714  if (v < 0)
715  {
716  mIsNegative = true;
717  mValue = static_cast<std::uint64_t>(-v);
718  }
719  else
720  {
721  mIsNegative = false;
722  mValue = static_cast<std::uint64_t>(v);
723  }
724 }
725 
726 //------------------------------------------------------------------------------
727 
728 STAmount
730 {
731  if (rate == 0)
732  return STAmount (noIssue());
733 
734  std::uint64_t mantissa = rate & ~ (255ull << (64 - 8));
735  int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
736 
737  return STAmount (noIssue(), mantissa, exponent);
738 }
739 
740 STAmount
741 amountFromString (Issue const& issue, std::string const& amount)
742 {
743  static boost::regex const reNumber (
744  "^" // the beginning of the string
745  "([-+]?)" // (optional) + or - character
746  "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
747  "(\\.([0-9]+))?" // (optional) period followed by any number
748  "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
749  "$",
750  boost::regex_constants::optimize);
751 
752  boost::smatch match;
753 
754  if (!boost::regex_match (amount, match, reNumber))
755  Throw<std::runtime_error> ("Number '" + amount + "' is not valid");
756 
757  // Match fields:
758  // 0 = whole input
759  // 1 = sign
760  // 2 = integer portion
761  // 3 = whole fraction (with '.')
762  // 4 = fraction (without '.')
763  // 5 = whole exponent (with 'e')
764  // 6 = exponent sign
765  // 7 = exponent number
766 
767  // CHECKME: Why 32? Shouldn't this be 16?
768  if ((match[2].length () + match[4].length ()) > 32)
769  Throw<std::runtime_error> ("Number '" + amount + "' is overlong");
770 
771  bool negative = (match[1].matched && (match[1] == "-"));
772 
773  // Can't specify XRP using fractional representation
774  if (isXRP(issue) && match[3].matched)
775  Throw<std::runtime_error> ("XRP must be specified in integral drops.");
776 
777  std::uint64_t mantissa;
778  int exponent;
779 
780  if (!match[4].matched) // integer only
781  {
782  mantissa = beast::lexicalCastThrow <std::uint64_t> (std::string (match[2]));
783  exponent = 0;
784  }
785  else
786  {
787  // integer and fraction
788  mantissa = beast::lexicalCastThrow <std::uint64_t> (match[2] + match[4]);
789  exponent = -(match[4].length ());
790  }
791 
792  if (match[5].matched)
793  {
794  // we have an exponent
795  if (match[6].matched && (match[6] == "-"))
796  exponent -= beast::lexicalCastThrow <int> (std::string (match[7]));
797  else
798  exponent += beast::lexicalCastThrow <int> (std::string (match[7]));
799  }
800 
801  return { issue, mantissa, exponent, negative };
802 }
803 
804 STAmount
805 amountFromJson (SField const& name, Json::Value const& v)
806 {
807  STAmount::mantissa_type mantissa = 0;
808  STAmount::exponent_type exponent = 0;
809  bool negative = false;
810  Issue issue;
811 
812  Json::Value value;
813  Json::Value currency;
814  Json::Value issuer;
815 
816  if (v.isNull())
817  {
818  Throw<std::runtime_error> ("XRP may not be specified with a null Json value");
819  }
820  else if (v.isObject())
821  {
822  value = v[jss::value];
823  currency = v[jss::currency];
824  issuer = v[jss::issuer];
825  }
826  else if (v.isArray())
827  {
828  value = v.get (Json::UInt (0), 0);
829  currency = v.get (Json::UInt (1), Json::nullValue);
830  issuer = v.get (Json::UInt (2), Json::nullValue);
831  }
832  else if (v.isString ())
833  {
834  std::string val = v.asString ();
835  std::vector<std::string> elements;
836  boost::split (elements, val, boost::is_any_of ("\t\n\r ,/"));
837 
838  if (elements.size () > 3)
839  Throw<std::runtime_error> ("invalid amount string");
840 
841  value = elements[0];
842 
843  if (elements.size () > 1)
844  currency = elements[1];
845 
846  if (elements.size () > 2)
847  issuer = elements[2];
848  }
849  else
850  {
851  value = v;
852  }
853 
854  bool const native = ! currency.isString () ||
855  currency.asString ().empty () ||
856  (currency.asString () == systemCurrencyCode());
857 
858  if (native)
859  {
860  if (v.isObjectOrNull ())
861  Throw<std::runtime_error> ("XRP may not be specified as an object");
862  issue = xrpIssue ();
863  }
864  else
865  {
866  // non-XRP
867  if (! to_currency (issue.currency, currency.asString ()))
868  Throw<std::runtime_error> ("invalid currency");
869 
870  if (! issuer.isString ()
871  || !to_issuer (issue.account, issuer.asString ()))
872  Throw<std::runtime_error> ("invalid issuer");
873 
874  if (isXRP (issue.currency))
875  Throw<std::runtime_error> ("invalid issuer");
876  }
877 
878  if (value.isInt ())
879  {
880  if (value.asInt () >= 0)
881  {
882  mantissa = value.asInt ();
883  }
884  else
885  {
886  mantissa = -value.asInt ();
887  negative = true;
888  }
889  }
890  else if (value.isUInt ())
891  {
892  mantissa = v.asUInt ();
893  }
894  else if (value.isString ())
895  {
896  auto const ret = amountFromString (issue, value.asString ());
897 
898  mantissa = ret.mantissa ();
899  exponent = ret.exponent ();
900  negative = ret.negative ();
901  }
902  else
903  {
904  Throw<std::runtime_error> ("invalid amount type");
905  }
906 
907  return { name, issue, mantissa, exponent, native, negative };
908 }
909 
910 bool
911 amountFromJsonNoThrow (STAmount& result, Json::Value const& jvSource)
912 {
913  try
914  {
915  result = amountFromJson (sfGeneric, jvSource);
916  return true;
917  }
918  catch (const std::exception& e)
919  {
920  JLOG (debugLog().warn()) <<
921  "amountFromJsonNoThrow: caught: " << e.what ();
922  }
923  return false;
924 }
925 
926 //------------------------------------------------------------------------------
927 //
928 // Operators
929 //
930 //------------------------------------------------------------------------------
931 
932 bool
933 operator== (STAmount const& lhs, STAmount const& rhs)
934 {
935  return areComparable (lhs, rhs) &&
936  lhs.negative() == rhs.negative() &&
937  lhs.exponent() == rhs.exponent() &&
938  lhs.mantissa() == rhs.mantissa();
939 }
940 
941 bool
942 operator< (STAmount const& lhs, STAmount const& rhs)
943 {
944  if (!areComparable (lhs, rhs))
945  Throw<std::runtime_error> ("Can't compare amounts that are't comparable!");
946 
947  if (lhs.negative() != rhs.negative())
948  return lhs.negative();
949 
950  if (lhs.mantissa() == 0)
951  {
952  if (rhs.negative())
953  return false;
954  return rhs.mantissa() != 0;
955  }
956 
957  // We know that lhs is non-zero and both sides have the same sign. Since
958  // rhs is zero (and thus not negative), lhs must, therefore, be strictly
959  // greater than zero. So if rhs is zero, the comparison must be false.
960  if (rhs.mantissa() == 0) return false;
961 
962  if (lhs.exponent() > rhs.exponent()) return lhs.negative();
963  if (lhs.exponent() < rhs.exponent()) return ! lhs.negative();
964  if (lhs.mantissa() > rhs.mantissa()) return lhs.negative();
965  if (lhs.mantissa() < rhs.mantissa()) return ! lhs.negative();
966 
967  return false;
968 }
969 
970 STAmount
971 operator- (STAmount const& value)
972 {
973  if (value.mantissa() == 0)
974  return value;
975  return STAmount (value.getFName (),
976  value.issue(), value.mantissa(), value.exponent(),
977  value.native(), ! value.negative(), STAmount::unchecked{});
978 }
979 
980 //------------------------------------------------------------------------------
981 //
982 // Arithmetic
983 //
984 //------------------------------------------------------------------------------
985 
986 // Calculate (a * b) / c when all three values are 64-bit
987 // without loss of precision:
988 static
991  std::uint64_t multiplier,
992  std::uint64_t multiplicand,
993  std::uint64_t divisor)
994 {
995  boost::multiprecision::uint128_t ret;
996 
997  boost::multiprecision::multiply(ret, multiplier, multiplicand);
998  ret /= divisor;
999 
1001  {
1002  Throw<std::overflow_error> ("overflow: (" +
1003  std::to_string (multiplier) + " * " +
1004  std::to_string (multiplicand) + ") / " +
1005  std::to_string (divisor));
1006  }
1007 
1008  return static_cast<uint64_t>(ret);
1009 }
1010 
1011 static
1014  std::uint64_t multiplier,
1015  std::uint64_t multiplicand,
1016  std::uint64_t divisor,
1017  std::uint64_t rounding)
1018 {
1019  boost::multiprecision::uint128_t ret;
1020 
1021  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1022  ret += rounding;
1023  ret /= divisor;
1024 
1026  {
1027  Throw<std::overflow_error> ("overflow: ((" +
1028  std::to_string (multiplier) + " * " +
1029  std::to_string (multiplicand) + ") + " +
1030  std::to_string (rounding) + ") / " +
1031  std::to_string (divisor));
1032  }
1033 
1034  return static_cast<uint64_t>(ret);
1035 }
1036 
1037 STAmount
1038 divide (STAmount const& num, STAmount const& den, Issue const& issue)
1039 {
1040  if (den == beast::zero)
1041  Throw<std::runtime_error> ("division by zero");
1042 
1043  if (num == beast::zero)
1044  return {issue};
1045 
1046  std::uint64_t numVal = num.mantissa();
1047  std::uint64_t denVal = den.mantissa();
1048  int numOffset = num.exponent();
1049  int denOffset = den.exponent();
1050 
1051  if (num.native())
1052  {
1053  while (numVal < STAmount::cMinValue)
1054  {
1055  // Need to bring into range
1056  numVal *= 10;
1057  --numOffset;
1058  }
1059  }
1060 
1061  if (den.native())
1062  {
1063  while (denVal < STAmount::cMinValue)
1064  {
1065  denVal *= 10;
1066  --denOffset;
1067  }
1068  }
1069 
1070  // We divide the two mantissas (each is between 10^15
1071  // and 10^16). To maintain precision, we multiply the
1072  // numerator by 10^17 (the product is in the range of
1073  // 10^32 to 10^33) followed by a division, so the result
1074  // is in the range of 10^16 to 10^15.
1075  return STAmount (issue,
1076  muldiv(numVal, tenTo17, denVal) + 5,
1077  numOffset - denOffset - 17,
1078  num.negative() != den.negative());
1079 }
1080 
1081 STAmount
1082 multiply (STAmount const& v1, STAmount const& v2, Issue const& issue)
1083 {
1084  if (v1 == beast::zero || v2 == beast::zero)
1085  return STAmount (issue);
1086 
1087  if (v1.native() && v2.native() && isXRP (issue))
1088  {
1089  std::uint64_t const minV = getSNValue (v1) < getSNValue (v2)
1090  ? getSNValue (v1) : getSNValue (v2);
1091  std::uint64_t const maxV = getSNValue (v1) < getSNValue (v2)
1092  ? getSNValue (v2) : getSNValue (v1);
1093 
1094  if (minV > 3000000000ull) // sqrt(cMaxNative)
1095  Throw<std::runtime_error> ("Native value overflow");
1096 
1097  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1098  Throw<std::runtime_error> ("Native value overflow");
1099 
1100  return STAmount (v1.getFName (), minV * maxV);
1101  }
1102 
1103  std::uint64_t value1 = v1.mantissa();
1104  std::uint64_t value2 = v2.mantissa();
1105  int offset1 = v1.exponent();
1106  int offset2 = v2.exponent();
1107 
1108  if (v1.native())
1109  {
1110  while (value1 < STAmount::cMinValue)
1111  {
1112  value1 *= 10;
1113  --offset1;
1114  }
1115  }
1116 
1117  if (v2.native())
1118  {
1119  while (value2 < STAmount::cMinValue)
1120  {
1121  value2 *= 10;
1122  --offset2;
1123  }
1124  }
1125 
1126  // We multiply the two mantissas (each is between 10^15
1127  // and 10^16), so their product is in the 10^30 to 10^32
1128  // range. Dividing their product by 10^14 maintains the
1129  // precision, by scaling the result to 10^16 to 10^18.
1130  return STAmount (issue,
1131  muldiv(value1, value2, tenTo14) + 7,
1132  offset1 + offset2 + 14,
1133  v1.negative() != v2.negative());
1134 }
1135 
1136 static
1137 void
1138 canonicalizeRound (bool native, std::uint64_t& value, int& offset)
1139 {
1140  if (native)
1141  {
1142  if (offset < 0)
1143  {
1144  int loops = 0;
1145 
1146  while (offset < -1)
1147  {
1148  value /= 10;
1149  ++offset;
1150  ++loops;
1151  }
1152 
1153  value += (loops >= 2) ? 9 : 10; // add before last divide
1154  value /= 10;
1155  ++offset;
1156  }
1157  }
1158  else if (value > STAmount::cMaxValue)
1159  {
1160  while (value > (10 * STAmount::cMaxValue))
1161  {
1162  value /= 10;
1163  ++offset;
1164  }
1165 
1166  value += 9; // add before last divide
1167  value /= 10;
1168  ++offset;
1169  }
1170 }
1171 
1172 STAmount
1173 mulRound (STAmount const& v1, STAmount const& v2, Issue const& issue,
1174  bool roundUp)
1175 {
1176  if (v1 == beast::zero || v2 == beast::zero)
1177  return {issue};
1178 
1179  bool const xrp = isXRP (issue);
1180 
1181  if (v1.native() && v2.native() && xrp)
1182  {
1183  std::uint64_t minV = (getSNValue (v1) < getSNValue (v2)) ?
1184  getSNValue (v1) : getSNValue (v2);
1185  std::uint64_t maxV = (getSNValue (v1) < getSNValue (v2)) ?
1186  getSNValue (v2) : getSNValue (v1);
1187 
1188  if (minV > 3000000000ull) // sqrt(cMaxNative)
1189  Throw<std::runtime_error> ("Native value overflow");
1190 
1191  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1192  Throw<std::runtime_error> ("Native value overflow");
1193 
1194  return STAmount (v1.getFName (), minV * maxV);
1195  }
1196 
1197  std::uint64_t value1 = v1.mantissa(), value2 = v2.mantissa();
1198  int offset1 = v1.exponent(), offset2 = v2.exponent();
1199 
1200  if (v1.native())
1201  {
1202  while (value1 < STAmount::cMinValue)
1203  {
1204  value1 *= 10;
1205  --offset1;
1206  }
1207  }
1208 
1209  if (v2.native())
1210  {
1211  while (value2 < STAmount::cMinValue)
1212  {
1213  value2 *= 10;
1214  --offset2;
1215  }
1216  }
1217 
1218  bool const resultNegative = v1.negative() != v2.negative();
1219 
1220  // We multiply the two mantissas (each is between 10^15
1221  // and 10^16), so their product is in the 10^30 to 10^32
1222  // range. Dividing their product by 10^14 maintains the
1223  // precision, by scaling the result to 10^16 to 10^18.
1224  //
1225  // If the we're rounding up, we want to round up away
1226  // from zero, and if we're rounding down, truncation
1227  // is implicit.
1228  std::uint64_t amount = muldiv_round (
1229  value1, value2, tenTo14,
1230  (resultNegative != roundUp) ? tenTo14m1 : 0);
1231 
1232  int offset = offset1 + offset2 + 14;
1233  if (resultNegative != roundUp)
1234  canonicalizeRound (xrp, amount, offset);
1235  STAmount result (issue, amount, offset, resultNegative);
1236 
1237  if (roundUp && !resultNegative && !result)
1238  {
1239  if (xrp)
1240  {
1241  // return the smallest value above zero
1242  amount = 1;
1243  offset = 0;
1244  }
1245  else
1246  {
1247  // return the smallest value above zero
1248  amount = STAmount::cMinValue;
1249  offset = STAmount::cMinOffset;
1250  }
1251  return STAmount(issue, amount, offset, resultNegative);
1252  }
1253  return result;
1254 }
1255 
1256 STAmount
1257 divRound (STAmount const& num, STAmount const& den,
1258  Issue const& issue, bool roundUp)
1259 {
1260  if (den == beast::zero)
1261  Throw<std::runtime_error> ("division by zero");
1262 
1263  if (num == beast::zero)
1264  return {issue};
1265 
1266  std::uint64_t numVal = num.mantissa(), denVal = den.mantissa();
1267  int numOffset = num.exponent(), denOffset = den.exponent();
1268 
1269  if (num.native())
1270  {
1271  while (numVal < STAmount::cMinValue)
1272  {
1273  numVal *= 10;
1274  --numOffset;
1275  }
1276  }
1277 
1278  if (den.native())
1279  {
1280  while (denVal < STAmount::cMinValue)
1281  {
1282  denVal *= 10;
1283  --denOffset;
1284  }
1285  }
1286 
1287  bool const resultNegative =
1288  (num.negative() != den.negative());
1289 
1290  // We divide the two mantissas (each is between 10^15
1291  // and 10^16). To maintain precision, we multiply the
1292  // numerator by 10^17 (the product is in the range of
1293  // 10^32 to 10^33) followed by a division, so the result
1294  // is in the range of 10^16 to 10^15.
1295  //
1296  // We round away from zero if we're rounding up or
1297  // truncate if we're rounding down.
1298  std::uint64_t amount = muldiv_round (
1299  numVal, tenTo17, denVal,
1300  (resultNegative != roundUp) ? denVal - 1 : 0);
1301 
1302  int offset = numOffset - denOffset - 17;
1303 
1304  if (resultNegative != roundUp)
1305  canonicalizeRound (isXRP (issue), amount, offset);
1306 
1307  STAmount result (issue, amount, offset, resultNegative);
1308  if (roundUp && !resultNegative && !result)
1309  {
1310  if (isXRP(issue))
1311  {
1312  // return the smallest value above zero
1313  amount = 1;
1314  offset = 0;
1315  }
1316  else
1317  {
1318  // return the smallest value above zero
1319  amount = STAmount::cMinValue;
1320  offset = STAmount::cMinOffset;
1321  }
1322  return STAmount(issue, amount, offset, resultNegative);
1323  }
1324  return result;
1325 }
1326 
1327 } // ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:1012
ripple::STAmount::mIsNative
bool mIsNative
Definition: STAmount.h:54
ripple::systemCurrencyCode
static std::string const & systemCurrencyCode()
Definition: SystemParameters.h:57
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:67
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:1013
ripple::amountFromJsonNoThrow
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:911
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1069
std::string
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1049
ripple::STAmount::cMinValue
static const std::uint64_t cMinValue
Definition: STAmount.h:64
std::exception
STL class.
ripple::STAmount::set
void set(std::int64_t v)
Definition: STAmount.cpp:712
ripple::JsonOptions
JsonOptions
Definition: STBase.h:34
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:317
ripple::STAmount::mantissa
std::uint64_t mantissa() const noexcept
Definition: STAmount.h:155
std::string::reserve
T reserve(T... args)
ripple::XRPAmount::drops
constexpr value_type drops() const
Returns the number of drops.
Definition: XRPAmount.h:185
Json::UInt
unsigned int UInt
Definition: json_forwards.h:28
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:853
std::vector< std::string >
std::find_if
T find_if(T... args)
std::string::length
T length(T... args)
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:492
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:582
ripple::STAmount::mValue
mantissa_type mValue
Definition: STAmount.h:52
iterator
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::tenTo14
static const std::uint64_t tenTo14
Definition: STAmount.cpp:38
std::distance
T distance(T... args)
ripple::STAmount::cMinOffset
static const int cMinOffset
Definition: STAmount.h:60
ripple::noIssue
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition: Issue.h:104
ripple::operator-
STAmount operator-(STAmount const &v1, STAmount const &v2)
Definition: STAmount.cpp:397
Json::Value::isNull
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:998
ripple::STAmount::cNotNative
static const std::uint64_t cNotNative
Definition: STAmount.h:70
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:41
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::getSNValue
static std::int64_t getSNValue(STAmount const &amount)
Definition: STAmount.cpp:45
iostream
ripple::STAmount::iou
IOUAmount iou() const
Definition: STAmount.cpp:309
ripple::STAmount::operator-=
STAmount & operator-=(STAmount const &)
Definition: STAmount.cpp:335
ripple::debugLog
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:417
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:294
ripple::operator==
bool operator==(Manifest const &lhs, Manifest const &rhs)
Definition: Manifest.h:148
ripple::mulRound
STAmount mulRound(STAmount const &v1, STAmount const &v2, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1173
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:423
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:92
ripple::STAmount::getFullText
std::string getFullText() const override
Definition: STAmount.cpp:469
ripple::STAmount::exponent
int exponent() const noexcept
Definition: STAmount.h:152
ripple::STAmount::mIssue
Issue mIssue
Definition: STAmount.h:51
ripple::STAmount::setJson
void setJson(Json::Value &) const
Definition: STAmount.cpp:444
ripple::operator+
const base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:533
ripple::STAmount::STAmount
STAmount(SerialIter &sit, SField const &name)
Definition: STAmount.cpp:68
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:45
ripple::SerialIter::get64
std::uint64_t get64()
Definition: Serializer.cpp:475
ripple::divRound
STAmount divRound(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1257
ripple::SerialIter::get160
uint160 get160()
Definition: Serializer.h:374
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:553
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:990
ripple::STAmount
Definition: STAmount.h:42
ripple::amountFromJson
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:805
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:121
ripple::SerialIter
Definition: Serializer.h:311
std::uint64_t
ripple::STAmount::setIssue
void setIssue(Issue const &issue)
Set the Issue for this amount and update mIsNative.
Definition: STAmount.cpp:407
ripple::canonicalizeRound
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset)
Definition: STAmount.cpp:1138
ripple::STAmount::construct
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
Definition: STAmount.cpp:283
ripple::amountFromQuality
STAmount amountFromQuality(std::uint64_t rate)
Definition: STAmount.cpp:729
ripple::areComparable
static bool areComparable(STAmount const &v1, STAmount const &v2)
Definition: STAmount.cpp:62
memory
std::string::append
T append(T... args)
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1056
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:37
ripple::STBase::getFName
SField const & getFName() const
Definition: STBase.cpp:135
ripple::Serializer
Definition: Serializer.h:43
ripple::STAmount::isEquivalent
bool isEquivalent(const STBase &t) const override
Definition: STAmount.cpp:616
ripple::STAmount::native
bool native() const noexcept
Definition: STAmount.h:153
ripple::STAmount::operator+=
STAmount & operator+=(STAmount const &)
Definition: STAmount.cpp:329
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:55
ripple::IOUAmount::mantissa
std::int64_t mantissa() const noexcept
Definition: IOUAmount.h:132
ripple::amountFromString
STAmount amountFromString(Issue const &issue, std::string const &amount)
Definition: STAmount.cpp:741
ripple::STAmount::unchecked
Definition: STAmount.h:78
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:65
std::string::begin
T begin(T... args)
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:156
std
STL namespace.
ripple::STAmount::canonicalize
void canonicalize()
Definition: STAmount.cpp:640
ripple::STAmount::add
void add(Serializer &s) const override
Definition: STAmount.cpp:590
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:555
Json::Value::isUInt
bool isUInt() const
Definition: json_value.cpp:1019
ripple::STAmount::value
STAmount const & value() const noexcept
Definition: STAmount.h:179
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:38
ripple::STAmount::negative
bool negative() const noexcept
Definition: STAmount.h:154
ripple::Serializer::add64
int add64(std::uint64_t)
Definition: Serializer.cpp:67
std::string::empty
T empty(T... args)
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:97
ripple::STAmount::exponent_type
int exponent_type
Definition: STAmount.h:47
ripple::Serializer::add160
int add160(base_uint< 160, Tag > const &i)
Definition: Serializer.h:105
Json::Value::asInt
Int asInt() const
Definition: json_value.cpp:516
std::string::end
T end(T... args)
ripple::STAmount::cMaxNativeN
static const std::uint64_t cMaxNativeN
Definition: STAmount.h:69
ripple::STAmount::cMaxOffset
static const int cMaxOffset
Definition: STAmount.h:61
ripple::operator<
bool operator<(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:456
std::make_reverse_iterator
T make_reverse_iterator(T... args)
std::unique_ptr
STL class.
ripple::tenTo14m1
static const std::uint64_t tenTo14m1
Definition: STAmount.cpp:39
std::numeric_limits
ripple::STAmount::mOffset
exponent_type mOffset
Definition: STAmount.h:53
Json::Value::isObjectOrNull
bool isObjectOrNull() const
Definition: json_value.cpp:1075
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:156
ripple::STAmount::cPosNative
static const std::uint64_t cPosNative
Definition: STAmount.h:71
ripple::STAmount::uRateOne
static const std::uint64_t uRateOne
Definition: STAmount.h:73
ripple::Issue::account
AccountID account
Definition: Issue.h:38
ripple::STAmount::cMaxValue
static const std::uint64_t cMaxValue
Definition: STAmount.h:65
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:141
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:163
ripple::tenTo17
static const std::uint64_t tenTo17
Definition: STAmount.cpp:40
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:482
beast
Definition: base_uint.h:582