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