3#include <xrpl/protocol/Feature.h>
4#include <xrpl/protocol/jss.h>
26 Json::Value const meta = env.
rpc(
"tx", txHash)[jss::result][jss::meta];
29 if (!BEAST_EXPECT(meta.
isMember(sfDeliveredAmount.jsonName)))
35 BEAST_EXPECT(meta[sfDeliveredAmount.jsonName] == jsonExpect);
36 BEAST_EXPECT(meta[jss::delivered_amount] == jsonExpect);
50 jv[jss::TransactionType] = jss::PaymentChannelCreate;
51 jv[jss::Account] = account.human();
52 jv[jss::Destination] = to.
human();
54 jv[sfSettleDelay.jsonName] = settleDelay.
count();
74 env.fund(
XRP(10000), alice, becky, carol, gw);
88 auto const acctDelFee{
drops(env.current()->fees().increment)};
98 env(
trust(becky, gw[
"USD"](1000)));
105 env(
offer(carol, gw[
"USD"](51),
XRP(51)));
108 env(
signers(carol, 1, {{alice, 1}, {becky, 1}}));
127 auto const aliceOldBalance{env.balance(alice)};
128 auto const beckyOldBalance{env.balance(becky)};
143 BEAST_EXPECT(env.balance(becky) == aliceOldBalance + beckyOldBalance - acctDelFee);
164 for (
int i = 0; i < 8; ++i)
168 auto const beckyOldBalance{env.balance(becky)};
169 auto const carolOldBalance{env.balance(carol)};
176 BEAST_EXPECT(env.closed()->exists(
keylet::offer(carol.
id(), carolOfferSeq)));
177 BEAST_EXPECT(env.closed()->exists(
keylet::ticket(carol.
id(), carolTicketSeq)));
190 BEAST_EXPECT(!env.closed()->exists(
keylet::offer(carol.
id(), carolOfferSeq)));
191 BEAST_EXPECT(!env.closed()->exists(
keylet::ticket(carol.
id(), carolTicketSeq)));
195 BEAST_EXPECT(env.balance(becky) == carolOldBalance + beckyOldBalance - acctDelFee);
217 env.fund(
XRP(10000), alice, gw);
221 for (
int i{0}; i < 45; ++i)
223 env(
offer(alice, gw[
"USD"](1),
XRP(1)));
226 env.require(
offers(alice, 45));
234 BEAST_EXPECT(env.closed()->exists(aliceRootKey));
235 BEAST_EXPECT(env.closed()->exists(alicePageKey));
238 auto const acctDelFee{
drops(env.current()->fees().increment)};
239 auto const aliceBalance{env.balance(alice)};
245 BEAST_EXPECT(!env.closed()->exists(aliceRootKey));
246 BEAST_EXPECT(!env.closed()->exists(alicePageKey));
262 env.fund(
XRP(100000), alice, becky, gw);
268 for (
int i{0}; i < 200; ++i)
270 env(
offer(alice, gw[
"USD"](1),
XRP(1)));
271 env(
offer(becky, gw[
"USD"](1),
XRP(1)));
274 env.require(
offers(alice, 200));
275 env.require(
offers(becky, 200));
289 auto const acctDelFee{
drops(env.current()->fees().increment)};
300 using namespace std::chrono_literals;
316 bool const withTokenEscrow = env.current()->rules().enabled(featureTokenEscrow);
321 auto const USD = gw1[
"USD"];
322 env.fund(
XRP(100000), carol, gw1);
323 env(
fset(gw1, asfAllowTrustLineLocking));
325 env.trust(USD(10000), carol);
327 env(
pay(gw1, carol, USD(100)));
355 auto const beckyBalance{env.balance(becky)};
367 jv[jss::TransactionType] = jss::PaymentChannelClaim;
368 jv[jss::Flags] = tfClose;
369 jv[jss::Account] = account.human();
370 jv[sfChannel.jsonName] =
to_string(payChanKeylet.key);
371 jv[sfPublicKey.jsonName] =
strHex(pk.slice());
374 env(payChanClose(alice, alicePayChanKey, alice.
pk()));
390 env(payChanClose(alice, gwPayChanKey, alice.
pk()));
394 auto const aliceBalance{env.balance(alice)};
413 env.fund(
XRP(10000000), alice, gw);
423 constexpr int offerCount{1001};
424 for (
int i{0}; i < offerCount; ++i)
426 env(
offer(alice, gw[currency](1),
XRP(1)));
431 if (currency[0] >
'Z')
436 if (currency[1] >
'Z')
441 if (currency[2] >
'Z')
457 BEAST_EXPECT(closed->exists(aliceOwnerDirKey));
461 BEAST_EXPECT(closed->exists(
keylet::page(aliceOwnerDirKey, i)));
465 BEAST_EXPECT(closed->exists(
keylet::offer(alice.
id(), offerSeq0 + i)));
470 auto const acctDelFee{
drops(env.current()->fees().increment)};
475 env.require(
offers(alice, offerCount));
478 env.require(
offers(alice, offerCount - 1));
481 auto const alicePreDelBal{env.balance(alice)};
491 BEAST_EXPECT(!closed->exists(aliceOwnerDirKey));
495 BEAST_EXPECT(!closed->exists(
keylet::page(aliceOwnerDirKey, i)));
499 BEAST_EXPECT(!closed->exists(
keylet::offer(alice.
id(), offerSeq0 + i)));
510 testcase(
"Implicitly created trust line");
515 auto const BUX{gw[
"BUX"]};
517 env.fund(
XRP(10000), alice, gw);
522 env(
offer(alice, BUX(30),
XRP(30)));
528 env.require(
balance(alice, BUX(30)));
535 auto const acctDelFee{
drops(env.current()->fees().increment)};
555 testcase(
"Balance too small for fee");
563 env.fund(env.current()->fees().reserve,
noripple(alice));
568 env(
noop(alice),
fee(env.balance(alice) -
XRP(1)));
571 auto const acctDelFee{
drops(env.current()->fees().increment)};
572 BEAST_EXPECT(acctDelFee > env.balance(alice));
578 auto const masterBalance{env.balance(env.master)};
584 BEAST_EXPECT(env.balance(env.master) == masterBalance);
589 BEAST_EXPECT(env.balance(alice) ==
XRP(1));
595 BEAST_EXPECT(env.balance(env.master) == masterBalance);
604 using namespace test::jtx;
610 env.
fund(
XRP(100000), alice, bob);
617 env.require(
owners(bob, 250));
624 BEAST_EXPECT(closed->exists(
keylet::ticket(bob.id(), ticketSeq + i)));
633 auto const acctDelFee{
drops(env.current()->fees().increment)};
634 auto const bobOldBalance{env.balance(bob)};
643 BEAST_EXPECT(!closed->exists(
keylet::ticket(bob.id(), ticketSeq + i)));
651 testcase(
"Destination Constraints");
653 using namespace test::jtx;
661 env.
fund(
XRP(100000), alice, becky, carol);
667 env(
fset(alice, asfDepositAuth));
670 env(
fset(carol, asfRequireDest));
678 auto const acctDelFee{
drops(env.current()->fees().increment)};
697 auto const beckyOldBalance{env.balance(becky)};
707 testcase(
"Destination Constraints with DepositPreauth and Credentials");
709 using namespace test::jtx;
716 char const credType[] =
"abcd";
719 env.
fund(
XRP(100000), alice, becky, carol, daria);
728 std::string const credIdx = jv[jss::result][jss::index].asString();
733 auto const acctDelFee{
drops(env.current()->fees().increment)};
746 env(
fset(alice, asfDepositAuth));
787 credentials::ids({
"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6E"
801 jNoCred.isObject() && jNoCred.isMember(jss::result) &&
802 jNoCred[jss::result].isMember(jss::error) &&
803 jNoCred[jss::result][jss::error] ==
"entryNotFound");
806 testcase(
"Credentials that aren't required");
825 jNoCred.isObject() && jNoCred.isMember(jss::result) &&
826 jNoCred[jss::result].isMember(jss::error) &&
827 jNoCred[jss::result][jss::error] ==
"entryNotFound");
834 env.fund(
XRP(5000), eaton, fred);
846 env(
fset(fred, asfDepositAuth));
853 auto const acctDelFee{
drops(env.current()->fees().increment)};
864 jNoCred.isObject() && jNoCred.isMember(jss::result) &&
865 jNoCred[jss::result].isMember(jss::error) &&
866 jNoCred[jss::result][jss::error] ==
"entryNotFound");
873 env.fund(
XRP(10000), john);
878 env.current()->header().parentCloseTime.time_since_epoch().count() + 20;
879 jv[sfExpiration.jsonName] = t;
885 std::string const credIdx = jv[jss::result][jss::index].asString();
901 jv.isObject() && jv.isMember(jss::result) &&
902 jv[jss::result].isMember(jss::error) &&
903 jv[jss::result][jss::error] ==
"entryNotFound");
909 testcase(
"Credentials feature disabled");
910 using namespace test::jtx;
917 env.fund(
XRP(100000), alice, becky, carol);
923 env(
fset(alice, asfDepositAuth));
929 auto const acctDelFee{
drops(env.current()->fees().increment)};
932 "098B7F1B146470A1C5084DC7832C04A72939E3EBC58E68AB8B579BA072B0CE"
951 testcase(
"Deleting Issuer deletes issued credentials");
953 using namespace test::jtx;
959 char const credType[] =
"abcd";
962 env.
fund(
XRP(100000), alice, becky, carol);
973 std::string const credIdx = jv[jss::result][jss::index].asString();
978 auto const acctDelFee{
drops(env.current()->fees().increment)};
983 BEAST_EXPECT(!env.le(credIdx));
986 jv.isObject() && jv.isMember(jss::result) &&
987 jv[jss::result].isMember(jss::error) &&
988 jv[jss::result][jss::error] ==
"entryNotFound");
993 testcase(
"Deleting Subject deletes issued credentials");
995 using namespace test::jtx;
1001 char const credType[] =
"abcd";
1004 env.
fund(
XRP(100000), alice, becky, carol);
1015 std::string const credIdx = jv[jss::result][jss::index].asString();
1020 auto const acctDelFee{
drops(env.current()->fees().increment)};
1025 BEAST_EXPECT(!env.le(credIdx));
1028 jv.isObject() && jv.isMember(jss::result) &&
1029 jv[jss::result].isMember(jss::error) &&
1030 jv[jss::result][jss::error] ==
"entryNotFound");
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
testcase_t testcase
Memberspace for declaring test cases.
Slice slice() const noexcept
void run() override
Runs the suite.
static Json::Value payChanCreate(jtx::Account const &account, jtx::Account const &to, STAmount const &amount, NetClock::duration const &settleDelay, NetClock::time_point const &cancelAfter, PublicKey const &pk)
void testDeleteCredentialsOwner()
void verifyDeliveredAmount(jtx::Env &env, STAmount const &amount)
void testBalanceTooSmallForFee()
void testDestinationDepositAuthCredentials()
void testImplicitlyCreatedTrustline()
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
PublicKey const & pk() const
Return the public key.
static Account const master
The master account.
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.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
Set a multisignature on a JTx.
Match the number of items in the account's owner directory.
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.
Set a ticket sequence on a JTx.
Keylet signers(AccountID const &account) noexcept
A SignerList.
static ticket_t const ticket
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Json::Value create(A const &account, A const &dest, STAmount const &sendMax)
Create a check.
Json::Value cancel(jtx::Account const &dest, uint256 const &checkId)
Cancel a check.
Json::Value accept(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Json::Value ledgerEntry(jtx::Env &env, 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)
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 setValid(jtx::Account const &account)
auto const finish_time
Set the "FinishAfter" time tag on a JTx.
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 cancel_time
Set the "CancelAfter" time tag on a JTx.
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
XRP_t const XRP
Converts to XRP Issue or STAmount.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
void incLgrSeqForAccDel(jtx::Env &env, jtx::Account const &acc, std::uint32_t margin=0)
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
FeatureBitset testable_amendments()
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
owner_count< ltOFFER > offers
Match the number of offers in the account's owner directory.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string to_string(base_uint< Bits, Tag > const &a)
std::string strHex(FwdIt begin, FwdIt end)
A pair of SHAMap key and LedgerEntryType.
T time_since_epoch(T... args)