#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl::test::jtx { [[maybe_unused]] std::vector fund( jtx::Env& env, jtx::Account const& gw, std::vector const& accounts, std::vector const& amts, Fund how) { return fund(env, gw, accounts, XRP(30000), amts, how); } [[maybe_unused]] std::vector fund( jtx::Env& env, std::vector const& accounts, STAmount const& xrp, std::vector const& amts, Fund how, std::optional const& mptIssuer) { for (auto const& account : accounts) { if (how == Fund::All || how == Fund::Acct) { env.fund(xrp, account); } } env.close(); std::vector amtsOut; for (auto const& account : accounts) { int i = 0; for (auto const& amt : amts) { auto amount = [&]() { if (amtsOut.size() == amts.size()) { return amtsOut[i++]; } if (amt.holds() && mptIssuer) { MPTTester const mpt({.env = env, .issuer = *mptIssuer, .holders = accounts}); return STAmount{mpt.issuanceID(), amt.mpt().value()}; } return amt; }(); if (amount.holds()) env.trust(amount + amount, account); if (amtsOut.size() != amts.size()) amtsOut.push_back(amount); env(pay(amount.getIssuer(), account, amount)); } } env.close(); return amtsOut; } [[maybe_unused]] std::vector fund( jtx::Env& env, jtx::Account const& gw, std::vector const& accounts, STAmount const& xrp, std::vector const& amts, Fund how) { if (how == Fund::All || how == Fund::Gw) env.fund(xrp, gw); env.close(); return fund(env, accounts, xrp, amts, how, gw); } AMMTestBase::AMMTestBase() : gw_("gateway") , carol_("carol") , alice_("alice") , bob_("bob") , USD(gw_["USD"]) , EUR(gw_["EUR"]) , GBP(gw_["GBP"]) , BTC(gw_["BTC"]) , BAD(jtx::IOU(gw_, badCurrency())) { } void AMMTestBase::testAMM( std::function const& cb, std::optional> const& pool, std::uint16_t tfee, std::optional const& ter, std::vector const& vfeatures) { testAMM(cb, TestAMMArg{.pool = pool, .tfee = tfee, .ter = ter, .features = vfeatures}); } void AMMTestBase::testAMM(std::function const& cb, TestAMMArg const& arg) { using namespace jtx; std::string logs; for (auto const& features : arg.features) { // Use small Number mantissas for the life of this test. NumberMantissaScaleGuard const sg{xrpl::MantissaRange::MantissaScale::Small}; // For now, just disable SAV entirely, which locks in the small Number // mantissas Env env{ *this, features - featureSingleAssetVault - featureLendingProtocol, arg.noLog ? std::make_unique(&logs) : nullptr}; auto const [asset1, asset2] = arg.pool ? *arg.pool : std::make_pair(XRP(10000), USD(10000)); auto toFund = [&](STAmount const& a) -> STAmount { if (a.native()) { auto const defXRP = XRP(30000); if (a <= defXRP) return defXRP; return a + XRP(1000); } auto defAmt = STAmount{a.asset(), 30000}; if (a <= defAmt) return defAmt; return a + STAmount{a.asset(), 1000}; }; auto const toFund1 = toFund(asset1); auto const toFund2 = toFund(asset2); BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2); // asset1/asset2 could be dummy MPT. In this case real MPT // is created by fund(), which returns the funded amounts. // The amounts then can be used to figure out the created // MPT if any. std::vector funded; if (!asset1.native() && !asset2.native()) { funded = fund(env, gw_, {alice_, carol_}, {toFund1, toFund2}, Fund::All); } else if (asset1.native()) { funded = fund(env, gw_, {alice_, carol_}, toFund1, {toFund2}, Fund::All); funded.insert(funded.begin(), toFund1); } else if (asset2.native()) { funded = fund(env, gw_, {alice_, carol_}, toFund2, {toFund1}, Fund::All); funded.push_back(toFund2); } auto const pool1 = STAmount{funded[0].asset(), static_cast(asset1)}; auto const pool2 = STAmount{funded[1].asset(), static_cast(asset2)}; AMM ammAlice( env, alice_, pool1, pool2, CreateArg{.log = false, .tfee = arg.tfee, .err = arg.ter}); if (BEAST_EXPECT(ammAlice.expectBalances(pool1, pool2, ammAlice.tokens()))) cb(ammAlice, env); } } XRPAmount AMMTest::reserve(jtx::Env& env, std::uint32_t count) { return env.current()->fees().accountReserve(count); } XRPAmount AMMTest::ammCrtFee(jtx::Env& env) { return env.current()->fees().increment; } jtx::Env AMMTest::pathTestEnv() { // These tests were originally written with search parameters that are // different from the current defaults. This function creates an env // with the search parameters that the tests were written for. return Env(*this, envconfig([](std::unique_ptr cfg) { cfg->PATH_SEARCH_OLD = 7; cfg->PATH_SEARCH = 7; cfg->PATH_SEARCH_MAX = 10; return cfg; })); } } // namespace xrpl::test::jtx