21#include <xrpl/protocol/Feature.h>
33 return env.
current()->fees().accountReserve(count);
94 IOU const USD = gw[
"USD"];
98 env.
fund(
XRP(10000), alice, bob, carol, gw);
99 env.
trust(USD(1000), alice, bob);
102 env(
pay(gw, alice, USD(150)));
103 env(
offer(carol, USD(100),
XRP(100)));
107 env(
pay(alice, bob, USD(50)));
115 auto failedIouPayments = [
this, &env, &alice, &bob, &USD]() {
132 BEAST_EXPECT(bobXrpBalance == env.
balance(bob,
XRP));
133 BEAST_EXPECT(bobUsdBalance == env.
balance(bob, USD));
141 env(
pay(bob, alice, USD(25)));
147 env(
pay(bob, alice, bobPaysXRP),
fee(bobPaysFee));
153 BEAST_EXPECT(env.
balance(bob, USD) == USD(25));
170 env(
pay(alice, bob, USD(50)));
190 env.
fund(
XRP(10000), alice, bob);
206 env(
pay(bob, alice, bobPaysXRP),
fee(bobPaysFee));
292 IOU const USD1(gw1[
"USD"]);
293 IOU const USD2(gw2[
"USD"]);
298 bool withDepositAuth) {
299 assert(!withDepositAuth || features[featureDepositAuth]);
301 Env env(*
this, features);
303 env.
fund(
XRP(10000), gw1, alice, bob);
306 env.
trust(USD1(10), alice, bob);
308 env(
pay(gw1, alice, USD1(10)));
315 env(
pay(alice, bob, USD1(10)),
path(gw1),
ter(result));
321 bool withDepositAuth) {
322 assert(!withDepositAuth || features[featureDepositAuth]);
324 Env env(*
this, features);
326 env.
fund(
XRP(10000), gw1, gw2, alice);
329 env(
pay(gw2, alice, USD2(10)));
336 env(
pay(gw1, gw2, USD2(10)),
343 for (
int i = 0; i < 8; ++i)
345 auto const noRipplePrev = i & 0x1;
346 auto const noRippleNext = i & 0x2;
347 auto const withDepositAuth = i & 0x4;
354 if (!withDepositAuth)
367 if (!withDepositAuth)
393 jvParams[jss::ledger_index] = jss::validated;
394 jvParams[jss::deposit_preauth][jss::owner] = acc.
human();
395 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
397 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
398 for (
auto const& o :
auth)
400 arr.append(o.toLEJson());
402 return env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
418 env.
fund(
XRP(10000), alice, becky);
440 env.
fund(
XRP(10000), alice, becky);
459 env.
fund(
XRP(10000), alice, becky);
476 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
484 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
509 env.
fund(
XRP(10000), alice, becky);
530 tx[sfUnauthorize.jsonName] = becky.human();
616 IOU const USD(gw[
"USD"]);
618 bool const supportsPreauth = {features[featureDepositPreauth]};
624 Env env(*
this, features);
625 env.
fund(
XRP(5000), alice, becky, gw);
628 env.
trust(USD(1000), alice);
629 env.
trust(USD(1000), becky);
632 env(
pay(gw, alice, USD(500)));
653 env(
pay(becky, becky, USD(10)),
661 const char credType[] =
"abcde";
665 bool const supportsCredentials = features[featureCredentials];
667 TER const expectCredentials(
669 TER const expectPayment(
686 ter(expectCredentials));
689 ter(expectCredentials));
694 ? jv[jss::result][jss::index].asString()
695 :
"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6"
698 env(
pay(gw, becky, USD(100)),
707 if (!supportsPreauth)
709 auto const seq1 = env.
seq(alice);
715 env(
finish(gw, alice, seq1),
729 Env env(*
this, features);
730 env.
fund(
XRP(5000), alice, becky, carol, gw);
733 env.
trust(USD(1000), alice);
734 env.
trust(USD(1000), becky);
735 env.
trust(USD(1000), carol);
738 env(
pay(gw, alice, USD(1000)));
742 env(
pay(alice, becky,
XRP(100)));
743 env(
pay(alice, becky, USD(100)));
770 env(
pay(alice, becky,
XRP(100)));
771 env(
pay(alice, becky, USD(100)));
788 env(
pay(alice, becky,
XRP(100)));
789 env(
pay(alice, becky, USD(100)));
805 env(
pay(alice, becky,
XRP(100)));
806 env(
pay(alice, becky, USD(100)));
816 const char credType[] =
"abcde";
817 Account const issuer{
"issuer"};
824 testcase(
"Payment failed with disabled credentials rule.");
828 env.
fund(
XRP(5000), issuer, bob, alice);
847 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
849 env(
pay(alice, bob,
XRP(10)),
856 testcase(
"Payment with credentials.");
860 env.
fund(
XRP(5000), issuer, alice, bob, john);
870 std::string const credIdx = jv[jss::result][jss::index].asString();
884 jDP.isObject() && jDP.isMember(jss::result) &&
885 !jDP[jss::result].isMember(jss::error) &&
886 jDP[jss::result].isMember(jss::node) &&
887 jDP[jss::result][jss::node].isMember(
"LedgerEntryType") &&
888 jDP[jss::result][jss::node][
"LedgerEntryType"] ==
889 jss::DepositPreauth);
893 auto jv =
pay(alice, bob,
XRP(100));
900 env(
pay(alice, bob,
XRP(100)),
926 testcase(
"Payment failed with invalid credentials.");
930 env.
fund(
XRP(10000), issuer, alice, bob, maria);
942 std::string const credIdx = jv[jss::result][jss::index].asString();
956 env(
pay(alice, bob,
XRP(100)),
963 bob, {{issuer, credType}, {issuer, credType}}),
972 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
975 env(
pay(alice, bob,
XRP(100)),
982 env(
pay(maria, bob,
XRP(100)),
989 const char credType2[] =
"fghij";
997 jv[jss::result][jss::index].asString();
1000 env(
pay(alice, bob,
XRP(100)),
1006 env(
pay(alice, bob,
XRP(100)),
1019 using namespace jtx;
1021 const char credType[] =
"abcde";
1022 Account const issuer{
"issuer"};
1028 testcase(
"Creating / deleting with credentials.");
1032 env.
fund(
XRP(5000), issuer, alice, bob);
1045 jv[sfUnauthorize.jsonName] = issuer.human();
1052 jv[sfAuthorize.jsonName] = issuer.human();
1059 jv[sfUnauthorize.jsonName] = issuer.human();
1066 jv[sfAuthorize.jsonName] = issuer.human();
1079 auto& arr(jv[sfAuthorizeCredentials.jsonName]);
1082 cred[sfCredentialType.jsonName] =
1085 credParent[jss::Credential] = cred;
1086 arr.
append(std::move(credParent));
1099 Account const a(
"a"), b(
"b"), c(
"c"), d(
"d"), e(
"e"), f(
"f"),
1100 g(
"g"), h(
"h"), i(
"i");
1101 auto const& z = credType;
1127 env.
fund(env.
current()->fees().accountReserve(0), john);
1146 jDP.isObject() && jDP.isMember(jss::result) &&
1147 !jDP[jss::result].isMember(jss::error) &&
1148 jDP[jss::result].isMember(jss::node) &&
1149 jDP[jss::result][jss::node].isMember(
"LedgerEntryType") &&
1150 jDP[jss::result][jss::node][
"LedgerEntryType"] ==
1151 jss::DepositPreauth);
1155 jDP[jss::result][jss::node][jss::Account] == bob.human());
1156 auto const& credentials(
1157 jDP[jss::result][jss::node][
"AuthorizeCredentials"]);
1158 BEAST_EXPECT(credentials.isArray() && credentials.size() == 1);
1159 for (
auto const& o : credentials)
1161 auto const& c(o[jss::Credential]);
1162 BEAST_EXPECT(c[jss::Issuer].asString() == issuer.human());
1164 c[
"CredentialType"].asString() ==
1180 jDP.isObject() && jDP.isMember(jss::result) &&
1181 jDP[jss::result].isMember(jss::error) &&
1182 jDP[jss::result][jss::error] ==
"entryNotFound");
1190 using namespace jtx;
1191 const char credType[] =
"abcde";
1192 const char credType2[] =
"fghijkl";
1193 Account const issuer{
"issuer"};
1197 IOU const USD = gw[
"USD"];
1201 testcase(
"Payment failed with expired credentials.");
1205 env.
fund(
XRP(10000), issuer, alice, bob, gw);
1214 .parentCloseTime.time_since_epoch()
1217 jv[sfExpiration.jsonName] = t;
1229 .parentCloseTime.time_since_epoch()
1232 jv[sfExpiration.jsonName] = t2;
1243 std::string const credIdx = jv[jss::result][jss::index].asString();
1245 std::string const credIdx2 = jv[jss::result][jss::index].asString();
1252 bob, {{issuer, credType}, {issuer, credType2}}));
1257 env(
pay(alice, bob,
XRP(100)),
1263 env(
pay(alice, bob,
XRP(100)),
1270 auto const jDelCred =
1273 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1274 jDelCred[jss::result].isMember(jss::error) &&
1275 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1283 jle.isObject() && jle.isMember(jss::result) &&
1284 !jle[jss::result].isMember(jss::error) &&
1285 jle[jss::result].isMember(jss::node) &&
1286 jle[jss::result][jss::node].isMember(
1287 "LedgerEntryType") &&
1288 jle[jss::result][jss::node][
"LedgerEntryType"] ==
1290 jle[jss::result][jss::node][jss::Issuer] ==
1292 jle[jss::result][jss::node][jss::Subject] ==
1294 jle[jss::result][jss::node][
"CredentialType"] ==
1306 .parentCloseTime.time_since_epoch()
1309 jv[sfExpiration.jsonName] = t;
1317 jv[jss::result][jss::index].asString();
1327 env(
pay(gw, bob, USD(150)),
1333 auto const jDelCred =
1336 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1337 jDelCred[jss::result].isMember(jss::error) &&
1338 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1348 testcase(
"Escrow failed with expired credentials.");
1352 env.
fund(
XRP(5000), issuer, alice, bob, zelda);
1359 .parentCloseTime.time_since_epoch()
1362 jv[sfExpiration.jsonName] = t;
1372 std::string const credIdx = jv[jss::result][jss::index].asString();
1381 auto const seq = env.
seq(alice);
1396 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
1414 auto const jDelCred =
1417 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1418 jDelCred[jss::result].isMember(jss::error) &&
1419 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1426 using namespace jtx;
1436 env.
fund(
XRP(5000), stock, alice, bob);
1448 for (
auto const& c : credentials)
1449 env.
fund(
XRP(5000), c.issuer);
1457 for (
auto const& c : credentials)
1458 pubKey2Acc.
emplace(c.issuer.human(), c.issuer);
1461 for (
int i = 0; i < 10; ++i)
1463 std::ranges::shuffle(credentials, gen);
1469 auto const& authCred(
1470 dp[jss::result][jss::node][
"AuthorizeCredentials"]);
1472 authCred.isArray() &&
1473 authCred.size() == credentials.size());
1475 for (
auto const& o : authCred)
1477 auto const& c(o[jss::Credential]);
1478 auto issuer = c[jss::Issuer].asString();
1480 if (BEAST_EXPECT(pubKey2Acc.
contains(issuer)))
1482 pubKey2Acc.
at(issuer),
1483 c[
"CredentialType"].asString());
1486 BEAST_EXPECT(std::ranges::is_sorted(readedCreds));
1494 std::ranges::shuffle(credentials, gen);
1499 for (
int i = 0; i < 10; ++i)
1501 std::ranges::shuffle(credentials, gen);
1507 testcase(
"Check duplicate credentials.");
1511 credentials.
begin(), credentials.
end() - 1);
1513 std::ranges::shuffle(copyCredentials, gen);
1514 for (
auto const& c : copyCredentials)
1516 auto credentials2 = copyCredentials;
1524 for (
auto const& c : credentials)
1535 c.credType)[jss::result][jss::index]
1540 for (
auto const& h : credentialIDs)
1542 auto credentialIDs2 = credentialIDs;
1545 env(
pay(alice, bob,
XRP(100)),
1558 testPayment(supported - featureDepositPreauth - featureCredentials);
1569BEAST_DEFINE_TESTSUITE(DepositAuth, app,
ripple);
Value & append(const Value &value)
Append value to array at the end.
Value removeMember(const char *key)
Remove and return the named member.
std::string asString() const
Returns the unquoted string value.
testcase_t testcase
Memberspace for declaring test cases.
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
NetClock::time_point now()
Returns the current network time.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
void memoize(Account const &account)
Associate AccountID with account.
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Converts to IOU Issue or STAmount.
Match clear account flags.
Match the number of items in the account's owner directory.
Check a set of conditions.
Sets the SendMax 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.
T emplace_back(T... args)
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
Json::Value create(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 ledgerEntry(jtx::Env &env, jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Json::Value unauth(Account const &account, Account const &unauth)
Remove preauthorization for deposit.
Json::Value auth(Account const &account, Account const &auth)
Preauthorize for deposit.
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 create(Account const &account, std::uint32_t count)
Create one of more tickets.
std::uint32_t ownerCount(Env const &env, Account const &account)
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Json::Value escrow(AccountID const &account, AccountID const &to, STAmount const &amount)
owner_count< ltOFFER > offers
Match the number of offers in the account's owner directory.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Json::Value noop(Account const &account)
The null transaction.
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
owner_count< ltTICKET > tickets
Match the number of tickets on the account.
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
static Json::Value ledgerEntryDepositPreauth(jtx::Env &env, jtx::Account const &acc, std::vector< jtx::deposit::AuthorizeCredentials > const &auth)
static bool hasDepositAuth(jtx::Env const &env, jtx::Account const &acct)
static XRPAmount reserve(jtx::Env &env, std::uint32_t count)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t asfDepositAuth
AccountID const & xrpAccount()
Compute AccountID from public key.
constexpr std::uint32_t tfPassive
std::string strHex(FwdIt begin, FwdIt end)
@ tecINSUFFICIENT_RESERVE
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t tfSell
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfSetNoRipple
void run() override
Runs the suite.
void testCredentialsCreation()
void testPayment(FeatureBitset features)
void run() override
Runs the suite.
void testSortingCredentials()
void testCredentialsPayment()
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Set the "FinishAfter" time tag on a JTx.
Set the sequence number on a JTx.