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));
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),
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)),
1095 (tfSponsorshipCreate | tfSponsorshipReassign | tfSponsorshipEnd) + 1),
1104 tfSponsorshipCreate | tfSponsorshipReassign,
1105 tfSponsorshipCreate | tfSponsorshipEnd,
1106 tfSponsorshipReassign | tfSponsorshipEnd,
1107 tfSponsorshipCreate | tfSponsorshipReassign | tfSponsorshipEnd,
1170 Account const charlie(
"charlie");
1215 Account const sponsor1(
"sponsor1");
1216 Account const sponsor2(
"sponsor2");
1217 env.
fund(
XRP(10000), alice, bob, sponsor1, sponsor2);
1229 Sig(sfSponsorSignature, sponsor1),
1237 Sig(sfSponsorSignature, sponsor1));
1247 BEAST_EXPECT(sle1->isFieldPresent(sfSponsor));
1248 BEAST_EXPECT(sle1->getAccountID(sfSponsor) == sponsor1.
id());
1255 Sig(sfSponsorSignature, sponsor2),
1263 Sig(sfSponsorSignature, sponsor2));
1278 BEAST_EXPECT(sle2->isFieldPresent(sfSponsor));
1279 BEAST_EXPECT(sle2->getAccountID(sfSponsor) == sponsor2.
id());
1284 Sig(sfSponsorSignature, sponsor2),
1294 Sig(sfSponsorSignature, sponsor2));
1318 BEAST_EXPECT(!sle3->isFieldPresent(sfSponsor));
1335 BEAST_EXPECT(!sle4->isFieldPresent(sfSponsor));
1355 BEAST_EXPECT(env.
le(alice)->getAccountID(sfSponsor) ==
sponsor.id());
1361 BEAST_EXPECT(!env.
le(alice)->isFieldPresent(sfSponsor));
1370 Account const sponsor1(
"sponsor1");
1371 Account const sponsor2(
"sponsor2");
1372 env.
fund(
XRP(10000), alice, bob, sponsor1, sponsor2);
1378 auto const seq = env.
seq(alice);
1387 Sig(sfSponsorSignature, sponsor1),
1391 env(
pay(alice, sponsor1,
drops(1)));
1398 Sig(sfSponsorSignature, sponsor1),
1405 Sig(sfSponsorSignature, sponsor1),
1412 Sig(sfSponsorSignature, sponsor1),
1419 Sig(sfSponsorSignature, sponsor1));
1430 BEAST_EXPECT(sle1->isFieldPresent(sfSponsor));
1431 BEAST_EXPECT(sle1->getAccountID(sfSponsor) == sponsor1.
id());
1436 Sig(sfSponsorSignature, sponsor2),
1443 Sig(sfSponsorSignature, sponsor1),
1452 Sig(sfSponsorSignature, sponsor2),
1455 env(
pay(alice, sponsor2,
drops(1)));
1460 Sig(sfSponsorSignature, sponsor2));
1473 BEAST_EXPECT(sle2->isFieldPresent(sfSponsor));
1474 BEAST_EXPECT(sle2->getAccountID(sfSponsor) == sponsor2.
id());
1495 BEAST_EXPECT(!sle3->isFieldPresent(sfSponsor));
1500 auto const ticketSeq = env.
seq(alice);
1515 Account const sponsor1(
"sponsor1");
1516 Account const sponsor2(
"sponsor2");
1517 env.
fund(
XRP(10000), alice, bob, sponsor1, sponsor2);
1520 auto const seq = env.
seq(alice);
1549 Account const sponsor1(
"sponsor1");
1550 Account const sponsor2(
"sponsor2");
1551 env.
fund(
XRP(10000), alice, bob, sponsor1, sponsor2);
1554 auto const seq = env.
seq(alice);
1584 BEAST_EXPECT(checkSle->isFieldPresent(sfSponsor));
1585 BEAST_EXPECT(checkSle->getAccountID(sfSponsor) == sponsor1.
id());
1587 BEAST_EXPECT(sponsor1Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1597 BEAST_EXPECT(sponsor1Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1618 BEAST_EXPECT(checkSle->isFieldPresent(sfSponsor));
1619 BEAST_EXPECT(checkSle->getAccountID(sfSponsor) == sponsor2.
id());
1621 BEAST_EXPECT(sponsor1Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1623 BEAST_EXPECT(sponsor2Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1642 BEAST_EXPECT(!checkSle->isFieldPresent(sfSponsor));
1644 BEAST_EXPECT(sponsor2Sle->getFieldU32(sfRemainingOwnerCount) == 99);
1656 auto const seq = env.
seq(alice);
1696 auto const seq = env.
seq(alice);
1742 auto const& highAcc = alice > bob ? alice : bob;
1743 auto const& lowAcc = alice > bob ? bob : alice;
1745 for (
bool const isIssuerHigh : {
false,
true})
1751 auto const& issuer = isIssuerHigh ? highAcc : lowAcc;
1752 auto const& user = isIssuerHigh ? lowAcc : highAcc;
1754 auto const usd = issuer[
"usd"];
1755 auto const currency = usd.currency;
1757 env(
trust(user, issuer[
"usd"](100)));
1761 BEAST_EXPECT(env.
le(trustId));
1769 BEAST_EXPECT(env.
le(trustId));
1772 env.
le(trustId)->getAccountID(isIssuerHigh ? sfLowSponsor : sfHighSponsor) ==
1775 !env.
le(trustId)->isFieldPresent(isIssuerHigh ? sfHighSponsor : sfLowSponsor));
1781 BEAST_EXPECT(env.
le(trustId));
1783 !env.
le(trustId)->isFieldPresent(isIssuerHigh ? sfLowSponsor : sfHighSponsor));
1785 !env.
le(trustId)->isFieldPresent(isIssuerHigh ? sfHighSponsor : sfLowSponsor));
1808 auto const keylets = {
1816 for (
auto const&
keylet : keylets)
1834 auto const checkBlocked = [&](
Account const& account,
uint256 const& objectID) {
1842 auto const ticketSeq = env.
seq(alice);
1847 checkBlocked(alice, ticketID);
1852 BEAST_EXPECT(env.
le(didKeylet));
1853 checkBlocked(alice, didKeylet.key);
1858 BEAST_EXPECT(env.
le(nftPageKeylet));
1859 checkBlocked(alice, nftPageKeylet.key);
1861 Account const borrower(
"borrower");
1862 env.
fund(
XRP(1000000), borrower);
1866 Vault const vault{env};
1867 auto [vaultTx, vaultKeylet] = vault.create({.owner = alice, .asset = xrpAsset});
1872 {.depositor = alice, .id = vaultKeylet.key, .amount = xrpAsset(1000)}));
1875 auto const brokerKeylet =
1885 env(
loan::set(borrower, brokerKeylet.key, xrpAsset(100).value()),
1886 Sig(sfCounterpartySignature, alice),
1889 BEAST_EXPECT(env.
le(loanKeylet));
1890 checkBlocked(borrower, loanKeylet.key);
1907 env.
fund(
XRP(10000), alice, bob);
1913 auto aliceBalance = env.
balance(alice);
1914 auto bobBalance = env.
balance(bob);
1917 env(
pay(alice, bob,
XRP(100)),
1923 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
1924 BEAST_EXPECT(env.
balance(bob) == bobBalance);
1933 auto aliceBalance = env.
balance(alice);
1934 auto bobBalance = env.
balance(bob);
1937 auto const sendAmt =
XRP(100);
1938 auto const feeAmt =
XRP(10);
1939 env(
pay(alice, bob, sendAmt),
1944 BEAST_EXPECT(env.
balance(alice) == aliceBalance - sendAmt);
1945 BEAST_EXPECT(env.
balance(bob) == bobBalance + sendAmt);
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);
1969 auto aliceBalance = env.
balance(alice);
1970 auto bobBalance = env.
balance(bob);
1972 auto const feeAmt =
XRP(10);
1974 env(
pay(alice, bob,
XRP(20000)),
1981 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
1982 BEAST_EXPECT(env.
balance(bob) == bobBalance);
1991 auto const feeAmt =
XRP(10);
2038 auto aliceBalance = env.
balance(alice);
2039 auto bobBalance = env.
balance(bob);
2042 env(
pay(alice, bob,
XRP(100)),
2047 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2048 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2057 auto aliceBalance = env.
balance(alice);
2058 auto bobBalance = env.
balance(bob);
2062 auto const sendAmt =
XRP(100);
2063 auto const feeAmt =
XRP(10);
2067 BEAST_EXPECT(env.
balance(alice) == aliceBalance - sendAmt);
2068 BEAST_EXPECT(env.
balance(bob) == bobBalance + sendAmt);
2078 auto aliceBalance = env.
balance(alice);
2079 auto bobBalance = env.
balance(bob);
2083 env(
pay(alice, bob,
XRP(100)),
2089 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2090 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2097 auto aliceBalance = env.
balance(alice);
2098 auto bobBalance = env.
balance(bob);
2101 env(
pay(alice, bob,
XRP(100)),
2107 BEAST_EXPECT(env.
balance(alice) == aliceBalance -
XRP(100));
2108 BEAST_EXPECT(env.
balance(bob) == bobBalance +
XRP(100));
2122 auto aliceBalance = env.
balance(alice);
2123 auto bobBalance = env.
balance(bob);
2127 env(
pay(alice, bob,
XRP(100)),
2133 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2134 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2143 auto aliceBalance = env.
balance(alice);
2144 auto bobBalance = env.
balance(bob);
2147 auto const feeAmt =
XRP(1);
2149 env(
pay(alice, bob,
XRP(20000)),
2155 BEAST_EXPECT(env.
balance(alice) == aliceBalance);
2156 BEAST_EXPECT(env.
balance(bob) == bobBalance);
2173 Fee(sponsorAvailableFee),
2188 Account const carol(
"sponsor");
2190 env.
fund(
XRP(10000), alice, carol);
2209 BEAST_EXPECT(result.applied);
2214 BEAST_EXPECT(sle->isFieldPresent(sfFeeAmount));
2215 BEAST_EXPECT(sle->getFieldAmount(sfFeeAmount) ==
drops(990));
2228 auto const fixFee =
drops(env.
current()->fees().increment);
2238 BEAST_EXPECT(!sle->isFieldPresent(sfFeeAmount));
2250 auto const fixFee =
drops(env.
current()->fees().increment);
2266 if (BEAST_EXPECT(original))
2269 sle->makeFieldAbsent(sfFeeAmount);
2273 auto const result =
doApply(pc, env.
app(), overlay);
2275 BEAST_EXPECT(!result.applied);
2292 env(
pay(alice, bob,
XRP(100)),
2326 env(
pay(alice, bob,
XRP(100)),
2333 env(
pay(alice, bob,
XRP(100)),
2353 Account const sponsor2(
"sponsor2");
2354 Account const sponsor3(
"sponsor3");
2356 Account const charlie(
"charlie");
2359 auto const usd = gw[
"usd"];
2381 env(
pay(alice, bob,
XRP(100)),
2382 Txflags(tfSponsorCreatedAccount | flag),
2394 Txflags(tfSponsorCreatedAccount),
2400 Txflags(tfSponsorCreatedAccount),
2407 env(
pay(alice, bob,
drops(env.
current()->fees().accountReserve(0, 1))),
2413 BEAST_EXPECT(!bobSle->isFieldPresent(sfSponsor));
2422 Txflags(tfSponsorCreatedAccount),
2427 BEAST_EXPECT(env.
balance(sponsor2) ==
XRP(9999));
2431 Txflags(tfSponsorCreatedAccount),
2436 auto const sponsor2BalanceBefore = env.
balance(sponsor2);
2441 BEAST_EXPECT(charlieSle->isFieldPresent(sfSponsor));
2442 BEAST_EXPECT(charlieSle->getAccountID(sfSponsor) == sponsor2.
id());
2446 BEAST_EXPECT(env.
balance(sponsor2) == sponsor2BalanceBefore -
drops(1) -
XRP(1));
2451 auto const sendAmount =
drops(1);
2455 env(
pay(sponsor3, dave, sendAmount),
2456 Txflags(tfSponsorCreatedAccount),
2462 env(
pay(sponsor3, dave, sendAmount),
2463 Txflags(tfSponsorCreatedAccount),
2475 testcase(
"SponsorshipRequireSignForReserve");
2510 testcase(
"SponsorshipRequireSignForFee");
2598 template <
typename SubmitCallback>
2605 uint32_t reserveCount,
2606 uint32_t sponsorReserveCount,
2607 TER insufficientReserveResult,
2608 SubmitCallback callback,
2612 auto const sponseeOwnerCountBefore =
ownerCount(env, sponsee);
2625 auto submit = [&](
TER ter) {
2626 return [&, ter](
json::Value const& jv,
auto const&... fN) {
2645 reserve(env, sponsorCurrentOwnerCount + sponsorReserveCount) -
drops(1));
2656 if (sponsorReserveCount > 1)
2671 auto const sponseeOwnerCountBeforeAttempt =
ownerCount(env, sponsee);
2673 auto const sponseeSponsoringOwnerCountBeforeAttempt =
2677 auto const sponsorSponsoringOwnerCountBeforeAttempt =
2680 bool const reserveCountPresentBeforeAttempt = sponsorshipSleBeforeAttempt &&
2681 sponsorshipSleBeforeAttempt->isFieldPresent(sfRemainingOwnerCount);
2682 std::uint32_t const reserveCountBeforeAttempt = reserveCountPresentBeforeAttempt
2683 ? sponsorshipSleBeforeAttempt->getFieldU32(sfRemainingOwnerCount)
2686 callback(env, submit(insufficientReserveResult));
2689 BEAST_EXPECT(
ownerCount(env, sponsee) == sponseeOwnerCountBeforeAttempt);
2702 static_cast<bool>(sponsorshipSleAfterAttempt) ==
2703 static_cast<bool>(sponsorshipSleBeforeAttempt));
2704 if (sponsorshipSleAfterAttempt)
2707 sponsorshipSleAfterAttempt->isFieldPresent(sfRemainingOwnerCount) ==
2708 reserveCountPresentBeforeAttempt);
2709 if (reserveCountPresentBeforeAttempt)
2712 sponsorshipSleAfterAttempt->getFieldU32(sfRemainingOwnerCount) ==
2713 reserveCountBeforeAttempt);
2723 env,
sponsor,
reserve(env, sponsorCurrentOwnerCount + sponsorReserveCount));
2740 BEAST_EXPECT(sponsorshipSle);
2742 !sponsorshipSle->isFieldPresent(sfRemainingOwnerCount) ||
2743 sponsorshipSle->getFieldU32(sfRemainingOwnerCount) == 0);
2757 BEAST_EXPECT(
ownerCount(env, sponsee) - sponseeOwnerCountBefore == reserveCount);
2760 sponsorReserveCount);
2767 sponsorReserveCount);
2780 Account const sponsor2(
"sponsor2");
2782 auto const usd = gw[
"usd"];
2800 [&](
Env& env,
auto const& submit) {
2801 seq = env.
seq(alice);
2811 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) ==
sponsor.id());
2818 Sig(sfSponsorSignature, sponsor2));
2838 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) == sponsor2.
id());
2865 [&](
Env& env,
auto const& submit) {
2866 seq2 = env.
seq(alice);
2891 env.
trust(usd(100), alice);
2893 env(
pay(gw, alice, usd(100)));
2906 [&](
Env& env,
auto const& submit) {
2907 seq2 = env.
seq(alice);
2915 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) ==
sponsor.id());
2936 bool const bobLow = bob.
id() < gw.
id();
2938 BEAST_EXPECT(lineSle);
2942 lineSle->getAccountID(bobLow ? sfLowSponsor : sfHighSponsor) ==
2945 !lineSle->isFieldPresent(bobLow ? sfHighSponsor : sfLowSponsor));
2958 MPTTester mptGw(env, gw, {.holders = {alice}});
2959 mptGw.
create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
2960 mptGw.authorize({.account = alice});
2961 auto const mpt = mptGw[
"MPT"];
2962 env(
pay(gw, alice, mpt(10'000)));
2975 [&](
Env& env,
auto const& submit) {
2976 seq2 = env.
seq(alice);
2981 BEAST_EXPECT(env.
le(checkKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
2993 [&](
Env& env,
auto const& submit) {
2994 submit(
check::cash(bob, checkKeylet.key, mpt(1)));
3015 Account const sponsor2(
"sponsor2");
3031 [&](
Env& env,
auto const& submit) {
3037 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) ==
sponsor.id());
3044 Sig(sfSponsorSignature, sponsor2));
3061 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) == sponsor2.
id());
3080 Account const sponsor2(
"sponsor2");
3101 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) ==
sponsor.id());
3108 Sig(sfSponsorSignature, sponsor2));
3121 BEAST_EXPECT(sponsor2Sle);
3125 !sponsor2Sle->isFieldPresent(sfRemainingOwnerCount) ||
3126 sponsor2Sle->getFieldU32(sfRemainingOwnerCount) == 0);
3134 BEAST_EXPECT(env.
le(
keylet)->getAccountID(sfSponsor) == sponsor2.
id());
3151 {.issuer =
sponsor, .credType = credType}};
3155 {sponsor.id(), Slice(credType.data(), credType.size())}});
3166 [&](
Env&,
auto const& submit) {
3171 BEAST_EXPECT(env.
le(preauthKeylet));
3172 BEAST_EXPECT(env.
le(preauthKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3180 BEAST_EXPECT(!env.
le(preauthKeylet));
3195 Account const sponsor2(
"sponsor2");
3212 [&](
Env& env,
auto const& submit) {
3217 BEAST_EXPECT(env.
le(credKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3229 Sig(sfSponsorSignature, sponsor2));
3245 BEAST_EXPECT(env.
le(credKeylet)->getAccountID(sfSponsor) == sponsor2.
id());
3272 [&](
Env& env,
auto const& submit) {
3278 BEAST_EXPECT(env.
le(credKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3334 [&](
Env& env,
auto const& submit) {
3344 BEAST_EXPECT(env.
le(credKeylet)->getAccountID(sfSponsor) ==
sponsor.id());
3357 using namespace std::chrono_literals;
3362 Account const sponsor2(
"sponsor2");
3366 auto const baseFee = env.
current()->fees().base;
3381 [&](
Env& env,
auto const& submit) {
3382 seq = env.
seq(alice);
3390 ->getAccountID(sfSponsor) ==
sponsor.id());
3397 tfSponsorshipReassign,
3400 Sig(sfSponsorSignature, sponsor2));
3410 tfSponsorshipReassign,
3423 ->getAccountID(sfSponsor) == sponsor2.
id());
3429 Fee(baseFee * 150));
3439 auto const usd = gw[
"usd"];
3443 auto const baseFee = env.
current()->fees().base;
3448 env(
fset(gw, asfAllowTrustLineLocking));
3451 env.
trust(usd(1000000), alice);
3453 env(
pay(gw, alice, usd(10000)));
3468 [&](
Env& env,
auto const& submit) {
3469 seq = env.
seq(alice);
3478 ->getAccountID(sfSponsor) ==
sponsor.id());
3489 [&](
Env& env,
auto const& submit) {
3494 Fee(baseFee * 150));
3509 auto const baseFee = env.
current()->fees().base;
3514 env(
fset(gw, asfAllowTrustLineLocking));
3517 env.
trust(usd(1000000), alice);
3519 env(
pay(gw, alice, usd(10000)));
3531 [&](
Env& env,
auto const& submit) {
3532 seq = env.
seq(alice);
3541 ->getAccountID(sfSponsor) ==
sponsor.id());
3596 env(
fset(gw, asfAllowTrustLineLocking));
3599 env.
trust(usd(1000000), alice);
3601 env(
pay(gw, alice, usd(10000)));
3607 auto const cancelAfter = env.
now() + 100s;
3608 auto const seq = env.
seq(alice);
3617 env(
trust(alice, usd(0)));
3623 for (; env.
now() < cancelAfter; env.
close())
3631 bool const aliceLow = alice.
id() < gw.
id();
3640 [&](
Env& env,
auto const& submit) { submit(
escrow::cancel(alice, alice, seq)); },
3644 BEAST_EXPECT(trustSle);
3648 trustSle->getAccountID(aliceLow ? sfLowSponsor : sfHighSponsor) ==
3651 !trustSle->isFieldPresent(aliceLow ? sfHighSponsor : sfLowSponsor));
3664 MPTTester mptGw(env, gw, {.holders = {alice}});
3666 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3667 mptGw.authorize({.account = alice});
3668 auto const mpt = mptGw[
"MPT"];
3669 env(
pay(gw, alice, mpt(10'000)));
3673 auto const seq = env.
seq(alice);
3695 [&](
Env& env,
auto const& submit) {
3715 auto const baseFee = env.
current()->fees().base;
3719 MPTTester mptGw(env, gw, {.holders = {alice}});
3721 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3722 mptGw.authorize({.account = alice});
3723 auto const mpt = mptGw[
"MPT"];
3724 env(
pay(gw, alice, mpt(10'000)));
3736 [&](
Env& env,
auto const& submit) {
3737 seq = env.
seq(alice);
3746 ->getAccountID(sfSponsor) ==
sponsor.id());
3803 auto const escrowAmount =
XRP(2);
3804 auto const seq = env.
seq(alice);
3843 Account const sponsor2(
"sponsor2");
3852 jv[sfAccount] = alice.
human();
3853 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3863 [&](
Env& env,
auto const& submit) {
3875 Sig(sfSponsorSignature, sponsor2));
3890 jv[sfTransactionType] = jss::MPTokenAuthorize;
3891 jv[sfAccount] = bob.
human();
3892 jv[sfMPTokenIssuanceID] =
to_string(mptid);
3909 [&](
Env& env,
auto const& submit) { submit(jv); });
3920 Sig(sfSponsorSignature, sponsor2));
3942 jv[sfTransactionType] = jss::MPTokenAuthorize;
3943 jv[sfAccount] = bob.
human();
3944 jv[sfMPTokenIssuanceID] =
to_string(mptid);
3945 jv[sfFlags] = tfMPTUnauthorize;
3957 jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
3958 jv[sfAccount] = alice.
human();
3959 jv[sfMPTokenIssuanceID] =
to_string(mptid);
3975 jv[sfAccount] = alice.
human();
3976 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3987 jv[sfTransactionType] = jss::MPTokenAuthorize;
3988 jv[sfAccount] = bob.
human();
3989 jv[sfMPTokenIssuanceID] =
to_string(mptid);
4042 Account const sponsor2(
"sponsor2");
4050 auto const pk = alice.
pk();
4051 auto const settleDelay = 10s;
4061 [&](
Env& env,
auto const& submit) {
4067 BEAST_EXPECT(env.
le(
Keylet(ltPAYCHAN, chan))->getAccountID(sfSponsor) ==
sponsor.id());
4074 Sig(sfSponsorSignature, sponsor2));
4091 BEAST_EXPECT(env.
le(
Keylet(ltPAYCHAN, chan))->getAccountID(sfSponsor) == sponsor2.
id());
4093 env.
close(env.
now() + settleDelay);
4117 auto const pk = alice.
pk();
4118 auto const settleDelay = 10s;
4119 auto const channelAmount =
XRP(2);
4155 Account const sponsor2(
"sponsor2");
4170 [&](
Env& env,
auto const& submit) { submit(
signers(alice, 1, {{bob, 1}})); });
4182 Sig(sfSponsorSignature, sponsor2),
4186 env(
signers(bob, 1, {{alice, 1}}));
4190 Sig(sfSponsorSignature, sponsor2),
4194 Sig(sfSponsorSignature, sponsor2));
4227 testcase(
"Legacy SignerList sponsorship reserve");
4241 env(
signers(alice, 1, {{bob, 1}, {carol, 1}, {dave, 1}}));
4252 if (
auto const sle = env.
le(sponsorKeylet); BEAST_EXPECT(sle))
4253 BEAST_EXPECT(sle->getFieldU32(sfRemainingOwnerCount) == legacyWeight);
4260 signerList->clearFlag(lsfOneOwnerCount);
4261 account->setFieldU32(sfOwnerCount, legacyWeight);
4266 if (
auto const sle = env.
le(signerListKeylet); BEAST_EXPECT(sle))
4267 BEAST_EXPECT((sle->getFlags() & lsfOneOwnerCount) == 0);
4268 BEAST_EXPECT(
ownerCount(env, alice) == legacyWeight);
4278 if (
auto const sle = env.
le(sponsorKeylet); BEAST_EXPECT(sle))
4279 BEAST_EXPECT(!sle->isFieldPresent(sfRemainingOwnerCount));
4285 BEAST_EXPECT(!env.
le(signerListKeylet));
4289 if (
auto const sle = env.
le(sponsorKeylet); BEAST_EXPECT(sle))
4290 BEAST_EXPECT(!sle->isFieldPresent(sfRemainingOwnerCount));
4299 testcase(
"Sponsored trust line gets no free-reserve exception");
4302 Account const issuer(
"issuer");
4310 auto const usd = issuer[
"usd"];
4319 env(
trust(alice, usd(100)),
4325 BEAST_EXPECT(!env.
le(lineKeylet));
4332 env(
trust(alice, usd(100)),
4337 BEAST_EXPECT(env.
le(lineKeylet));
4348 testcase(
"Co-signed reserve sponsorship is bounded by Sponsorship budget");
4353 Account const sponsee(
"sponsee");
4399 Account const charlie(
"charlie");
4401 Account const sponsor2(
"sponsor2");
4403 auto const validateSponsoredTrustline =
4406 sle->getAccountID(isIssuerHigh ? sfLowSponsor : sfHighSponsor) ==
sponsor.id());
4407 BEAST_EXPECT(!sle->isFieldPresent(isIssuerHigh ? sfHighSponsor : sfLowSponsor));
4410 auto const& highAcc = alice > bob ? alice : bob;
4411 auto const& lowAcc = alice > bob ? bob : alice;
4414 for (
bool const isIssuerHigh : {
false,
true})
4420 auto const& issuer = isIssuerHigh ? highAcc : lowAcc;
4421 auto const& user = isIssuerHigh ? lowAcc : highAcc;
4423 auto const usd = issuer[
"usd"];
4424 auto const currency = usd.currency;
4442 [&](
Env& env,
auto const& submit) { submit(
trust(user, usd(100))); });
4451 Sig(sfSponsorSignature, sponsor2),
4456 Sig(sfSponsorSignature, sponsor2),
4460 Sig(sfSponsorSignature, sponsor2));
4473 env(
trust(user, usd(0)));
4484 for (
bool const isIssuerHigh : {
false,
true})
4490 auto const& issuer = isIssuerHigh ? highAcc : lowAcc;
4491 auto const& user = isIssuerHigh ? lowAcc : highAcc;
4493 auto const usd = issuer[
"usd"];
4494 auto const currency = usd.currency;
4497 env(
trust(issuer, user[
"usd"](100)));
4517 [&](
Env& env,
auto const& submit) { submit(
trust(user, usd(100))); });
4520 validateSponsoredTrustline(line, isIssuerHigh,
sponsor);
4523 env(
trust(user, usd(0)));
4532 env(
trust(issuer, user[
"usd"](0)));
4544 env(
trust(alice, bob[
"usd"](100)),
4548 env(
trust(bob, alice[
"usd"](100)),
4555 BEAST_EXPECT(sle->isFlag(lsfHighReserve));
4556 BEAST_EXPECT(sle->isFlag(lsfLowReserve));
4557 BEAST_EXPECT(sle->getAccountID(sfHighSponsor) ==
sponsor.id());
4558 BEAST_EXPECT(sle->getAccountID(sfLowSponsor) ==
sponsor.id());
4567 env(
trust(alice, bob[
"usd"](0)));
4569 env(
trust(bob, alice[
"usd"](0)));
4606 auto const sponsorObj = env.
le(
keylet);
4607 BEAST_EXPECT(sponsorObj);
4610 auto const requiredFee =
drops(env.
current()->fees().increment);
4629 auto const requiredFee =
drops(env.
current()->fees().increment);
4634 BEAST_EXPECT(aliceSle);
4636 BEAST_EXPECT(aliceSle->getAccountID(sfSponsor) ==
sponsor.id());
4639 BEAST_EXPECT(sponsorSle->getFieldU32(sfSponsoringAccountCount) == 1);
4647 BEAST_EXPECT(!sponsorSle2->isFieldPresent(sfSponsoringAccountCount));
4657 auto const usd = gw[
"usd"];
4660 env(
trust(alice, usd(1000)));
4665 BEAST_EXPECT(env.
le(trustId));
4674 BEAST_EXPECT(sponsorSle->isFieldPresent(sfSponsoringOwnerCount));
4681 auto const requiredFee =
drops(env.
current()->fees().increment);
4685 BEAST_EXPECT(sponsorSleAfter->isFieldPresent(sfSponsoringOwnerCount));
4703 BEAST_EXPECT(sponsorSle->isFieldPresent(sfSponsoringAccountCount));
4710 auto const requiredFee =
drops(env.
current()->fees().increment);
4714 BEAST_EXPECT(sponsorSleAfter->isFieldPresent(sfSponsoringAccountCount));
4733 BEAST_EXPECT(sponsorSle->at(sfSponsoringOwnerCount) == 1);
4734 BEAST_EXPECT(aliceSle->at(sfOwnerCount) == 1);
4735 BEAST_EXPECT(aliceSle->at(sfSponsoredOwnerCount) == 1);
4742 auto const requiredFee =
drops(env.
current()->fees().increment);
4746 BEAST_EXPECT(sponsorSle->at(sfSponsoringOwnerCount) == 0);
4765 env.
fund(
XRP(1000000), alice, bob, carol);
4768 auto const seq = env.
seq(alice);
4776 Sig(sfSponsorSignature, bob),
4787 env.
fund(
XRP(1000000), alice, bob, carol);
4809 testcase(
"Delegate Block Reserve Sponsor");
4852 testcase(
"Delegate Sponsor Fee Payer");
4868 auto const aliceBalance = env.
balance(alice);
4869 auto const bobBalance = env.
balance(bob);
4870 auto const carolBalance = env.
balance(carol);
4872 auto const sendAmt =
XRP(100);
4873 auto const feeAmt =
XRP(10);
4875 env(
pay(alice, carol, sendAmt),
4882 BEAST_EXPECT(env.
balance(alice) == aliceBalance - sendAmt);
4883 BEAST_EXPECT(env.
balance(bob) == bobBalance);
4884 BEAST_EXPECT(env.
balance(carol) == carolBalance + sendAmt);
4900 auto const aliceBalance = env.
balance(alice);
4901 auto const bobBalance = env.
balance(bob);
4902 auto const carolBalance = env.
balance(carol);
4905 auto const sendAmt =
XRP(100);
4906 auto const feeAmt =
XRP(10);
4912 env(
pay(alice, carol, sendAmt),
4918 BEAST_EXPECT(env.
balance(alice) == aliceBalance - sendAmt);
4919 BEAST_EXPECT(env.
balance(bob) == bobBalance);
4920 BEAST_EXPECT(env.
balance(carol) == carolBalance + sendAmt);
4945 auto const seq = env.
seq(alice);
4960 BEAST_EXPECT(env.
balance(alice) ==
XRP(1000));
4971 auto const seq = env.
seq(alice);
4984 env.
fund(
XRP(1000), alice, bob);
4994 auto const seq = env.
seq(alice);
5008 BEAST_EXPECT(env.
balance(alice) ==
XRP(1000));
5012 BEAST_EXPECT(sponsorshipSle);
5013 BEAST_EXPECT(sponsorshipSle->at(sfFeeAmount) ==
XRP(100 - 1));
5014 BEAST_EXPECT(sponsorshipSle->at(sfRemainingOwnerCount) == 100);
5021 Account const signerAccount(
"signer");
5036 auto const seq = env.
seq(alice);
5039 BEAST_EXPECT(jt.jv[sfSponsorSignature.jsonName].isMember(sfTxnSignature.jsonName));
5050 Msig(sfSponsorSignature,
sponsor, signerAccount));
5053 auto const seq = env.
seq(alice);
5056 BEAST_EXPECT(jt.jv[sfSponsorSignature.jsonName].isMember(sfSigners.jsonName));
5069 jt.jv[sfSponsorSignature.jsonName].
removeMember(sfTxnSignature.jsonName);
5070 jt.jv[sfSponsorSignature.jsonName][sfSigningPubKey.jsonName] =
"";
5072 auto const seq = env.
seq(alice);
5084 env.
fund(
XRP(1000), alice, bob);
5100 auto const seq = env.
seq(alice);
5113 BEAST_EXPECT(env.
balance(alice) ==
XRP(999));
5118 BEAST_EXPECT(sponsorshipSle);
5119 BEAST_EXPECT(sponsorshipSle->at(sfFeeAmount) ==
XRP(100));
5120 BEAST_EXPECT(sponsorshipSle->at(sfRemainingOwnerCount) == 99);
5135 jt.jv[sfSponsorSignature.jsonName].
removeMember(sfTxnSignature.jsonName);
5136 jt.jv[sfSponsorSignature.jsonName][sfSigningPubKey.jsonName] =
"";
5138 auto const seq = env.
seq(alice);
5152 BEAST_EXPECT(env.
balance(alice) ==
XRP(999));
5166 auto const seq = env.
seq(alice);
5170 auto innerPay =
pay(alice, bob,
XRP(1));
5171 innerPay[sfSponsor.jsonName] =
sponsor.human();
5175 env(
batch::outer(alice, seq, batchFee, tfAllOrNothing),
5188 auto const seq = env.
seq(alice);
5191 auto innerPay =
pay(alice, bob,
XRP(1));
5192 innerPay[sfSponsor.jsonName] =
sponsor.human();
5196 env(
batch::outer(alice, seq, batchFee, tfAllOrNothing),
5210 auto const seq = env.
seq(alice);
5214 innerTx[sfSponsor.jsonName] =
sponsor.human();
5215 innerTx[sfSponsorFlags.jsonName] =
5219 env(
batch::outer(alice, seq, batchFee, tfAllOrNothing),
5232 auto const seq = env.
seq(bob);
5254 testcase(
"Reserve sponsor allow-list gate");
5275 checkBlocked(
offer(alice,
XRP(100), bob[
"USD"](100)));
5303 testcase(
"Sponsored Payment: minimal-balance account with sponsor-pays-fee");
5305 using namespace jtx;
5311 auto const baseFee = env.
current()->fees().base;
5312 auto const baseReserve = env.
current()->fees().reserve;
5316 env.
fund(baseReserve +
XRP(1), alice);
5320 BEAST_EXPECT(env.
balance(alice) == baseReserve +
XRP(1));
5324 auto const preDest = env.
balance(dest);
5328 env(
pay(alice, dest,
XRP(1)),
5336 BEAST_EXPECT(env.
balance(alice) == baseReserve);
5339 BEAST_EXPECT(env.
balance(dest) == preDest +
XRP(1));
5357 testcase(
"TrustSet modify with sponsor does not misroute onto counterparty side");
5362 Account const alice{
"alice_t2178"};
5363 Account const bob{
"bob_t2178"};
5364 Account const carol{
"carol_t2178"};
5367 env.
fund(
XRP(100'000), alice, bob, carol);
5371 bool const aliceIsHigh = alice.
id() > bob.
id();
5379 auto const issuer = aliceIsHigh ? bob : alice;
5380 auto const holder = aliceIsHigh ? alice : bob;
5381 auto const usd = issuer[
"USD"];
5385 env(
fclear(issuer, asfDefaultRipple));
5391 env(
trust(holder, usd(1'000)));
5397 env(
fset(issuer, asfDefaultRipple));
5400 SF_ACCOUNT const& issuerSponsorField = aliceIsHigh ? sfLowSponsor : sfHighSponsor;
5401 SF_ACCOUNT const& holderSponsorField = aliceIsHigh ? sfHighSponsor : sfLowSponsor;
5404 auto const sleLineBefore = env.
le(lineKey);
5405 if (!BEAST_EXPECT(sleLineBefore))
5407 BEAST_EXPECT(!sleLineBefore->isFieldPresent(sfLowSponsor));
5408 BEAST_EXPECT(!sleLineBefore->isFieldPresent(sfHighSponsor));
5411 BEAST_EXPECT(carolBefore == 0);
5413 BEAST_EXPECT(issuerSponsoredBefore == 0);
5418 env(
trust(holder, usd(2'000)),
5420 Sig(sfSponsorSignature, carol),
5424 auto const sleLineAfter = env.
le(lineKey);
5425 if (!BEAST_EXPECT(sleLineAfter))
5429 BEAST_EXPECT(!sleLineAfter->isFieldPresent(issuerSponsorField));
5433 BEAST_EXPECT(!sleLineAfter->isFieldPresent(holderSponsorField));
5437 BEAST_EXPECT(carolAfter == carolBefore);
5441 BEAST_EXPECT(issuerSponsoredAfter == issuerSponsoredBefore);
5447 testcase(
"Self-escrow finish reserve order gated by amendment");
5449 using namespace std::chrono_literals;
5461 auto const usd = gw[
"usd"];
5463 Env env{*
this, features};
5464 auto const baseFee = env.
current()->fees().base;
5466 env.
fund(
XRP(10000), alice, gw);
5469 env(
fset(gw, asfAllowTrustLineLocking));
5472 env.
trust(usd(1000), alice);
5474 env(
pay(gw, alice, usd(100)));
5479 auto const seq = env.
seq(alice);
5488 env(
trust(alice, usd(0)));
5498 BEAST_EXPECT(env.
balance(alice) == target);
5511 BEAST_EXPECT(env.
balance(alice, usd) == usd(100));
5541 testcase(
"Fee-sponsored VaultDeposit/VaultWithdraw pass ValidVault invariant");
5551 Vault const vault{env};
5552 auto [vaultTx, vaultKeylet] = vault.create({.owner = alice, .asset = xrpAsset});
5557 env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = xrpAsset(100)}),
5562 env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = xrpAsset(100)}),
5572 env(vault.withdraw({.depositor = alice, .id = vaultKeylet.key, .amount = xrpAsset(50)}),
5585 testcase(
"Sponsored object deletion refunds sponsor owner count");
5599 Account const checkOwner(
"check_owner");
5600 Account const dest(
"check_dest");
5601 env.
fund(
XRP(100000), checkOwner, dest);
5606 auto const checkSeq = env.
seq(checkOwner);
5613 BEAST_EXPECT(sponsorCountBefore == 1);
5621 BEAST_EXPECT(sponsorCountAfter == 0);
5627 testcase(
" — TrustLine deletion");
5629 Account const issuer(
"issuer");
5630 Account const holder(
"holder");
5631 env.
fund(
XRP(100000), issuer, holder);
5634 auto const usd = issuer[
"USD"];
5637 env(
trust(holder, usd(1000)),
5643 BEAST_EXPECT(sponsorCountBefore == 1);
5646 env(
trust(holder, usd(0)));
5650 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(modify_type const &f)
Modify the open ledger.
Writable ledger view that accumulates state and tx changes.
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.
void rawReplace(SLE::ref sle) override
Unconditionally replace a state item.
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{})
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 unchecked(uint256 const &key) noexcept
Any ledger entry.
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Keylet loan(uint256 const &loanBrokerID, SeqProxy const &loanSeq) noexcept
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 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 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 create(A const &account, A const &dest, STAmount const &sendMax)
Create 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 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 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)
uint256 channel(AccountID const &account, AccountID const &dst, std::uint32_t seqProxyValue)
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)
bool channelExists(ReadView const &view, uint256 const &chan)
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.