1#include <test/jtx/Account.h>
2#include <test/jtx/Env.h>
3#include <test/jtx/TestHelpers.h>
4#include <test/jtx/acctdelete.h>
5#include <test/jtx/amount.h>
6#include <test/jtx/batch.h>
7#include <test/jtx/check.h>
8#include <test/jtx/credentials.h>
9#include <test/jtx/delegate.h>
10#include <test/jtx/deposit.h>
11#include <test/jtx/did.h>
12#include <test/jtx/escrow.h>
13#include <test/jtx/fee.h>
14#include <test/jtx/flags.h>
15#include <test/jtx/ledgerStateFix.h>
16#include <test/jtx/mpt.h>
17#include <test/jtx/multisign.h>
18#include <test/jtx/noop.h>
19#include <test/jtx/offer.h>
20#include <test/jtx/paths.h>
21#include <test/jtx/pay.h>
22#include <test/jtx/sendmax.h>
23#include <test/jtx/seq.h>
24#include <test/jtx/sig.h>
25#include <test/jtx/sponsor.h>
26#include <test/jtx/ter.h>
27#include <test/jtx/ticket.h>
28#include <test/jtx/token.h>
29#include <test/jtx/trust.h>
30#include <test/jtx/txflags.h>
31#include <test/jtx/vault.h>
33#include <xrpl/basics/Number.h>
34#include <xrpl/basics/Slice.h>
35#include <xrpl/basics/base_uint.h>
36#include <xrpl/basics/chrono.h>
37#include <xrpl/basics/strHex.h>
38#include <xrpl/beast/unit_test/suite.h>
39#include <xrpl/beast/utility/instrumentation.h>
40#include <xrpl/core/ServiceRegistry.h>
41#include <xrpl/json/json_value.h>
42#include <xrpl/ledger/ApplyView.h>
43#include <xrpl/ledger/OpenView.h>
44#include <xrpl/protocol/AccountID.h>
45#include <xrpl/protocol/Asset.h>
46#include <xrpl/protocol/Feature.h>
47#include <xrpl/protocol/Indexes.h>
48#include <xrpl/protocol/Issue.h>
49#include <xrpl/protocol/LedgerFormats.h>
50#include <xrpl/protocol/SField.h>
51#include <xrpl/protocol/STAmount.h>
52#include <xrpl/protocol/SeqProxy.h>
53#include <xrpl/protocol/TER.h>
54#include <xrpl/protocol/TxFlags.h>
55#include <xrpl/protocol/UintTypes.h>
56#include <xrpl/protocol/jss.h>
57#include <xrpl/tx/apply.h>
58#include <xrpl/tx/applySteps.h>
75 return env.
current()->fees().reserve * count;
81 return env.
current()->fees().accountReserve(count, 1);
88 XRPL_ASSERT(
isXRP(balanceTo),
"adjustAccountXRPBalance: balanceTo must be XRP");
89 auto const currentBalance = env.
balance(account);
90 if (currentBalance == balanceTo)
93 auto const baseFee = env.
current()->fees().base;
94 if (currentBalance > balanceTo)
96 env(
pay(account, env.
master, currentBalance - balanceTo),
103 env(
pay(env.
master, account, balanceTo - currentBalance),
Fee(baseFee));
123 auto const jt =
noop(alice);
125 jt1[sfSponsor.jsonName] =
sponsor.human();
147 Account const noFunded(
"noFunded");
150 auto const usd = gw[
"usd"];
166 tfSponsorshipSetRequireSignForFee | tfSponsorshipClearRequireSignForFee),
172 tfSponsorshipSetRequireSignForReserve |
173 tfSponsorshipClearRequireSignForReserve),
178 {tfSponsorshipSetRequireSignForFee,
179 tfSponsorshipClearRequireSignForFee,
180 tfSponsorshipSetRequireSignForReserve,
181 tfSponsorshipClearRequireSignForReserve})
203 for (
auto const& amt : {
XRP(0), usd(1)})
210 for (
auto const& amt : {
XRP(-1), usd(1)})
340 testcase(
"Pseudo account sponsorship");
348 Asset const asset = gw[
"IOU"].asset();
350 env.
fund(
XRP(1000000), alice, bob, gw, sp);
354 Vault const vault{env};
355 auto [tx,
keylet] = vault.create({.owner = alice, .asset = asset});
359 auto const vaultSle = env.
le(
keylet);
360 BEAST_EXPECT(vaultSle);
361 Account const pseudoAcc(
"vault", vaultSle->getAccountID(sfAccount));
383 Env env{*
this, features};
386 Account const invalid(
"invalid");
392 auto tx =
noop(alice);
393 tx[sfSponsor.jsonName] =
sponsor.human();
394 tx[sfSponsorSignature.jsonName][sfSigningPubKey.jsonName] =
strHex(
sponsor.pk().slice());
399 tx[sfSponsorSignature.jsonName][sfTxnSignature.jsonName] =
"DEADBEEF";
406 Sig(sfSponsorSignature, invalid),
422 Env env{*
this, features};
426 Account const signer1(
"signer1");
427 Account const signer2(
"signer2");
436 auto tx =
noop(alice);
437 auto& signers1 = tx[sfSponsorSignature.jsonName][sfSigners.jsonName][0U][sfSigner.jsonName];
438 signers1[sfAccount.jsonName] = signer1.
human();
439 signers1[sfSigningPubKey.jsonName] =
strHex(signer1.
pk().
slice());
440 signers1[sfTxnSignature.jsonName] =
"DEADBEEF";
447 Msig(sfSponsorSignature, {signer1}),
453 Msig(sfSponsorSignature, {signer1}),
461 auto const baseFee = env.
current()->fees().base;
463 Fee(baseFee + 2 * baseFee - 1),
465 Msig(sfSponsorSignature, {signer1, signer2}),
469 Fee(baseFee + 2 * baseFee),
471 Msig(sfSponsorSignature, {signer1, signer2}),
483 Account const noFunded(
"noFunded");
498 Sig(sfSponsorSignature, noFunded),
510 auto tx =
noop(alice);
511 tx[sfSponsor.jsonName] =
sponsor.human();
535 tfSponsorshipSetRequireSignForFee | tfSponsorshipSetRequireSignForReserve,
546 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 100);
547 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(100));
548 BEAST_EXPECT(sle->at(sfMaxFee) ==
XRP(1));
549 BEAST_EXPECT(sle->isFlag(lsfSponsorshipRequireSignForFee));
550 BEAST_EXPECT(sle->isFlag(lsfSponsorshipRequireSignForReserve));
562 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 50);
563 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(50));
564 BEAST_EXPECT(sle->at(sfMaxFee) ==
XRP(0.5));
576 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 200);
577 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(200));
578 BEAST_EXPECT(sle->at(sfMaxFee) ==
XRP(2));
589 tfSponsorshipSetRequireSignForFee | tfSponsorshipSetRequireSignForReserve,
634 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 100);
635 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(101));
636 BEAST_EXPECT(sle->at(sfMaxFee) ==
XRP(1));
639 auto testFlagUpdate = [&](
auto setFlag,
auto clearFlag,
auto ledgerFlag) {
645 BEAST_EXPECT(sle->isFlag(ledgerFlag));
652 BEAST_EXPECT(!sle->isFlag(ledgerFlag));
656 tfSponsorshipSetRequireSignForFee,
657 tfSponsorshipClearRequireSignForFee,
658 lsfSponsorshipRequireSignForFee);
660 tfSponsorshipSetRequireSignForReserve,
661 tfSponsorshipClearRequireSignForReserve,
662 lsfSponsorshipRequireSignForReserve);
673 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 100);
674 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(101));
675 BEAST_EXPECT(sle->at(sfMaxFee) ==
XRP(1));
692 BEAST_EXPECT(!sle->isFieldPresent(sfFeeAmount));
693 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 100);
715 BEAST_EXPECT(!sle->isFieldPresent(sfFeeAmount));
716 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 100);
734 BEAST_EXPECT(!sle->isFieldPresent(sfRemainingOwnerCount));
735 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(100));
750 BEAST_EXPECT(!sle->isFieldPresent(sfRemainingOwnerCount));
751 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(100));
807 testcase(
"RemainingOwnerCount overflow and underflow clamping");
868 BEAST_EXPECT(!sle->isFieldPresent(sfRemainingOwnerCount));
869 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(100));
904 auto const baseFee = env.
current()->fees().base;
913 auto const jt = env.
jt(
921 BEAST_EXPECT(!pf.consequences.isBlocker());
922 BEAST_EXPECT(pf.consequences.fee() ==
drops(baseFee));
923 BEAST_EXPECT(pf.consequences.potentialSpend() ==
XRP(100));
929 auto const jt = env.
jt(
937 BEAST_EXPECT(!pf.consequences.isBlocker());
938 BEAST_EXPECT(pf.consequences.fee() ==
drops(baseFee));
939 BEAST_EXPECT(pf.consequences.potentialSpend() ==
XRP(0));
944 auto const jt = env.
jt(
952 BEAST_EXPECT(!pf.consequences.isBlocker());
953 BEAST_EXPECT(pf.consequences.fee() ==
drops(baseFee));
954 BEAST_EXPECT(pf.consequences.potentialSpend() ==
XRP(0));
965 Account const charlie(
"charlie");
979 auto const checkSeq = env.
seq(alice);
989 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 99);
990 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(99));
998 BEAST_EXPECT(sle->at(sfRemainingOwnerCount) == 99);
999 BEAST_EXPECT(sle->at(sfFeeAmount) ==
XRP(99));
1037 testcase(
"Sponsored Free-Tier Reserve");
1040 Account const issuer(
"issuer");
1048 env.
fund(
XRP(10000), alice, issuer);
1055 MPTTester mptt(env, issuer, {.fund =
false});
1061 env(
trust(alice, issuer[
"USD"](100)),
1080 (features[fixCleanup3_4_0] ?
"(fixCleanup3_4_0 enabled)"
1081 :
"(fixCleanup3_4_0 disabled)"));
1086 Env env{*
this, features};
1098 (tfSponsorshipCreate | tfSponsorshipReassign | tfSponsorshipEnd) + 1),
1107 tfSponsorshipCreate | tfSponsorshipReassign,
1108 tfSponsorshipCreate | tfSponsorshipEnd,
1109 tfSponsorshipReassign | tfSponsorshipEnd,
1110 tfSponsorshipCreate | tfSponsorshipReassign | tfSponsorshipEnd,
1169 if (features[fixCleanup3_5_0])
1189 Env env{*
this, features};
1192 Account const charlie(
"charlie");
1234 Env env{*
this, features};
1237 Account const sponsor1(
"sponsor1");
1238 Account const sponsor2(
"sponsor2");
1239 env.
fund(
XRP(10000), alice, bob, sponsor1, sponsor2);
1251 Sig(sfSponsorSignature, sponsor1),
1259 Sig(sfSponsorSignature, sponsor1));
1269 BEAST_EXPECT(sle1->isFieldPresent(sfSponsor));
1270 BEAST_EXPECT(sle1->getAccountID(sfSponsor) == sponsor1.
id());
1277 Sig(sfSponsorSignature, sponsor2),
1285 Sig(sfSponsorSignature, sponsor2));
1300 BEAST_EXPECT(sle2->isFieldPresent(sfSponsor));
1301 BEAST_EXPECT(sle2->getAccountID(sfSponsor) == sponsor2.
id());
1306 Sig(sfSponsorSignature, sponsor2),
1316 Sig(sfSponsorSignature, sponsor2));
1340 BEAST_EXPECT(!sle3->isFieldPresent(sfSponsor));
1357 BEAST_EXPECT(!sle4->isFieldPresent(sfSponsor));
1365 Env env{*
this, features};
1377 BEAST_EXPECT(env.
le(alice)->getAccountID(sfSponsor) ==
sponsor.id());
1383 BEAST_EXPECT(!env.
le(alice)->isFieldPresent(sfSponsor));
1389 Env env{*
this, features};
1392 Account const sponsor1(
"sponsor1");
1393 Account const sponsor2(
"sponsor2");
1394 env.
fund(
XRP(10000), alice, bob, sponsor1, sponsor2);
1400 auto const seq = env.
seq(alice);
1409 Sig(sfSponsorSignature, sponsor1),
1413 env(
pay(alice, sponsor1,
drops(1)));
1420 Sig(sfSponsorSignature, sponsor1),
1427 Sig(sfSponsorSignature, sponsor1),
1434 Sig(sfSponsorSignature, sponsor1),
1441 Sig(sfSponsorSignature, sponsor1));
1452 BEAST_EXPECT(sle1->isFieldPresent(sfSponsor));
1453 BEAST_EXPECT(sle1->getAccountID(sfSponsor) == sponsor1.
id());
1458 Sig(sfSponsorSignature, sponsor2),
1465 Sig(sfSponsorSignature, sponsor1),
1474 Sig(sfSponsorSignature, sponsor2),
1477 env(
pay(alice, sponsor2,
drops(1)));
1482 Sig(sfSponsorSignature, sponsor2));
1495 BEAST_EXPECT(sle2->isFieldPresent(sfSponsor));
1496 BEAST_EXPECT(sle2->getAccountID(sfSponsor) == sponsor2.
id());
1502 if (features[fixCleanup3_4_0])
1527 BEAST_EXPECT(!sle3->isFieldPresent(sfSponsor));
1532 auto const ticketSeq = env.
seq(alice);
1544 Env env{*
this, features};
1547 Account const sponsor1(
"sponsor1");
1548 Account const sponsor2(
"sponsor2");
1549 env.
fund(
XRP(10000), alice, bob, sponsor1, sponsor2);
1552 auto const seq = env.
seq(alice);
1578 Env env{*
this, features};
1581 Account const sponsor1(
"sponsor1");
1582 Account const sponsor2(
"sponsor2");
1583 env.
fund(
XRP(10000), alice, bob, sponsor1, sponsor2);
1586 auto const seq = env.
seq(alice);
1616 BEAST_EXPECT(checkSle->isFieldPresent(sfSponsor));
1617 BEAST_EXPECT(checkSle->getAccountID(sfSponsor) == sponsor1.
id());
1619 BEAST_EXPECT(sponsor1Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1629 BEAST_EXPECT(sponsor1Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1650 BEAST_EXPECT(checkSle->isFieldPresent(sfSponsor));
1651 BEAST_EXPECT(checkSle->getAccountID(sfSponsor) == sponsor2.
id());
1653 BEAST_EXPECT(sponsor1Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1655 BEAST_EXPECT(sponsor2Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1674 BEAST_EXPECT(!checkSle->isFieldPresent(sfSponsor));
1676 BEAST_EXPECT(sponsor2Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1681 Env env{*
this, features};
1688 auto const seq = env.
seq(alice);
1721 Env env{*
this, features};
1728 auto const seq = env.
seq(alice);
1774 auto const& highAcc = alice > bob ? alice : bob;
1775 auto const& lowAcc = alice > bob ? bob : alice;
1777 for (
bool const isIssuerHigh : {
false,
true})
1779 Env env{*
this, features};
1783 auto const& issuer = isIssuerHigh ? highAcc : lowAcc;
1784 auto const& user = isIssuerHigh ? lowAcc : highAcc;
1786 auto const usd = issuer[
"usd"];
1787 auto const currency = usd.currency;
1789 env(
trust(user, issuer[
"usd"](100)));
1793 BEAST_EXPECT(env.
le(trustId));
1801 BEAST_EXPECT(env.
le(trustId));
1804 env.
le(trustId)->getAccountID(isIssuerHigh ? sfLowSponsor : sfHighSponsor) ==
1807 !env.
le(trustId)->isFieldPresent(isIssuerHigh ? sfHighSponsor : sfLowSponsor));
1813 BEAST_EXPECT(env.
le(trustId));
1815 !env.
le(trustId)->isFieldPresent(isIssuerHigh ? sfLowSponsor : sfHighSponsor));
1817 !env.
le(trustId)->isFieldPresent(isIssuerHigh ? sfHighSponsor : sfLowSponsor));
1823 Env env{*
this, features};
1840 auto const keylets = {
1848 for (
auto const&
keylet : keylets)
1860 Env env{*
this, features};
1866 auto const checkBlocked = [&](
Account const& account,
UInt256 const& objectID) {
1874 auto const ticketSeq = env.
seq(alice);
1879 checkBlocked(alice, ticketID);
1884 BEAST_EXPECT(env.
le(didKeylet));
1885 checkBlocked(alice, didKeylet.key);
1890 BEAST_EXPECT(env.
le(nftPageKeylet));
1891 checkBlocked(alice, nftPageKeylet.key);
1893 Account const borrower(
"borrower");
1894 env.
fund(
XRP(1000000), borrower);
1898 Vault const vault{env};
1902 auto [vaultTx, vaultKeylet, subscriptionDate] =
1903 vault.createClosedEnded({.owner = alice, .asset = xrpAsset});
1908 {.depositor = alice, .id = vaultKeylet.key, .amount = xrpAsset(1000)}));
1911 vault.closePastSubscription(subscriptionDate);
1913 auto const brokerKeylet =
1923 env(
loan::set(borrower, brokerKeylet.key, xrpAsset(100).value()),
1924 Sig(sfCounterpartySignature, alice),
1927 BEAST_EXPECT(env.
le(loanKeylet));
1928 checkBlocked(borrower, loanKeylet.key);
1945 env.
fund(
XRP(10000), alice, bob);
1951 auto aliceBalance = env.
balance(alice);
1952 auto bobBalance = env.
balance(bob);
1955 env(
pay(alice, bob,
XRP(100)),
1961 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
1962 BEAST_EXPECT(env.
balance(bob) == bobBalance);
1971 auto aliceBalance = env.
balance(alice);
1972 auto bobBalance = env.
balance(bob);
1975 auto const sendAmt =
XRP(100);
1976 auto const feeAmt =
XRP(10);
1977 env(
pay(alice, bob, sendAmt),
1982 BEAST_EXPECT(env.
balance(alice) == aliceBalance - sendAmt);
1983 BEAST_EXPECT(env.
balance(bob) == bobBalance + sendAmt);
1989 auto aliceBalance = env.
balance(alice);
1990 auto bobBalance = env.
balance(bob);
1993 env(
pay(alice, bob,
XRP(100)),
1999 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2000 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2007 auto aliceBalance = env.
balance(alice);
2008 auto bobBalance = env.
balance(bob);
2010 auto const feeAmt =
XRP(10);
2012 env(
pay(alice, bob,
XRP(20000)),
2019 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2020 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2029 auto const feeAmt =
XRP(10);
2076 auto aliceBalance = env.
balance(alice);
2077 auto bobBalance = env.
balance(bob);
2080 env(
pay(alice, bob,
XRP(100)),
2085 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2086 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2095 auto aliceBalance = env.
balance(alice);
2096 auto bobBalance = env.
balance(bob);
2100 auto const sendAmt =
XRP(100);
2101 auto const feeAmt =
XRP(10);
2105 BEAST_EXPECT(env.
balance(alice) == aliceBalance - sendAmt);
2106 BEAST_EXPECT(env.
balance(bob) == bobBalance + sendAmt);
2116 auto aliceBalance = env.
balance(alice);
2117 auto bobBalance = env.
balance(bob);
2121 env(
pay(alice, bob,
XRP(100)),
2127 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2128 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2135 auto aliceBalance = env.
balance(alice);
2136 auto bobBalance = env.
balance(bob);
2139 env(
pay(alice, bob,
XRP(100)),
2145 BEAST_EXPECT(env.
balance(alice) == aliceBalance -
XRP(100));
2146 BEAST_EXPECT(env.
balance(bob) == bobBalance +
XRP(100));
2160 auto aliceBalance = env.
balance(alice);
2161 auto bobBalance = env.
balance(bob);
2165 env(
pay(alice, bob,
XRP(100)),
2171 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2172 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2181 auto aliceBalance = env.
balance(alice);
2182 auto bobBalance = env.
balance(bob);
2185 auto const feeAmt =
XRP(1);
2187 env(
pay(alice, bob,
XRP(20000)),
2193 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2194 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2211 Fee(sponsorAvailableFee),
2226 Account const carol(
"sponsor");
2228 env.
fund(
XRP(10000), alice, carol);
2247 BEAST_EXPECT(result.applied);
2252 BEAST_EXPECT(sle->isFieldPresent(sfFeeAmount));
2253 BEAST_EXPECT(sle->getFieldAmount(sfFeeAmount) ==
drops(990));
2266 auto const fixFee =
drops(env.
current()->fees().increment);
2276 BEAST_EXPECT(!sle->isFieldPresent(sfFeeAmount));
2288 auto const fixFee =
drops(env.
current()->fees().increment);
2304 if (BEAST_EXPECT(original))
2307 sle->makeFieldAbsent(sfFeeAmount);
2311 auto const result =
doApply(pc, env.
app(), overlay);
2313 BEAST_EXPECT(!result.applied);
2330 env(
pay(alice, bob,
XRP(100)),
2364 env(
pay(alice, bob,
XRP(100)),
2371 env(
pay(alice, bob,
XRP(100)),
2391 Account const sponsor2(
"sponsor2");
2392 Account const sponsor3(
"sponsor3");
2394 Account const charlie(
"charlie");
2397 auto const usd = gw[
"usd"];
2419 env(
pay(alice, bob,
XRP(100)),
2420 Txflags(tfSponsorCreatedAccount | flag),
2432 Txflags(tfSponsorCreatedAccount),
2438 Txflags(tfSponsorCreatedAccount),
2445 env(
pay(alice, bob,
drops(env.
current()->fees().accountReserve(0, 1))),
2451 BEAST_EXPECT(!bobSle->isFieldPresent(sfSponsor));
2460 Txflags(tfSponsorCreatedAccount),
2465 BEAST_EXPECT(env.
balance(sponsor2) ==
XRP(9999));
2469 Txflags(tfSponsorCreatedAccount),
2474 auto const sponsor2BalanceBefore = env.
balance(sponsor2);
2479 BEAST_EXPECT(charlieSle->isFieldPresent(sfSponsor));
2480 BEAST_EXPECT(charlieSle->getAccountID(sfSponsor) == sponsor2.
id());
2484 BEAST_EXPECT(env.
balance(sponsor2) == sponsor2BalanceBefore -
drops(1) -
XRP(1));
2489 auto const sendAmount =
drops(1);
2493 env(
pay(sponsor3, dave, sendAmount),
2494 Txflags(tfSponsorCreatedAccount),
2500 env(
pay(sponsor3, dave, sendAmount),
2501 Txflags(tfSponsorCreatedAccount),
2513 testcase(
"SponsorshipRequireSignForReserve");
2548 testcase(
"SponsorshipRequireSignForFee");
2636 template <
typename SubmitCallback>
2643 uint32_t reserveCount,
2644 uint32_t sponsorReserveCount,
2645 TER insufficientReserveResult,
2646 SubmitCallback callback,
2650 auto const sponseeOwnerCountBefore =
ownerCount(env, sponsee);
2663 auto submit = [&](
TER ter) {
2664 return [&, ter](
json::Value const& jv,
auto const&... fN) {
2683 reserve(env, sponsorCurrentOwnerCount + sponsorReserveCount) -
drops(1));
2694 if (sponsorReserveCount > 1)
2709 auto const sponseeOwnerCountBeforeAttempt =
ownerCount(env, sponsee);
2711 auto const sponseeSponsoringOwnerCountBeforeAttempt =
2715 auto const sponsorSponsoringOwnerCountBeforeAttempt =
2718 bool const reserveCountPresentBeforeAttempt = sponsorshipSleBeforeAttempt &&
2719 sponsorshipSleBeforeAttempt->isFieldPresent(sfRemainingOwnerCount);
2720 std::uint32_t const reserveCountBeforeAttempt = reserveCountPresentBeforeAttempt
2721 ? sponsorshipSleBeforeAttempt->getFieldU32(sfRemainingOwnerCount)
2724 callback(env, submit(insufficientReserveResult));
2727 BEAST_EXPECT(
ownerCount(env, sponsee) == sponseeOwnerCountBeforeAttempt);
2740 static_cast<bool>(sponsorshipSleAfterAttempt) ==
2741 static_cast<bool>(sponsorshipSleBeforeAttempt));
2742 if (sponsorshipSleAfterAttempt)
2745 sponsorshipSleAfterAttempt->isFieldPresent(sfRemainingOwnerCount) ==
2746 reserveCountPresentBeforeAttempt);
2747 if (reserveCountPresentBeforeAttempt)
2750 sponsorshipSleAfterAttempt->getFieldU32(sfRemainingOwnerCount) ==
2751 reserveCountBeforeAttempt);
2761 env,
sponsor,
reserve(env, sponsorCurrentOwnerCount + sponsorReserveCount));
2778 BEAST_EXPECT(sponsorshipSle);
2780 !sponsorshipSle->isFieldPresent(sfRemainingOwnerCount) ||
2781 sponsorshipSle->getFieldU32(sfRemainingOwnerCount) == 0);
2795 BEAST_EXPECT(
ownerCount(env, sponsee) - sponseeOwnerCountBefore == reserveCount);
2798 sponsorReserveCount);
2805 sponsorReserveCount);
2818 Account const sponsor2(
"sponsor2");
2820 auto const usd = gw[
"usd"];
2838 [&](
Env& env,
auto const& submit) {
2839 seq = env.
seq(alice);
2849 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) ==
sponsor.id());
2856 Sig(sfSponsorSignature, sponsor2));
2876 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) == sponsor2.
id());
2903 [&](
Env& env,
auto const& submit) {
2904 seq2 = env.
seq(alice);
2929 env.
trust(usd(100), alice);
2931 env(
pay(gw, alice, usd(100)));
2944 [&](
Env& env,
auto const& submit) {
2945 seq2 = env.
seq(alice);
2953 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) ==
sponsor.id());
2974 bool const bobLow = bob.
id() < gw.
id();
2976 BEAST_EXPECT(lineSle);
2980 lineSle->getAccountID(bobLow ? sfLowSponsor : sfHighSponsor) ==
2983 !lineSle->isFieldPresent(bobLow ? sfHighSponsor : sfLowSponsor));
2996 MPTTester mptGw(env, gw, {.holders = {alice}});
2997 mptGw.
create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
2998 mptGw.authorize({.account = alice});
2999 auto const mpt = mptGw[
"MPT"];
3000 env(
pay(gw, alice, mpt(10'000)));
3013 [&](
Env& env,
auto const& submit) {
3014 seq2 = env.
seq(alice);
3019 BEAST_EXPECT(env.
le(checkKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3031 [&](
Env& env,
auto const& submit) {
3032 submit(
check::cash(bob, checkKeylet.key, mpt(1)));
3053 Account const sponsor2(
"sponsor2");
3069 [&](
Env& env,
auto const& submit) {
3075 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) ==
sponsor.id());
3082 Sig(sfSponsorSignature, sponsor2));
3099 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) == sponsor2.
id());
3118 Account const sponsor2(
"sponsor2");
3139 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) ==
sponsor.id());
3146 Sig(sfSponsorSignature, sponsor2));
3159 BEAST_EXPECT(sponsor2Sle);
3163 !sponsor2Sle->isFieldPresent(sfRemainingOwnerCount) ||
3164 sponsor2Sle->getFieldU32(sfRemainingOwnerCount) == 0);
3172 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) == sponsor2.
id());
3189 {.issuer =
sponsor, .credType = credType}};
3193 {sponsor.id(), Slice(credType.data(), credType.size())}});
3204 [&](
Env&,
auto const& submit) {
3209 BEAST_EXPECT(env.
le(preauthKeylet));
3210 BEAST_EXPECT(env.
le(preauthKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3218 BEAST_EXPECT(!env.
le(preauthKeylet));
3233 Account const sponsor2(
"sponsor2");
3250 [&](
Env& env,
auto const& submit) {
3255 BEAST_EXPECT(env.
le(credKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3267 Sig(sfSponsorSignature, sponsor2));
3283 BEAST_EXPECT(env.
le(credKeylet)->getAccountID(sfSponsor) == sponsor2.
id());
3310 [&](
Env& env,
auto const& submit) {
3316 BEAST_EXPECT(env.
le(credKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3372 [&](
Env& env,
auto const& submit) {
3382 BEAST_EXPECT(env.
le(credKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3395 using namespace std::chrono_literals;
3400 Account const sponsor2(
"sponsor2");
3404 auto const baseFee = env.
current()->fees().base;
3419 [&](
Env& env,
auto const& submit) {
3420 seq = env.
seq(alice);
3428 ->getAccountID(sfSponsor) ==
sponsor.id());
3435 tfSponsorshipReassign,
3438 Sig(sfSponsorSignature, sponsor2));
3448 tfSponsorshipReassign,
3461 ->getAccountID(sfSponsor) == sponsor2.
id());
3467 Fee(baseFee * 150));
3477 auto const usd = gw[
"usd"];
3481 auto const baseFee = env.
current()->fees().base;
3486 env(
fset(gw, asfAllowTrustLineLocking));
3489 env.
trust(usd(1000000), alice);
3491 env(
pay(gw, alice, usd(10000)));
3506 [&](
Env& env,
auto const& submit) {
3507 seq = env.
seq(alice);
3516 ->getAccountID(sfSponsor) ==
sponsor.id());
3527 [&](
Env& env,
auto const& submit) {
3532 Fee(baseFee * 150));
3547 auto const baseFee = env.
current()->fees().base;
3552 env(
fset(gw, asfAllowTrustLineLocking));
3555 env.
trust(usd(1000000), alice);
3557 env(
pay(gw, alice, usd(10000)));
3569 [&](
Env& env,
auto const& submit) {
3570 seq = env.
seq(alice);
3579 ->getAccountID(sfSponsor) ==
sponsor.id());
3634 env(
fset(gw, asfAllowTrustLineLocking));
3637 env.
trust(usd(1000000), alice);
3639 env(
pay(gw, alice, usd(10000)));
3645 auto const cancelAfter = env.
now() + 100s;
3646 auto const seq = env.
seq(alice);
3655 env(
trust(alice, usd(0)));
3661 for (; env.
now() < cancelAfter; env.
close())
3669 bool const aliceLow = alice.
id() < gw.
id();
3678 [&](
Env& env,
auto const& submit) { submit(
escrow::cancel(alice, alice, seq)); },
3682 BEAST_EXPECT(trustSle);
3686 trustSle->getAccountID(aliceLow ? sfLowSponsor : sfHighSponsor) ==
3689 !trustSle->isFieldPresent(aliceLow ? sfHighSponsor : sfLowSponsor));
3702 MPTTester mptGw(env, gw, {.holders = {alice}});
3704 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3705 mptGw.authorize({.account = alice});
3706 auto const mpt = mptGw[
"MPT"];
3707 env(
pay(gw, alice, mpt(10'000)));
3711 auto const seq = env.
seq(alice);
3733 [&](
Env& env,
auto const& submit) {
3753 auto const baseFee = env.
current()->fees().base;
3757 MPTTester mptGw(env, gw, {.holders = {alice}});
3759 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3760 mptGw.authorize({.account = alice});
3761 auto const mpt = mptGw[
"MPT"];
3762 env(
pay(gw, alice, mpt(10'000)));
3774 [&](
Env& env,
auto const& submit) {
3775 seq = env.
seq(alice);
3784 ->getAccountID(sfSponsor) ==
sponsor.id());
3841 auto const escrowAmount =
XRP(2);
3842 auto const seq = env.
seq(alice);
3881 Account const sponsor2(
"sponsor2");
3890 jv[sfAccount] = alice.
human();
3891 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3901 [&](
Env& env,
auto const& submit) {
3913 Sig(sfSponsorSignature, sponsor2));
3928 jv[sfTransactionType] = jss::MPTokenAuthorize;
3929 jv[sfAccount] = bob.
human();
3930 jv[sfMPTokenIssuanceID] =
to_string(mptid);
3947 [&](
Env& env,
auto const& submit) { submit(jv); });
3958 Sig(sfSponsorSignature, sponsor2));
3980 jv[sfTransactionType] = jss::MPTokenAuthorize;
3981 jv[sfAccount] = bob.
human();
3982 jv[sfMPTokenIssuanceID] =
to_string(mptid);
3983 jv[sfFlags] = tfMPTUnauthorize;
3995 jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
3996 jv[sfAccount] = alice.
human();
3997 jv[sfMPTokenIssuanceID] =
to_string(mptid);
4013 jv[sfAccount] = alice.
human();
4014 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
4025 jv[sfTransactionType] = jss::MPTokenAuthorize;
4026 jv[sfAccount] = bob.
human();
4027 jv[sfMPTokenIssuanceID] =
to_string(mptid);
4080 Account const sponsor2(
"sponsor2");
4088 auto const pk = alice.
pk();
4089 auto const settleDelay = 10s;
4099 [&](
Env& env,
auto const& submit) {
4105 BEAST_EXPECT(env.
le(
Keylet(ltPAYCHAN, chan))->getAccountID(sfSponsor) ==
sponsor.id());
4112 Sig(sfSponsorSignature, sponsor2));
4129 BEAST_EXPECT(env.
le(
Keylet(ltPAYCHAN, chan))->getAccountID(sfSponsor) == sponsor2.
id());
4131 env.
close(env.
now() + settleDelay);
4155 auto const pk = alice.
pk();
4156 auto const settleDelay = 10s;
4157 auto const channelAmount =
XRP(2);
4193 Account const sponsor2(
"sponsor2");
4208 [&](
Env& env,
auto const& submit) { submit(
signers(alice, 1, {{bob, 1}})); });
4220 Sig(sfSponsorSignature, sponsor2),
4224 env(
signers(bob, 1, {{alice, 1}}));
4228 Sig(sfSponsorSignature, sponsor2),
4232 Sig(sfSponsorSignature, sponsor2));
4265 testcase(
"Legacy SignerList sponsorship reserve");
4279 env(
signers(alice, 1, {{bob, 1}, {carol, 1}, {dave, 1}}));
4290 if (
auto const sle = env.
le(sponsorKeylet); BEAST_EXPECT(sle))
4291 BEAST_EXPECT(sle->getFieldU32(sfRemainingOwnerCount) == legacyWeight);
4298 signerList->clearFlag(lsfOneOwnerCount);
4299 account->setFieldU32(sfOwnerCount, legacyWeight);
4304 if (
auto const sle = env.
le(signerListKeylet); BEAST_EXPECT(sle))
4305 BEAST_EXPECT((sle->getFlags() & lsfOneOwnerCount) == 0);
4306 BEAST_EXPECT(
ownerCount(env, alice) == legacyWeight);
4316 if (
auto const sle = env.
le(sponsorKeylet); BEAST_EXPECT(sle))
4317 BEAST_EXPECT(!sle->isFieldPresent(sfRemainingOwnerCount));
4323 BEAST_EXPECT(!env.
le(signerListKeylet));
4327 if (
auto const sle = env.
le(sponsorKeylet); BEAST_EXPECT(sle))
4328 BEAST_EXPECT(!sle->isFieldPresent(sfRemainingOwnerCount));
4337 testcase(
"Sponsored trust line gets no free-reserve exception");
4340 Account const issuer(
"issuer");
4348 auto const usd = issuer[
"usd"];
4357 env(
trust(alice, usd(100)),
4363 BEAST_EXPECT(!env.
le(lineKeylet));
4370 env(
trust(alice, usd(100)),
4375 BEAST_EXPECT(env.
le(lineKeylet));
4386 testcase(
"Co-signed reserve sponsorship is bounded by Sponsorship budget");
4391 Account const sponsee(
"sponsee");
4437 Account const charlie(
"charlie");
4439 Account const sponsor2(
"sponsor2");
4441 auto const validateSponsoredTrustline =
4444 sle->getAccountID(isIssuerHigh ? sfLowSponsor : sfHighSponsor) ==
sponsor.id());
4445 BEAST_EXPECT(!sle->isFieldPresent(isIssuerHigh ? sfHighSponsor : sfLowSponsor));
4448 auto const& highAcc = alice > bob ? alice : bob;
4449 auto const& lowAcc = alice > bob ? bob : alice;
4452 for (
bool const isIssuerHigh : {
false,
true})
4458 auto const& issuer = isIssuerHigh ? highAcc : lowAcc;
4459 auto const& user = isIssuerHigh ? lowAcc : highAcc;
4461 auto const usd = issuer[
"usd"];
4462 auto const currency = usd.currency;
4480 [&](
Env& env,
auto const& submit) { submit(
trust(user, usd(100))); });
4489 Sig(sfSponsorSignature, sponsor2),
4494 Sig(sfSponsorSignature, sponsor2),
4498 Sig(sfSponsorSignature, sponsor2));
4511 env(
trust(user, usd(0)));
4522 for (
bool const isIssuerHigh : {
false,
true})
4528 auto const& issuer = isIssuerHigh ? highAcc : lowAcc;
4529 auto const& user = isIssuerHigh ? lowAcc : highAcc;
4531 auto const usd = issuer[
"usd"];
4532 auto const currency = usd.currency;
4535 env(
trust(issuer, user[
"usd"](100)));
4555 [&](
Env& env,
auto const& submit) { submit(
trust(user, usd(100))); });
4558 validateSponsoredTrustline(line, isIssuerHigh,
sponsor);
4561 env(
trust(user, usd(0)));
4570 env(
trust(issuer, user[
"usd"](0)));
4582 env(
trust(alice, bob[
"usd"](100)),
4586 env(
trust(bob, alice[
"usd"](100)),
4593 BEAST_EXPECT(sle->isFlag(lsfHighReserve));
4594 BEAST_EXPECT(sle->isFlag(lsfLowReserve));
4595 BEAST_EXPECT(sle->getAccountID(sfHighSponsor) ==
sponsor.id());
4596 BEAST_EXPECT(sle->getAccountID(sfLowSponsor) ==
sponsor.id());
4605 env(
trust(alice, bob[
"usd"](0)));
4607 env(
trust(bob, alice[
"usd"](0)));
4644 auto const sponsorObj = env.
le(
keylet);
4645 BEAST_EXPECT(sponsorObj);
4648 auto const requiredFee =
drops(env.
current()->fees().increment);
4667 auto const requiredFee =
drops(env.
current()->fees().increment);
4672 BEAST_EXPECT(aliceSle);
4674 BEAST_EXPECT(aliceSle->getAccountID(sfSponsor) ==
sponsor.id());
4677 BEAST_EXPECT(sponsorSle->getFieldU32(sfSponsoringAccountCount) == 1);
4685 BEAST_EXPECT(!sponsorSle2->isFieldPresent(sfSponsoringAccountCount));
4695 auto const usd = gw[
"usd"];
4698 env(
trust(alice, usd(1000)));
4703 BEAST_EXPECT(env.
le(trustId));
4712 BEAST_EXPECT(sponsorSle->isFieldPresent(sfSponsoringOwnerCount));
4719 auto const requiredFee =
drops(env.
current()->fees().increment);
4723 BEAST_EXPECT(sponsorSleAfter->isFieldPresent(sfSponsoringOwnerCount));
4741 BEAST_EXPECT(sponsorSle->isFieldPresent(sfSponsoringAccountCount));
4748 auto const requiredFee =
drops(env.
current()->fees().increment);
4752 BEAST_EXPECT(sponsorSleAfter->isFieldPresent(sfSponsoringAccountCount));
4771 BEAST_EXPECT(sponsorSle->at(sfSponsoringOwnerCount) == 1);
4772 BEAST_EXPECT(aliceSle->at(sfOwnerCount) == 1);
4773 BEAST_EXPECT(aliceSle->at(sfSponsoredOwnerCount) == 1);
4780 auto const requiredFee =
drops(env.
current()->fees().increment);
4784 BEAST_EXPECT(sponsorSle->at(sfSponsoringOwnerCount) == 0);
4803 env.
fund(
XRP(1000000), alice, bob, carol);
4806 auto const seq = env.
seq(alice);
4814 Sig(sfSponsorSignature, bob),
4825 env.
fund(
XRP(1000000), alice, bob, carol);
4847 testcase(
"Delegate Block Reserve Sponsor");
4890 testcase(
"Delegate Sponsor Fee Payer");
4906 auto const aliceBalance = env.
balance(alice);
4907 auto const bobBalance = env.
balance(bob);
4908 auto const carolBalance = env.
balance(carol);
4910 auto const sendAmt =
XRP(100);
4911 auto const feeAmt =
XRP(10);
4913 env(
pay(alice, carol, sendAmt),
4920 BEAST_EXPECT(env.
balance(alice) == aliceBalance - sendAmt);
4921 BEAST_EXPECT(env.
balance(bob) == bobBalance);
4922 BEAST_EXPECT(env.
balance(carol) == carolBalance + sendAmt);
4938 auto const aliceBalance = env.
balance(alice);
4939 auto const bobBalance = env.
balance(bob);
4940 auto const carolBalance = env.
balance(carol);
4943 auto const sendAmt =
XRP(100);
4944 auto const feeAmt =
XRP(10);
4950 env(
pay(alice, carol, sendAmt),
4956 BEAST_EXPECT(env.
balance(alice) == aliceBalance - sendAmt);
4957 BEAST_EXPECT(env.
balance(bob) == bobBalance);
4958 BEAST_EXPECT(env.
balance(carol) == carolBalance + sendAmt);
4983 auto const seq = env.
seq(alice);
4998 BEAST_EXPECT(env.
balance(alice) ==
XRP(1000));
5009 auto const seq = env.
seq(alice);
5022 env.
fund(
XRP(1000), alice, bob);
5032 auto const seq = env.
seq(alice);
5046 BEAST_EXPECT(env.
balance(alice) ==
XRP(1000));
5050 BEAST_EXPECT(sponsorshipSle);
5051 BEAST_EXPECT(sponsorshipSle->at(sfFeeAmount) ==
XRP(100 - 1));
5052 BEAST_EXPECT(sponsorshipSle->at(sfRemainingOwnerCount) == 100);
5059 Account const signerAccount(
"signer");
5074 auto const seq = env.
seq(alice);
5077 BEAST_EXPECT(jt.jv[sfSponsorSignature.jsonName].isMember(sfTxnSignature.jsonName));
5088 Msig(sfSponsorSignature,
sponsor, signerAccount));
5091 auto const seq = env.
seq(alice);
5094 BEAST_EXPECT(jt.jv[sfSponsorSignature.jsonName].isMember(sfSigners.jsonName));
5107 jt.jv[sfSponsorSignature.jsonName].
removeMember(sfTxnSignature.jsonName);
5108 jt.jv[sfSponsorSignature.jsonName][sfSigningPubKey.jsonName] =
"";
5110 auto const seq = env.
seq(alice);
5122 env.
fund(
XRP(1000), alice, bob);
5138 auto const seq = env.
seq(alice);
5151 BEAST_EXPECT(env.
balance(alice) ==
XRP(999));
5156 BEAST_EXPECT(sponsorshipSle);
5157 BEAST_EXPECT(sponsorshipSle->at(sfFeeAmount) ==
XRP(100));
5158 BEAST_EXPECT(sponsorshipSle->at(sfRemainingOwnerCount) == 99);
5173 jt.jv[sfSponsorSignature.jsonName].
removeMember(sfTxnSignature.jsonName);
5174 jt.jv[sfSponsorSignature.jsonName][sfSigningPubKey.jsonName] =
"";
5176 auto const seq = env.
seq(alice);
5190 BEAST_EXPECT(env.
balance(alice) ==
XRP(999));
5204 auto const seq = env.
seq(alice);
5208 auto innerPay =
pay(alice, bob,
XRP(1));
5209 innerPay[sfSponsor.jsonName] =
sponsor.human();
5213 env(
batch::outer(alice, seq, batchFee, tfAllOrNothing),
5226 auto const seq = env.
seq(alice);
5229 auto innerPay =
pay(alice, bob,
XRP(1));
5230 innerPay[sfSponsor.jsonName] =
sponsor.human();
5234 env(
batch::outer(alice, seq, batchFee, tfAllOrNothing),
5248 auto const seq = env.
seq(alice);
5252 innerTx[sfSponsor.jsonName] =
sponsor.human();
5253 innerTx[sfSponsorFlags.jsonName] =
5257 env(
batch::outer(alice, seq, batchFee, tfAllOrNothing),
5270 auto const seq = env.
seq(bob);
5292 testcase(
"Reserve sponsor allow-list gate");
5313 checkBlocked(
offer(alice,
XRP(100), bob[
"USD"](100)));
5341 testcase(
"Sponsored Payment: minimal-balance account with sponsor-pays-fee");
5343 using namespace jtx;
5349 auto const baseFee = env.
current()->fees().base;
5350 auto const baseReserve = env.
current()->fees().reserve;
5354 env.
fund(baseReserve +
XRP(1), alice);
5358 BEAST_EXPECT(env.
balance(alice) == baseReserve +
XRP(1));
5362 auto const preDest = env.
balance(dest);
5366 env(
pay(alice, dest,
XRP(1)),
5374 BEAST_EXPECT(env.
balance(alice) == baseReserve);
5377 BEAST_EXPECT(env.
balance(dest) == preDest +
XRP(1));
5395 testcase(
"TrustSet modify with sponsor does not misroute onto counterparty side");
5400 Account const alice{
"alice_t2178"};
5401 Account const bob{
"bob_t2178"};
5402 Account const carol{
"carol_t2178"};
5405 env.
fund(
XRP(100'000), alice, bob, carol);
5409 bool const aliceIsHigh = alice.
id() > bob.
id();
5417 auto const issuer = aliceIsHigh ? bob : alice;
5418 auto const holder = aliceIsHigh ? alice : bob;
5419 auto const usd = issuer[
"USD"];
5423 env(
fclear(issuer, asfDefaultRipple));
5429 env(
trust(holder, usd(1'000)));
5435 env(
fset(issuer, asfDefaultRipple));
5438 SF_ACCOUNT const& issuerSponsorField = aliceIsHigh ? sfLowSponsor : sfHighSponsor;
5439 SF_ACCOUNT const& holderSponsorField = aliceIsHigh ? sfHighSponsor : sfLowSponsor;
5442 auto const sleLineBefore = env.
le(lineKey);
5443 if (!BEAST_EXPECT(sleLineBefore))
5445 BEAST_EXPECT(!sleLineBefore->isFieldPresent(sfLowSponsor));
5446 BEAST_EXPECT(!sleLineBefore->isFieldPresent(sfHighSponsor));
5449 BEAST_EXPECT(carolBefore == 0);
5451 BEAST_EXPECT(issuerSponsoredBefore == 0);
5456 env(
trust(holder, usd(2'000)),
5458 Sig(sfSponsorSignature, carol),
5462 auto const sleLineAfter = env.
le(lineKey);
5463 if (!BEAST_EXPECT(sleLineAfter))
5467 BEAST_EXPECT(!sleLineAfter->isFieldPresent(issuerSponsorField));
5471 BEAST_EXPECT(!sleLineAfter->isFieldPresent(holderSponsorField));
5475 BEAST_EXPECT(carolAfter == carolBefore);
5479 BEAST_EXPECT(issuerSponsoredAfter == issuerSponsoredBefore);
5485 testcase(
"Self-escrow finish reserve order gated by amendment");
5487 using namespace std::chrono_literals;
5498 auto const usd = gw[
"usd"];
5500 Env env{*
this, features};
5501 auto const baseFee = env.
current()->fees().base;
5503 env.
fund(
XRP(10000), alice, gw);
5506 env(
fset(gw, asfAllowTrustLineLocking));
5509 env.
trust(usd(1000), alice);
5511 env(
pay(gw, alice, usd(100)));
5516 auto const seq = env.
seq(alice);
5525 env(
trust(alice, usd(0)));
5535 BEAST_EXPECT(env.
balance(alice) == target);
5548 BEAST_EXPECT(env.
balance(alice, usd) == usd(100));
5576 testcase(
"Fee-sponsored VaultDeposit/VaultWithdraw pass ValidVault invariant");
5586 Vault const vault{env};
5587 auto [vaultTx, vaultKeylet] = vault.create({.owner = alice, .asset = xrpAsset});
5592 env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = xrpAsset(100)}),
5597 env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = xrpAsset(100)}),
5607 env(vault.withdraw({.depositor = alice, .id = vaultKeylet.key, .amount = xrpAsset(50)}),
5620 testcase(
"Sponsored object deletion refunds sponsor owner count");
5634 Account const checkOwner(
"check_owner");
5635 Account const dest(
"check_dest");
5636 env.
fund(
XRP(100000), checkOwner, dest);
5641 auto const checkSeq = env.
seq(checkOwner);
5648 BEAST_EXPECT(sponsorCountBefore == 1);
5656 BEAST_EXPECT(sponsorCountAfter == 0);
5662 testcase(
" — TrustLine deletion");
5664 Account const issuer(
"issuer");
5665 Account const holder(
"holder");
5666 env.
fund(
XRP(100000), issuer, holder);
5669 auto const usd = issuer[
"USD"];
5672 env(
trust(holder, usd(1000)),
5678 BEAST_EXPECT(sponsorCountBefore == 1);
5681 env(
trust(holder, usd(0)));
5685 BEAST_EXPECT(sponsorCountAfter == 0);
A generic endpoint for log messages.
TestcaseT testcase
Memberspace for declaring test cases.
Value removeMember(char const *key)
Remove and return the named member.
Number is a floating point type that can represent a wide range of values.
bool modify(ModifyType const &f)
Modify the open ledger.
Writable ledger view that accumulates state and tx changes.
void rawReplace(SLE::Ref sle) override
Unconditionally replace a state item.
SLE::const_pointer read(Keylet const &k) const override
Return the state item associated with a key.
Rules const & rules() const override
Returns the tx processing rules.
Slice slice() const noexcept
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
static constexpr SeqProxy rawTicket(std::uint32_t v)
Factory function to return a ticket-based SeqProxy.
virtual OpenLedger & getOpenLedger()=0
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
PublicKey const & pk() const
Return the public key.
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.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
JTx jtnofill(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
void memoize(Account const &account)
Associate AccountID with account.
beast::Journal const journal
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
NetClock::time_point now()
Returns the current network time.
Test helper for creating, mutating, and asserting MPT and confidential MPT ledger state.
static json::Value authorizeJV(MPTAuthorize const &arg=MPTAuthorize{})
void create(MPTCreate const &arg=MPTCreate{}, std::source_location const &loc=std::source_location::current())
Set a multisignature on a JTx.
Sets the SendMax on a JTx.
Set the regular signature on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Adds an inner Batch transaction to a JTx and autofills it.
Sets the Batch transaction signers on a JTx.
Set a ticket sequence on a JTx.
Keylet computation functions.
Keylet const & skip() noexcept
The index of the "short" skip list.
Keylet escrow(AccountID const &src, SeqProxy const &seq) noexcept
An escrow entry.
Keylet did(AccountID const &account) noexcept
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Keylet const & feeSettings() noexcept
The (fixed) index of the object containing the ledger fees.
Keylet signerList(AccountID const &account) noexcept
A SignerList.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet check(AccountID const &id, SeqProxy const &seq) noexcept
A Check.
Keylet unchecked(UInt256 const &key) noexcept
Any ledger entry.
Keylet ticket(AccountID const &id, SeqProxy const &ticketSeq)
A ticket belonging to an account.
Keylet nftokenPageMax(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Keylet loanBroker(AccountID const &owner, SeqProxy const &seq) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet sponsorship(AccountID const &sponsor, AccountID const &sponsee) noexcept
A Sponsorship.
Keylet loan(UInt256 const &loanBrokerID, SeqProxy const &loanSeq) noexcept
Keylet mptokenIssuance(MPTID const &issuanceID) noexcept
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
json::Value outer(jtx::Account const &account, uint32_t seq, STAmount const &fee, std::uint32_t flags)
Build an outer Batch transaction JSON object.
XRPAmount calcBatchFee(jtx::Env const &env, uint32_t const &numSigners, uint32_t const &txns=0)
Calculate the expected outer Batch transaction fee.
json::Value cancel(jtx::Account const &dest, UInt256 const &checkId)
Cancel a check.
json::Value cash(jtx::Account const &dest, UInt256 const &checkId, STAmount const &amount)
Cash a check requiring that a specific amount be delivered.
json::Value create(A const &account, A const &dest, STAmount const &sendMax)
Create a check.
json::Value deleteCred(jtx::Account const &acc, jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
json::Value accept(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
json::Value create(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Keylet keylet(test::jtx::Account const &subject, test::jtx::Account const &issuer, std::string_view credType)
json::Value set(jtx::Account const &account, jtx::Account const &authorize, std::vector< std::string > const &permissions)
json::Value unauthCredentials(jtx::Account const &account, std::vector< AuthorizeCredentials > const &auth)
json::Value authCredentials(jtx::Account const &account, std::vector< AuthorizeCredentials > const &auth)
json::Value auth(Account const &account, Account const &auth)
Preauthorize for deposit.
json::Value unauth(Account const &account, Account const &unauth)
Remove pre-authorization for deposit.
json::Value setValid(jtx::Account const &account)
json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount)
json::Value cancel(AccountID const &account, Account const &from, std::uint32_t seq)
auto const kCancelTime
Set the "CancelAfter" time tag on a JTx.
json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
std::array< std::uint8_t, 4 > const kFb1
std::array< std::uint8_t, 39 > const kCb1
json::Value nftPageLinks(jtx::Account const &acct, jtx::Account const &owner)
Repair the links in an NFToken directory.
auto const kManagementFeeRate
json::Value set(AccountID const &account, UInt256 const &vaultId, uint32_t flags)
auto const kCoverRateMinimum
auto const kCoverRateLiquidation
json::Value set(AccountID const &account, UInt256 const &loanBrokerID, Number principalRequested, std::uint32_t flags)
json::Value claim(AccountID const &account, UInt256 const &channel, std::optional< STAmount > const &balance, std::optional< STAmount > const &amount, std::optional< Slice > const &signature, std::optional< PublicKey > const &pk)
json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter, std::optional< std::uint32_t > const &dstTag)
bool channelExists(ReadView const &view, UInt256 const &chan)
UInt256 channel(AccountID const &account, AccountID const &dst, std::uint32_t seqProxyValue)
json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
json::Value mint(jtx::Account const &account, std::uint32_t nfTokenTaxon)
Mint an NFToken.
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
XrpT const XRP
Converts to XRP Issue or STAmount.
json::Value noop(Account const &account)
The null transaction.
std::uint32_t sponsoringAccountCount(Env const &env, Account const &account)
std::uint32_t ownerCount(Env const &env, Account const &account)
json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
std::uint32_t sponsoringOwnerCount(Env const &env, Account const &account)
FeatureBitset testableAmendments()
json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
void incLgrSeqForAccDel(jtx::Env &env, jtx::Account const &acc, std::uint32_t margin=0)
json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
std::uint32_t sponsoredOwnerCount(Env const &env, Account const &account)
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
json::Value signers(Account const &account, std::uint32_t quorum, std::vector< Signer > const &v)
json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
static XRPAmount reserve(jtx::Env &env, std::uint32_t count)
static STAmount accountReserve(jtx::Env &env, std::uint32_t count=1)
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
static void adjustAccountXRPBalance(jtx::Env &env, jtx::Account const &account, STAmount const &balanceTo)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr FlagValue spfSponsorFee
@ terNO_DELEGATE_PERMISSION
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
constexpr FlagValue tfInnerBatchTxn
PreflightResult preflight(ServiceRegistry ®istry, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
bool isXRP(AccountID const &c)
PreclaimResult preclaim(PreflightResult const &preflightResult, ServiceRegistry ®istry, OpenView const &view)
Gate a transaction based on static ledger information.
ApplyResult apply(ServiceRegistry ®istry, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
std::string strHex(FwdIt begin, FwdIt end)
TenthBips< std::uint32_t > TenthBips32
TenthBips< std::uint16_t > TenthBips16
std::string to_string(BaseUInt< Bits, Tag > const &a)
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
MPTID makeMptID(std::uint32_t const sequence, AccountID const &account)
bool isTesSuccess(TER x) noexcept
TERSubset< CanCvtToTER > TER
@ tecNO_LINE_INSUF_RESERVE
@ tecNO_SPONSOR_PERMISSION
@ tecINSUFFICIENT_RESERVE
TypedField< STAccount > SF_ACCOUNT
ApplyResult doApply(PreclaimResult const &preclaimResult, ServiceRegistry ®istry, OpenView &view)
Apply a prechecked transaction to an OpenView.
constexpr FlagValue spfSponsorReserve
A pair of SHAMap key and LedgerEntryType.
Set the sequence number on a JTx.
A signer in a SignerList.