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);
101 env.
trust(USD(1000), alice, bob);
104 env(
pay(gw, alice, USD(150)));
105 env(
offer(carol, USD(100),
XRP(100)));
109 env(
pay(alice, bob, USD(50)));
117 auto failedIouPayments = [
this, &env, &alice, &bob, &USD]() {
134 BEAST_EXPECT(bobXrpBalance == env.
balance(bob,
XRP));
135 BEAST_EXPECT(bobUsdBalance == env.
balance(bob, USD));
143 env(
pay(bob, alice, USD(25)));
149 env(
pay(bob, alice, bobPaysXRP),
fee(bobPaysFee));
155 BEAST_EXPECT(env.
balance(bob, USD) == USD(25));
172 env(
pay(alice, bob, USD(50)));
191 auto const baseFee = env.
current()->fees().base;
193 env.
fund(
XRP(10000), alice, bob);
210 env(
pay(bob, alice, bobPaysXRP),
fee(bobPaysFee));
266 env(
pay(alice, bob,
drops(baseFee - 1)));
296 IOU const USD1(gw1[
"USD"]);
297 IOU const USD2(gw2[
"USD"]);
302 bool withDepositAuth) {
303 assert(!withDepositAuth || features[featureDepositAuth]);
305 Env env(*
this, features);
307 env.
fund(
XRP(10000), gw1, alice, bob);
311 env.
trust(USD1(10), alice, bob);
313 env(
pay(gw1, alice, USD1(10)));
320 env(
pay(alice, bob, USD1(10)),
path(gw1),
ter(result));
326 bool withDepositAuth) {
327 assert(!withDepositAuth || features[featureDepositAuth]);
329 Env env(*
this, features);
331 env.
fund(
XRP(10000), gw1, gw2, alice);
335 env(
pay(gw2, alice, USD2(10)));
342 env(
pay(gw1, gw2, USD2(10)),
349 for (
int i = 0; i < 8; ++i)
351 auto const noRipplePrev = i & 0x1;
352 auto const noRippleNext = i & 0x2;
353 auto const withDepositAuth = i & 0x4;
360 if (!withDepositAuth)
373 if (!withDepositAuth)
399 jvParams[jss::ledger_index] = jss::validated;
400 jvParams[jss::deposit_preauth][jss::owner] = acc.
human();
401 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
403 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
404 for (
auto const& o :
auth)
406 arr.append(o.toLEJson());
408 return env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
424 env.
fund(
XRP(10000), alice, becky);
446 env.
fund(
XRP(10000), alice, becky);
465 env.
fund(
XRP(10000), alice, becky);
482 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
490 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
515 env.
fund(
XRP(10000), alice, becky);
536 tx[sfUnauthorize.jsonName] = becky.human();
622 IOU const USD(gw[
"USD"]);
624 bool const supportsPreauth = {features[featureDepositPreauth]};
630 Env env(*
this, features);
631 env.
fund(
XRP(5000), alice, becky, gw);
634 env.
trust(USD(1000), alice);
635 env.
trust(USD(1000), becky);
638 env(
pay(gw, alice, USD(500)));
659 env(
pay(becky, becky, USD(10)),
667 char const credType[] =
"abcde";
672 bool const supportsCredentials = features[featureCredentials];
674 TER const expectCredentials(
676 TER const expectPayment(
693 ter(expectCredentials));
696 ter(expectCredentials));
701 ? jv[jss::result][jss::index].asString()
702 :
"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6"
705 env(
pay(gw, becky, USD(100)),
714 if (!supportsPreauth)
716 auto const seq1 = env.
seq(alice);
736 Env env(*
this, features);
737 env.
fund(
XRP(5000), alice, becky, carol, gw);
740 env.
trust(USD(1000), alice);
741 env.
trust(USD(1000), becky);
742 env.
trust(USD(1000), carol);
745 env(
pay(gw, alice, USD(1000)));
749 env(
pay(alice, becky,
XRP(100)));
750 env(
pay(alice, becky, USD(100)));
777 env(
pay(alice, becky,
XRP(100)));
778 env(
pay(alice, becky, USD(100)));
795 env(
pay(alice, becky,
XRP(100)));
796 env(
pay(alice, becky, USD(100)));
812 env(
pay(alice, becky,
XRP(100)));
813 env(
pay(alice, becky, USD(100)));
823 char const credType[] =
"abcde";
824 Account const issuer{
"issuer"};
831 testcase(
"Payment failure with disabled credentials rule.");
835 env.
fund(
XRP(5000), issuer, bob, alice);
854 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
856 env(
pay(alice, bob,
XRP(10)),
863 testcase(
"Payment with credentials.");
867 env.
fund(
XRP(5000), issuer, alice, bob, john);
877 std::string const credIdx = jv[jss::result][jss::index].asString();
891 jDP.isObject() && jDP.isMember(jss::result) &&
892 !jDP[jss::result].isMember(jss::error) &&
893 jDP[jss::result].isMember(jss::node) &&
894 jDP[jss::result][jss::node].isMember(
"LedgerEntryType") &&
895 jDP[jss::result][jss::node][
"LedgerEntryType"] ==
896 jss::DepositPreauth);
900 auto jv =
pay(alice, bob,
XRP(100));
907 env(
pay(alice, bob,
XRP(100)),
933 testcase(
"Payment failure with invalid credentials.");
937 env.
fund(
XRP(10000), issuer, alice, bob, maria);
949 std::string const credIdx = jv[jss::result][jss::index].asString();
963 env(
pay(alice, bob,
XRP(100)),
970 bob, {{issuer, credType}, {issuer, credType}}),
979 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
982 env(
pay(alice, bob,
XRP(100)),
989 env(
pay(maria, bob,
XRP(100)),
996 char const credType2[] =
"fghij";
1004 jv[jss::result][jss::index].asString();
1007 env(
pay(alice, bob,
XRP(100)),
1013 env(
pay(alice, bob,
XRP(100)),
1026 using namespace jtx;
1028 char const credType[] =
"abcde";
1029 Account const issuer{
"issuer"};
1035 testcase(
"Creating / deleting with credentials.");
1039 env.
fund(
XRP(5000), issuer, alice, bob);
1052 jv[sfUnauthorize.jsonName] = issuer.human();
1059 jv[sfAuthorize.jsonName] = issuer.human();
1066 jv[sfUnauthorize.jsonName] = issuer.human();
1073 jv[sfAuthorize.jsonName] = issuer.human();
1086 auto& arr(jv[sfAuthorizeCredentials.jsonName]);
1089 cred[sfCredentialType.jsonName] =
1092 credParent[jss::Credential] = cred;
1093 arr.
append(std::move(credParent));
1106 Account const a(
"a"), b(
"b"), c(
"c"), d(
"d"), e(
"e"), f(
"f"),
1107 g(
"g"), h(
"h"), i(
"i");
1108 auto const& z = credType;
1134 env.
fund(env.
current()->fees().accountReserve(0), john);
1154 jDP.isObject() && jDP.isMember(jss::result) &&
1155 !jDP[jss::result].isMember(jss::error) &&
1156 jDP[jss::result].isMember(jss::node) &&
1157 jDP[jss::result][jss::node].isMember(
"LedgerEntryType") &&
1158 jDP[jss::result][jss::node][
"LedgerEntryType"] ==
1159 jss::DepositPreauth);
1163 jDP[jss::result][jss::node][jss::Account] == bob.human());
1164 auto const& credentials(
1165 jDP[jss::result][jss::node][
"AuthorizeCredentials"]);
1166 BEAST_EXPECT(credentials.isArray() && credentials.size() == 1);
1167 for (
auto const& o : credentials)
1169 auto const& c(o[jss::Credential]);
1170 BEAST_EXPECT(c[jss::Issuer].asString() == issuer.human());
1172 c[
"CredentialType"].asString() ==
1188 jDP.isObject() && jDP.isMember(jss::result) &&
1189 jDP[jss::result].isMember(jss::error) &&
1190 jDP[jss::result][jss::error] ==
"entryNotFound");
1198 using namespace jtx;
1199 char const credType[] =
"abcde";
1200 char const credType2[] =
"fghijkl";
1201 Account const issuer{
"issuer"};
1205 IOU const USD = gw[
"USD"];
1209 testcase(
"Payment failure with expired credentials.");
1213 env.
fund(
XRP(10000), issuer, alice, bob, gw);
1222 .parentCloseTime.time_since_epoch()
1225 jv[sfExpiration.jsonName] = t;
1237 .parentCloseTime.time_since_epoch()
1240 jv[sfExpiration.jsonName] = t2;
1251 std::string const credIdx = jv[jss::result][jss::index].asString();
1253 std::string const credIdx2 = jv[jss::result][jss::index].asString();
1260 bob, {{issuer, credType}, {issuer, credType2}}));
1265 env(
pay(alice, bob,
XRP(100)),
1271 env(
pay(alice, bob,
XRP(100)),
1278 auto const jDelCred =
1281 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1282 jDelCred[jss::result].isMember(jss::error) &&
1283 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1291 jle.isObject() && jle.isMember(jss::result) &&
1292 !jle[jss::result].isMember(jss::error) &&
1293 jle[jss::result].isMember(jss::node) &&
1294 jle[jss::result][jss::node].isMember(
1295 "LedgerEntryType") &&
1296 jle[jss::result][jss::node][
"LedgerEntryType"] ==
1298 jle[jss::result][jss::node][jss::Issuer] ==
1300 jle[jss::result][jss::node][jss::Subject] ==
1302 jle[jss::result][jss::node][
"CredentialType"] ==
1314 .parentCloseTime.time_since_epoch()
1317 jv[sfExpiration.jsonName] = t;
1325 jv[jss::result][jss::index].asString();
1335 env(
pay(gw, bob, USD(150)),
1341 auto const jDelCred =
1344 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1345 jDelCred[jss::result].isMember(jss::error) &&
1346 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1356 testcase(
"Escrow failure with expired credentials.");
1360 env.
fund(
XRP(5000), issuer, alice, bob, zelda);
1367 .parentCloseTime.time_since_epoch()
1370 jv[sfExpiration.jsonName] = t;
1380 std::string const credIdx = jv[jss::result][jss::index].asString();
1389 auto const seq = env.
seq(alice);
1405 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
1423 auto const jDelCred =
1426 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1427 jDelCred[jss::result].isMember(jss::error) &&
1428 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1435 using namespace jtx;
1445 env.
fund(
XRP(5000), stock, alice, bob);
1457 for (
auto const& c : credentials)
1458 env.
fund(
XRP(5000), c.issuer);
1466 for (
auto const& c : credentials)
1467 pubKey2Acc.
emplace(c.issuer.human(), c.issuer);
1470 for (
int i = 0; i < 10; ++i)
1478 auto const& authCred(
1479 dp[jss::result][jss::node][
"AuthorizeCredentials"]);
1481 authCred.isArray() &&
1482 authCred.size() == credentials.size());
1484 for (
auto const& o : authCred)
1486 auto const& c(o[jss::Credential]);
1487 auto issuer = c[jss::Issuer].asString();
1489 if (BEAST_EXPECT(pubKey2Acc.
contains(issuer)))
1491 pubKey2Acc.
at(issuer),
1492 c[
"CredentialType"].asString());
1508 for (
int i = 0; i < 10; ++i)
1516 testcase(
"Check duplicate credentials.");
1520 credentials.
begin(), credentials.
end() - 1);
1523 for (
auto const& c : copyCredentials)
1525 auto credentials2 = copyCredentials;
1533 for (
auto const& c : credentials)
1544 c.credType)[jss::result][jss::index]
1549 for (
auto const& h : credentialIDs)
1551 auto credentialIDs2 = credentialIDs;
1554 env(
pay(alice, bob,
XRP(100)),
1567 testPayment(supported - featureDepositPreauth - featureCredentials);
1578BEAST_DEFINE_TESTSUITE(DepositAuth, app,
ripple);
Value & append(Value const &value)
Append value to array at the end.
Value removeMember(char const *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(AccountID const &account, AccountID const &to, STAmount const &amount)
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
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.
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.
FeatureBitset testable_amendments()
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.
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.