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