rippled
Flow_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/paths/Flow.h>
21 #include <ripple/app/paths/impl/Steps.h>
22 #include <ripple/basics/contract.h>
23 #include <ripple/core/Config.h>
24 #include <ripple/ledger/ApplyViewImpl.h>
25 #include <ripple/ledger/PaymentSandbox.h>
26 #include <ripple/ledger/Sandbox.h>
27 #include <ripple/protocol/Feature.h>
28 #include <ripple/protocol/jss.h>
29 #include <test/jtx.h>
30 #include <test/jtx/PathSet.h>
31 
32 namespace ripple {
33 namespace test {
34 
35 bool
37  jtx::Env const& env,
38  jtx::Account const& src,
39  jtx::Account const& dst,
40  Currency const& cur)
41 {
42  if (auto sle = env.le(keylet::line(src, dst, cur)))
43  {
44  auto const flag =
45  (src.id() > dst.id()) ? lsfHighNoRipple : lsfLowNoRipple;
46  return sle->isFlag(flag);
47  }
48  Throw<std::runtime_error>("No line in getTrustFlag");
49  return false; // silence warning
50 }
51 
52 jtx::PrettyAmount
53 xrpMinusFee(jtx::Env const& env, std::int64_t xrpAmount)
54 {
55  using namespace jtx;
56  auto feeDrops = env.current()->fees().base;
57  return drops(dropsPerXRP * xrpAmount - feeDrops);
58 };
59 
60 struct Flow_test : public beast::unit_test::suite
61 {
62  void
64  {
65  testcase("Direct Step");
66 
67  using namespace jtx;
68  auto const alice = Account("alice");
69  auto const bob = Account("bob");
70  auto const carol = Account("carol");
71  auto const dan = Account("dan");
72  auto const erin = Account("erin");
73  auto const USDA = alice["USD"];
74  auto const USDB = bob["USD"];
75  auto const USDC = carol["USD"];
76  auto const USDD = dan["USD"];
77  auto const gw = Account("gw");
78  auto const USD = gw["USD"];
79  {
80  // Pay USD, trivial path
81  Env env(*this, features);
82 
83  env.fund(XRP(10000), alice, bob, gw);
84  env.trust(USD(1000), alice, bob);
85  env(pay(gw, alice, USD(100)));
86  env(pay(alice, bob, USD(10)), paths(USD));
87  env.require(balance(bob, USD(10)));
88  }
89  {
90  // XRP transfer
91  Env env(*this, features);
92 
93  env.fund(XRP(10000), alice, bob);
94  env(pay(alice, bob, XRP(100)));
95  env.require(balance(bob, XRP(10000 + 100)));
96  env.require(balance(alice, xrpMinusFee(env, 10000 - 100)));
97  }
98  {
99  // Partial payments
100  Env env(*this, features);
101 
102  env.fund(XRP(10000), alice, bob, gw);
103  env.trust(USD(1000), alice, bob);
104  env(pay(gw, alice, USD(100)));
105  env(pay(alice, bob, USD(110)), paths(USD), ter(tecPATH_PARTIAL));
106  env.require(balance(bob, USD(0)));
107  env(pay(alice, bob, USD(110)),
108  paths(USD),
110  env.require(balance(bob, USD(100)));
111  }
112  {
113  // Pay by rippling through accounts, use path finder
114  Env env(*this, features);
115 
116  env.fund(XRP(10000), alice, bob, carol, dan);
117  env.trust(USDA(10), bob);
118  env.trust(USDB(10), carol);
119  env.trust(USDC(10), dan);
120  env(pay(alice, dan, USDC(10)), paths(USDA));
121  env.require(
122  balance(bob, USDA(10)),
123  balance(carol, USDB(10)),
124  balance(dan, USDC(10)));
125  }
126  {
127  // Pay by rippling through accounts, specify path
128  // and charge a transfer fee
129  Env env(*this, features);
130 
131  env.fund(XRP(10000), alice, bob, carol, dan);
132  env.trust(USDA(10), bob);
133  env.trust(USDB(10), alice, carol);
134  env.trust(USDC(10), dan);
135  env(rate(bob, 1.1));
136 
137  // alice will redeem to bob; a transfer fee will be charged
138  env(pay(bob, alice, USDB(6)));
139  env(pay(alice, dan, USDC(5)),
140  path(bob, carol),
141  sendmax(USDA(6)),
143  env.require(balance(dan, USDC(5)));
144  env.require(balance(alice, USDB(0.5)));
145  }
146  {
147  // Pay by rippling through accounts, specify path and transfer fee
148  // Test that the transfer fee is not charged when alice issues
149  Env env(*this, features);
150 
151  env.fund(XRP(10000), alice, bob, carol, dan);
152  env.trust(USDA(10), bob);
153  env.trust(USDB(10), alice, carol);
154  env.trust(USDC(10), dan);
155  env(rate(bob, 1.1));
156 
157  env(pay(alice, dan, USDC(5)),
158  path(bob, carol),
159  sendmax(USDA(6)),
161  env.require(balance(dan, USDC(5)));
162  env.require(balance(bob, USDA(5)));
163  }
164  {
165  // test best quality path is taken
166  // Paths: A->B->D->E ; A->C->D->E
167  Env env(*this, features);
168 
169  env.fund(XRP(10000), alice, bob, carol, dan, erin);
170  env.trust(USDA(10), bob, carol);
171  env.trust(USDB(10), dan);
172  env.trust(USDC(10), alice, dan);
173  env.trust(USDD(20), erin);
174  env(rate(bob, 1));
175  env(rate(carol, 1.1));
176 
177  // Pay alice so she redeems to carol and a transfer fee is charged
178  env(pay(carol, alice, USDC(10)));
179  env(pay(alice, erin, USDD(5)),
180  path(carol, dan),
181  path(bob, dan),
183 
184  env.require(balance(erin, USDD(5)));
185  env.require(balance(dan, USDB(5)));
186  env.require(balance(dan, USDC(0)));
187  }
188  {
189  // Limit quality
190  Env env(*this, features);
191 
192  env.fund(XRP(10000), alice, bob, carol);
193  env.trust(USDA(10), bob);
194  env.trust(USDB(10), carol);
195 
196  env(pay(alice, carol, USDB(5)),
197  sendmax(USDA(4)),
199  ter(tecPATH_DRY));
200  env.require(balance(carol, USDB(0)));
201 
202  env(pay(alice, carol, USDB(5)),
203  sendmax(USDA(4)),
205  env.require(balance(carol, USDB(4)));
206  }
207  }
208 
209  void
211  {
212  testcase("Line Quality");
213 
214  using namespace jtx;
215  auto const alice = Account("alice");
216  auto const bob = Account("bob");
217  auto const carol = Account("carol");
218  auto const dan = Account("dan");
219  auto const USDA = alice["USD"];
220  auto const USDB = bob["USD"];
221  auto const USDC = carol["USD"];
222  auto const USDD = dan["USD"];
223 
224  // Dan -> Bob -> Alice -> Carol; vary bobDanQIn and bobAliceQOut
225  for (auto bobDanQIn : {80, 100, 120})
226  for (auto bobAliceQOut : {80, 100, 120})
227  {
228  Env env(*this, features);
229  env.fund(XRP(10000), alice, bob, carol, dan);
230  env(trust(bob, USDD(100)), qualityInPercent(bobDanQIn));
231  env(trust(bob, USDA(100)), qualityOutPercent(bobAliceQOut));
232  env(trust(carol, USDA(100)));
233 
234  env(pay(alice, bob, USDA(100)));
235  env.require(balance(bob, USDA(100)));
236  env(pay(dan, carol, USDA(10)),
237  path(bob),
238  sendmax(USDD(100)),
240  env.require(balance(bob, USDA(90)));
241  if (bobAliceQOut > bobDanQIn)
242  env.require(balance(
243  bob,
244  USDD(10.0 * double(bobAliceQOut) / double(bobDanQIn))));
245  else
246  env.require(balance(bob, USDD(10)));
247  env.require(balance(carol, USDA(10)));
248  }
249 
250  // bob -> alice -> carol; vary carolAliceQIn
251  for (auto carolAliceQIn : {80, 100, 120})
252  {
253  Env env(*this, features);
254  env.fund(XRP(10000), alice, bob, carol);
255  env(trust(bob, USDA(10)));
256  env(trust(carol, USDA(10)), qualityInPercent(carolAliceQIn));
257 
258  env(pay(alice, bob, USDA(10)));
259  env.require(balance(bob, USDA(10)));
260  env(pay(bob, carol, USDA(5)), sendmax(USDA(10)));
261  auto const effectiveQ =
262  carolAliceQIn > 100 ? 1.0 : carolAliceQIn / 100.0;
263  env.require(balance(bob, USDA(10.0 - 5.0 / effectiveQ)));
264  }
265 
266  // bob -> alice -> carol; bobAliceQOut varies.
267  for (auto bobAliceQOut : {80, 100, 120})
268  {
269  Env env(*this, features);
270  env.fund(XRP(10000), alice, bob, carol);
271  env(trust(bob, USDA(10)), qualityOutPercent(bobAliceQOut));
272  env(trust(carol, USDA(10)));
273 
274  env(pay(alice, bob, USDA(10)));
275  env.require(balance(bob, USDA(10)));
276  env(pay(bob, carol, USDA(5)), sendmax(USDA(5)));
277  env.require(balance(carol, USDA(5)));
278  env.require(balance(bob, USDA(10 - 5)));
279  }
280  }
281 
282  void
284  {
285  testcase("Book Step");
286 
287  using namespace jtx;
288 
289  auto const gw = Account("gateway");
290  auto const USD = gw["USD"];
291  auto const BTC = gw["BTC"];
292  auto const EUR = gw["EUR"];
293  Account const alice("alice");
294  Account const bob("bob");
295  Account const carol("carol");
296 
297  {
298  // simple IOU/IOU offer
299  Env env(*this, features);
300 
301  env.fund(XRP(10000), alice, bob, carol, gw);
302  env.trust(USD(1000), alice, bob, carol);
303  env.trust(BTC(1000), alice, bob, carol);
304 
305  env(pay(gw, alice, BTC(50)));
306  env(pay(gw, bob, USD(50)));
307 
308  env(offer(bob, BTC(50), USD(50)));
309 
310  env(pay(alice, carol, USD(50)), path(~USD), sendmax(BTC(50)));
311 
312  env.require(balance(alice, BTC(0)));
313  env.require(balance(bob, BTC(50)));
314  env.require(balance(bob, USD(0)));
315  env.require(balance(carol, USD(50)));
316  BEAST_EXPECT(!isOffer(env, bob, BTC(50), USD(50)));
317  }
318  {
319  // simple IOU/XRP XRP/IOU offer
320  Env env(*this, features);
321 
322  env.fund(XRP(10000), alice, bob, carol, gw);
323  env.trust(USD(1000), alice, bob, carol);
324  env.trust(BTC(1000), alice, bob, carol);
325 
326  env(pay(gw, alice, BTC(50)));
327  env(pay(gw, bob, USD(50)));
328 
329  env(offer(bob, BTC(50), XRP(50)));
330  env(offer(bob, XRP(50), USD(50)));
331 
332  env(pay(alice, carol, USD(50)), path(~XRP, ~USD), sendmax(BTC(50)));
333 
334  env.require(balance(alice, BTC(0)));
335  env.require(balance(bob, BTC(50)));
336  env.require(balance(bob, USD(0)));
337  env.require(balance(carol, USD(50)));
338  BEAST_EXPECT(!isOffer(env, bob, XRP(50), USD(50)));
339  BEAST_EXPECT(!isOffer(env, bob, BTC(50), XRP(50)));
340  }
341  {
342  // simple XRP -> USD through offer and sendmax
343  Env env(*this, features);
344 
345  env.fund(XRP(10000), alice, bob, carol, gw);
346  env.trust(USD(1000), alice, bob, carol);
347  env.trust(BTC(1000), alice, bob, carol);
348 
349  env(pay(gw, bob, USD(50)));
350 
351  env(offer(bob, XRP(50), USD(50)));
352 
353  env(pay(alice, carol, USD(50)), path(~USD), sendmax(XRP(50)));
354 
355  env.require(balance(alice, xrpMinusFee(env, 10000 - 50)));
356  env.require(balance(bob, xrpMinusFee(env, 10000 + 50)));
357  env.require(balance(bob, USD(0)));
358  env.require(balance(carol, USD(50)));
359  BEAST_EXPECT(!isOffer(env, bob, XRP(50), USD(50)));
360  }
361  {
362  // simple USD -> XRP through offer and sendmax
363  Env env(*this, features);
364 
365  env.fund(XRP(10000), alice, bob, carol, gw);
366  env.trust(USD(1000), alice, bob, carol);
367  env.trust(BTC(1000), alice, bob, carol);
368 
369  env(pay(gw, alice, USD(50)));
370 
371  env(offer(bob, USD(50), XRP(50)));
372 
373  env(pay(alice, carol, XRP(50)), path(~XRP), sendmax(USD(50)));
374 
375  env.require(balance(alice, USD(0)));
376  env.require(balance(bob, xrpMinusFee(env, 10000 - 50)));
377  env.require(balance(bob, USD(50)));
378  env.require(balance(carol, XRP(10000 + 50)));
379  BEAST_EXPECT(!isOffer(env, bob, USD(50), XRP(50)));
380  }
381  {
382  // test unfunded offers are removed when payment succeeds
383  Env env(*this, features);
384 
385  env.fund(XRP(10000), alice, bob, carol, gw);
386  env.trust(USD(1000), alice, bob, carol);
387  env.trust(BTC(1000), alice, bob, carol);
388  env.trust(EUR(1000), alice, bob, carol);
389 
390  env(pay(gw, alice, BTC(60)));
391  env(pay(gw, bob, USD(50)));
392  env(pay(gw, bob, EUR(50)));
393 
394  env(offer(bob, BTC(50), USD(50)));
395  env(offer(bob, BTC(40), EUR(50)));
396  env(offer(bob, EUR(50), USD(50)));
397 
398  // unfund offer
399  env(pay(bob, gw, EUR(50)));
400  BEAST_EXPECT(isOffer(env, bob, BTC(50), USD(50)));
401  BEAST_EXPECT(isOffer(env, bob, BTC(40), EUR(50)));
402  BEAST_EXPECT(isOffer(env, bob, EUR(50), USD(50)));
403 
404  env(pay(alice, carol, USD(50)),
405  path(~USD),
406  path(~EUR, ~USD),
407  sendmax(BTC(60)));
408 
409  env.require(balance(alice, BTC(10)));
410  env.require(balance(bob, BTC(50)));
411  env.require(balance(bob, USD(0)));
412  env.require(balance(bob, EUR(0)));
413  env.require(balance(carol, USD(50)));
414  // used in the payment
415  BEAST_EXPECT(!isOffer(env, bob, BTC(50), USD(50)));
416  // found unfunded
417  BEAST_EXPECT(!isOffer(env, bob, BTC(40), EUR(50)));
418  // unfunded, but should not yet be found unfunded
419  BEAST_EXPECT(isOffer(env, bob, EUR(50), USD(50)));
420  }
421  {
422  // test unfunded offers are returned when the payment fails.
423  // bob makes two offers: a funded 50 USD for 50 BTC and an unfunded
424  // 50 EUR for 60 BTC. alice pays carol 61 USD with 61 BTC. alice
425  // only has 60 BTC, so the payment will fail. The payment uses two
426  // paths: one through bob's funded offer and one through his
427  // unfunded offer. When the payment fails `flow` should return the
428  // unfunded offer. This test is intentionally similar to the one
429  // that removes unfunded offers when the payment succeeds.
430  Env env(*this, features);
431 
432  env.fund(XRP(10000), alice, bob, carol, gw);
433  env.trust(USD(1000), alice, bob, carol);
434  env.trust(BTC(1000), alice, bob, carol);
435  env.trust(EUR(1000), alice, bob, carol);
436 
437  env(pay(gw, alice, BTC(60)));
438  env(pay(gw, bob, USD(60)));
439  env(pay(gw, bob, EUR(50)));
440  env(pay(gw, carol, EUR(1)));
441 
442  env(offer(bob, BTC(50), USD(50)));
443  env(offer(bob, BTC(60), EUR(50)));
444  env(offer(carol, BTC(1000), EUR(1)));
445  env(offer(bob, EUR(50), USD(50)));
446 
447  // unfund offer
448  env(pay(bob, gw, EUR(50)));
449  BEAST_EXPECT(isOffer(env, bob, BTC(50), USD(50)));
450  BEAST_EXPECT(isOffer(env, bob, BTC(60), EUR(50)));
451  BEAST_EXPECT(isOffer(env, carol, BTC(1000), EUR(1)));
452 
453  auto flowJournal = env.app().logs().journal("Flow");
454  auto const flowResult = [&] {
455  STAmount deliver(USD(51));
456  STAmount smax(BTC(61));
457  PaymentSandbox sb(env.current().get(), tapNONE);
459  auto IPE = [](Issue const& iss) {
460  return STPathElement(
462  xrpAccount(),
463  iss.currency,
464  iss.account);
465  };
466  {
467  // BTC -> USD
468  STPath p1({IPE(USD.issue())});
469  paths.push_back(p1);
470  // BTC -> EUR -> USD
471  STPath p2({IPE(EUR.issue()), IPE(USD.issue())});
472  paths.push_back(p2);
473  }
474 
475  return flow(
476  sb,
477  deliver,
478  alice,
479  carol,
480  paths,
481  false,
482  false,
483  true,
484  false,
485  std::nullopt,
486  smax,
487  flowJournal);
488  }();
489 
490  BEAST_EXPECT(flowResult.removableOffers.size() == 1);
491  env.app().openLedger().modify(
492  [&](OpenView& view, beast::Journal j) {
493  if (flowResult.removableOffers.empty())
494  return false;
495  Sandbox sb(&view, tapNONE);
496  for (auto const& o : flowResult.removableOffers)
497  if (auto ok = sb.peek(keylet::offer(o)))
498  offerDelete(sb, ok, flowJournal);
499  sb.apply(view);
500  return true;
501  });
502 
503  // used in payment, but since payment failed should be untouched
504  BEAST_EXPECT(isOffer(env, bob, BTC(50), USD(50)));
505  BEAST_EXPECT(isOffer(env, carol, BTC(1000), EUR(1)));
506  // found unfunded
507  BEAST_EXPECT(!isOffer(env, bob, BTC(60), EUR(50)));
508  }
509  {
510  // Do not produce more in the forward pass than the reverse pass
511  // This test uses a path that whose reverse pass will compute a
512  // 0.5 USD input required for a 1 EUR output. It sets a sendmax of
513  // 0.4 USD, so the payment engine will need to do a forward pass.
514  // Without limits, the 0.4 USD would produce 1000 EUR in the forward
515  // pass. This test checks that the payment produces 1 EUR, as
516  // expected.
517 
518  Env env(*this, features);
519  env.fund(XRP(10000), alice, bob, carol, gw);
520  env.trust(USD(1000), alice, bob, carol);
521  env.trust(EUR(1000), alice, bob, carol);
522 
523  env(pay(gw, alice, USD(1000)));
524  env(pay(gw, bob, EUR(1000)));
525 
526  env(offer(bob, USD(1), drops(2)), txflags(tfPassive));
527  env(offer(bob, drops(1), EUR(1000)), txflags(tfPassive));
528 
529  env(pay(alice, carol, EUR(1)),
530  path(~XRP, ~EUR),
531  sendmax(USD(0.4)),
533 
534  env.require(balance(carol, EUR(1)));
535  env.require(balance(bob, USD(0.4)));
536  env.require(balance(bob, EUR(999)));
537  }
538  }
539 
540  void
542  {
543  testcase("Transfer Rate");
544 
545  using namespace jtx;
546 
547  auto const gw = Account("gateway");
548  auto const USD = gw["USD"];
549  auto const BTC = gw["BTC"];
550  auto const EUR = gw["EUR"];
551  Account const alice("alice");
552  Account const bob("bob");
553  Account const carol("carol");
554 
555  {
556  // Simple payment through a gateway with a
557  // transfer rate
558  Env env(*this, features);
559 
560  env.fund(XRP(10000), alice, bob, carol, gw);
561  env(rate(gw, 1.25));
562  env.trust(USD(1000), alice, bob, carol);
563  env(pay(gw, alice, USD(50)));
564  env.require(balance(alice, USD(50)));
565  env(pay(alice, bob, USD(40)), sendmax(USD(50)));
566  env.require(balance(bob, USD(40)), balance(alice, USD(0)));
567  }
568  {
569  // transfer rate is not charged when issuer is src or dst
570  Env env(*this, features);
571 
572  env.fund(XRP(10000), alice, bob, carol, gw);
573  env(rate(gw, 1.25));
574  env.trust(USD(1000), alice, bob, carol);
575  env(pay(gw, alice, USD(50)));
576  env.require(balance(alice, USD(50)));
577  env(pay(alice, gw, USD(40)), sendmax(USD(40)));
578  env.require(balance(alice, USD(10)));
579  }
580  {
581  // transfer fee on an offer
582  Env env(*this, features);
583 
584  env.fund(XRP(10000), alice, bob, carol, gw);
585  env(rate(gw, 1.25));
586  env.trust(USD(1000), alice, bob, carol);
587  env(pay(gw, bob, USD(65)));
588 
589  env(offer(bob, XRP(50), USD(50)));
590 
591  env(pay(alice, carol, USD(50)), path(~USD), sendmax(XRP(50)));
592  env.require(
593  balance(alice, xrpMinusFee(env, 10000 - 50)),
594  balance(bob, USD(2.5)), // owner pays transfer fee
595  balance(carol, USD(50)));
596  }
597 
598  {
599  // Transfer fee two consecutive offers
600  Env env(*this, features);
601 
602  env.fund(XRP(10000), alice, bob, carol, gw);
603  env(rate(gw, 1.25));
604  env.trust(USD(1000), alice, bob, carol);
605  env.trust(EUR(1000), alice, bob, carol);
606  env(pay(gw, bob, USD(50)));
607  env(pay(gw, bob, EUR(50)));
608 
609  env(offer(bob, XRP(50), USD(50)));
610  env(offer(bob, USD(50), EUR(50)));
611 
612  env(pay(alice, carol, EUR(40)), path(~USD, ~EUR), sendmax(XRP(40)));
613  env.require(
614  balance(alice, xrpMinusFee(env, 10000 - 40)),
615  balance(bob, USD(40)),
616  balance(bob, EUR(0)),
617  balance(carol, EUR(40)));
618  }
619 
620  {
621  // First pass through a strand redeems, second pass issues, no
622  // offers limiting step is not an endpoint
623  Env env(*this, features);
624  auto const USDA = alice["USD"];
625  auto const USDB = bob["USD"];
626 
627  env.fund(XRP(10000), alice, bob, carol, gw);
628  env(rate(gw, 1.25));
629  env.trust(USD(1000), alice, bob, carol);
630  env.trust(USDA(1000), bob);
631  env.trust(USDB(1000), gw);
632  env(pay(gw, bob, USD(50)));
633  // alice -> bob -> gw -> carol. $50 should have transfer fee; $10,
634  // no fee
635  env(pay(alice, carol, USD(50)), path(bob), sendmax(USDA(60)));
636  env.require(
637  balance(bob, USD(-10)),
638  balance(bob, USDA(60)),
639  balance(carol, USD(50)));
640  }
641  {
642  // First pass through a strand redeems, second pass issues, through
643  // an offer limiting step is not an endpoint
644  Env env(*this, features);
645  auto const USDA = alice["USD"];
646  auto const USDB = bob["USD"];
647  Account const dan("dan");
648 
649  env.fund(XRP(10000), alice, bob, carol, dan, gw);
650  env(rate(gw, 1.25));
651  env.trust(USD(1000), alice, bob, carol, dan);
652  env.trust(EUR(1000), carol, dan);
653  env.trust(USDA(1000), bob);
654  env.trust(USDB(1000), gw);
655  env(pay(gw, bob, USD(50)));
656  env(pay(gw, dan, EUR(100)));
657  env(offer(dan, USD(100), EUR(100)));
658  // alice -> bob -> gw -> carol. $50 should have transfer fee; $10,
659  // no fee
660  env(pay(alice, carol, EUR(50)),
661  path(bob, gw, ~EUR),
662  sendmax(USDA(60)),
664  env.require(
665  balance(bob, USD(-10)),
666  balance(bob, USDA(60)),
667  balance(dan, USD(50)),
668  balance(dan, EUR(37.5)),
669  balance(carol, EUR(50)));
670  }
671 
672  {
673  // Offer where the owner is also the issuer, owner pays fee
674  Env env(*this, features);
675 
676  env.fund(XRP(10000), alice, bob, gw);
677  env(rate(gw, 1.25));
678  env.trust(USD(1000), alice, bob);
679  env(offer(gw, XRP(100), USD(100)));
680  env(pay(alice, bob, USD(100)), sendmax(XRP(100)));
681  env.require(
682  balance(alice, xrpMinusFee(env, 10000 - 100)),
683  balance(bob, USD(100)));
684  }
685  if (!features[featureOwnerPaysFee])
686  {
687  // Offer where the owner is also the issuer, sender pays fee
688  Env env(*this, features);
689 
690  env.fund(XRP(10000), alice, bob, gw);
691  env(rate(gw, 1.25));
692  env.trust(USD(1000), alice, bob);
693  env(offer(gw, XRP(125), USD(125)));
694  env(pay(alice, bob, USD(100)), sendmax(XRP(200)));
695  env.require(
696  balance(alice, xrpMinusFee(env, 10000 - 125)),
697  balance(bob, USD(100)));
698  }
699  }
700 
701  void
703  {
704  testcase("falseDryChanges");
705 
706  using namespace jtx;
707 
708  auto const gw = Account("gateway");
709  auto const USD = gw["USD"];
710  auto const EUR = gw["EUR"];
711  Account const alice("alice");
712  Account const bob("bob");
713  Account const carol("carol");
714 
715  Env env(*this, features);
716 
717  env.fund(XRP(10000), alice, carol, gw);
718  env.fund(reserve(env, 5), bob);
719  env.trust(USD(1000), alice, bob, carol);
720  env.trust(EUR(1000), alice, bob, carol);
721 
722  env(pay(gw, alice, EUR(50)));
723  env(pay(gw, bob, USD(50)));
724 
725  // Bob has _just_ slightly less than 50 xrp available
726  // If his owner count changes, he will have more liquidity.
727  // This is one error case to test (when Flow is used).
728  // Computing the incoming xrp to the XRP/USD offer will require two
729  // recursive calls to the EUR/XRP offer. The second call will return
730  // tecPATH_DRY, but the entire path should not be marked as dry. This
731  // is the second error case to test (when flowV1 is used).
732  env(offer(bob, EUR(50), XRP(50)));
733  env(offer(bob, XRP(50), USD(50)));
734 
735  env(pay(alice, carol, USD(1000000)),
736  path(~XRP, ~USD),
737  sendmax(EUR(500)),
739 
740  auto const carolUSD = env.balance(carol, USD).value();
741  BEAST_EXPECT(carolUSD > USD(0) && carolUSD < USD(50));
742  }
743 
744  void
746  {
747  // Single path with two offers and limit quality. The quality limit is
748  // such that the first offer should be taken but the second should not.
749  // The total amount delivered should be the sum of the two offers and
750  // sendMax should be more than the first offer.
751  testcase("limitQuality");
752  using namespace jtx;
753 
754  auto const gw = Account("gateway");
755  auto const USD = gw["USD"];
756  Account const alice("alice");
757  Account const bob("bob");
758  Account const carol("carol");
759 
760  {
761  Env env(*this);
762 
763  env.fund(XRP(10000), alice, bob, carol, gw);
764 
765  env.trust(USD(100), alice, bob, carol);
766  env(pay(gw, bob, USD(100)));
767  env(offer(bob, XRP(50), USD(50)));
768  env(offer(bob, XRP(100), USD(50)));
769 
770  env(pay(alice, carol, USD(100)),
771  path(~USD),
772  sendmax(XRP(100)),
774 
775  env.require(balance(carol, USD(50)));
776  }
777  }
778 
779  // Helper function that returns the reserve on an account based on
780  // the passed in number of owners.
781  static XRPAmount
783  {
784  return env.current()->fees().accountReserve(count);
785  }
786 
787  // Helper function that returns the Offers on an account.
790  {
792  forEachItem(
793  *env.current(),
794  account,
795  [&result](std::shared_ptr<SLE const> const& sle) {
796  if (sle->getType() == ltOFFER)
797  result.push_back(sle);
798  });
799  return result;
800  }
801 
802  void
804  {
805  testcase("Self-payment 1");
806 
807  // In this test case the new flow code mis-computes the amount
808  // of money to move. Fortunately the new code's re-execute
809  // check catches the problem and throws out the transaction.
810  //
811  // The old payment code handles the payment correctly.
812  using namespace jtx;
813 
814  auto const gw1 = Account("gw1");
815  auto const gw2 = Account("gw2");
816  auto const alice = Account("alice");
817  auto const USD = gw1["USD"];
818  auto const EUR = gw2["EUR"];
819 
820  Env env(*this, features);
821 
822  env.fund(XRP(1000000), gw1, gw2);
823  env.close();
824 
825  // The fee that's charged for transactions.
826  auto const f = env.current()->fees().base;
827 
828  env.fund(reserve(env, 3) + f * 4, alice);
829  env.close();
830 
831  env(trust(alice, USD(2000)));
832  env(trust(alice, EUR(2000)));
833  env.close();
834 
835  env(pay(gw1, alice, USD(1)));
836  env(pay(gw2, alice, EUR(1000)));
837  env.close();
838 
839  env(offer(alice, USD(500), EUR(600)));
840  env.close();
841 
842  env.require(owners(alice, 3));
843  env.require(balance(alice, USD(1)));
844  env.require(balance(alice, EUR(1000)));
845 
846  auto aliceOffers = offersOnAccount(env, alice);
847  BEAST_EXPECT(aliceOffers.size() == 1);
848  for (auto const& offerPtr : aliceOffers)
849  {
850  auto const offer = *offerPtr;
851  BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
852  BEAST_EXPECT(offer[sfTakerGets] == EUR(600));
853  BEAST_EXPECT(offer[sfTakerPays] == USD(500));
854  }
855 
856  env(pay(alice, alice, EUR(600)),
857  sendmax(USD(500)),
859  env.close();
860 
861  env.require(owners(alice, 3));
862  env.require(balance(alice, USD(1)));
863  env.require(balance(alice, EUR(1000)));
864  aliceOffers = offersOnAccount(env, alice);
865  BEAST_EXPECT(aliceOffers.size() == 1);
866  for (auto const& offerPtr : aliceOffers)
867  {
868  auto const offer = *offerPtr;
869  BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
870  BEAST_EXPECT(offer[sfTakerGets] == EUR(598.8));
871  BEAST_EXPECT(offer[sfTakerPays] == USD(499));
872  }
873  }
874 
875  void
877  {
878  testcase("Self-payment 2");
879 
880  // In this case the difference between the old payment code and
881  // the new is the values left behind in the offer. Not saying either
882  // ios ring, they are just different.
883  using namespace jtx;
884 
885  auto const gw1 = Account("gw1");
886  auto const gw2 = Account("gw2");
887  auto const alice = Account("alice");
888  auto const USD = gw1["USD"];
889  auto const EUR = gw2["EUR"];
890 
891  Env env(*this, features);
892 
893  env.fund(XRP(1000000), gw1, gw2);
894  env.close();
895 
896  // The fee that's charged for transactions.
897  auto const f = env.current()->fees().base;
898 
899  env.fund(reserve(env, 3) + f * 4, alice);
900  env.close();
901 
902  env(trust(alice, USD(506)));
903  env(trust(alice, EUR(606)));
904  env.close();
905 
906  env(pay(gw1, alice, USD(500)));
907  env(pay(gw2, alice, EUR(600)));
908  env.close();
909 
910  env(offer(alice, USD(500), EUR(600)));
911  env.close();
912 
913  env.require(owners(alice, 3));
914  env.require(balance(alice, USD(500)));
915  env.require(balance(alice, EUR(600)));
916 
917  auto aliceOffers = offersOnAccount(env, alice);
918  BEAST_EXPECT(aliceOffers.size() == 1);
919  for (auto const& offerPtr : aliceOffers)
920  {
921  auto const offer = *offerPtr;
922  BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
923  BEAST_EXPECT(offer[sfTakerGets] == EUR(600));
924  BEAST_EXPECT(offer[sfTakerPays] == USD(500));
925  }
926 
927  env(pay(alice, alice, EUR(60)),
928  sendmax(USD(50)),
930  env.close();
931 
932  env.require(owners(alice, 3));
933  env.require(balance(alice, USD(500)));
934  env.require(balance(alice, EUR(600)));
935  aliceOffers = offersOnAccount(env, alice);
936  BEAST_EXPECT(aliceOffers.size() == 1);
937  for (auto const& offerPtr : aliceOffers)
938  {
939  auto const offer = *offerPtr;
940  BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
941  BEAST_EXPECT(offer[sfTakerGets] == EUR(594));
942  BEAST_EXPECT(offer[sfTakerPays] == USD(495));
943  }
944  }
945  void
946  testSelfFundedXRPEndpoint(bool consumeOffer, FeatureBitset features)
947  {
948  // Test that the deferred credit table is not bypassed for
949  // XRPEndpointSteps. If the account in the first step is sending XRP and
950  // that account also owns an offer that receives XRP, it should not be
951  // possible for that step to use the XRP received in the offer as part
952  // of the payment.
953  testcase("Self funded XRPEndpoint");
954 
955  using namespace jtx;
956 
957  Env env(*this, features);
958 
959  auto const alice = Account("alice");
960  auto const gw = Account("gw");
961  auto const USD = gw["USD"];
962 
963  env.fund(XRP(10000), alice, gw);
964  env(trust(alice, USD(20)));
965  env(pay(gw, alice, USD(10)));
966  env(offer(alice, XRP(50000), USD(10)));
967 
968  // Consuming the offer changes the owner count, which could also cause
969  // liquidity to decrease in the forward pass
970  auto const toSend = consumeOffer ? USD(10) : USD(9);
971  env(pay(alice, alice, toSend),
972  path(~USD),
973  sendmax(XRP(20000)),
975  }
976 
977  void
979  {
980  testcase("Unfunded Offer");
981 
982  using namespace jtx;
983  {
984  // Test reverse
985  Env env(*this, features);
986 
987  auto const alice = Account("alice");
988  auto const bob = Account("bob");
989  auto const gw = Account("gw");
990  auto const USD = gw["USD"];
991 
992  env.fund(XRP(100000), alice, bob, gw);
993  env(trust(bob, USD(20)));
994 
995  STAmount tinyAmt1{
996  USD.issue(),
997  9000000000000000ll,
998  -17,
999  false,
1000  false,
1002  STAmount tinyAmt3{
1003  USD.issue(),
1004  9000000000000003ll,
1005  -17,
1006  false,
1007  false,
1009 
1010  env(offer(gw, drops(9000000000), tinyAmt3));
1011  env(pay(alice, bob, tinyAmt1),
1012  path(~USD),
1013  sendmax(drops(9000000000)),
1015 
1016  BEAST_EXPECT(!isOffer(env, gw, XRP(0), USD(0)));
1017  }
1018  {
1019  // Test forward
1020  Env env(*this, features);
1021 
1022  auto const alice = Account("alice");
1023  auto const bob = Account("bob");
1024  auto const gw = Account("gw");
1025  auto const USD = gw["USD"];
1026 
1027  env.fund(XRP(100000), alice, bob, gw);
1028  env(trust(alice, USD(20)));
1029 
1030  STAmount tinyAmt1{
1031  USD.issue(),
1032  9000000000000000ll,
1033  -17,
1034  false,
1035  false,
1037  STAmount tinyAmt3{
1038  USD.issue(),
1039  9000000000000003ll,
1040  -17,
1041  false,
1042  false,
1044 
1045  env(pay(gw, alice, tinyAmt1));
1046 
1047  env(offer(gw, tinyAmt3, drops(9000000000)));
1048  env(pay(alice, bob, drops(9000000000)),
1049  path(~XRP),
1050  sendmax(USD(1)),
1052 
1053  BEAST_EXPECT(!isOffer(env, gw, USD(0), XRP(0)));
1054  }
1055  }
1056 
1057  void
1059  {
1060  testcase("ReexecuteDirectStep");
1061 
1062  using namespace jtx;
1063  Env env(*this, features);
1064 
1065  auto const alice = Account("alice");
1066  auto const bob = Account("bob");
1067  auto const gw = Account("gw");
1068  auto const USD = gw["USD"];
1069  auto const usdC = USD.currency;
1070 
1071  env.fund(XRP(10000), alice, bob, gw);
1072  env.close();
1073  env(trust(alice, USD(100)));
1074  env.close();
1075 
1076  BEAST_EXPECT(!getNoRippleFlag(env, gw, alice, usdC));
1077 
1078  env(pay(
1079  gw,
1080  alice,
1081  // 12.55....
1082  STAmount{
1083  USD.issue(), std::uint64_t(1255555555555555ull), -14, false}));
1084 
1085  env(offer(
1086  gw,
1087  // 5.0...
1088  STAmount{
1089  USD.issue(), std::uint64_t(5000000000000000ull), -15, false},
1090  XRP(1000)));
1091 
1092  env(offer(
1093  gw,
1094  // .555...
1095  STAmount{
1096  USD.issue(), std::uint64_t(5555555555555555ull), -16, false},
1097  XRP(10)));
1098 
1099  env(offer(
1100  gw,
1101  // 4.44....
1102  STAmount{
1103  USD.issue(), std::uint64_t(4444444444444444ull), -15, false},
1104  XRP(.1)));
1105 
1106  env(offer(
1107  alice,
1108  // 17
1109  STAmount{
1110  USD.issue(), std::uint64_t(1700000000000000ull), -14, false},
1111  XRP(.001)));
1112 
1113  env(pay(alice, bob, XRP(10000)),
1114  path(~XRP),
1115  sendmax(USD(100)),
1117  }
1118 
1119  void
1121  {
1122  testcase("ripd1443");
1123 
1124  using namespace jtx;
1125  Env env(*this);
1126  auto const alice = Account("alice");
1127  auto const bob = Account("bob");
1128  auto const carol = Account("carol");
1129  auto const gw = Account("gw");
1130 
1131  env.fund(XRP(100000000), alice, noripple(bob), carol, gw);
1132  env.trust(gw["USD"](10000), alice, carol);
1133  env(trust(bob, gw["USD"](10000), tfSetNoRipple));
1134  env.trust(gw["USD"](10000), bob);
1135  env.close();
1136 
1137  // set no ripple between bob and the gateway
1138 
1139  env(pay(gw, alice, gw["USD"](1000)));
1140  env.close();
1141 
1142  env(offer(alice, bob["USD"](1000), XRP(1)));
1143  env.close();
1144 
1145  env(pay(alice, alice, XRP(1)),
1146  path(gw, bob, ~XRP),
1147  sendmax(gw["USD"](1000)),
1149  ter(tecPATH_DRY));
1150  env.close();
1151 
1152  env.trust(bob["USD"](10000), alice);
1153  env(pay(bob, alice, bob["USD"](1000)));
1154 
1155  env(offer(alice, XRP(1000), bob["USD"](1000)));
1156  env.close();
1157 
1158  env(pay(carol, carol, gw["USD"](1000)),
1159  path(~bob["USD"], gw),
1160  sendmax(XRP(100000)),
1162  ter(tecPATH_DRY));
1163  env.close();
1164 
1165  pass();
1166  }
1167 
1168  void
1170  {
1171  testcase("ripd1449");
1172 
1173  using namespace jtx;
1174  Env env(*this);
1175 
1176  // pay alice -> xrp -> USD/bob -> bob -> gw -> alice
1177  // set no ripple on bob's side of the bob/gw trust line
1178  // carol has the bob/USD and makes an offer, bob has USD/gw
1179 
1180  auto const alice = Account("alice");
1181  auto const bob = Account("bob");
1182  auto const carol = Account("carol");
1183  auto const gw = Account("gw");
1184  auto const USD = gw["USD"];
1185 
1186  env.fund(XRP(100000000), alice, bob, carol, gw);
1187  env.close();
1188  env.trust(USD(10000), alice, carol);
1189  env(trust(bob, USD(10000), tfSetNoRipple));
1190  env.trust(USD(10000), bob);
1191  env.trust(bob["USD"](10000), carol);
1192  env.close();
1193 
1194  env(pay(bob, carol, bob["USD"](1000)));
1195  env(pay(gw, bob, USD(1000)));
1196  env.close();
1197 
1198  env(offer(carol, XRP(1), bob["USD"](1000)));
1199  env.close();
1200 
1201  env(pay(alice, alice, USD(1000)),
1202  path(~bob["USD"], bob, gw),
1203  sendmax(XRP(1)),
1205  ter(tecPATH_DRY));
1206  env.close();
1207  }
1208 
1209  void
1211  {
1212  // The new payment code used to assert if an offer was made for more
1213  // XRP than the offering account held. This unit test reproduces
1214  // that failing case.
1215  testcase("Self crossing low quality offer");
1216 
1217  using namespace jtx;
1218 
1219  Env env(*this, features);
1220 
1221  auto const ann = Account("ann");
1222  auto const gw = Account("gateway");
1223  auto const CTB = gw["CTB"];
1224 
1225  auto const fee = env.current()->fees().base;
1226  env.fund(reserve(env, 2) + drops(9999640) + fee, ann);
1227  env.fund(reserve(env, 2) + fee * 4, gw);
1228  env.close();
1229 
1230  env(rate(gw, 1.002));
1231  env(trust(ann, CTB(10)));
1232  env.close();
1233 
1234  env(pay(gw, ann, CTB(2.856)));
1235  env.close();
1236 
1237  env(offer(ann, drops(365611702030), CTB(5.713)));
1238  env.close();
1239 
1240  // This payment caused the assert.
1241  env(pay(ann, ann, CTB(0.687)),
1242  sendmax(drops(20000000000)),
1244  }
1245 
1246  void
1248  {
1249  testcase("Empty Strand");
1250  using namespace jtx;
1251 
1252  auto const alice = Account("alice");
1253 
1254  Env env(*this, features);
1255 
1256  env.fund(XRP(10000), alice);
1257 
1258  env(pay(alice, alice, alice["USD"](100)),
1259  path(~alice["USD"]),
1260  ter(temBAD_PATH));
1261  }
1262 
1263  void
1265  {
1266  testcase("Circular XRP");
1267 
1268  using namespace jtx;
1269  auto const alice = Account("alice");
1270  auto const bob = Account("bob");
1271  auto const gw = Account("gw");
1272  auto const USD = gw["USD"];
1273  auto const EUR = gw["EUR"];
1274 
1275  for (auto const withFix : {true, false})
1276  {
1277  auto const feats = [&withFix]() -> FeatureBitset {
1278  if (withFix)
1279  return supported_amendments();
1281  }();
1282  {
1283  // Payment path starting with XRP
1284  Env env(*this, feats);
1285  env.fund(XRP(10000), alice, bob, gw);
1286  env.trust(USD(1000), alice, bob);
1287  env.trust(EUR(1000), alice, bob);
1288  env(pay(gw, alice, USD(100)));
1289  env(pay(gw, alice, EUR(100)));
1290  env.close();
1291 
1292  env(offer(alice, XRP(100), USD(100)), txflags(tfPassive));
1293  env(offer(alice, USD(100), XRP(100)), txflags(tfPassive));
1294  env(offer(alice, XRP(100), EUR(100)), txflags(tfPassive));
1295  env.close();
1296 
1297  TER const expectedTer =
1298  withFix ? TER{temBAD_PATH_LOOP} : TER{tesSUCCESS};
1299  env(pay(alice, bob, EUR(1)),
1300  path(~USD, ~XRP, ~EUR),
1301  sendmax(XRP(1)),
1303  ter(expectedTer));
1304  }
1305  pass();
1306  }
1307  {
1308  // Payment path ending with XRP
1309  Env env(*this);
1310  env.fund(XRP(10000), alice, bob, gw);
1311  env.trust(USD(1000), alice, bob);
1312  env.trust(EUR(1000), alice, bob);
1313  env(pay(gw, alice, USD(100)));
1314  env(pay(gw, alice, EUR(100)));
1315  env.close();
1316 
1317  env(offer(alice, XRP(100), USD(100)), txflags(tfPassive));
1318  env(offer(alice, EUR(100), XRP(100)), txflags(tfPassive));
1319  env.close();
1320  // EUR -> //XRP -> //USD ->XRP
1321  env(pay(alice, bob, XRP(1)),
1322  path(~XRP, ~USD, ~XRP),
1323  sendmax(EUR(1)),
1326  }
1327  {
1328  // Payment where loop is formed in the middle of the path, not on an
1329  // endpoint
1330  auto const JPY = gw["JPY"];
1331  Env env(*this);
1332  env.fund(XRP(10000), alice, bob, gw);
1333  env.close();
1334  env.trust(USD(1000), alice, bob);
1335  env.trust(EUR(1000), alice, bob);
1336  env.trust(JPY(1000), alice, bob);
1337  env.close();
1338  env(pay(gw, alice, USD(100)));
1339  env(pay(gw, alice, EUR(100)));
1340  env(pay(gw, alice, JPY(100)));
1341  env.close();
1342 
1343  env(offer(alice, USD(100), XRP(100)), txflags(tfPassive));
1344  env(offer(alice, XRP(100), EUR(100)), txflags(tfPassive));
1345  env(offer(alice, EUR(100), XRP(100)), txflags(tfPassive));
1346  env(offer(alice, XRP(100), JPY(100)), txflags(tfPassive));
1347  env.close();
1348 
1349  env(pay(alice, bob, JPY(1)),
1350  path(~XRP, ~EUR, ~XRP, ~JPY),
1351  sendmax(USD(1)),
1354  }
1355  }
1356 
1357  void
1359  {
1360  testcase("Payment with ticket");
1361  using namespace jtx;
1362 
1363  auto const alice = Account("alice");
1364  auto const bob = Account("bob");
1365 
1366  Env env(*this, features);
1367 
1368  env.fund(XRP(10000), alice);
1369 
1370  // alice creates a ticket for the payment.
1371  std::uint32_t const ticketSeq{env.seq(alice) + 1};
1372  env(ticket::create(alice, 1));
1373 
1374  // Make a payment using the ticket.
1375  env(pay(alice, bob, XRP(1000)), ticket::use(ticketSeq));
1376  env.close();
1377  env.require(balance(bob, XRP(1000)));
1378  env.require(balance(alice, XRP(9000) - drops(20)));
1379  }
1380 
1381  void
1383  {
1384  using namespace jtx;
1385  FeatureBitset const ownerPaysFee{featureOwnerPaysFee};
1386 
1387  testLineQuality(features);
1388  testFalseDry(features);
1389  testDirectStep(features);
1390  testBookStep(features);
1391  testDirectStep(features | ownerPaysFee);
1392  testBookStep(features | ownerPaysFee);
1393  testTransferRate(features | ownerPaysFee);
1394  testSelfPayment1(features);
1395  testSelfPayment2(features);
1396  testSelfFundedXRPEndpoint(false, features);
1397  testSelfFundedXRPEndpoint(true, features);
1398  testUnfundedOffer(features);
1399  testReexecuteDirectStep(features);
1400  testSelfPayLowQualityOffer(features);
1401  testTicketPay(features);
1402  }
1403 
1404  void
1405  run() override
1406  {
1407  testLimitQuality();
1408  testXRPPathLoop();
1409  testRIPD1443();
1410  testRIPD1449();
1411 
1412  using namespace jtx;
1413  auto const sa = supported_amendments();
1415  testWithFeats(sa);
1416  testEmptyStrand(sa);
1417  }
1418 };
1419 
1421 {
1422  void
1423  run() override
1424  {
1425  using namespace jtx;
1426  auto const all = supported_amendments();
1427  FeatureBitset const flowCross{featureFlowCross};
1428  FeatureBitset const f1513{fix1513};
1429 
1430  testWithFeats(all - flowCross - f1513);
1431  testWithFeats(all - flowCross);
1432  testWithFeats(all - f1513);
1433  testWithFeats(all);
1434 
1435  testEmptyStrand(all - f1513);
1437  }
1438 };
1439 
1440 BEAST_DEFINE_TESTSUITE_PRIO(Flow, app, ripple, 2);
1441 BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Flow_manual, app, ripple, 4);
1442 
1443 } // namespace test
1444 } // namespace ripple
ripple::test::Flow_test::testLineQuality
void testLineQuality(FeatureBitset features)
Definition: Flow_test.cpp:210
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::jtx::dropsPerXRP
constexpr XRPAmount dropsPerXRP
Definition: amount.h:67
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
std::shared_ptr
STL class.
ripple::test::Flow_manual_test::run
void run() override
Definition: Flow_test.cpp:1423
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::test::Flow_test::testReexecuteDirectStep
void testReexecuteDirectStep(FeatureBitset features)
Definition: Flow_test.cpp:1058
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:347
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::PaymentSandbox
A wrapper which makes credits unavailable to balances.
Definition: PaymentSandbox.h:112
ripple::test::jtx::owners
Match the number of items in the account's owner directory.
Definition: owners.h:69
ripple::test::jtx::Env::require
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:466
ripple::TxSearched::all
@ all
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:55
ripple::lsfLowNoRipple
@ lsfLowNoRipple
Definition: LedgerFormats.h:256
std::vector
STL class.
ripple::test::jtx::trust
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition: trust.cpp:30
ripple::test::Flow_test::testFalseDry
void testFalseDry(FeatureBitset features)
Definition: Flow_test.cpp:702
ripple::tfSetNoRipple
constexpr std::uint32_t tfSetNoRipple
Definition: TxFlags.h:109
ripple::test::Flow_test::testSelfFundedXRPEndpoint
void testSelfFundedXRPEndpoint(bool consumeOffer, FeatureBitset features)
Definition: Flow_test.cpp:946
ripple::keylet::offer
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition: Indexes.cpp:222
ripple::fix1781
const uint256 fix1781
ripple::test::Flow_test::testWithFeats
void testWithFeats(FeatureBitset features)
Definition: Flow_test.cpp:1382
ripple::test::jtx::Env::balance
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:183
ripple::tfPassive
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:93
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::test::Flow_test::testRIPD1443
void testRIPD1443()
Definition: Flow_test.cpp:1120
ripple::Application::openLedger
virtual OpenLedger & openLedger()=0
ripple::test::Flow_test::testEmptyStrand
void testEmptyStrand(FeatureBitset features)
Definition: Flow_test.cpp:1247
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:30
ripple::temBAD_PATH
@ temBAD_PATH
Definition: TER.h:94
ripple::test::Flow_test::testUnfundedOffer
void testUnfundedOffer(FeatureBitset features)
Definition: Flow_test.cpp:978
ripple::test::jtx::qualityInPercent
Sets the QualityIn on a trust JTx.
Definition: quality.h:45
ripple::test::Flow_test::run
void run() override
Definition: Flow_test.cpp:1405
ripple::STPathElement::typeCurrency
@ typeCurrency
Definition: STPathSet.h:49
ripple::STPathSet
Definition: STPathSet.h:176
ripple::test::jtx::Env::trust
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:259
ripple::test::BEAST_DEFINE_TESTSUITE_PRIO
BEAST_DEFINE_TESTSUITE_PRIO(AccountDelete, app, ripple, 2)
ripple::STPathElement::typeIssuer
@ typeIssuer
Definition: STPathSet.h:50
ripple::test::jtx::Account::id
AccountID id() const
Returns the Account ID.
Definition: Account.h:106
ripple::test::Flow_test::testSelfPayment1
void testSelfPayment1(FeatureBitset features)
Definition: Flow_test.cpp:803
ripple::tfLimitQuality
constexpr std::uint32_t tfLimitQuality
Definition: TxFlags.h:103
ripple::base_uint< 160, detail::CurrencyTag >
ripple::sfTakerPays
const SF_AMOUNT sfTakerPays
ripple::test::jtx::ticket::use
Set a ticket sequence on a JTx.
Definition: ticket.h:47
ripple::flow
path::RippleCalc::Output flow(PaymentSandbox &view, STAmount const &deliver, AccountID const &src, AccountID const &dst, STPathSet const &paths, bool defaultPaths, bool partialPayment, bool ownerPaysTransferFee, bool offerCrossing, std::optional< Quality > const &limitQuality, std::optional< STAmount > const &sendMax, beast::Journal j, path::detail::FlowDebugInfo *flowDebugInfo=nullptr)
Make a payment from the src account to the dst account.
ripple::ltOFFER
@ ltOFFER
A ledger object which describes an offer on the DEX.
Definition: LedgerFormats.h:92
ripple::test::BEAST_DEFINE_TESTSUITE_MANUAL_PRIO
BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(CrossingLimits, tx, ripple, 10)
ripple::tfPartialPayment
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:102
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:893
ripple::fix1513
const uint256 fix1513
ripple::TERSubset< CanCvtToTER >
ripple::test::jtx::sendmax
Sets the SendMax on a JTx.
Definition: sendmax.h:31
ripple::Sandbox
Discardable, editable view to a ledger.
Definition: Sandbox.h:34
ripple::test::jtx::txflags
Set the flags on a JTx.
Definition: txflags.h:30
ripple::test::jtx::paths
Set Paths, SendMax on a JTx.
Definition: paths.h:32
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::test::getNoRippleFlag
bool getNoRippleFlag(jtx::Env const &env, jtx::Account const &src, jtx::Account const &dst, Currency const &cur)
Definition: Flow_test.cpp:36
ripple::STAmount
Definition: STAmount.h:45
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:168
ripple::test::isOffer
bool isOffer(jtx::Env &env, jtx::Account const &account, STAmount const &takerPays, STAmount const &takerGets)
An offer exists.
Definition: PathSet.h:71
ripple::test::Flow_manual_test
Definition: Flow_test.cpp:1420
ripple::Application::logs
virtual Logs & logs()=0
ripple::sfTakerGets
const SF_AMOUNT sfTakerGets
ripple::test::jtx::path
Add a path.
Definition: paths.h:55
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
std::int64_t
ripple::tecPATH_PARTIAL
@ tecPATH_PARTIAL
Definition: TER.h:249
ripple::keylet::line
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:193
ripple::test::jtx::Env::seq
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:207
ripple::test::Flow_test::testTransferRate
void testTransferRate(FeatureBitset features)
Definition: Flow_test.cpp:541
ripple::test::Flow_test::testRIPD1449
void testRIPD1449()
Definition: Flow_test.cpp:1169
ripple::test::jtx::qualityOutPercent
Sets the QualityOut on a trust JTx as a percentage.
Definition: quality.h:73
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple::lsfHighNoRipple
@ lsfHighNoRipple
Definition: LedgerFormats.h:257
ripple::test::Flow_test::reserve
static XRPAmount reserve(jtx::Env &env, std::uint32_t count)
Definition: Flow_test.cpp:782
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::Flow_test::offersOnAccount
static std::vector< std::shared_ptr< SLE const > > offersOnAccount(jtx::Env &env, jtx::Account account)
Definition: Flow_test.cpp:789
ripple::test::jtx::noripple
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
Definition: Env.h:64
ripple::STAmount::unchecked
Definition: STAmount.h:80
ripple::Logs::journal
beast::Journal journal(std::string const &name)
Definition: Log.cpp:144
ripple::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::STPathElement
Definition: STPathSet.h:34
ripple::test::Flow_test::testDirectStep
void testDirectStep(FeatureBitset features)
Definition: Flow_test.cpp:63
ripple::test::Flow_test::testLimitQuality
void testLimitQuality()
Definition: Flow_test.cpp:745
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:216
ripple::test::IPE
auto IPE(Issue const &iss)
Definition: Path_test.cpp:162
ripple::test::Flow_test::testTicketPay
void testTicketPay(FeatureBitset features)
Definition: Flow_test.cpp:1358
ripple::FeatureBitset
Definition: Feature.h:113
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:261
ripple::forEachItem
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
Definition: View.cpp:367
ripple::test::jtx::PrettyAmount::value
STAmount const & value() const
Definition: amount.h:124
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::temBAD_PATH_LOOP
@ temBAD_PATH_LOOP
Definition: TER.h:95
ripple::featureOwnerPaysFee
const uint256 featureOwnerPaysFee
ripple::test::Flow_test::testXRPPathLoop
void testXRPPathLoop()
Definition: Flow_test.cpp:1264
ripple::featureFlowCross
const uint256 featureFlowCross
ripple::STPath
Definition: STPathSet.h:118
ripple::test::Flow_test::testBookStep
void testBookStep(FeatureBitset features)
Definition: Flow_test.cpp:283
ripple::test::xrpMinusFee
jtx::PrettyAmount xrpMinusFee(jtx::Env const &env, std::int64_t xrpAmount)
Definition: Flow_test.cpp:53
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:222
ripple::OpenLedger::modify
bool modify(modify_type const &f)
Modify the open ledger.
Definition: OpenLedger.cpp:57
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:300
ripple::test::Flow_test::testSelfPayLowQualityOffer
void testSelfPayLowQualityOffer(FeatureBitset features)
Definition: Flow_test.cpp:1210
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::tfNoRippleDirect
constexpr std::uint32_t tfNoRippleDirect
Definition: TxFlags.h:101
ripple::test::Flow_test::testSelfPayment2
void testSelfPayment2(FeatureBitset features)
Definition: Flow_test.cpp:876
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::test::jtx::rate
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition: rate.cpp:30
ripple::test::Flow_test
Definition: Flow_test.cpp:60