21#include <test/jtx/WSClient.h>
22#include <xrpl/beast/unit_test.h>
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/SField.h>
25#include <xrpl/protocol/jss.h>
34 testcase(
"Payment to Nonexistent Account");
35 using namespace test::jtx;
37 Env env{*
this, features};
45 testcase(
"Trust Nonexistent Account");
46 using namespace test::jtx;
49 Account alice{
"alice"};
51 env(trust(env.master, alice[
"USD"](100)), ter(
tecNO_DST));
58 using namespace test::jtx;
61 Account gw{
"gateway"};
62 Account alice{
"alice"};
65 env.fund(XRP(10000), gw, alice, bob);
70 auto jrr = ledgerEntryState(env, gw, alice,
"USD");
71 BEAST_EXPECT(jrr[jss::error] ==
"entryNotFound");
74 env(trust(alice, gw[
"USD"](800)));
76 jrr = ledgerEntryState(env, gw, alice,
"USD");
77 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
79 jrr[jss::node][sfHighLimit.fieldName][jss::value] ==
"800");
81 jrr[jss::node][sfHighLimit.fieldName][jss::issuer] ==
84 jrr[jss::node][sfHighLimit.fieldName][jss::currency] ==
"USD");
85 BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] ==
"0");
87 jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == gw.human());
89 jrr[jss::node][sfLowLimit.fieldName][jss::currency] ==
"USD");
92 env(trust(alice, gw[
"USD"](700)));
94 jrr = ledgerEntryState(env, gw, alice,
"USD");
95 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
97 jrr[jss::node][sfHighLimit.fieldName][jss::value] ==
"700");
99 jrr[jss::node][sfHighLimit.fieldName][jss::issuer] ==
102 jrr[jss::node][sfHighLimit.fieldName][jss::currency] ==
"USD");
103 BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] ==
"0");
105 jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == gw.human());
107 jrr[jss::node][sfLowLimit.fieldName][jss::currency] ==
"USD");
113 env(trust(alice, gw[
"USD"](0)));
116 jrr = ledgerEntryState(env, gw, alice,
"USD");
117 BEAST_EXPECT(jrr[jss::error] ==
"entryNotFound");
122 env(trust(alice, bob[
"USD"](600)));
125 env(trust(bob, alice[
"USD"](500)));
128 jrr = ledgerEntryState(env, alice, bob,
"USD");
129 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
131 jrr[jss::node][sfHighLimit.fieldName][jss::value] ==
"500");
133 jrr[jss::node][sfHighLimit.fieldName][jss::issuer] == bob.human());
135 jrr[jss::node][sfHighLimit.fieldName][jss::currency] ==
"USD");
136 BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] ==
"600");
138 jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == alice.human());
140 jrr[jss::node][sfLowLimit.fieldName][jss::currency] ==
"USD");
147 using namespace test::jtx;
149 Env env{*
this, features};
150 Account alice{
"alice"};
153 env.fund(XRP(10000), alice, bob);
156 env(trust(alice, bob[
"USD"](600)));
157 env(trust(bob, alice[
"USD"](700)));
160 env(pay(alice, bob, alice[
"USD"](24)));
161 env.require(balance(bob, alice[
"USD"](24)));
164 env(pay(alice, bob, bob[
"USD"](33)));
165 env.require(balance(bob, alice[
"USD"](57)));
168 env(pay(bob, alice, bob[
"USD"](90)));
169 env.require(balance(bob, alice[
"USD"](-33)));
172 env(pay(alice, bob, bob[
"USD"](733)));
173 env.require(balance(bob, alice[
"USD"](700)));
176 env(pay(bob, alice, bob[
"USD"](1300)));
177 env.require(balance(bob, alice[
"USD"](-600)));
180 env(pay(bob, alice, bob[
"USD"](1)), ter(
tecPATH_DRY));
181 env.require(balance(bob, alice[
"USD"](-600)));
189 (with_rate ?
"With " :
"Without ") +
" Xfer Fee, " +
190 (subscribe ?
"With " :
"Without ") +
" Subscribe");
191 using namespace test::jtx;
193 Env env{*
this, features};
195 Account gw{
"gateway"};
196 Account alice{
"alice"};
199 env.fund(XRP(10000), gw, alice, bob);
202 env(trust(alice, gw[
"AUD"](100)));
203 env(trust(bob, gw[
"AUD"](100)));
205 env(pay(gw, alice, alice[
"AUD"](1)));
208 env.require(balance(alice, gw[
"AUD"](1)));
211 env(pay(alice, bob, gw[
"AUD"](1)));
214 env.require(balance(alice, gw[
"AUD"](0)));
215 env.require(balance(bob, gw[
"AUD"](1)));
216 env.require(balance(gw, bob[
"AUD"](-1)));
224 env(pay(bob, alice, gw[
"AUD"](0.5)), sendmax(gw[
"AUD"](0.55)));
229 env(pay(bob, alice, gw[
"AUD"](0.5)));
232 env.require(balance(alice, gw[
"AUD"](0.5)));
233 env.require(balance(bob, gw[
"AUD"](with_rate ? 0.45 : 0.5)));
234 env.require(balance(gw, bob[
"AUD"](with_rate ? -0.45 : -0.5)));
240 jvs[jss::accounts].
append(gw.human());
242 jvs[jss::streams].
append(
"transactions");
243 jvs[jss::streams].
append(
"ledger");
244 auto jv = wsc->invoke(
"subscribe", jvs);
245 BEAST_EXPECT(jv[jss::status] ==
"success");
249 using namespace std::chrono_literals;
250 BEAST_EXPECT(wsc->findMsg(5s, [](
auto const& jval) {
251 auto const& t = jval[jss::transaction];
252 return t[jss::TransactionType] == jss::Payment;
254 BEAST_EXPECT(wsc->findMsg(5s, [](
auto const& jval) {
255 return jval[jss::type] ==
"ledgerClosed";
259 wsc->invoke(
"unsubscribe", jv)[jss::status] ==
"success");
266 testcase(
"Payments With Paths and Fees");
267 using namespace test::jtx;
269 Env env{*
this, features};
270 Account gw{
"gateway"};
271 Account alice{
"alice"};
274 env.fund(XRP(10000), gw, alice, bob);
280 env(trust(alice, gw[
"AUD"](100)));
281 env(trust(bob, gw[
"AUD"](100)));
283 env(pay(gw, alice, alice[
"AUD"](4.4)));
284 env.require(balance(alice, gw[
"AUD"](4.4)));
288 env(pay(alice, bob, gw[
"AUD"](1)), sendmax(gw[
"AUD"](1.1)));
289 env.require(balance(alice, gw[
"AUD"](3.3)));
290 env.require(balance(bob, gw[
"AUD"](1)));
293 env(pay(alice, bob, bob[
"AUD"](1)), sendmax(gw[
"AUD"](1.1)));
294 env.require(balance(alice, gw[
"AUD"](2.2)));
295 env.require(balance(bob, gw[
"AUD"](2)));
298 env(pay(alice, bob, gw[
"AUD"](1)), sendmax(alice[
"AUD"](1.1)));
299 env.require(balance(alice, gw[
"AUD"](1.1)));
300 env.require(balance(bob, gw[
"AUD"](3)));
304 env(pay(alice, bob, bob[
"AUD"](1)),
305 sendmax(alice[
"AUD"](1.1)),
308 env.require(balance(alice, gw[
"AUD"](1.1)));
309 env.require(balance(bob, gw[
"AUD"](3)));
316 using namespace test::jtx;
318 Env env{*
this, features};
319 Account gw{
"gateway"};
320 Account alice{
"alice"};
323 env.fund(XRP(10000), gw, alice, bob);
326 env(trust(alice, gw[
"USD"](600)));
327 env(trust(bob, gw[
"USD"](700)));
329 env(pay(gw, alice, alice[
"USD"](70)));
330 env(pay(gw, bob, bob[
"USD"](50)));
332 env.require(balance(alice, gw[
"USD"](70)));
333 env.require(balance(bob, gw[
"USD"](50)));
343 env.require(balance(alice, gw[
"USD"](70)));
344 env.require(balance(bob, gw[
"USD"](50)));
349 env.require(balance(alice, gw[
"USD"](65)));
350 env.require(balance(bob, gw[
"USD"](55)));
358 (with_rate ?
"With " :
"Without ") +
" Xfer Fee, ");
359 using namespace test::jtx;
361 Env env{*
this, features};
362 Account gw{
"gateway"};
363 Account amazon{
"amazon"};
364 Account alice{
"alice"};
366 Account carol{
"carol"};
368 env.fund(XRP(10000), gw, amazon, alice, bob, carol);
371 env(trust(amazon, gw[
"USD"](2000)));
372 env(trust(bob, alice[
"USD"](600)));
373 env(trust(bob, gw[
"USD"](1000)));
374 env(trust(carol, alice[
"USD"](700)));
375 env(trust(carol, gw[
"USD"](1000)));
380 env(pay(gw, bob, bob[
"USD"](100)));
381 env(pay(gw, carol, carol[
"USD"](100)));
386 env(pay(alice, amazon, gw[
"USD"](150)),
387 sendmax(alice[
"USD"](200)),
391 env(pay(alice, amazon, gw[
"USD"](150)),
400 carol[
"USD"].issue(),
405 env.require(balance(carol, gw[
"USD"](35)));
409 env.require(balance(alice, carol[
"USD"](-50)));
410 env.require(balance(carol, gw[
"USD"](50)));
412 env.require(balance(alice, bob[
"USD"](-100)));
413 env.require(balance(amazon, gw[
"USD"](150)));
414 env.require(balance(bob, gw[
"USD"](0)));
420 testcase(
"Set Invoice ID on Payment");
421 using namespace test::jtx;
423 Env env{*
this, features};
424 Account alice{
"alice"};
427 env.fund(XRP(10000), alice);
432 jvs[jss::accounts].
append(env.master.human());
434 jvs[jss::streams].
append(
"transactions");
435 BEAST_EXPECT(wsc->invoke(
"subscribe", jvs)[jss::status] ==
"success");
437 char const* invoiceid =
438 "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89";
442 pay(env.master, alice, XRP(10000)),
443 json(sfInvoiceID.fieldName, invoiceid));
444 jv[jss::tx_blob] =
strHex(tx.stx->getSerializer().slice());
445 auto jrr = wsc->invoke(
"submit", jv)[jss::result];
446 BEAST_EXPECT(jrr[jss::status] ==
"success");
447 BEAST_EXPECT(jrr[jss::tx_json][sfInvoiceID.fieldName] == invoiceid);
450 using namespace std::chrono_literals;
451 BEAST_EXPECT(wsc->findMsg(2s, [invoiceid](
auto const& jval) {
452 auto const& t = jval[jss::transaction];
453 return t[jss::TransactionType] == jss::Payment &&
454 t[sfInvoiceID.fieldName] == invoiceid;
457 BEAST_EXPECT(wsc->invoke(
"unsubscribe", jv)[jss::status] ==
"success");
481 using namespace test::jtx;
482 auto const sa = supported_amendments();
483 testWithFeatures(sa - featureFlowCross);
484 testWithFeatures(sa);
488BEAST_DEFINE_TESTSUITE(TrustAndBalance, app,
ripple);
Value & append(const Value &value)
Append value to array at the end.
testcase_t testcase
Memberspace for declaring test cases.
void testInvoiceID(FeatureBitset features)
void run() override
Runs the suite.
void testWithTransferFee(bool subscribe, bool with_rate, FeatureBitset features)
void testPayNonexistent(FeatureBitset features)
void testDirectRipple(FeatureBitset features)
void testTrustNonexistent()
void testWithPath(FeatureBitset features)
void testIndirectMultiPath(bool with_rate, FeatureBitset features)
void testIndirect(FeatureBitset features)
@ arrayValue
array value (ordered list)
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string strHex(FwdIt begin, FwdIt end)