1#include <test/jtx/Account.h>
2#include <test/jtx/Env.h>
3#include <test/jtx/PathSet.h>
4#include <test/jtx/TestHelpers.h>
5#include <test/jtx/amount.h>
6#include <test/jtx/balance.h>
7#include <test/jtx/flags.h>
8#include <test/jtx/jtx_json.h>
9#include <test/jtx/offer.h>
10#include <test/jtx/owners.h>
11#include <test/jtx/pay.h>
12#include <test/jtx/sendmax.h>
13#include <test/jtx/ter.h>
14#include <test/jtx/trust.h>
15#include <test/jtx/txflags.h>
17#include <xrpl/basics/contract.h>
18#include <xrpl/basics/safe_cast.h>
19#include <xrpl/beast/unit_test/suite.h>
20#include <xrpl/ledger/ApplyView.h>
21#include <xrpl/ledger/PaymentSandbox.h>
22#include <xrpl/protocol/AccountID.h>
23#include <xrpl/protocol/Book.h>
24#include <xrpl/protocol/Feature.h>
25#include <xrpl/protocol/Indexes.h>
26#include <xrpl/protocol/Issue.h>
27#include <xrpl/protocol/Keylet.h>
28#include <xrpl/protocol/LedgerFormats.h>
29#include <xrpl/protocol/SField.h>
30#include <xrpl/protocol/STAmount.h>
31#include <xrpl/protocol/STPathSet.h>
32#include <xrpl/protocol/TER.h>
33#include <xrpl/protocol/TxFlags.h>
34#include <xrpl/protocol/UintTypes.h>
35#include <xrpl/tx/paths/RippleCalc.h>
36#include <xrpl/tx/paths/detail/Steps.h>
37#include <xrpl/tx/transactors/dex/AMMContext.h>
69 return lsfHighNoRipple;
70 return lsfLowNoRipple;
85 auto const useHigh = src.
id() > dst.
id();
86 return sle->isFlag(
trustFlag(flag, useHigh));
129 for (
auto const s : sb)
142 for (
auto const s : sb)
183 template <
class Col,
class AccFactory,
class IssFactory,
class CurrencyFactory>
189 CurrencyFactory&& currencyF,
227 col.emplace_back(acc, cur, iss);
302 assert(!offererIndex || offererIndex < numAct);
311 static constexpr size_t kBufSize = 32;
314 for (
size_t id = 0;
id < numAct; ++id)
316 snprintf(buf, kBufSize,
"A%zu",
id);
320 for (
size_t id = 0;
id < numCur; ++id)
324 snprintf(buf, kBufSize,
"CC%zu",
id);
328 snprintf(buf, kBufSize,
"C%zu",
id);
332 snprintf(buf, kBufSize,
"%zu",
id);
344 for (
auto ai2 =
accounts.begin(); ai2 != aie; ++ai2)
350 env.
trust((*ai1)[cn](1'000'000), *ai2);
356 auto const& src = *ai1;
357 auto const& dst = *ai2;
358 env(
pay(src, dst, src[cn](500000)));
374 for (
auto takerPays = ious.
begin(), ie = ious.
end(); takerPays != ie; ++takerPays)
376 for (
auto takerGets = ious.
begin(); takerGets != ie; ++takerGets)
378 if (takerPays == takerGets)
380 auto const owner = offererIndex ?
accounts[*offererIndex] : takerGets->account;
381 if (owner.id() != takerGets->account.id())
382 env(
pay(takerGets->account, owner, (*takerGets)(1000)));
384 env(
offer(owner, (*takerPays)(1000), (*takerGets)(1000)),
Txflags(tfPassive));
390 for (
auto const& iou : ious)
392 auto const owner = offererIndex ?
accounts[*offererIndex] : iou.account;
403 auto add = [&](
auto const& a) {
408 auto const b = (*sle)[sfBalance];
426 auto const sle = v.
read(k);
429 return (*sle)[sfBalance];
432 auto const sle = v.
read(k);
435 return (*sle)[sfBalance];
443 auto const b1 = xrpBalance(v1, ak);
444 auto const b2 = xrpBalance(v2, ak);
450 for (
auto ai2 =
accounts.begin(); ai2 != aie; ++ai2)
458 auto const b1 = lineBalance(v1, lk);
459 auto const b2 = lineBalance(v2, lk);
465 return diffs.
empty();
501 auto const resultSize = prefix.
size() + suffix.
size() + 2;
502 outerResult.
reserve(resultSize);
507 outerResult = prefix;
509 outerResult, accF, issF, currencyF, existingAcc, existingCur, existingIss);
515 result = outerResult;
517 result, accF, issF, currencyF, existingAcc, existingCur, existingIss);
519 f(sendMax, deliver, result);
534 auto const alice =
Account(
"alice");
535 auto const bob =
Account(
"bob");
536 auto const carol =
Account(
"carol");
539 auto const usd = gw[
"USD"];
540 auto const eur = gw[
"EUR"];
542 auto const eurC = eur.currency;
543 auto const usdC = usd.currency;
551 auto test = [&,
this](
553 Issue const& deliver,
557 auto&&... expSteps) {
571 BEAST_EXPECT(ter == expTer);
572 if (
sizeof...(expSteps) != 0)
577 Env env(*
this, features);
578 env.
fund(
XRP(10000), alice, bob, gw);
579 env.
trust(usd(1000), alice, bob);
580 env.
trust(eur(1000), alice, bob);
581 env(
pay(gw, alice, eur(100)));
622 Env env(*
this, features);
623 env.
fund(
XRP(10000), alice, bob, carol, gw);
627 env.
trust(usd(1000), alice, bob, carol);
630 env(
pay(gw, alice, usd(100)));
631 env(
pay(gw, carol, usd(100)));
640 D{.src = alice, .dst = gw, .currency = usdC},
641 D{.src = gw, .dst = bob, .currency = usdC});
642 env.
trust(eur(1000), alice, bob);
651 D{.src = alice, .dst = gw, .currency = usdC},
652 B{usd, eur, std::nullopt},
653 D{.src = gw, .dst = bob, .currency = eurC});
662 D{.src = alice, .dst = gw, .currency = usdC},
663 B{usd, eur, std::nullopt},
664 D{.src = gw, .dst = bob, .currency = eurC});
667 env.
trust(carol[
"USD"](1000), bob);
674 D{.src = alice, .dst = gw, .currency = usdC},
675 B{usd, carol[
"USD"], std::nullopt},
676 D{.src = carol, .dst = bob, .currency = usdC});
686 B{
XRP, usd, std::nullopt},
687 D{.src = gw, .dst = bob, .currency = usdC});
697 D{.src = alice, .dst = gw, .currency = usdC},
698 B{usd,
XRP, std::nullopt},
708 D{.src = alice, .dst = gw, .currency = usdC},
709 B{usd,
XRP, std::nullopt},
710 B{
XRP, eur, std::nullopt},
711 D{.src = gw, .dst = bob, .currency = eurC});
796 Env env(*
this, features);
798 env.
fund(
XRP(10000), alice, bob, carol, gw);
799 env.
trust(usd(10000), alice, bob, carol);
800 env.
trust(eur(10000), alice, bob, carol);
802 env(
pay(gw, bob, usd(100)));
803 env(
pay(gw, bob, eur(100)));
805 env(
offer(bob,
XRP(100), usd(100)));
806 env(
offer(bob, usd(100), eur(100)),
Txflags(tfPassive));
807 env(
offer(bob, eur(100), usd(100)),
Txflags(tfPassive));
810 env(
pay(alice, carol, usd(100)),
811 Path(~usd, ~eur, ~usd),
818 Env env(*
this, features);
820 env.
trust(usd(1000), alice, bob);
821 env(
pay(gw, alice, usd(100)));
827 Env env(*
this, features);
828 env.
fund(
XRP(10000), alice, bob, gw);
829 env.
trust(usd(1000), alice, bob);
830 env(
pay(gw, alice, usd(100)));
833 env(
fset(alice, asfGlobalFreeze));
835 env(
fclear(alice, asfGlobalFreeze));
839 env(
fset(gw, asfGlobalFreeze));
841 env(
fclear(gw, asfGlobalFreeze));
845 env(
fset(bob, asfGlobalFreeze));
847 env(
fclear(bob, asfGlobalFreeze));
852 Env env(*
this, features);
853 env.
fund(
XRP(10000), alice, bob, gw);
854 env.
trust(usd(1000), alice, bob);
855 env(
pay(gw, alice, usd(100)));
857 env(
trust(gw, alice[
"USD"](0), tfSetFreeze));
865 Env env(*
this, features);
866 env.
fund(
XRP(10000), alice, bob, gw);
867 env(
fset(gw, asfRequireAuth));
868 env.
trust(usd(1000), alice, bob);
870 env(
trust(gw, alice[
"USD"](1000), tfSetfAuth));
872 env(
pay(gw, alice, usd(100)));
891 BEAST_EXPECT(
equal(strand, D{alice, gw, usdC}));
896 Env env(*
this, features);
897 env.
fund(
XRP(10000), alice, bob, gw);
898 env.
trust(usd(1000), alice, bob);
899 env(
pay(gw, alice, usd(100)));
920 equal(strand, D{alice, gw, usdC}, B{usd,
xrpIssue(), std::nullopt}, XRPS{bob}));
930 auto const alice =
Account(
"alice");
931 auto const bob =
Account(
"bob");
932 auto const carol =
Account(
"carol");
934 auto const usd = gw[
"USD"];
935 auto const eur = gw[
"EUR"];
938 Env env(*
this, features);
939 env.
fund(
XRP(10000), alice, bob, gw);
941 env.
trust(usd(1000), alice, bob);
942 env.
trust(eur(1000), alice, bob);
943 env.
trust(bob[
"USD"](1000), alice, gw);
944 env.
trust(bob[
"EUR"](1000), alice, gw);
949 env(
offer(bob, bob[
"USD"](100), bob[
"EUR"](100)),
Txflags(tfPassive));
961 env(
pay(alice, alice, eur(1)),
964 Txflags(tfNoRippleDirect | tfPartialPayment),
969 Env env(*
this, features);
971 env.
fund(
XRP(10000), alice, bob, carol, gw);
972 env.
trust(usd(10000), alice, bob, carol);
974 env(
pay(gw, bob, usd(100)));
980 env(
pay(alice, carol,
XRP(100)),
987 Env env(*
this, features);
989 env.
fund(
XRP(10000), alice, bob, carol, gw);
990 env.
trust(usd(10000), alice, bob, carol);
992 env(
pay(gw, bob, usd(100)));
998 env(
pay(alice, carol,
XRP(100)),
1010 using namespace jtx;
1012 auto const alice =
Account(
"alice");
1013 auto const bob =
Account(
"bob");
1014 auto const carol =
Account(
"carol");
1015 auto const gw =
Account(
"gw");
1016 auto const usd = gw[
"USD"];
1017 auto const eur = gw[
"EUR"];
1018 auto const cny = gw[
"CNY"];
1021 Env env(*
this, features);
1023 env.
fund(
XRP(10000), alice, bob, carol, gw);
1024 env.
trust(usd(10000), alice, bob, carol);
1026 env(
pay(gw, bob, usd(100)));
1027 env(
pay(gw, alice, usd(100)));
1033 env(
pay(alice, carol, usd(100)),
1040 Env env(*
this, features);
1042 env.
fund(
XRP(10000), alice, bob, carol, gw);
1043 env.
trust(usd(10000), alice, bob, carol);
1044 env.
trust(eur(10000), alice, bob, carol);
1045 env.
trust(cny(10000), alice, bob, carol);
1047 env(
pay(gw, bob, usd(100)));
1048 env(
pay(gw, bob, eur(100)));
1049 env(
pay(gw, bob, cny(100)));
1052 env(
offer(bob, usd(100), eur(100)),
Txflags(tfPassive));
1053 env(
offer(bob, eur(100), cny(100)),
Txflags(tfPassive));
1056 env(
pay(alice, carol, cny(100)),
1058 Path(~usd, ~eur, ~usd, ~cny),
1068 using namespace jtx;
1070 auto const alice =
Account(
"alice");
1071 auto const bob =
Account(
"bob");
1072 auto const gw =
Account(
"gw");
1073 auto const usd = gw[
"USD"];
1075 Env env(*
this, features);
1076 env.
fund(
XRP(10000), alice, bob, gw);
1078 STAmount const sendMax{usd, 100, 1};
1151 using namespace jtx;
1159 testLoop(sa - featurePermissionedDEX);
void fail(String const &reason, char const *file, int line)
Record a failure.
TestcaseT testcase
Memberspace for declaring test cases.
Maintains AMM info per overall payment engine execution and individual iteration.
A currency issued by an account.
A wrapper which makes credits unavailable to balances.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
virtual beast::Journal getJournal(std::string const &name)=0
static Output rippleCalculate(PaymentSandbox &view, STAmount const &saMaxAmountReq, STAmount const &saDstAmountReq, AccountID const &uDstAccountID, AccountID const &uSrcAccountID, STPathSet const &spsPaths, std::optional< uint256 > const &domainID, ServiceRegistry ®istry, Input const *const pInputs=nullptr)
ElementComboIter(STPathElement const *prev=nullptr)
bool const allowCompound_
void emplaceInto(Col &col, AccFactory &&accF, IssFactory &&issF, CurrencyFactory &¤cyF, std::optional< AccountID > const &existingAcc, std::optional< Currency > const &existingCur, std::optional< AccountID > const &existingIss)
bool hasAny(std::initializer_list< SB > sb) const
STPathElement const * prev_
size_t count(std::initializer_list< SB > sb) const
TestPath & pushBack(Issue const &iss)
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
SLE::const_pointer le(Account const &account) const
Return an account root.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Sets the SendMax on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
T emplace_back(T... args)
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
STPathElement allPathElements(AccountID const &a, Asset const &asset)
XrpT const XRP
Converts to XRP Issue or STAmount.
json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
FeatureBitset testableAmendments()
STPathElement cpe(PathAsset const &pa)
STPathElement ipe(Asset const &asset)
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
bool equal(STAmount const &sa1, STAmount const &sa2)
STPathElement iape(AccountID const &account)
json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
STPathElement ape(AccountID const &a)
json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
bool getTrustFlag(jtx::Env const &env, jtx::Account const &src, jtx::Account const &dst, Currency const &cur, TrustFlag flag)
std::uint32_t trustFlag(TrustFlag f, bool useHigh)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
std::pair< TER, Strand > toStrand(ReadView const &sb, AccountID const &src, AccountID const &dst, Asset const &deliver, std::optional< Quality > const &limitQuality, std::optional< Asset > const &sendMaxAsset, STPath const &path, bool ownerPaysTransferFee, OfferCrossing offerCrossing, AMMContext &ammContext, std::optional< uint256 > const &domainID, beast::Journal j)
Create a Strand for the specified path.
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safeCast(Src s) noexcept
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
bool toCurrency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Currency const & xrpCurrency()
XRP currency.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
AccountID const & noAccount()
A placeholder for empty accounts.
bool isTesSuccess(TER x) noexcept
TERSubset< CanCvtToTER > TER
AccountID const & xrpAccount()
Compute AccountID from public key.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
A pair of SHAMap key and LedgerEntryType.
StateGuard(ExistingElementPool &p)
std::vector< jtx::Account > accounts
std::int64_t totalXRP(ReadView const &v, bool incRoot)
bool checkBalances(ReadView const &v1, ReadView const &v2)
ResetState getResetState() const
std::vector< xrpl::Currency > currencies
void resetTo(ResetState const &s)
jtx::Account getAccount(size_t id)
jtx::Account getAvailAccount()
void setupEnv(jtx::Env &env, size_t numAct, size_t numCur, std::optional< size_t > const &offererIndex)
void forEachElementPair(STAmount const &sendMax, STAmount const &deliver, std::vector< STPathElement > const &prefix, std::vector< STPathElement > const &suffix, std::optional< AccountID > const &existingAcc, std::optional< Currency > const &existingCur, std::optional< AccountID > const &existingIss, F &&f)
std::vector< std::string > currencyNames
xrpl::Currency getCurrency(size_t id)
xrpl::Currency getAvailCurrency()
std::tuple< size_t, size_t > ResetState
void testRIPD1373(FeatureBitset features)
void testLoop(FeatureBitset features)
void run() override
Runs the suite.
void testToStrand(FeatureBitset features)
void testNoAccount(FeatureBitset features)