1#include <xrpl/basics/LocalValue.h>
2#include <xrpl/basics/Log.h>
3#include <xrpl/basics/Number.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/basics/contract.h>
6#include <xrpl/basics/safe_cast.h>
7#include <xrpl/beast/core/LexicalCast.h>
8#include <xrpl/beast/utility/Zero.h>
9#include <xrpl/beast/utility/instrumentation.h>
10#include <xrpl/json/json_forwards.h>
11#include <xrpl/json/json_value.h>
12#include <xrpl/protocol/AccountID.h>
13#include <xrpl/protocol/Asset.h>
14#include <xrpl/protocol/Feature.h>
15#include <xrpl/protocol/IOUAmount.h>
16#include <xrpl/protocol/Issue.h>
17#include <xrpl/protocol/MPTAmount.h>
18#include <xrpl/protocol/MPTIssue.h>
19#include <xrpl/protocol/Protocol.h>
20#include <xrpl/protocol/Rules.h>
21#include <xrpl/protocol/SField.h>
22#include <xrpl/protocol/STAmount.h>
23#include <xrpl/protocol/STBase.h>
24#include <xrpl/protocol/STNumber.h>
25#include <xrpl/protocol/Serializer.h>
26#include <xrpl/protocol/SystemParameters.h>
27#include <xrpl/protocol/UintTypes.h>
28#include <xrpl/protocol/XRPAmount.h>
29#include <xrpl/protocol/jss.h>
31#include <boost/algorithm/string/classification.hpp>
32#include <boost/algorithm/string/split.hpp>
33#include <boost/multiprecision/detail/default_ops.hpp>
34#include <boost/multiprecision/fwd.hpp>
35#include <boost/regex/v5/regbase.hpp>
36#include <boost/regex/v5/regex.hpp>
37#include <boost/regex/v5/regex_fwd.hpp>
38#include <boost/regex/v5/regex_match.hpp>
63 Throw<std::runtime_error>(error);
64 XRPL_ASSERT(amount.exponent() == 0,
"xrpl::getInt64Value : exponent is zero");
70 "xrpl::getInt64Value : mantissa must roundtrip");
72 if (amount.negative())
81 return getInt64Value(amount, amount.native(),
"amount is not native!");
131 Throw<std::runtime_error>(
"negative zero is not canonical");
143 Throw<std::runtime_error>(
"invalid native currency");
148 Throw<std::runtime_error>(
"invalid native account");
151 int offset =
static_cast<int>(
value >> (64 - 10));
153 value &= ~(1023ull << (64 - 10));
157 bool const isNegative = (offset & 256) == 0;
158 offset = (offset & 255) - 97;
162 Throw<std::runtime_error>(
"invalid currency value");
174 Throw<std::runtime_error>(
"invalid currency value");
190 :
STBase(name), mAsset(
xrpIssue()), mValue(mantissa), mOffset(0), mIsNegative(negative)
194 "xrpl::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
200 , mAsset(from.mAsset)
201 , mValue(from.mValue)
202 , mOffset(from.mOffset)
203 , mIsNegative(from.mIsNegative)
207 "xrpl::STAmount::STAmount(SField, STAmount) : maximum input");
214 : mAsset(
xrpIssue()), mValue(mantissa), mOffset(0), mIsNegative(mantissa != 0 && negative)
218 "xrpl::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
223 : mAsset(
xrpIssue()), mOffset(0), mIsNegative(amount <
beast::zero)
227 mValue = unsafe_cast<std::uint64_t>(-amount.drops());
231 mValue = unsafe_cast<std::uint64_t>(amount.drops());
252 return emplace(n, buf, std::move(*
this));
264 Throw<std::logic_error>(
"Cannot return non-native STAmount as XRPAmount");
267 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::xrp : amount is canonical");
279 Throw<std::logic_error>(
"Cannot return non-IOU STAmount as IOUAmount");
293 if (!holds<MPTIssue>())
294 Throw<std::logic_error>(
"Cannot return STAmount as MPTAmount");
297 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::mpt : amount is canonical");
308 XRPL_ASSERT(
integral() ==
false,
"xrpl::STAmount::operator=(IOUAmount) : is not integral");
332 auto const originalMantissa = number.
mantissa();
365 Throw<std::runtime_error>(
"Can't add amounts that are't comparable!");
367 if (v2 == beast::zero)
370 if (v1 == beast::zero)
415 if ((fv >= -10) && (fv <= 10))
452 if (offerOut == beast::zero)
458 if (r == beast::zero)
462 "xrpl::getRate : exponent inside range");
464 return (ret << (64 - 8)) | r.
mantissa();
499 if (a == beast::zero || b == beast::zero)
522 return ((rhs.
negative() ? -rhs : rhs) + (lhs.
negative() ? -lhs : lhs)) <= maxLoss;
537 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
567 if (b == beast::zero)
610 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
659 if (*
this == beast::zero)
683 XRPL_ASSERT(
mOffset + 43 > 0,
"xrpl::STAmount::getText : minimum offset");
685 size_t const pad_prefix = 27;
686 size_t const pad_suffix = 23;
690 val.
append(pad_prefix,
'0');
692 val.
append(pad_suffix,
'0');
694 size_t const offset(
mOffset + 43);
696 auto pre_from(val.
begin());
697 auto const pre_to(val.
begin() + offset);
699 auto const post_from(val.
begin() + offset);
700 auto post_to(val.
end());
705 pre_from += pad_prefix;
707 XRPL_ASSERT(post_to >= post_from,
"xrpl::STAmount::getText : first distance check");
709 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
714 post_to -= pad_suffix;
716 XRPL_ASSERT(post_to >= post_from,
"xrpl::STAmount::getText : second distance check");
721 [](
char c) {
return c !=
'0'; })
725 if (pre_from == pre_to)
731 ret.
append(pre_from, pre_to);
734 if (post_to != post_from)
737 ret.
append(post_from, post_to);
756 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::add : zero offset");
769 auto u8 =
static_cast<unsigned char>(
cMPToken >> 56);
771 u8 |=
static_cast<unsigned char>(
cPositive >> 56);
778 if (*
this == beast::zero)
799 return (v !=
nullptr) && (*v == *
this);
843 Throw<std::runtime_error>(
"Native currency amount out of range");
846 Throw<std::runtime_error>(
"MPT amount out of range");
851 auto set = [&](
auto const& val) {
866 Throw<std::runtime_error>(
"Unknown integral asset type");
884 Throw<std::runtime_error>(
"Native currency amount out of range");
888 Throw<std::runtime_error>(
"MPT amount out of range");
898 Throw<std::runtime_error>(
"Native currency amount out of range");
902 Throw<std::runtime_error>(
"MPT amount out of range");
930 Throw<std::runtime_error>(
"value overflow");
945 Throw<std::runtime_error>(
"value overflow");
949 "xrpl::STAmount::canonicalize : value inside range");
952 "xrpl::STAmount::canonicalize : offset inside range");
954 (
mValue != 0) || (
mOffset != -100),
"xrpl::STAmount::canonicalize : value or offset set");
981 int const exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
991 Throw<std::runtime_error>(
"XRP and MPT must be specified as integral amount.");
992 return {asset, parts.mantissa, parts.exponent, parts.negative};
1007 Throw<std::runtime_error>(
"XRP may not be specified with a null Json value");
1012 Throw<std::runtime_error>(
"Invalid Asset's Json specification");
1014 value = v[jss::value];
1015 if (v.
isMember(jss::mpt_issuance_id))
1018 currencyOrMPTID = v[jss::mpt_issuance_id];
1022 currencyOrMPTID = v[jss::currency];
1023 issuer = v[jss::issuer];
1036 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
1038 if (elements.
size() > 3)
1039 Throw<std::runtime_error>(
"invalid amount string");
1041 value = elements[0];
1043 if (elements.
size() > 1)
1044 currencyOrMPTID = elements[1];
1046 if (elements.
size() > 2)
1047 issuer = elements[2];
1060 Throw<std::runtime_error>(
"XRP may not be specified as an object");
1070 Throw<std::runtime_error>(
"invalid MPTokenIssuanceID");
1077 Throw<std::runtime_error>(
"invalid currency");
1079 Throw<std::runtime_error>(
"invalid issuer");
1081 Throw<std::runtime_error>(
"invalid issuer");
1090 if (value.
asInt() >= 0)
1109 Throw<std::runtime_error>(
"XRP and MPT must be specified as integral amount.");
1113 Throw<std::runtime_error>(
"invalid amount type");
1129 JLOG(
debugLog().warn()) <<
"amountFromJsonNoThrow: caught: " << e.
what();
1151 Throw<std::runtime_error>(
"Can't compare amounts that are't comparable!");
1206 boost::multiprecision::uint128_t ret;
1208 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1213 Throw<std::overflow_error>(
1218 return static_cast<uint64_t
>(ret);
1228 boost::multiprecision::uint128_t ret;
1230 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1236 Throw<std::overflow_error>(
1241 return static_cast<uint64_t
>(ret);
1247 if (den == beast::zero)
1248 Throw<std::runtime_error>(
"division by zero");
1250 if (num == beast::zero)
1285 numOffset - denOffset - 17,
1292 if (v1 == beast::zero || v2 == beast::zero)
1300 if (minV > 3000000000ull)
1301 Throw<std::runtime_error>(
"Native value overflow");
1303 if (((maxV >> 32) * minV) > 2095475792ull)
1304 Throw<std::runtime_error>(
"Native value overflow");
1313 if (minV > 3037000499ull)
1314 Throw<std::runtime_error>(
"MPT value overflow");
1316 if (((maxV >> 32) * minV) > 2147483648ull)
1317 Throw<std::runtime_error>(
"MPT value overflow");
1319 return STAmount(asset, minV * maxV);
1358 offset1 + offset2 + 14,
1398 value += (loops >= 2) ? 9 : 10;
1428 bool hadRemainder =
false;
1436 hadRemainder |= (value != (newValue * 10));
1440 value += (hadRemainder && roundUp) ? 10 : 9;
1466 if (value == beast::zero)
1482 return (value + referenceValue) - referenceValue;
1489class DontAffectNumberRoundMode
1496 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1498 DontAffectNumberRoundMode&
1499 operator=(DontAffectNumberRoundMode
const&) =
delete;
1508template <
void (*CanonicalizeFunc)(
bool, std::u
int64_t&,
int&,
bool),
typename MightSaveRound>
1512 if (v1 == beast::zero || v2 == beast::zero)
1515 bool const xrp = asset.
native();
1522 if (minV > 3000000000ull)
1523 Throw<std::runtime_error>(
"Native value overflow");
1525 if (((maxV >> 32) * minV) > 2095475792ull)
1526 Throw<std::runtime_error>(
"Native value overflow");
1536 if (minV > 3037000499ull)
1537 Throw<std::runtime_error>(
"MPT value overflow");
1539 if (((maxV >> 32) * minV) > 2147483648ull)
1540 Throw<std::runtime_error>(
"MPT value overflow");
1542 return STAmount(asset, minV * maxV);
1579 int offset = offset1 + offset2 + 14;
1580 if (resultNegative != roundUp)
1582 CanonicalizeFunc(xrp, amount, offset, roundUp);
1588 return STAmount(asset, amount, offset, resultNegative);
1591 if (roundUp && !resultNegative && !result)
1605 return STAmount(asset, amount, offset, resultNegative);
1613 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(v1, v2, asset, roundUp);
1619 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(v1, v2, asset, roundUp);
1624template <
typename MightSaveRound>
1628 if (den == beast::zero)
1629 Throw<std::runtime_error>(
"division by zero");
1631 if (num == beast::zero)
1668 int offset = numOffset - denOffset - 17;
1670 if (resultNegative != roundUp)
1678 MightSaveRound
const savedRound(roundUp ^ resultNegative ? upward : downward);
1679 return STAmount(asset, amount, offset, resultNegative);
1682 if (roundUp && !resultNegative && !result)
1696 return STAmount(asset, amount, offset, resultNegative);
1704 return divRoundImpl<DontAffectNumberRoundMode>(num, den, asset, roundUp);
1710 return divRoundImpl<NumberRoundModeGuard>(num, den, asset, roundUp);
bool isObjectOrNull() const
UInt asAbsUInt() const
Correct absolute value from int or unsigned int.
std::string asString() const
Returns the unquoted string value.
bool isNull() const
isNull() tests to see if this field is null.
bool isMember(char const *key) const
Return true if the object has a member named key.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
constexpr TIss const & get() const
std::string getText() const
void setJson(Json::Value &jv) const
constexpr bool holds() const
Floating point representation of amounts with high dynamic range.
mantissa_type mantissa() const noexcept
exponent_type exponent() const noexcept
A currency issued by an account.
constexpr value_type value() const
Returns the underlying value.
constexpr MPTID const & getMptID() const
Number is a floating point type that can represent a wide range of values.
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
constexpr bool holds() const noexcept
Json::Value getJson(JsonOptions=JsonOptions::none) const override
constexpr TIss const & get() const
void setIssue(Asset const &asset)
Set the Issue for this amount.
std::string getFullText() const override
static constexpr std::uint64_t cMaxValue
Issue const & issue() const
static std::uint64_t const uRateOne
static STAmount fromNumber(A const &asset, Number const &number)
void add(Serializer &s) const override
std::uint64_t mantissa() const noexcept
bool isEquivalent(STBase const &t) const override
STBase * copy(std::size_t n, void *buf) const override
static constexpr std::uint64_t cValueMask
std::string getText() const override
void setJson(Json::Value &) const
SerializedTypeID getSType() const override
bool negative() const noexcept
static int const cMaxOffset
bool isDefault() const override
bool integral() const noexcept
STAmount & operator=(beast::Zero)
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
static constexpr std::uint64_t cIssuedCurrency
bool native() const noexcept
static constexpr std::uint64_t cMinValue
Asset const & asset() const
static int const cMinOffset
STAmount & operator+=(STAmount const &)
STAmount & operator-=(STAmount const &)
static constexpr std::uint64_t cMPToken
int exponent() const noexcept
static constexpr std::uint64_t cMaxNativeN
STBase * move(std::size_t n, void *buf) override
static constexpr std::uint64_t cPositive
STAmount const & value() const noexcept
STAmount(SerialIter &sit, SField const &name)
A type which can be exported to a well known binary format.
SField const & getFName() const
static STBase * emplace(std::size_t n, void *buf, T &&val)
int addBitString(base_uint< Bits, Tag > const &v)
int add8(unsigned char i)
constexpr value_type drops() const
Returns the number of drops.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
T make_reverse_iterator(T... args)
@ objectValue
object value (collection of name/value pairs).
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static std::int64_t getMPTValue(STAmount const &amount)
STAmount divide(STAmount const &amount, Rate const &rate)
bool operator<(Slice const &lhs, Slice const &rhs) noexcept
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
static STAmount mulRoundImpl(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
static void canonicalizeRoundStrict(bool native, std::uint64_t &value, int &offset, bool roundUp)
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset, bool)
bool isXRP(AccountID const &c)
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
bool validJSONAsset(Json::Value const &jv)
beast::Journal debugLog()
Returns a debug journal.
NumberParts partsFromString(std::string const &number)
static std::uint64_t muldiv_round(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding)
Number operator-(Number const &x, Number const &y)
STAmount amountFromJson(SField const &name, Json::Value const &v)
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
static std::uint64_t const tenTo14m1
STAmount amountFromString(Asset const &asset, std::string const &amount)
std::optional< Rules > const & getCurrentTransactionRules()
static std::uint64_t const tenTo17
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
STAmount multiply(STAmount const &amount, Rate const &rate)
STAmount roundToScale(STAmount const &value, std::int32_t scale, Number::rounding_mode rounding=Number::getround())
Round an arbitrary precision Amount to the precision of an STAmount that has a given exponent.
static std::uint64_t const tenTo14
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
STAmount amountFromQuality(std::uint64_t rate)
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
static std::int64_t getSNValue(STAmount const &amount)
static bool areComparable(STAmount const &v1, STAmount const &v2)
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
static std::int64_t getInt64Value(STAmount const &amount, bool valid, char const *error)
bool canSubtract(STAmount const &amt1, STAmount const &amt2)
Determines if it is safe to subtract one STAmount from another.
STAmount divRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
static std::string const & systemCurrencyCode()
static STAmount divRoundImpl(STAmount const &num, STAmount const &den, Asset const &asset, bool roundUp)
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
bool isFeatureEnabled(uint256 const &feature)
bool getSTNumberSwitchover()
Note, should be treated as flags that can be | and &.