diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index 26b2c5eaea..b616dbc73b 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -7143,6 +7143,36 @@ private: }); } + void + testFailedPseudoAccount() + { + testcase("Failed pseudo-account allocation"); + using namespace test::jtx; + + Env env{*this}; + env.fund(XRP(30'000), gw, alice); + env.close(); + env(trust(alice, gw["USD"](30'000), 0)); + env(pay(gw, alice, USD(10'000))); + env.close(); + + STAmount amount = XRP(10'000); + STAmount amount2 = USD(10'000); + auto const keylet = keylet::amm(amount.issue(), amount2.issue()); + for (int i = 0; i < 256; ++i) + { + AccountID const accountId = + ripple::pseudoAccountAddress(*env.current(), keylet.key); + + env(pay(env.master.id(), accountId, XRP(1000)), + seq(autofill), + fee(autofill), + sig(autofill)); + } + + AMM ammAlice(env, alice, amount, amount2, ter(terADDRESS_COLLISION)); + } + void run() override { @@ -7198,6 +7228,7 @@ private: testAMMDepositWithFrozenAssets(all - fixAMMv1_1 - featureAMMClawback); testFixReserveCheckOnWithdrawal(all); testFixReserveCheckOnWithdrawal(all - fixAMMv1_2); + testFailedPseudoAccount(); } }; diff --git a/src/xrpld/app/tx/detail/AMMCreate.cpp b/src/xrpld/app/tx/detail/AMMCreate.cpp index 8e419c7bcb..d6a65dd083 100644 --- a/src/xrpld/app/tx/detail/AMMCreate.cpp +++ b/src/xrpld/app/tx/detail/AMMCreate.cpp @@ -183,6 +183,14 @@ AMMCreate::preclaim(PreclaimContext const& ctx) return tecAMM_INVALID_TOKENS; } + if (ctx.view.rules().enabled(featureSingleAssetVault)) + { + if (auto const accountId = pseudoAccountAddress( + ctx.view, keylet::amm(amount.issue(), amount2.issue()).key); + accountId == beast::zero) + return terADDRESS_COLLISION; + } + // If featureAMMClawback is enabled, allow AMMCreate without checking // if the issuer has clawback enabled if (ctx.view.rules().enabled(featureAMMClawback))