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);
65 amount.exponent() == 0,
"xrpl::getInt64Value : exponent is zero");
71 "xrpl::getInt64Value : mantissa must roundtrip");
73 if (amount.negative())
82 return getInt64Value(amount, amount.native(),
"amount is not native!");
89 amount, amount.holds<
MPTIssue>(),
"amount is not MPT!");
132 Throw<std::runtime_error>(
"negative zero is not canonical");
144 Throw<std::runtime_error>(
"invalid native currency");
149 Throw<std::runtime_error>(
"invalid native account");
152 int offset =
static_cast<int>(
value >> (64 - 10));
154 value &= ~(1023ull << (64 - 10));
158 bool isNegative = (offset & 256) == 0;
159 offset = (offset & 255) - 97;
164 Throw<std::runtime_error>(
"invalid currency value");
176 Throw<std::runtime_error>(
"invalid currency value");
196 , mIsNegative(negative)
200 "xrpl::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
206 , mAsset(from.mAsset)
207 , mValue(from.mValue)
208 , mOffset(from.mOffset)
209 , mIsNegative(from.mIsNegative)
213 "xrpl::STAmount::STAmount(SField, STAmount) : maximum input");
223 , mIsNegative(mantissa != 0 && negative)
227 "xrpl::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
232 : mAsset(
xrpIssue()), mOffset(0), mIsNegative(amount <
beast::zero)
235 mValue = unsafe_cast<std::uint64_t>(-amount.drops());
237 mValue = unsafe_cast<std::uint64_t>(amount.drops());
257 return emplace(n, buf, std::move(*
this));
269 Throw<std::logic_error>(
270 "Cannot return non-native STAmount as XRPAmount");
273 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::xrp : amount is canonical");
285 Throw<std::logic_error>(
"Cannot return non-IOU STAmount as IOUAmount");
299 if (!holds<MPTIssue>())
300 Throw<std::logic_error>(
"Cannot return STAmount as MPTAmount");
303 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::mpt : amount is canonical");
316 "xrpl::STAmount::operator=(IOUAmount) : is not integral");
337 auto const originalMantissa = number.
mantissa();
370 Throw<std::runtime_error>(
"Can't add amounts that are't comparable!");
372 if (v2 == beast::zero)
375 if (v1 == beast::zero)
425 if ((fv >= -10) && (fv <= 10))
468 if (offerOut == beast::zero)
473 if (r == beast::zero)
477 "xrpl::getRate : exponent inside range");
479 return (ret << (64 - 8)) | r.
mantissa();
515 if (a == beast::zero || b == beast::zero)
543 return ((rhs.
negative() ? -rhs : rhs) +
544 (lhs.
negative() ? -lhs : lhs)) <= maxLoss;
565 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
595 if (b == beast::zero)
640 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
689 if (*
this == beast::zero)
698 bool const scientific(
714 XRPL_ASSERT(
mOffset + 43 > 0,
"xrpl::STAmount::getText : minimum offset");
716 size_t const pad_prefix = 27;
717 size_t const pad_suffix = 23;
721 val.
append(pad_prefix,
'0');
723 val.
append(pad_suffix,
'0');
725 size_t const offset(
mOffset + 43);
727 auto pre_from(val.
begin());
728 auto const pre_to(val.
begin() + offset);
730 auto const post_from(val.
begin() + offset);
731 auto post_to(val.
end());
736 pre_from += pad_prefix;
739 post_to >= post_from,
"xrpl::STAmount::getText : first distance check");
741 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
746 post_to -= pad_suffix;
749 post_to >= post_from,
750 "xrpl::STAmount::getText : second distance check");
755 [](
char c) {
return c !=
'0'; })
759 if (pre_from == pre_to)
762 ret.
append(pre_from, pre_to);
764 if (post_to != post_from)
767 ret.
append(post_from, post_to);
786 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::add : zero offset");
795 auto u8 =
static_cast<unsigned char>(
cMPToken >> 56);
797 u8 |=
static_cast<unsigned char>(
cPositive >> 56);
804 if (*
this == beast::zero)
824 return v && (*v == *
this);
868 Throw<std::runtime_error>(
"Native currency amount out of range");
871 Throw<std::runtime_error>(
"MPT amount out of range");
876 auto set = [&](
auto const& val) {
886 Throw<std::runtime_error>(
"Unknown integral asset type");
902 Throw<std::runtime_error>(
903 "Native currency amount out of range");
905 Throw<std::runtime_error>(
"MPT amount out of range");
913 Throw<std::runtime_error>(
"Native currency amount out of range");
915 Throw<std::runtime_error>(
"MPT amount out of range");
942 Throw<std::runtime_error>(
"value overflow");
957 Throw<std::runtime_error>(
"value overflow");
961 "xrpl::STAmount::canonicalize : value inside range");
964 "xrpl::STAmount::canonicalize : offset inside range");
967 "xrpl::STAmount::canonicalize : value or offset set");
994 int exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
1004 Throw<std::runtime_error>(
1005 "XRP and MPT must be specified as integral amount.");
1006 return {asset, parts.mantissa, parts.exponent, parts.negative};
1021 Throw<std::runtime_error>(
1022 "XRP may not be specified with a null Json value");
1027 Throw<std::runtime_error>(
"Invalid Asset's Json specification");
1029 value = v[jss::value];
1030 if (v.
isMember(jss::mpt_issuance_id))
1033 currencyOrMPTID = v[jss::mpt_issuance_id];
1037 currencyOrMPTID = v[jss::currency];
1038 issuer = v[jss::issuer];
1051 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
1053 if (elements.
size() > 3)
1054 Throw<std::runtime_error>(
"invalid amount string");
1056 value = elements[0];
1058 if (elements.
size() > 1)
1059 currencyOrMPTID = elements[1];
1061 if (elements.
size() > 2)
1062 issuer = elements[2];
1069 bool const native = !currencyOrMPTID.
isString() ||
1076 Throw<std::runtime_error>(
"XRP may not be specified as an object");
1086 Throw<std::runtime_error>(
"invalid MPTokenIssuanceID");
1093 Throw<std::runtime_error>(
"invalid currency");
1096 Throw<std::runtime_error>(
"invalid issuer");
1098 Throw<std::runtime_error>(
"invalid issuer");
1107 if (value.
asInt() >= 0)
1126 Throw<std::runtime_error>(
1127 "XRP and MPT must be specified as integral amount.");
1131 Throw<std::runtime_error>(
"invalid amount type");
1148 <<
"amountFromJsonNoThrow: caught: " << e.
what();
1170 Throw<std::runtime_error>(
1171 "Can't compare amounts that are't comparable!");
1229 boost::multiprecision::uint128_t ret;
1231 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1236 Throw<std::overflow_error>(
1241 return static_cast<uint64_t
>(ret);
1251 boost::multiprecision::uint128_t ret;
1253 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1259 Throw<std::overflow_error>(
1265 return static_cast<uint64_t
>(ret);
1271 if (den == beast::zero)
1272 Throw<std::runtime_error>(
"division by zero");
1274 if (num == beast::zero)
1309 numOffset - denOffset - 17,
1316 if (v1 == beast::zero || v2 == beast::zero)
1324 if (minV > 3000000000ull)
1325 Throw<std::runtime_error>(
"Native value overflow");
1327 if (((maxV >> 32) * minV) > 2095475792ull)
1328 Throw<std::runtime_error>(
"Native value overflow");
1337 if (minV > 3037000499ull)
1338 Throw<std::runtime_error>(
"MPT value overflow");
1340 if (((maxV >> 32) * minV) > 2147483648ull)
1341 Throw<std::runtime_error>(
"MPT value overflow");
1343 return STAmount(asset, minV * maxV);
1382 offset1 + offset2 + 14,
1422 value += (loops >= 2) ? 9 : 10;
1456 bool hadRemainder =
false;
1464 hadRemainder |= (value != (newValue * 10));
1469 (hadRemainder && roundUp) ? 10 : 9;
1498 if (value == beast::zero)
1515 return (value + referenceValue) - referenceValue;
1522class DontAffectNumberRoundMode
1529 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1531 DontAffectNumberRoundMode&
1532 operator=(DontAffectNumberRoundMode
const&) =
delete;
1543 typename MightSaveRound>
1551 if (v1 == beast::zero || v2 == beast::zero)
1554 bool const xrp = asset.
native();
1561 if (minV > 3000000000ull)
1562 Throw<std::runtime_error>(
"Native value overflow");
1564 if (((maxV >> 32) * minV) > 2095475792ull)
1565 Throw<std::runtime_error>(
"Native value overflow");
1575 if (minV > 3037000499ull)
1576 Throw<std::runtime_error>(
"MPT value overflow");
1578 if (((maxV >> 32) * minV) > 2147483648ull)
1579 Throw<std::runtime_error>(
"MPT value overflow");
1581 return STAmount(asset, minV * maxV);
1618 int offset = offset1 + offset2 + 14;
1619 if (resultNegative != roundUp)
1621 CanonicalizeFunc(xrp, amount, offset, roundUp);
1627 return STAmount(asset, amount, offset, resultNegative);
1630 if (roundUp && !resultNegative && !result)
1644 return STAmount(asset, amount, offset, resultNegative);
1656 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(
1657 v1, v2, asset, roundUp);
1667 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(
1668 v1, v2, asset, roundUp);
1673template <
typename MightSaveRound>
1681 if (den == beast::zero)
1682 Throw<std::runtime_error>(
"division by zero");
1684 if (num == beast::zero)
1719 numVal,
tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1721 int offset = numOffset - denOffset - 17;
1723 if (resultNegative != roundUp)
1732 MightSaveRound
const savedRound(
1733 roundUp ^ resultNegative ? upward : downward);
1734 return STAmount(asset, amount, offset, resultNegative);
1737 if (roundUp && !resultNegative && !result)
1751 return STAmount(asset, amount, offset, resultNegative);
1763 return divRoundImpl<DontAffectNumberRoundMode>(num, den, asset, roundUp);
1773 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 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)
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 &.