#pragma once #include #include #include #include #include #include namespace xrpl { class STAmount; template requires( std::is_same_v || std::is_same_v || std::is_same_v) struct AmountType { using amount_type = T; }; /* Used to check for an asset with either badCurrency() * or MPT with 0 account. */ struct BadAsset { }; inline BadAsset const& badAsset() { static BadAsset const kA; return kA; } /* Asset is an abstraction of three different issue types: XRP, IOU, MPT. * For historical reasons, two issue types XRP and IOU are wrapped in Issue * type. Many functions and classes there were first written for Issue * have been rewritten for Asset. */ class Asset { public: using value_type = std::variant; using token_type = std::variant; using AmtType = std::variant, AmountType, AmountType>; private: value_type issue_; public: Asset() = default; /** Conversions to Asset are implicit and conversions to specific issue * type are explicit. This design facilitates the use of Asset. */ Asset(Issue const& issue) : issue_(issue) { } Asset(MPTIssue const& mptIssue) : issue_(mptIssue) { } Asset(MPTID const& issuanceID) : issue_(MPTIssue{issuanceID}) { } [[nodiscard]] AccountID const& getIssuer() const; template constexpr TIss const& get() const; template TIss& get(); template [[nodiscard]] constexpr bool holds() const; [[nodiscard]] std::string getText() const; [[nodiscard]] constexpr value_type const& value() const; [[nodiscard]] constexpr token_type token() const; void setJson(json::Value& jv) const; STAmount operator()(Number const&) const; [[nodiscard]] constexpr AmtType getAmountType() const; // Custom, generic visit implementation template constexpr auto visit(Visitors&&... visitors) const -> decltype(auto) { // Simple delegation to the reusable utility, passing the internal // variant data. return detail::visit(issue_, std::forward(visitors)...); } [[nodiscard]] constexpr bool native() const { return visit( [&](Issue const& issue) { return issue.native(); }, [&](MPTIssue const&) { return false; }); } [[nodiscard]] bool integral() const { return visit( [&](Issue const& issue) { return issue.native(); }, [&](MPTIssue const&) { return true; }); } friend constexpr bool operator==(Asset const& lhs, Asset const& rhs); friend constexpr std::weak_ordering operator<=>(Asset const& lhs, Asset const& rhs); friend constexpr bool operator==(Currency const& lhs, Asset const& rhs); // rhs is either badCurrency() or MPT issuer is 0 friend constexpr bool operator==(BadAsset const& lhs, Asset const& rhs); /** Return true if both assets refer to the same currency (regardless of * issuer) or MPT issuance. Otherwise return false. */ friend constexpr bool equalTokens(Asset const& lhs, Asset const& rhs); }; template constexpr bool kIS_ISSUE_V = std::is_same_v; template constexpr bool kIS_MPTISSUE_V = std::is_same_v; inline json::Value toJson(Asset const& asset) { json::Value jv; asset.setJson(jv); return jv; } template constexpr bool Asset::holds() const { return std::holds_alternative(issue_); } template [[nodiscard]] constexpr TIss const& Asset::get() const { if (!std::holds_alternative(issue_)) Throw("Asset is not a requested issue"); return std::get(issue_); } template TIss& Asset::get() { if (!std::holds_alternative(issue_)) Throw("Asset is not a requested issue"); return std::get(issue_); } constexpr Asset::value_type const& Asset::value() const { return issue_; } constexpr Asset::token_type Asset::token() const { return visit( [&](Issue const& issue) -> Asset::token_type { return issue.currency; }, [&](MPTIssue const& issue) -> Asset::token_type { return issue.getMptID(); }); } constexpr Asset::AmtType Asset::getAmountType() const { return visit( [&](Issue const& issue) -> Asset::AmtType { constexpr AmountType kXRP; constexpr AmountType kIOU; return native() ? AmtType(kXRP) : AmtType(kIOU); }, [&](MPTIssue const& issue) -> Asset::AmtType { constexpr AmountType kMPT; return AmtType(kMPT); }); } constexpr bool operator==(Asset const& lhs, Asset const& rhs) { return std::visit( [&](TLhs const& issLhs, TRhs const& issRhs) { if constexpr (std::is_same_v) { return issLhs == issRhs; } else { return false; } }, lhs.issue_, rhs.issue_); } constexpr std::weak_ordering operator<=>(Asset const& lhs, Asset const& rhs) { return std::visit( [](TLhs const& lhs, TRhs const& rhs) { if constexpr (std::is_same_v) { return std::weak_ordering(lhs <=> rhs); } else if constexpr (kIS_ISSUE_V && kIS_MPTISSUE_V) { return std::weak_ordering::greater; } else { return std::weak_ordering::less; } }, lhs.issue_, rhs.issue_); } constexpr bool operator==(Currency const& lhs, Asset const& rhs) { return rhs.visit( [&](Issue const& issue) { return issue.currency == lhs; }, [](MPTIssue const& issue) { return false; }); } constexpr bool operator==(BadAsset const&, Asset const& rhs) { return rhs.visit( [](Issue const& issue) -> bool { return badCurrency() == issue.currency; }, [](MPTIssue const& issue) -> bool { return issue.getIssuer() == xrpAccount(); }); } constexpr bool equalTokens(Asset const& lhs, Asset const& rhs) { return std::visit( [&](TLhs const& issLhs, TRhs const& issRhs) { if constexpr (std::is_same_v && std::is_same_v) { return issLhs.currency == issRhs.currency; } else if constexpr (std::is_same_v && std::is_same_v) { return issLhs.getMptID() == issRhs.getMptID(); } else { return false; } }, lhs.issue_, rhs.issue_); } inline bool isXRP(Asset const& asset) { return asset.native(); } std::string to_string(Asset const& asset); bool validJSONAsset(json::Value const& jv); Asset assetFromJson(json::Value const& jv); inline bool isConsistent(Asset const& asset) { return asset.visit( [](Issue const& issue) { return isConsistent(issue); }, [](MPTIssue const&) { return true; }); } inline bool validAsset(Asset const& asset) { return asset.visit( [](Issue const& issue) { return isConsistent(issue) && issue.currency != badCurrency(); }, [](MPTIssue const& issue) { return issue.getIssuer() != xrpAccount(); }); } template void hash_append(Hasher& h, Asset const& r) { using beast::hash_append; r.visit( [&](Issue const& issue) { hash_append(h, issue); }, [&](MPTIssue const& issue) { hash_append(h, issue); }); } std::ostream& operator<<(std::ostream& os, Asset const& x); } // namespace xrpl