22#include <xrpl/protocol/Feature.h>
34 return env.
current()->fees().accountReserve(count);
95 IOU const USD = gw[
"USD"];
99 env.
fund(
XRP(10000), alice, bob, carol, gw);
100 env.
trust(USD(1000), alice, bob);
103 env(
pay(gw, alice, USD(150)));
104 env(
offer(carol, USD(100),
XRP(100)));
108 env(
pay(alice, bob, USD(50)));
116 auto failedIouPayments = [
this, &env, &alice, &bob, &USD]() {
133 BEAST_EXPECT(bobXrpBalance == env.
balance(bob,
XRP));
134 BEAST_EXPECT(bobUsdBalance == env.
balance(bob, USD));
142 env(
pay(bob, alice, USD(25)));
148 env(
pay(bob, alice, bobPaysXRP),
fee(bobPaysFee));
154 BEAST_EXPECT(env.
balance(bob, USD) == USD(25));
171 env(
pay(alice, bob, USD(50)));
191 env.
fund(
XRP(10000), alice, bob);
207 env(
pay(bob, alice, bobPaysXRP),
fee(bobPaysFee));
293 IOU const USD1(gw1[
"USD"]);
294 IOU const USD2(gw2[
"USD"]);
299 bool withDepositAuth) {
300 assert(!withDepositAuth || features[featureDepositAuth]);
302 Env env(*
this, features);
304 env.
fund(
XRP(10000), gw1, alice, bob);
307 env.
trust(USD1(10), alice, bob);
309 env(
pay(gw1, alice, USD1(10)));
316 env(
pay(alice, bob, USD1(10)),
path(gw1),
ter(result));
322 bool withDepositAuth) {
323 assert(!withDepositAuth || features[featureDepositAuth]);
325 Env env(*
this, features);
327 env.
fund(
XRP(10000), gw1, gw2, alice);
330 env(
pay(gw2, alice, USD2(10)));
337 env(
pay(gw1, gw2, USD2(10)),
344 for (
int i = 0; i < 8; ++i)
346 auto const noRipplePrev = i & 0x1;
347 auto const noRippleNext = i & 0x2;
348 auto const withDepositAuth = i & 0x4;
355 if (!withDepositAuth)
368 if (!withDepositAuth)
394 jvParams[jss::ledger_index] = jss::validated;
395 jvParams[jss::deposit_preauth][jss::owner] = acc.
human();
396 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
398 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
399 for (
auto const& o :
auth)
401 arr.append(o.toLEJson());
403 return env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
419 env.
fund(
XRP(10000), alice, becky);
441 env.
fund(
XRP(10000), alice, becky);
460 env.
fund(
XRP(10000), alice, becky);
477 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
485 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
510 env.
fund(
XRP(10000), alice, becky);
531 tx[sfUnauthorize.jsonName] = becky.human();
617 IOU const USD(gw[
"USD"]);
619 bool const supportsPreauth = {features[featureDepositPreauth]};
625 Env env(*
this, features);
626 env.
fund(
XRP(5000), alice, becky, gw);
629 env.
trust(USD(1000), alice);
630 env.
trust(USD(1000), becky);
633 env(
pay(gw, alice, USD(500)));
654 env(
pay(becky, becky, USD(10)),
662 const char credType[] =
"abcde";
666 bool const supportsCredentials = features[featureCredentials];
668 TER const expectCredentials(
670 TER const expectPayment(
687 ter(expectCredentials));
690 ter(expectCredentials));
695 ? jv[jss::result][jss::index].asString()
696 :
"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6"
699 env(
pay(gw, becky, USD(100)),
708 if (!supportsPreauth)
710 auto const seq1 = env.
seq(alice);
716 env(
finish(gw, alice, seq1),
730 Env env(*
this, features);
731 env.
fund(
XRP(5000), alice, becky, carol, gw);
734 env.
trust(USD(1000), alice);
735 env.
trust(USD(1000), becky);
736 env.
trust(USD(1000), carol);
739 env(
pay(gw, alice, USD(1000)));
743 env(
pay(alice, becky,
XRP(100)));
744 env(
pay(alice, becky, USD(100)));
771 env(
pay(alice, becky,
XRP(100)));
772 env(
pay(alice, becky, USD(100)));
789 env(
pay(alice, becky,
XRP(100)));
790 env(
pay(alice, becky, USD(100)));
806 env(
pay(alice, becky,
XRP(100)));
807 env(
pay(alice, becky, USD(100)));
817 const char credType[] =
"abcde";
818 Account const issuer{
"issuer"};
825 testcase(
"Payment failed with disabled credentials rule.");
829 env.
fund(
XRP(5000), issuer, bob, alice);
848 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
850 env(
pay(alice, bob,
XRP(10)),
857 testcase(
"Payment with credentials.");
861 env.
fund(
XRP(5000), issuer, alice, bob, john);
871 std::string const credIdx = jv[jss::result][jss::index].asString();
885 jDP.isObject() && jDP.isMember(jss::result) &&
886 !jDP[jss::result].isMember(jss::error) &&
887 jDP[jss::result].isMember(jss::node) &&
888 jDP[jss::result][jss::node].isMember(
"LedgerEntryType") &&
889 jDP[jss::result][jss::node][
"LedgerEntryType"] ==
890 jss::DepositPreauth);
894 auto jv =
pay(alice, bob,
XRP(100));
901 env(
pay(alice, bob,
XRP(100)),
927 testcase(
"Payment failed with invalid credentials.");
931 env.
fund(
XRP(10000), issuer, alice, bob, maria);
943 std::string const credIdx = jv[jss::result][jss::index].asString();
957 env(
pay(alice, bob,
XRP(100)),
964 bob, {{issuer, credType}, {issuer, credType}}),
973 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
976 env(
pay(alice, bob,
XRP(100)),
983 env(
pay(maria, bob,
XRP(100)),
990 const char credType2[] =
"fghij";
998 jv[jss::result][jss::index].asString();
1001 env(
pay(alice, bob,
XRP(100)),
1007 env(
pay(alice, bob,
XRP(100)),
1020 using namespace jtx;
1022 const char credType[] =
"abcde";
1023 Account const issuer{
"issuer"};
1029 testcase(
"Creating / deleting with credentials.");
1033 env.
fund(
XRP(5000), issuer, alice, bob);
1046 jv[sfUnauthorize.jsonName] = issuer.human();
1053 jv[sfAuthorize.jsonName] = issuer.human();
1060 jv[sfUnauthorize.jsonName] = issuer.human();
1067 jv[sfAuthorize.jsonName] = issuer.human();
1080 auto& arr(jv[sfAuthorizeCredentials.jsonName]);
1083 cred[sfCredentialType.jsonName] =
1086 credParent[jss::Credential] = cred;
1087 arr.
append(std::move(credParent));
1100 Account const a(
"a"), b(
"b"), c(
"c"), d(
"d"), e(
"e"), f(
"f"),
1101 g(
"g"), h(
"h"), i(
"i");
1102 auto const& z = credType;
1128 env.
fund(env.
current()->fees().accountReserve(0), john);
1147 jDP.isObject() && jDP.isMember(jss::result) &&
1148 !jDP[jss::result].isMember(jss::error) &&
1149 jDP[jss::result].isMember(jss::node) &&
1150 jDP[jss::result][jss::node].isMember(
"LedgerEntryType") &&
1151 jDP[jss::result][jss::node][
"LedgerEntryType"] ==
1152 jss::DepositPreauth);
1156 jDP[jss::result][jss::node][jss::Account] == bob.human());
1157 auto const& credentials(
1158 jDP[jss::result][jss::node][
"AuthorizeCredentials"]);
1159 BEAST_EXPECT(credentials.isArray() && credentials.size() == 1);
1160 for (
auto const& o : credentials)
1162 auto const& c(o[jss::Credential]);
1163 BEAST_EXPECT(c[jss::Issuer].asString() == issuer.human());
1165 c[
"CredentialType"].asString() ==
1181 jDP.isObject() && jDP.isMember(jss::result) &&
1182 jDP[jss::result].isMember(jss::error) &&
1183 jDP[jss::result][jss::error] ==
"entryNotFound");
1191 using namespace jtx;
1192 const char credType[] =
"abcde";
1193 const char credType2[] =
"fghijkl";
1194 Account const issuer{
"issuer"};
1198 IOU const USD = gw[
"USD"];
1202 testcase(
"Payment failed with expired credentials.");
1206 env.
fund(
XRP(10000), issuer, alice, bob, gw);
1215 .parentCloseTime.time_since_epoch()
1218 jv[sfExpiration.jsonName] = t;
1230 .parentCloseTime.time_since_epoch()
1233 jv[sfExpiration.jsonName] = t2;
1244 std::string const credIdx = jv[jss::result][jss::index].asString();
1246 std::string const credIdx2 = jv[jss::result][jss::index].asString();
1253 bob, {{issuer, credType}, {issuer, credType2}}));
1258 env(
pay(alice, bob,
XRP(100)),
1264 env(
pay(alice, bob,
XRP(100)),
1271 auto const jDelCred =
1274 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1275 jDelCred[jss::result].isMember(jss::error) &&
1276 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1284 jle.isObject() && jle.isMember(jss::result) &&
1285 !jle[jss::result].isMember(jss::error) &&
1286 jle[jss::result].isMember(jss::node) &&
1287 jle[jss::result][jss::node].isMember(
1288 "LedgerEntryType") &&
1289 jle[jss::result][jss::node][
"LedgerEntryType"] ==
1291 jle[jss::result][jss::node][jss::Issuer] ==
1293 jle[jss::result][jss::node][jss::Subject] ==
1295 jle[jss::result][jss::node][
"CredentialType"] ==
1307 .parentCloseTime.time_since_epoch()
1310 jv[sfExpiration.jsonName] = t;
1318 jv[jss::result][jss::index].asString();
1328 env(
pay(gw, bob, USD(150)),
1334 auto const jDelCred =
1337 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1338 jDelCred[jss::result].isMember(jss::error) &&
1339 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1349 testcase(
"Escrow failed with expired credentials.");
1353 env.
fund(
XRP(5000), issuer, alice, bob, zelda);
1360 .parentCloseTime.time_since_epoch()
1363 jv[sfExpiration.jsonName] = t;
1373 std::string const credIdx = jv[jss::result][jss::index].asString();
1382 auto const seq = env.
seq(alice);
1397 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
1415 auto const jDelCred =
1418 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1419 jDelCred[jss::result].isMember(jss::error) &&
1420 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1427 using namespace jtx;
1437 env.
fund(
XRP(5000), stock, alice, bob);
1449 for (
auto const& c : credentials)
1450 env.
fund(
XRP(5000), c.issuer);
1458 for (
auto const& c : credentials)
1459 pubKey2Acc.
emplace(c.issuer.human(), c.issuer);
1462 for (
int i = 0; i < 10; ++i)
1464 std::ranges::shuffle(credentials, gen);
1470 auto const& authCred(
1471 dp[jss::result][jss::node][
"AuthorizeCredentials"]);
1473 authCred.isArray() &&
1474 authCred.size() == credentials.size());
1476 for (
auto const& o : authCred)
1478 auto const& c(o[jss::Credential]);
1479 auto issuer = c[jss::Issuer].asString();
1481 if (BEAST_EXPECT(pubKey2Acc.
contains(issuer)))
1483 pubKey2Acc.
at(issuer),
1484 c[
"CredentialType"].asString());
1487 BEAST_EXPECT(std::ranges::is_sorted(readedCreds));
1495 std::ranges::shuffle(credentials, gen);
1500 for (
int i = 0; i < 10; ++i)
1502 std::ranges::shuffle(credentials, gen);
1508 testcase(
"Check duplicate credentials.");
1512 credentials.
begin(), credentials.
end() - 1);
1514 std::ranges::shuffle(copyCredentials, gen);
1515 for (
auto const& c : copyCredentials)
1517 auto credentials2 = copyCredentials;
1525 for (
auto const& c : credentials)
1536 c.credType)[jss::result][jss::index]
1541 for (
auto const& h : credentialIDs)
1543 auto credentialIDs2 = credentialIDs;
1546 env(
pay(alice, bob,
XRP(100)),
1559 testPayment(supported - featureDepositPreauth - featureCredentials);
1570BEAST_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.