21#include <test/jtx/WSClient.h>
23#include <xrpl/beast/unit_test.h>
24#include <xrpl/protocol/Feature.h>
25#include <xrpl/protocol/SField.h>
26#include <xrpl/protocol/jss.h>
35 testcase(
"Payment to Nonexistent Account");
36 using namespace test::jtx;
38 Env env{*
this, features};
46 testcase(
"Trust Nonexistent Account");
47 using namespace test::jtx;
59 using namespace test::jtx;
66 env.fund(
XRP(10000), gw, alice, bob);
72 BEAST_EXPECT(jrr[jss::error] ==
"entryNotFound");
75 env(
trust(alice, gw[
"USD"](800)));
78 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
80 jrr[jss::node][sfHighLimit.fieldName][jss::value] ==
"800");
82 jrr[jss::node][sfHighLimit.fieldName][jss::issuer] ==
85 jrr[jss::node][sfHighLimit.fieldName][jss::currency] ==
"USD");
86 BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] ==
"0");
88 jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == gw.human());
90 jrr[jss::node][sfLowLimit.fieldName][jss::currency] ==
"USD");
93 env(
trust(alice, gw[
"USD"](700)));
96 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
98 jrr[jss::node][sfHighLimit.fieldName][jss::value] ==
"700");
100 jrr[jss::node][sfHighLimit.fieldName][jss::issuer] ==
103 jrr[jss::node][sfHighLimit.fieldName][jss::currency] ==
"USD");
104 BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] ==
"0");
106 jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == gw.human());
108 jrr[jss::node][sfLowLimit.fieldName][jss::currency] ==
"USD");
114 env(
trust(alice, gw[
"USD"](0)));
118 BEAST_EXPECT(jrr[jss::error] ==
"entryNotFound");
123 env(
trust(alice, bob[
"USD"](600)));
126 env(
trust(bob, alice[
"USD"](500)));
130 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
132 jrr[jss::node][sfHighLimit.fieldName][jss::value] ==
"500");
134 jrr[jss::node][sfHighLimit.fieldName][jss::issuer] == bob.human());
136 jrr[jss::node][sfHighLimit.fieldName][jss::currency] ==
"USD");
137 BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] ==
"600");
139 jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == alice.human());
141 jrr[jss::node][sfLowLimit.fieldName][jss::currency] ==
"USD");
148 using namespace test::jtx;
150 Env env{*
this, features};
154 env.fund(
XRP(10000), alice, bob);
157 env(
trust(alice, bob[
"USD"](600)));
158 env(
trust(bob, alice[
"USD"](700)));
161 env(
pay(alice, bob, alice[
"USD"](24)));
162 env.require(
balance(bob, alice[
"USD"](24)));
165 env(
pay(alice, bob, bob[
"USD"](33)));
166 env.require(
balance(bob, alice[
"USD"](57)));
169 env(
pay(bob, alice, bob[
"USD"](90)));
170 env.require(
balance(bob, alice[
"USD"](-33)));
173 env(
pay(alice, bob, bob[
"USD"](733)));
174 env.require(
balance(bob, alice[
"USD"](700)));
177 env(
pay(bob, alice, bob[
"USD"](1300)));
178 env.require(
balance(bob, alice[
"USD"](-600)));
182 env.require(
balance(bob, alice[
"USD"](-600)));
190 (with_rate ?
"With " :
"Without ") +
" Xfer Fee, " +
191 (subscribe ?
"With " :
"Without ") +
" Subscribe");
192 using namespace test::jtx;
194 Env env{*
this, features};
200 env.fund(
XRP(10000), gw, alice, bob);
203 env(
trust(alice, gw[
"AUD"](100)));
204 env(
trust(bob, gw[
"AUD"](100)));
206 env(
pay(gw, alice, alice[
"AUD"](1)));
209 env.require(
balance(alice, gw[
"AUD"](1)));
212 env(
pay(alice, bob, gw[
"AUD"](1)));
215 env.require(
balance(alice, gw[
"AUD"](0)));
216 env.require(
balance(bob, gw[
"AUD"](1)));
217 env.require(
balance(gw, bob[
"AUD"](-1)));
225 env(
pay(bob, alice, gw[
"AUD"](0.5)),
sendmax(gw[
"AUD"](0.55)));
230 env(
pay(bob, alice, gw[
"AUD"](0.5)));
233 env.require(
balance(alice, gw[
"AUD"](0.5)));
234 env.require(
balance(bob, gw[
"AUD"](with_rate ? 0.45 : 0.5)));
235 env.require(
balance(gw, bob[
"AUD"](with_rate ? -0.45 : -0.5)));
241 jvs[jss::accounts].
append(gw.human());
243 jvs[jss::streams].
append(
"transactions");
244 jvs[jss::streams].
append(
"ledger");
245 auto jv = wsc->invoke(
"subscribe", jvs);
246 BEAST_EXPECT(jv[jss::status] ==
"success");
250 using namespace std::chrono_literals;
251 BEAST_EXPECT(wsc->findMsg(5s, [](
auto const& jval) {
252 auto const& t = jval[jss::transaction];
253 return t[jss::TransactionType] == jss::Payment;
255 BEAST_EXPECT(wsc->findMsg(5s, [](
auto const& jval) {
256 return jval[jss::type] ==
"ledgerClosed";
260 wsc->invoke(
"unsubscribe", jv)[jss::status] ==
"success");
267 testcase(
"Payments With Paths and Fees");
268 using namespace test::jtx;
270 Env env{*
this, features};
275 env.fund(
XRP(10000), gw, alice, bob);
281 env(
trust(alice, gw[
"AUD"](100)));
282 env(
trust(bob, gw[
"AUD"](100)));
284 env(
pay(gw, alice, alice[
"AUD"](4.4)));
285 env.require(
balance(alice, gw[
"AUD"](4.4)));
289 env(
pay(alice, bob, gw[
"AUD"](1)),
sendmax(gw[
"AUD"](1.1)));
290 env.require(
balance(alice, gw[
"AUD"](3.3)));
291 env.require(
balance(bob, gw[
"AUD"](1)));
294 env(
pay(alice, bob, bob[
"AUD"](1)),
sendmax(gw[
"AUD"](1.1)));
295 env.require(
balance(alice, gw[
"AUD"](2.2)));
296 env.require(
balance(bob, gw[
"AUD"](2)));
299 env(
pay(alice, bob, gw[
"AUD"](1)),
sendmax(alice[
"AUD"](1.1)));
300 env.require(
balance(alice, gw[
"AUD"](1.1)));
301 env.require(
balance(bob, gw[
"AUD"](3)));
305 env(
pay(alice, bob, bob[
"AUD"](1)),
309 env.require(
balance(alice, gw[
"AUD"](1.1)));
310 env.require(
balance(bob, gw[
"AUD"](3)));
317 using namespace test::jtx;
319 Env env{*
this, features};
324 env.fund(
XRP(10000), gw, alice, bob);
327 env(
trust(alice, gw[
"USD"](600)));
328 env(
trust(bob, gw[
"USD"](700)));
330 env(
pay(gw, alice, alice[
"USD"](70)));
331 env(
pay(gw, bob, bob[
"USD"](50)));
333 env.require(
balance(alice, gw[
"USD"](70)));
334 env.require(
balance(bob, gw[
"USD"](50)));
344 env.require(
balance(alice, gw[
"USD"](70)));
345 env.require(
balance(bob, gw[
"USD"](50)));
350 env.require(
balance(alice, gw[
"USD"](65)));
351 env.require(
balance(bob, gw[
"USD"](55)));
359 (with_rate ?
"With " :
"Without ") +
" Xfer Fee, ");
360 using namespace test::jtx;
362 Env env{*
this, features};
369 env.fund(
XRP(10000), gw, amazon, alice, bob, carol);
372 env(
trust(amazon, gw[
"USD"](2000)));
373 env(
trust(bob, alice[
"USD"](600)));
374 env(
trust(bob, gw[
"USD"](1000)));
375 env(
trust(carol, alice[
"USD"](700)));
376 env(
trust(carol, gw[
"USD"](1000)));
381 env(
pay(gw, bob, bob[
"USD"](100)));
382 env(
pay(gw, carol, carol[
"USD"](100)));
387 env(
pay(alice, amazon, gw[
"USD"](150)),
392 env(
pay(alice, amazon, gw[
"USD"](150)),
401 carol[
"USD"].issue(),
406 env.require(
balance(carol, gw[
"USD"](35)));
410 env.require(
balance(alice, carol[
"USD"](-50)));
411 env.require(
balance(carol, gw[
"USD"](50)));
413 env.require(
balance(alice, bob[
"USD"](-100)));
414 env.require(
balance(amazon, gw[
"USD"](150)));
415 env.require(
balance(bob, gw[
"USD"](0)));
421 testcase(
"Set Invoice ID on Payment");
422 using namespace test::jtx;
424 Env env{*
this, features};
428 env.fund(
XRP(10000), alice);
433 jvs[jss::accounts].
append(env.master.human());
435 jvs[jss::streams].
append(
"transactions");
436 BEAST_EXPECT(wsc->invoke(
"subscribe", jvs)[jss::status] ==
"success");
438 char const* invoiceid =
439 "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89";
443 pay(env.master, alice,
XRP(10000)),
444 json(sfInvoiceID.fieldName, invoiceid));
445 jv[jss::tx_blob] =
strHex(tx.stx->getSerializer().slice());
446 auto jrr = wsc->invoke(
"submit", jv)[jss::result];
447 BEAST_EXPECT(jrr[jss::status] ==
"success");
448 BEAST_EXPECT(jrr[jss::tx_json][sfInvoiceID.fieldName] == invoiceid);
451 using namespace std::chrono_literals;
452 BEAST_EXPECT(wsc->findMsg(2s, [invoiceid](
auto const& jval) {
453 auto const& t = jval[jss::transaction];
454 return t[jss::TransactionType] == jss::Payment &&
455 t[sfInvoiceID.fieldName] == invoiceid;
458 BEAST_EXPECT(wsc->invoke(
"unsubscribe", jv)[jss::status] ==
"success");
482 using namespace test::jtx;
484 testWithFeatures(sa - featureFlowCross);
485 testWithFeatures(sa);
489BEAST_DEFINE_TESTSUITE(TrustAndBalance, app,
ripple);
Value & append(Value const &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)
Immutable cryptographic account descriptor.
A transaction testing environment.
Sets the SendMax on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
@ arrayValue
array value (ordered list)
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Json::Value ledgerEntryState(Env &env, Account const &acct_a, Account const &acct_b, std::string const ¤cy)
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
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)