#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { Currency ammLPTCurrency(Asset const& asset1, Asset const& asset2) { // AMM LPToken is 0x03 plus 19 bytes of the hash std::int32_t constexpr AMMCurrencyCode = 0x03; auto const& [minA, maxA] = std::minmax(asset1, asset2); uint256 const hash = std::visit( [](auto&& issue1, auto&& issue2) { auto fromIss = [](T const& issue) { if constexpr (std::is_same_v) return issue.currency; if constexpr (std::is_same_v) return issue.getMptID(); }; return sha512Half(fromIss(issue1), fromIss(issue2)); }, minA.value(), maxA.value()); Currency currency; *currency.begin() = AMMCurrencyCode; std::copy(hash.begin(), hash.begin() + currency.size() - 1, currency.begin() + 1); return currency; } Issue ammLPTIssue(Asset const& asset1, Asset const& asset2, AccountID const& ammAccountID) { return Issue(ammLPTCurrency(asset1, asset2), ammAccountID); } NotTEC invalidAMMAsset(Asset const& asset, std::optional> const& pair) { auto const err = asset.visit( [](MPTIssue const& issue) -> std::optional { if (issue.getIssuer() == beast::zero) return temBAD_MPT; return std::nullopt; }, [](Issue const& issue) -> std::optional { if (badCurrency() == issue.currency) return temBAD_CURRENCY; if (isXRP(issue) && issue.getIssuer().isNonZero()) return temBAD_ISSUER; return std::nullopt; }); if (err) return *err; if (pair && asset != pair->first && asset != pair->second) return temBAD_AMM_TOKENS; return tesSUCCESS; } NotTEC invalidAMMAssetPair( Asset const& asset1, Asset const& asset2, std::optional> const& pair) { if (asset1 == asset2) return temBAD_AMM_TOKENS; if (auto const res = invalidAMMAsset(asset1, pair)) return res; if (auto const res = invalidAMMAsset(asset2, pair)) return res; return tesSUCCESS; } NotTEC invalidAMMAmount( STAmount const& amount, std::optional> const& pair, bool validZero) { if (auto const res = invalidAMMAsset(amount.asset(), pair)) return res; if (amount < beast::zero || (!validZero && amount == beast::zero)) return temBAD_AMOUNT; return tesSUCCESS; } std::optional ammAuctionTimeSlot(std::uint64_t current, STObject const& auctionSlot) { // It should be impossible for expiration to be < TOTAL_TIME_SLOT_SECS, // but check just to be safe auto const expiration = auctionSlot[sfExpiration]; XRPL_ASSERT( expiration >= TOTAL_TIME_SLOT_SECS, "xrpl::ammAuctionTimeSlot : minimum expiration"); if (expiration >= TOTAL_TIME_SLOT_SECS) { if (auto const start = expiration - TOTAL_TIME_SLOT_SECS; current >= start) { if (auto const diff = current - start; diff < TOTAL_TIME_SLOT_SECS) return diff / AUCTION_SLOT_INTERVAL_DURATION; } } return std::nullopt; } bool ammEnabled(Rules const& rules) { return rules.enabled(featureAMM); } } // namespace xrpl