1#include <xrpl/protocol/STAmount.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/basics/contract.h>
6#include <xrpl/basics/safe_cast.h>
7#include <xrpl/beast/utility/Zero.h>
8#include <xrpl/beast/utility/instrumentation.h>
9#include <xrpl/json/json_forwards.h>
10#include <xrpl/json/json_value.h>
11#include <xrpl/protocol/AccountID.h>
12#include <xrpl/protocol/Asset.h>
13#include <xrpl/protocol/Concepts.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/STArray.h>
23#include <xrpl/protocol/STBase.h>
24#include <xrpl/protocol/STNumber.h>
25#include <xrpl/protocol/STObject.h>
26#include <xrpl/protocol/Serializer.h>
27#include <xrpl/protocol/SystemParameters.h>
28#include <xrpl/protocol/UintTypes.h>
29#include <xrpl/protocol/XRPAmount.h>
30#include <xrpl/protocol/jss.h>
32#include <boost/algorithm/string/classification.hpp>
33#include <boost/algorithm/string/split.hpp>
34#include <boost/multiprecision/detail/default_ops.hpp>
62 XRPL_ASSERT(amount.
exponent() == 0,
"xrpl::getInt64Value : exponent is zero");
68 "xrpl::getInt64Value : mantissa must roundtrip");
95 return v1.
native() == v2.
native() && issue1.currency == issue2.currency;
99 return issue1 == issue2;
161 int offset =
static_cast<int>(
value >> (64 - 10));
163 value &= ~(1023ull << (64 - 10));
167 bool const isNegative = (offset & 256) == 0;
168 offset = (offset & 255) - 97;
204 "xrpl::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
217 "xrpl::STAmount::STAmount(SField, STAmount) : maximum input");
228 "xrpl::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
262 return emplace(n, buf, std::move(*
this));
277 XRPL_ASSERT(
offset_ == 0,
"xrpl::STAmount::xrp : amount is canonical");
307 XRPL_ASSERT(
offset_ == 0,
"xrpl::STAmount::mpt : amount is canonical");
318 XRPL_ASSERT(
integral() ==
false,
"xrpl::STAmount::operator=(IOUAmount) : is not integral");
342 auto const originalMantissa = number.
mantissa();
377 if (v2 == beast::kZero)
380 if (v1 == beast::kZero)
424 if (offerOut == beast::kZero)
430 if (r == beast::kZero)
434 "xrpl::getRate : exponent inside range");
436 return (ret << (64 - 8)) | r.
mantissa();
471 if (a == beast::kZero || b == beast::kZero)
497 return ((rhs.
negative() ? -rhs : rhs) + (lhs.
negative() ? -lhs : lhs)) <= kMaxLoss;
518 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
548 if (b == beast::kZero)
600 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
649 if (*
this == beast::kZero)
673 XRPL_ASSERT(
offset_ + 43 > 0,
"xrpl::STAmount::getText : minimum offset");
675 size_t const padPrefix = 27;
676 size_t const padSuffix = 23;
680 val.
append(padPrefix,
'0');
682 val.
append(padSuffix,
'0');
684 size_t const offset(
offset_ + 43);
686 auto preFrom(val.
begin());
687 auto const preTo(val.
begin() + offset);
689 auto const postFrom(val.
begin() + offset);
690 auto postTo(val.
end());
695 preFrom += padPrefix;
697 XRPL_ASSERT(postTo >= postFrom,
"xrpl::STAmount::getText : first distance check");
699 preFrom =
std::find_if(preFrom, preTo, [](
char c) {
return c !=
'0'; });
706 XRPL_ASSERT(postTo >= postFrom,
"xrpl::STAmount::getText : second distance check");
711 [](
char c) {
return c !=
'0'; })
715 if (preFrom == preTo)
721 ret.
append(preFrom, preTo);
724 if (postTo != postFrom)
727 ret.
append(postFrom, postTo);
746 auto u8 =
static_cast<unsigned char>(
kMpToken >> 56);
748 u8 |=
static_cast<unsigned char>(
kPositive >> 56);
753 [&](
Issue const& issue) {
756 XRPL_ASSERT(
offset_ == 0,
"xrpl::STAmount::add : zero offset");
769 if (*
this == beast::kZero)
793 return (v !=
nullptr) && (*v == *
this);
843 auto set = [&](
auto const& val) {
844 auto const value = val.value();
901 int const exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
912 return {asset, parts.mantissa, parts.exponent, parts.negative};
934 value = v[jss::value];
935 if (v.
isMember(jss::mpt_issuance_id))
938 currencyOrMPTID = v[jss::mpt_issuance_id];
942 currencyOrMPTID = v[jss::currency];
943 issuer = v[jss::issuer];
956 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
958 if (elements.
size() > 3)
963 if (elements.
size() > 1)
964 currencyOrMPTID = elements[1];
966 if (elements.
size() > 2)
967 issuer = elements[2];
1010 if (value.asInt() >= 0)
1016 parts.
mantissa = value.asAbsUInt();
1020 else if (value.isUInt())
1024 else if (value.isString())
1049 JLOG(
debugLog().warn()) <<
"amountFromJsonNoThrow: caught: " << e.
what();
1104 if (value.mantissa() == 0)
1137 JLOG(j.
error()) <<
"hasInvalidAmount: depth exceeds 10";
1147 switch (field.getSType())
1155 case STI_LEDGERENTRY:
1156 case STI_TRANSACTION:
1164 dynamic_cast<STObject const*
>(&field) ==
nullptr,
1165 "xrpl::hasInvalidAmount : unhandled STObject type");
1188 boost::multiprecision::uint128_t ret;
1190 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1200 return static_cast<uint64_t
>(ret);
1210 boost::multiprecision::uint128_t ret;
1212 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1223 return static_cast<uint64_t
>(ret);
1229 if (den == beast::kZero)
1232 if (num == beast::kZero)
1267 numOffset - denOffset - 17,
1274 if (v1 == beast::kZero || v2 == beast::kZero)
1282 if (minV > 3000000000ull)
1285 if (((maxV >> 32) * minV) > 2095475792ull)
1295 if (minV > 3037000499ull)
1298 if (((maxV >> 32) * minV) > 2147483648ull)
1301 return STAmount(asset, minV * maxV);
1344 value += (loops >= 2) ? 9 : 10;
1374 bool hadRemainder =
false;
1382 hadRemainder |= (value != (newValue * 10));
1386 value += (hadRemainder && roundUp) ? 10 : 9;
1408 if (value.integral())
1412 if (value == beast::kZero)
1418 if (value.exponent() >=
scale)
1428 return (value + referenceValue) - referenceValue;
1435class DontAffectNumberRoundMode
1442 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1444 DontAffectNumberRoundMode&
1445 operator=(DontAffectNumberRoundMode
const&) =
delete;
1454template <
void (*CanonicalizeFunc)(
bool, std::u
int64_t&,
int&,
bool),
typename MightSaveRound>
1458 if (v1 == beast::kZero || v2 == beast::kZero)
1466 if (minV > 3000000000ull)
1469 if (((maxV >> 32) * minV) > 2095475792ull)
1480 if (minV > 3037000499ull)
1483 if (((maxV >> 32) * minV) > 2147483648ull)
1486 return STAmount(asset, minV * maxV);
1523 int offset = offset1 + offset2 + 14;
1524 if (resultNegative != roundUp)
1526 CanonicalizeFunc(asset.
integral(), amount, offset, roundUp);
1532 return STAmount(asset, amount, offset, resultNegative);
1535 if (roundUp && !resultNegative && !result)
1549 return STAmount(asset, amount, offset, resultNegative);
1568template <
typename MightSaveRound>
1572 if (den == beast::kZero)
1575 if (num == beast::kZero)
1612 int offset = numOffset - denOffset - 17;
1614 if (resultNegative != roundUp)
1622 MightSaveRound
const savedRound(roundUp ^ resultNegative ? Upward : Downward);
1623 return STAmount(asset, amount, offset, resultNegative);
1626 if (roundUp && !resultNegative && !result)
1640 return STAmount(asset, amount, offset, resultNegative);
A generic endpoint for log messages.
bool isNull() const
isNull() tests to see if this field is null.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
std::string asString() const
Returns the unquoted string value.
bool isObjectOrNull() const
bool isMember(char const *key) const
Return true if the object has a member named key.
constexpr bool native() const
constexpr bool holds() const
constexpr value_type const & value() const
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Floating point representation of amounts with high dynamic range.
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
void setIssue(Asset const &asset)
Set the Issue for this amount.
static constexpr std::uint64_t kIssuedCurrency
std::string getFullText() const override
static STAmount fromNumber(A const &asset, Number const &number)
void add(Serializer &s) const override
static std::uint64_t const kURateOne
std::uint64_t mantissa() const noexcept
static constexpr std::uint64_t kPositive
int signum() const noexcept
bool isEquivalent(STBase const &t) const override
STBase * copy(std::size_t n, void *buf) const override
std::string getText() const override
static constexpr int kMinOffset
SerializedTypeID getSType() const override
bool negative() const noexcept
static constexpr std::uint64_t kMaxNativeN
bool isDefault() const override
bool integral() const noexcept
static constexpr std::uint64_t kValueMask
STAmount & operator=(beast::Zero)
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
bool native() const noexcept
Asset const & asset() const
STAmount & operator+=(STAmount const &)
void setJson(json::Value &) const
static constexpr std::uint64_t kMpToken
json::Value getJson(JsonOptions=JsonOptions::Values::None) const override
STAmount & operator-=(STAmount const &)
int exponent() const noexcept
bool isZeroAtScale(int scale) const
Checks if this amount evaluates to zero when constrained to a specific accounting scale.
static constexpr std::uint64_t kMinValue
static constexpr std::uint64_t kMaxValue
STBase * move(std::size_t n, void *buf) override
static constexpr int kMaxOffset
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(BaseUInt< Bits, Tag > const &v)
int add8(unsigned char i)
constexpr value_type drops() const
Returns the number of drops.
T make_reverse_iterator(T... args)
@ Object
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.
constexpr BaseUInt< Bits, Tag > operator+(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
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
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
static STAmount mulRoundImpl(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
bool isFeatureEnabled(uint256 const &feature, bool resultIfNoRules)
Check whether a feature is enabled in the current ledger rules.
constexpr bool operator==(BaseUInt< Bits, Tag > const &lhs, BaseUInt< Bits, Tag > const &rhs)
bool isLegalMPT(STAmount const &value)
Dest safeDowncast(Src *s) noexcept
bool isXRP(AccountID const &c)
beast::Journal debugLog()
Returns a debug journal.
NumberParts partsFromString(std::string const &number)
Number operator-(Number const &x, Number const &y)
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
int scale(Number const &number, Asset const &asset)
Get the scale of a Number for a given asset.
bool isLegalNet(STAmount const &value)
bool validJSONAsset(json::Value const &jv)
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > unsafeCast(Src s) noexcept
STAmount amountFromString(Asset const &asset, std::string const &amount)
std::optional< Rules > const & getCurrentTransactionRules()
bool toCurrency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
static std::uint64_t const kTenTO14
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
STAmount roundToScale(STAmount const &value, std::int32_t scale, Number::RoundingMode rounding=Number::getround())
Round an arbitrary precision Amount to the precision of an STAmount that has a given exponent.
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
bool amountFromJsonNoThrow(STAmount &result, json::Value const &jvSource)
STAmount amountFromQuality(std::uint64_t rate)
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
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)
STAmount amountFromJson(SField const &name, json::Value const &v)
bool hasInvalidAmount(STBase const &field, beast::Journal j)
static std::uint64_t const kTenTO17
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.
static std::uint64_t muldivRound(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding)
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.
constexpr bool kIsMptissueV
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
static std::string const & systemCurrencyCode()
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
static STAmount divRoundImpl(STAmount const &num, STAmount const &den, Asset const &asset, bool roundUp)
constexpr std::uint64_t kMaxMpTokenAmount
The maximum amount of MPTokenIssuance.
constexpr XRPAmount kInitialXrp
Configure the native currency.
static void canonicalizeRoundStrict(bool integral, std::uint64_t &value, int &offset, bool roundUp)
bool toIssuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
static std::uint64_t const kTenTO14M1
static void canonicalizeRound(bool integral, std::uint64_t &value, int &offset, bool)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Note, should be treated as flags that can be | and &.