3#include <xrpl/protocol/Feature.h>
15 return env.
current()->fees().accountReserve(count);
22 return ((*env.
le(acct))[sfFlags] & lsfDepositAuth) == lsfDepositAuth;
39 env(
fset(alice, asfDepositAuth));
43 env(
fclear(alice, asfDepositAuth));
61 IOU const USD = gw[
"USD"];
65 env.
fund(
XRP(10000), alice, bob, carol, gw);
67 env.
trust(USD(1000), alice, bob);
70 env(
pay(gw, alice, USD(150)));
71 env(
offer(carol, USD(100),
XRP(100)));
75 env(
pay(alice, bob, USD(50)));
83 auto failedIouPayments = [
this, &env, &alice, &bob, &USD]() {
98 BEAST_EXPECT(bobXrpBalance == env.
balance(bob,
XRP));
99 BEAST_EXPECT(bobUsdBalance == env.
balance(bob, USD));
107 env(
pay(bob, alice, USD(25)));
113 env(
pay(bob, alice, bobPaysXRP),
fee(bobPaysFee));
119 BEAST_EXPECT(env.
balance(bob, USD) == USD(25));
133 env(
fclear(bob, asfDepositAuth));
136 env(
pay(alice, bob, USD(50)));
155 auto const baseFee = env.
current()->fees().base;
157 env.
fund(
XRP(10000), alice, bob);
174 env(
pay(bob, alice, bobPaysXRP),
fee(bobPaysFee));
228 env(
pay(alice, bob,
drops(baseFee - 1)));
258 IOU const USD1(gw1[
"USD"]);
259 IOU const USD2(gw2[
"USD"]);
264 bool withDepositAuth) {
265 Env env(*
this, features);
267 env.
fund(
XRP(10000), gw1, alice, bob);
269 env(
trust(gw1, alice[
"USD"](10), noRipplePrev ? tfSetNoRipple : 0));
270 env(
trust(gw1, bob[
"USD"](10), noRippleNext ? tfSetNoRipple : 0));
271 env.
trust(USD1(10), alice, bob);
273 env(
pay(gw1, alice, USD1(10)));
276 env(
fset(gw1, asfDepositAuth));
279 env(
pay(alice, bob, USD1(10)),
path(gw1),
ter(result));
285 bool withDepositAuth) {
286 Env env(*
this, features);
288 env.
fund(
XRP(10000), gw1, gw2, alice);
290 env(
trust(alice, USD1(10), noRipplePrev ? tfSetNoRipple : 0));
291 env(
trust(alice, USD2(10), noRippleNext ? tfSetNoRipple : 0));
292 env(
pay(gw2, alice, USD2(10)));
295 env(
fset(alice, asfDepositAuth));
302 for (
int i = 0; i < 8; ++i)
304 auto const noRipplePrev = i & 0x1;
305 auto const noRippleNext = i & 0x2;
306 auto const withDepositAuth = i & 0x4;
332 jvParams[jss::ledger_index] = jss::validated;
333 jvParams[jss::deposit_preauth][jss::owner] = acc.
human();
334 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
Json::arrayValue;
335 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
336 for (
auto const& o :
auth)
338 arr.append(o.toLEJson());
340 return env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
358 env.
fund(
XRP(10000), alice, becky);
377 env.
fund(
XRP(10000), alice, becky);
394 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
402 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
427 env.
fund(
XRP(10000), alice, becky);
448 tx[sfUnauthorize.jsonName] = becky.human();
534 IOU const USD(gw[
"USD"]);
540 Env env(*
this, features);
541 env.
fund(
XRP(5000), alice, becky, gw);
544 env.
trust(USD(1000), alice);
545 env.
trust(USD(1000), becky);
548 env(
pay(gw, alice, USD(500)));
560 env(
fset(becky, asfDepositAuth));
569 char const credType[] =
"abcde";
574 bool const supportsCredentials = features[featureCredentials];
589 ? jv[jss::result][jss::index].asString()
590 :
"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6"
602 Env env(*
this, features);
603 env.
fund(
XRP(5000), alice, becky, carol, gw);
606 env.
trust(USD(1000), alice);
607 env.
trust(USD(1000), becky);
608 env.
trust(USD(1000), carol);
611 env(
pay(gw, alice, USD(1000)));
615 env(
pay(alice, becky,
XRP(100)));
616 env(
pay(alice, becky, USD(100)));
620 env(
fset(becky, asfDepositAuth));
643 env(
pay(alice, becky,
XRP(100)));
644 env(
pay(alice, becky, USD(100)));
648 env(
fset(alice, asfDepositAuth));
661 env(
pay(alice, becky,
XRP(100)));
662 env(
pay(alice, becky, USD(100)));
675 env(
fclear(becky, asfDepositAuth));
678 env(
pay(alice, becky,
XRP(100)));
679 env(
pay(alice, becky, USD(100)));
688 char const credType[] =
"abcde";
689 Account const issuer{
"issuer"};
696 testcase(
"Payment failure with disabled credentials rule.");
700 env.
fund(
XRP(5000), issuer, bob, alice);
704 env(
fset(bob, asfDepositAuth));
718 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
725 testcase(
"Payment with credentials.");
729 env.
fund(
XRP(5000), issuer, alice, bob, john);
738 std::string const credIdx = jv[jss::result][jss::index].asString();
741 env(
fset(bob, asfDepositAuth));
751 jDP.isObject() && jDP.isMember(jss::result) &&
752 !jDP[jss::result].isMember(jss::error) && jDP[jss::result].isMember(jss::node) &&
753 jDP[jss::result][jss::node].isMember(
"LedgerEntryType") &&
754 jDP[jss::result][jss::node][
"LedgerEntryType"] == jss::DepositPreauth);
758 auto jv =
pay(alice, bob,
XRP(100));
782 env(
fset(john, asfDepositAuth));
789 testcase(
"Payment failure with invalid credentials.");
793 env.
fund(
XRP(10000), issuer, alice, bob, maria);
804 std::string const credIdx = jv[jss::result][jss::index].asString();
813 env(
fset(bob, asfDepositAuth));
831 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
834 env(
pay(alice, bob,
XRP(100)),
841 env(
pay(maria, bob,
XRP(100)),
848 char const credType2[] =
"fghij";
854 std::string const credIdx2 = jv[jss::result][jss::index].asString();
857 env(
pay(alice, bob,
XRP(100)),
876 char const credType[] =
"abcde";
877 Account const issuer{
"issuer"};
883 testcase(
"Creating / deleting with credentials.");
887 env.
fund(
XRP(5000), issuer, alice, bob);
900 jv[sfUnauthorize.jsonName] = issuer.human();
907 jv[sfAuthorize.jsonName] = issuer.human();
914 jv[sfUnauthorize.jsonName] = issuer.human();
921 jv[sfAuthorize.jsonName] = issuer.human();
934 auto& arr(jv[sfAuthorizeCredentials.jsonName]);
939 credParent[jss::Credential] = cred;
940 arr.
append(std::move(credParent));
953 Account const a(
"a"), b(
"b"), c(
"c"), d(
"d"), e(
"e"), f(
"f"), g(
"g"), h(
"h"),
955 auto const& z = credType;
957 bob, {{a, z}, {b, z}, {c, z}, {d, z}, {e, z}, {f, z}, {g, z}, {h, z}, {i, z}});
972 env.
fund(env.
current()->fees().accountReserve(0), john);
990 jDP.isObject() && jDP.isMember(jss::result) &&
991 !jDP[jss::result].isMember(jss::error) &&
992 jDP[jss::result].isMember(jss::node) &&
993 jDP[jss::result][jss::node].isMember(
"LedgerEntryType") &&
994 jDP[jss::result][jss::node][
"LedgerEntryType"] == jss::DepositPreauth);
997 BEAST_EXPECT(jDP[jss::result][jss::node][jss::Account] == bob.human());
998 auto const& credentials(jDP[jss::result][jss::node][
"AuthorizeCredentials"]);
999 BEAST_EXPECT(credentials.isArray() && credentials.size() == 1);
1000 for (
auto const& o : credentials)
1002 auto const& c(o[jss::Credential]);
1003 BEAST_EXPECT(c[jss::Issuer].asString() == issuer.human());
1018 jDP.isObject() && jDP.isMember(jss::result) &&
1019 jDP[jss::result].isMember(jss::error) &&
1020 jDP[jss::result][jss::error] ==
"entryNotFound");
1028 using namespace jtx;
1029 char const credType[] =
"abcde";
1030 char const credType2[] =
"fghijkl";
1031 Account const issuer{
"issuer"};
1035 IOU const USD = gw[
"USD"];
1039 testcase(
"Payment failure with expired credentials.");
1043 env.
fund(
XRP(10000), issuer, alice, bob, gw);
1051 env.
current()->header().parentCloseTime.time_since_epoch().count() + 60;
1052 jv[sfExpiration.jsonName] = t;
1063 env.
current()->header().parentCloseTime.time_since_epoch().count() + 1000;
1064 jv[sfExpiration.jsonName] = t2;
1075 std::string const credIdx = jv[jss::result][jss::index].asString();
1077 std::string const credIdx2 = jv[jss::result][jss::index].asString();
1080 env(
fset(bob, asfDepositAuth));
1093 env(
pay(alice, bob,
XRP(100)),
1102 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1103 jDelCred[jss::result].isMember(jss::error) &&
1104 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1111 jle.isObject() && jle.isMember(jss::result) &&
1112 !jle[jss::result].isMember(jss::error) &&
1113 jle[jss::result].isMember(jss::node) &&
1114 jle[jss::result][jss::node].isMember(
"LedgerEntryType") &&
1115 jle[jss::result][jss::node][
"LedgerEntryType"] == jss::Credential &&
1116 jle[jss::result][jss::node][jss::Issuer] == issuer.human() &&
1117 jle[jss::result][jss::node][jss::Subject] == alice.human() &&
1118 jle[jss::result][jss::node][
"CredentialType"] ==
1129 env.
current()->header().parentCloseTime.time_since_epoch().count() + 40;
1130 jv[sfExpiration.jsonName] = t;
1137 std::string const credIdx = jv[jss::result][jss::index].asString();
1153 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1154 jDelCred[jss::result].isMember(jss::error) &&
1155 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1165 testcase(
"Escrow failure with expired credentials.");
1169 env.
fund(
XRP(5000), issuer, alice, bob, zelda);
1175 env.
current()->header().parentCloseTime.time_since_epoch().count() + 50;
1176 jv[sfExpiration.jsonName] = t;
1186 std::string const credIdx = jv[jss::result][jss::index].asString();
1189 env(
fset(bob, asfDepositAuth));
1195 auto const seq = env.
seq(alice);
1208 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E"
1228 jDelCred.isObject() && jDelCred.isMember(jss::result) &&
1229 jDelCred[jss::result].isMember(jss::error) &&
1230 jDelCred[jss::result][jss::error] ==
"entryNotFound");
1237 using namespace jtx;
1247 env.
fund(
XRP(5000), stock, alice, bob);
1259 for (
auto const& c : credentials)
1260 env.
fund(
XRP(5000), c.issuer);
1268 for (
auto const& c : credentials)
1269 pubKey2Acc.
emplace(c.issuer.human(), c.issuer);
1272 for (
int i = 0; i < 10; ++i)
1279 auto const& authCred(dp[jss::result][jss::node][
"AuthorizeCredentials"]);
1280 BEAST_EXPECT(authCred.isArray() && authCred.size() == credentials.
size());
1282 for (
auto const& o : authCred)
1284 auto const& c(o[jss::Credential]);
1285 auto issuer = c[jss::Issuer].asString();
1287 if (BEAST_EXPECT(pubKey2Acc.
contains(issuer)))
1290 pubKey2Acc.
at(issuer), c[
"CredentialType"].asString());
1307 for (
int i = 0; i < 10; ++i)
1314 testcase(
"Check duplicate credentials.");
1318 credentials.
begin(), credentials.
end() - 1);
1321 for (
auto const& c : copyCredentials)
1323 auto credentials2 = copyCredentials;
1330 for (
auto const& c : credentials)
1339 env, alice, c.issuer, c.credType)[jss::result][jss::index]
1344 for (
auto const& h : credentialIDs)
1346 auto credentialIDs2 = credentialIDs;
1369BEAST_DEFINE_TESTSUITE(DepositAuth, app,
xrpl);
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.
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
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.
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
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 memoize(Account const &account)
Associate AccountID with account.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
NetClock::time_point now()
Returns the current network time.
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 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 unauth(Account const &account, Account const &unauth)
Remove pre-authorization 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)
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 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.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
std::uint32_t ownerCount(Env const &env, Account const &account)
XRP_t const XRP
Converts to XRP Issue or STAmount.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
FeatureBitset testable_amendments()
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.
owner_count< ltTICKET > tickets
Match the number of tickets on the 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.
static bool hasDepositAuth(jtx::Env const &env, jtx::Account const &acct)
static XRPAmount reserve(jtx::Env &env, std::uint32_t count)
static Json::Value ledgerEntryDepositPreauth(jtx::Env &env, jtx::Account const &acc, std::vector< jtx::deposit::AuthorizeCredentials > const &auth)
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)
TERSubset< CanCvtToTER > TER
AccountID const & xrpAccount()
Compute AccountID from public key.
@ tecINSUFFICIENT_RESERVE
void run() override
Runs the suite.
void testCredentialsPayment()
void run() override
Runs the suite.
void testSortingCredentials()
void testCredentialsCreation()
void testPayment(FeatureBitset features)
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Set the sequence number on a JTx.