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 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)
226 mValue = unsafe_cast<std::uint64_t>(-amount.drops());
228 mValue = unsafe_cast<std::uint64_t>(amount.drops());
248 return emplace(n, buf, std::move(*
this));
260 Throw<std::logic_error>(
"Cannot return non-native STAmount as XRPAmount");
263 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::xrp : amount is canonical");
275 Throw<std::logic_error>(
"Cannot return non-IOU STAmount as IOUAmount");
289 if (!holds<MPTIssue>())
290 Throw<std::logic_error>(
"Cannot return STAmount as MPTAmount");
293 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::mpt : amount is canonical");
304 XRPL_ASSERT(
integral() ==
false,
"xrpl::STAmount::operator=(IOUAmount) : is not integral");
324 auto const originalMantissa = number.
mantissa();
357 Throw<std::runtime_error>(
"Can't add amounts that are't comparable!");
359 if (v2 == beast::zero)
362 if (v1 == beast::zero)
407 if ((fv >= -10) && (fv <= 10))
444 if (offerOut == beast::zero)
449 if (r == beast::zero)
453 "xrpl::getRate : exponent inside range");
455 return (ret << (64 - 8)) | r.
mantissa();
491 if (a == beast::zero || b == beast::zero)
517 return ((rhs.
negative() ? -rhs : rhs) + (lhs.
negative() ? -lhs : lhs)) <= maxLoss;
536 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
566 if (b == beast::zero)
609 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
658 if (*
this == beast::zero)
682 XRPL_ASSERT(
mOffset + 43 > 0,
"xrpl::STAmount::getText : minimum offset");
684 size_t const pad_prefix = 27;
685 size_t const pad_suffix = 23;
689 val.
append(pad_prefix,
'0');
691 val.
append(pad_suffix,
'0');
693 size_t const offset(
mOffset + 43);
695 auto pre_from(val.
begin());
696 auto const pre_to(val.
begin() + offset);
698 auto const post_from(val.
begin() + offset);
699 auto post_to(val.
end());
704 pre_from += pad_prefix;
706 XRPL_ASSERT(post_to >= post_from,
"xrpl::STAmount::getText : first distance check");
708 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
713 post_to -= pad_suffix;
715 XRPL_ASSERT(post_to >= post_from,
"xrpl::STAmount::getText : second distance check");
720 [](
char c) {
return c !=
'0'; })
724 if (pre_from == pre_to)
727 ret.
append(pre_from, pre_to);
729 if (post_to != post_from)
732 ret.
append(post_from, post_to);
751 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::add : zero offset");
760 auto u8 =
static_cast<unsigned char>(
cMPToken >> 56);
762 u8 |=
static_cast<unsigned char>(
cPositive >> 56);
769 if (*
this == beast::zero)
784 return v && (*v == *
this);
828 Throw<std::runtime_error>(
"Native currency amount out of range");
831 Throw<std::runtime_error>(
"MPT amount out of range");
836 auto set = [&](
auto const& val) {
846 Throw<std::runtime_error>(
"Unknown integral asset type");
862 Throw<std::runtime_error>(
"Native currency amount out of range");
864 Throw<std::runtime_error>(
"MPT amount out of range");
872 Throw<std::runtime_error>(
"Native currency amount out of range");
874 Throw<std::runtime_error>(
"MPT amount out of range");
901 Throw<std::runtime_error>(
"value overflow");
916 Throw<std::runtime_error>(
"value overflow");
920 "xrpl::STAmount::canonicalize : value inside range");
923 "xrpl::STAmount::canonicalize : offset inside range");
925 (
mValue != 0) || (
mOffset != -100),
"xrpl::STAmount::canonicalize : value or offset set");
952 int exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
962 Throw<std::runtime_error>(
"XRP and MPT must be specified as integral amount.");
963 return {asset, parts.mantissa, parts.exponent, parts.negative};
978 Throw<std::runtime_error>(
"XRP may not be specified with a null Json value");
983 Throw<std::runtime_error>(
"Invalid Asset's Json specification");
985 value = v[jss::value];
986 if (v.
isMember(jss::mpt_issuance_id))
989 currencyOrMPTID = v[jss::mpt_issuance_id];
993 currencyOrMPTID = v[jss::currency];
994 issuer = v[jss::issuer];
1007 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
1009 if (elements.
size() > 3)
1010 Throw<std::runtime_error>(
"invalid amount string");
1012 value = elements[0];
1014 if (elements.
size() > 1)
1015 currencyOrMPTID = elements[1];
1017 if (elements.
size() > 2)
1018 issuer = elements[2];
1031 Throw<std::runtime_error>(
"XRP may not be specified as an object");
1041 Throw<std::runtime_error>(
"invalid MPTokenIssuanceID");
1048 Throw<std::runtime_error>(
"invalid currency");
1050 Throw<std::runtime_error>(
"invalid issuer");
1052 Throw<std::runtime_error>(
"invalid issuer");
1061 if (value.
asInt() >= 0)
1080 Throw<std::runtime_error>(
"XRP and MPT must be specified as integral amount.");
1084 Throw<std::runtime_error>(
"invalid amount type");
1100 JLOG(
debugLog().warn()) <<
"amountFromJsonNoThrow: caught: " << e.
what();
1122 Throw<std::runtime_error>(
"Can't compare amounts that are't comparable!");
1177 boost::multiprecision::uint128_t ret;
1179 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1184 Throw<std::overflow_error>(
1189 return static_cast<uint64_t
>(ret);
1199 boost::multiprecision::uint128_t ret;
1201 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1207 Throw<std::overflow_error>(
1212 return static_cast<uint64_t
>(ret);
1218 if (den == beast::zero)
1219 Throw<std::runtime_error>(
"division by zero");
1221 if (num == beast::zero)
1256 numOffset - denOffset - 17,
1263 if (v1 == beast::zero || v2 == beast::zero)
1271 if (minV > 3000000000ull)
1272 Throw<std::runtime_error>(
"Native value overflow");
1274 if (((maxV >> 32) * minV) > 2095475792ull)
1275 Throw<std::runtime_error>(
"Native value overflow");
1284 if (minV > 3037000499ull)
1285 Throw<std::runtime_error>(
"MPT value overflow");
1287 if (((maxV >> 32) * minV) > 2147483648ull)
1288 Throw<std::runtime_error>(
"MPT value overflow");
1290 return STAmount(asset, minV * maxV);
1329 offset1 + offset2 + 14,
1369 value += (loops >= 2) ? 9 : 10;
1399 bool hadRemainder =
false;
1407 hadRemainder |= (value != (newValue * 10));
1411 value += (hadRemainder && roundUp) ? 10 : 9;
1437 if (value == beast::zero)
1453 return (value + referenceValue) - referenceValue;
1460class DontAffectNumberRoundMode
1467 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1469 DontAffectNumberRoundMode&
1470 operator=(DontAffectNumberRoundMode
const&) =
delete;
1479template <
void (*CanonicalizeFunc)(
bool, std::u
int64_t&,
int&,
bool),
typename MightSaveRound>
1483 if (v1 == beast::zero || v2 == beast::zero)
1486 bool const xrp = asset.
native();
1493 if (minV > 3000000000ull)
1494 Throw<std::runtime_error>(
"Native value overflow");
1496 if (((maxV >> 32) * minV) > 2095475792ull)
1497 Throw<std::runtime_error>(
"Native value overflow");
1507 if (minV > 3037000499ull)
1508 Throw<std::runtime_error>(
"MPT value overflow");
1510 if (((maxV >> 32) * minV) > 2147483648ull)
1511 Throw<std::runtime_error>(
"MPT value overflow");
1513 return STAmount(asset, minV * maxV);
1550 int offset = offset1 + offset2 + 14;
1551 if (resultNegative != roundUp)
1553 CanonicalizeFunc(xrp, amount, offset, roundUp);
1559 return STAmount(asset, amount, offset, resultNegative);
1562 if (roundUp && !resultNegative && !result)
1576 return STAmount(asset, amount, offset, resultNegative);
1584 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(v1, v2, asset, roundUp);
1590 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(v1, v2, asset, roundUp);
1595template <
typename MightSaveRound>
1599 if (den == beast::zero)
1600 Throw<std::runtime_error>(
"division by zero");
1602 if (num == beast::zero)
1639 int offset = numOffset - denOffset - 17;
1641 if (resultNegative != roundUp)
1649 MightSaveRound
const savedRound(roundUp ^ resultNegative ? upward : downward);
1650 return STAmount(asset, amount, offset, resultNegative);
1653 if (roundUp && !resultNegative && !result)
1667 return STAmount(asset, amount, offset, resultNegative);
1675 return divRoundImpl<DontAffectNumberRoundMode>(num, den, asset, roundUp);
1681 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 &.