rippled
Loading...
Searching...
No Matches
Check_test.cpp
1#include <test/jtx.h>
2
3#include <xrpl/protocol/Feature.h>
4#include <xrpl/protocol/jss.h>
5
6namespace xrpl {
7namespace test {
8namespace jtx {
9
12{
13private:
15
16public:
17 explicit expiration(NetClock::time_point const& expiry)
18 : expiry_{expiry.time_since_epoch().count()}
19 {
20 }
21
22 void
23 operator()(Env&, JTx& jt) const
24 {
25 jt[sfExpiration.jsonName] = expiry_;
26 }
27};
28
31{
32private:
34
35public:
36 explicit source_tag(std::uint32_t tag) : tag_{tag}
37 {
38 }
39
40 void
41 operator()(Env&, JTx& jt) const
42 {
43 jt[sfSourceTag.jsonName] = tag_;
44 }
45};
46
49{
50private:
52
53public:
54 explicit dest_tag(std::uint32_t tag) : tag_{tag}
55 {
56 }
57
58 void
59 operator()(Env&, JTx& jt) const
60 {
61 jt[sfDestinationTag.jsonName] = tag_;
62 }
63};
64
65} // namespace jtx
66} // namespace test
67
69{
70 static uint256
71 getCheckIndex(AccountID const& account, std::uint32_t uSequence)
72 {
73 return keylet::check(account, uSequence).key;
74 }
75
76 // Helper function that returns the Checks on an account.
79 {
82 *env.current(),
83 account,
84 [&result](std::shared_ptr<SLE const> const& sle) {
85 if (sle && sle->getType() == ltCHECK)
86 result.push_back(sle);
87 });
88 return result;
89 }
90
91 // Helper function that verifies the expected DeliveredAmount is present.
92 //
93 // NOTE: the function _infers_ the transaction to operate on by calling
94 // env.tx(), which returns the result from the most recent transaction.
95 void
97 {
98 // Get the hash for the most recent transaction.
99 std::string const txHash{
100 env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
101
102 // Verify DeliveredAmount and delivered_amount metadata are correct.
103 env.close();
104 Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta];
105
106 // Expect there to be a DeliveredAmount field.
107 if (!BEAST_EXPECT(meta.isMember(sfDeliveredAmount.jsonName)))
108 return;
109
110 // DeliveredAmount and delivered_amount should both be present and
111 // equal amount.
112 BEAST_EXPECT(
113 meta[sfDeliveredAmount.jsonName] ==
114 amount.getJson(JsonOptions::none));
115 BEAST_EXPECT(
116 meta[jss::delivered_amount] == amount.getJson(JsonOptions::none));
117 }
118
119 void
121 {
122 testcase("Enabled");
123
124 using namespace test::jtx;
125 Account const alice{"alice"};
126 {
127 // If the Checks amendment is enabled all check-related
128 // facilities should be available.
129 Env env{*this, features};
130
131 env.fund(XRP(1000), alice);
132 env.close();
133
134 uint256 const checkId1{
135 getCheckIndex(env.master, env.seq(env.master))};
136 env(check::create(env.master, alice, XRP(100)));
137 env.close();
138
139 env(check::cash(alice, checkId1, XRP(100)));
140 env.close();
141
142 uint256 const checkId2{
143 getCheckIndex(env.master, env.seq(env.master))};
144 env(check::create(env.master, alice, XRP(100)));
145 env.close();
146
147 env(check::cancel(alice, checkId2));
148 env.close();
149 }
150 }
151
152 void
154 {
155 // Explore many of the valid ways to create a check.
156 testcase("Create valid");
157
158 using namespace test::jtx;
159
160 Account const gw{"gateway"};
161 Account const alice{"alice"};
162 Account const bob{"bob"};
163 IOU const USD{gw["USD"]};
164
165 Env env{*this, features};
166
167 STAmount const startBalance{XRP(1000).value()};
168 env.fund(startBalance, gw, alice, bob);
169 env.close();
170
171 // Note that no trust line has been set up for alice, but alice can
172 // still write a check for USD. You don't have to have the funds
173 // necessary to cover a check in order to write a check.
174 auto writeTwoChecks = [&env, &USD, this](
175 Account const& from, Account const& to) {
176 std::uint32_t const fromOwnerCount{ownerCount(env, from)};
177 std::uint32_t const toOwnerCount{ownerCount(env, to)};
178
179 std::size_t const fromCkCount{checksOnAccount(env, from).size()};
180 std::size_t const toCkCount{checksOnAccount(env, to).size()};
181
182 env(check::create(from, to, XRP(2000)));
183 env.close();
184
185 env(check::create(from, to, USD(50)));
186 env.close();
187
188 BEAST_EXPECT(checksOnAccount(env, from).size() == fromCkCount + 2);
189 BEAST_EXPECT(checksOnAccount(env, to).size() == toCkCount + 2);
190
191 env.require(owners(from, fromOwnerCount + 2));
192 env.require(
193 owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount));
194 };
195 // from to
196 writeTwoChecks(alice, bob);
197 writeTwoChecks(gw, alice);
198 writeTwoChecks(alice, gw);
199
200 // Now try adding the various optional fields. There's no
201 // expected interaction between these optional fields; other than
202 // the expiration, they are just plopped into the ledger. So I'm
203 // not looking at interactions.
204 using namespace std::chrono_literals;
205 std::size_t const aliceCount{checksOnAccount(env, alice).size()};
206 std::size_t const bobCount{checksOnAccount(env, bob).size()};
207 env(check::create(alice, bob, USD(50)), expiration(env.now() + 1s));
208 env.close();
209
210 env(check::create(alice, bob, USD(50)), source_tag(2));
211 env.close();
212 env(check::create(alice, bob, USD(50)), dest_tag(3));
213 env.close();
214 env(check::create(alice, bob, USD(50)), invoice_id(uint256{4}));
215 env.close();
216 env(check::create(alice, bob, USD(50)),
217 expiration(env.now() + 1s),
218 source_tag(12),
219 dest_tag(13),
220 invoice_id(uint256{4}));
221 env.close();
222
223 BEAST_EXPECT(checksOnAccount(env, alice).size() == aliceCount + 5);
224 BEAST_EXPECT(checksOnAccount(env, bob).size() == bobCount + 5);
225
226 // Use a regular key and also multisign to create a check.
227 Account const alie{"alie", KeyType::ed25519};
228 env(regkey(alice, alie));
229 env.close();
230
231 Account const bogie{"bogie", KeyType::secp256k1};
232 Account const demon{"demon", KeyType::ed25519};
233 env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie));
234 env.close();
235
236 // alice uses her regular key to create a check.
237 env(check::create(alice, bob, USD(50)), sig(alie));
238 env.close();
239 BEAST_EXPECT(checksOnAccount(env, alice).size() == aliceCount + 6);
240 BEAST_EXPECT(checksOnAccount(env, bob).size() == bobCount + 6);
241
242 // alice uses multisigning to create a check.
243 XRPAmount const baseFeeDrops{env.current()->fees().base};
244 env(check::create(alice, bob, USD(50)),
245 msig(bogie, demon),
246 fee(3 * baseFeeDrops));
247 env.close();
248 BEAST_EXPECT(checksOnAccount(env, alice).size() == aliceCount + 7);
249 BEAST_EXPECT(checksOnAccount(env, bob).size() == bobCount + 7);
250 }
251
252 void
254 {
255 testcase("Create valid with disallow incoming");
256
257 using namespace test::jtx;
258
259 Account const gw{"gateway"};
260 Account const alice{"alice"};
261 Account const bob{"bob"};
262 IOU const USD{gw["USD"]};
263
264 Env env{*this, features};
265
266 STAmount const startBalance{XRP(1000).value()};
267 env.fund(startBalance, gw, alice, bob);
268 env.close();
269
270 /*
271 * Attempt to create two checks from `from` to `to` and
272 * require they both result in error/success code `expected`
273 */
274 auto writeTwoChecksDI = [&env, &USD, this](
275 Account const& from,
276 Account const& to,
277 TER expected) {
278 std::uint32_t const fromOwnerCount{ownerCount(env, from)};
279 std::uint32_t const toOwnerCount{ownerCount(env, to)};
280
281 std::size_t const fromCkCount{checksOnAccount(env, from).size()};
282 std::size_t const toCkCount{checksOnAccount(env, to).size()};
283
284 env(check::create(from, to, XRP(2000)), ter(expected));
285 env.close();
286
287 env(check::create(from, to, USD(50)), ter(expected));
288 env.close();
289
290 if (expected == tesSUCCESS)
291 {
292 BEAST_EXPECT(
293 checksOnAccount(env, from).size() == fromCkCount + 2);
294 BEAST_EXPECT(checksOnAccount(env, to).size() == toCkCount + 2);
295
296 env.require(owners(from, fromOwnerCount + 2));
297 env.require(
298 owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount));
299 return;
300 }
301
302 BEAST_EXPECT(checksOnAccount(env, from).size() == fromCkCount);
303 BEAST_EXPECT(checksOnAccount(env, to).size() == toCkCount);
304
305 env.require(owners(from, fromOwnerCount));
306 env.require(owners(to, to == from ? fromOwnerCount : toOwnerCount));
307 };
308
309 // enable the DisallowIncoming flag on both bob and alice
310 env(fset(bob, asfDisallowIncomingCheck));
311 env(fset(alice, asfDisallowIncomingCheck));
312 env.close();
313
314 // both alice and bob can't receive checks
315 writeTwoChecksDI(alice, bob, tecNO_PERMISSION);
316 writeTwoChecksDI(gw, alice, tecNO_PERMISSION);
317
318 // remove the flag from alice but not from bob
319 env(fclear(alice, asfDisallowIncomingCheck));
320 env.close();
321
322 // now bob can send alice a cheque but not visa-versa
323 writeTwoChecksDI(bob, alice, tesSUCCESS);
324 writeTwoChecksDI(alice, bob, tecNO_PERMISSION);
325
326 // remove bob's flag too
327 env(fclear(bob, asfDisallowIncomingCheck));
328 env.close();
329
330 // now they can send checks freely
331 writeTwoChecksDI(bob, alice, tesSUCCESS);
332 writeTwoChecksDI(alice, bob, tesSUCCESS);
333 }
334
335 void
337 {
338 // Explore many of the invalid ways to create a check.
339 testcase("Create invalid");
340
341 using namespace test::jtx;
342
343 Account const gw1{"gateway1"};
344 Account const gwF{"gatewayFrozen"};
345 Account const alice{"alice"};
346 Account const bob{"bob"};
347 IOU const USD{gw1["USD"]};
348
349 Env env{*this, features};
350
351 STAmount const startBalance{XRP(1000).value()};
352 env.fund(startBalance, gw1, gwF, alice, bob);
353 env.close();
354
355 // Bad fee.
356 env(check::create(alice, bob, USD(50)),
357 fee(drops(-10)),
358 ter(temBAD_FEE));
359 env.close();
360
361 // Bad flags.
362 env(check::create(alice, bob, USD(50)),
363 txflags(tfImmediateOrCancel),
364 ter(temINVALID_FLAG));
365 env.close();
366
367 // Check to self.
368 env(check::create(alice, alice, XRP(10)), ter(temREDUNDANT));
369 env.close();
370
371 // Bad amount.
372 env(check::create(alice, bob, drops(-1)), ter(temBAD_AMOUNT));
373 env.close();
374
375 env(check::create(alice, bob, drops(0)), ter(temBAD_AMOUNT));
376 env.close();
377
378 env(check::create(alice, bob, drops(1)));
379 env.close();
380
381 env(check::create(alice, bob, USD(-1)), ter(temBAD_AMOUNT));
382 env.close();
383
384 env(check::create(alice, bob, USD(0)), ter(temBAD_AMOUNT));
385 env.close();
386
387 env(check::create(alice, bob, USD(1)));
388 env.close();
389 {
390 IOU const BAD{gw1, badCurrency()};
391 env(check::create(alice, bob, BAD(2)), ter(temBAD_CURRENCY));
392 env.close();
393 }
394
395 // Bad expiration.
396 env(check::create(alice, bob, USD(50)),
397 expiration(NetClock::time_point{}),
398 ter(temBAD_EXPIRATION));
399 env.close();
400
401 // Destination does not exist.
402 Account const bogie{"bogie"};
403 env(check::create(alice, bogie, USD(50)), ter(tecNO_DST));
404 env.close();
405
406 // Require destination tag.
407 env(fset(bob, asfRequireDest));
408 env.close();
409
410 env(check::create(alice, bob, USD(50)), ter(tecDST_TAG_NEEDED));
411 env.close();
412
413 env(check::create(alice, bob, USD(50)), dest_tag(11));
414 env.close();
415
416 env(fclear(bob, asfRequireDest));
417 env.close();
418 {
419 // Globally frozen asset.
420 IOU const USF{gwF["USF"]};
421 env(fset(gwF, asfGlobalFreeze));
422 env.close();
423
424 env(check::create(alice, bob, USF(50)), ter(tecFROZEN));
425 env.close();
426
427 env(fclear(gwF, asfGlobalFreeze));
428 env.close();
429
430 env(check::create(alice, bob, USF(50)));
431 env.close();
432 }
433 {
434 // Frozen trust line. Check creation should be similar to payment
435 // behavior in the face of frozen trust lines.
436 env.trust(USD(1000), alice);
437 env.trust(USD(1000), bob);
438 env.close();
439 env(pay(gw1, alice, USD(25)));
440 env(pay(gw1, bob, USD(25)));
441 env.close();
442
443 // Setting trustline freeze in one direction prevents alice from
444 // creating a check for USD. But bob and gw1 should still be able
445 // to create a check for USD to alice.
446 env(trust(gw1, alice["USD"](0), tfSetFreeze));
447 env.close();
448 env(check::create(alice, bob, USD(50)), ter(tecFROZEN));
449 env.close();
450 env(pay(alice, bob, USD(1)), ter(tecPATH_DRY));
451 env.close();
452 env(check::create(bob, alice, USD(50)));
453 env.close();
454 env(pay(bob, alice, USD(1)));
455 env.close();
456 env(check::create(gw1, alice, USD(50)));
457 env.close();
458 env(pay(gw1, alice, USD(1)));
459 env.close();
460
461 // Clear that freeze. Now check creation works.
462 env(trust(gw1, alice["USD"](0), tfClearFreeze));
463 env.close();
464 env(check::create(alice, bob, USD(50)));
465 env.close();
466 env(check::create(bob, alice, USD(50)));
467 env.close();
468 env(check::create(gw1, alice, USD(50)));
469 env.close();
470
471 // Freezing in the other direction does not effect alice's USD
472 // check creation, but prevents bob and gw1 from writing a check
473 // for USD to alice.
474 env(trust(alice, USD(0), tfSetFreeze));
475 env.close();
476 env(check::create(alice, bob, USD(50)));
477 env.close();
478 env(pay(alice, bob, USD(1)));
479 env.close();
480 env(check::create(bob, alice, USD(50)), ter(tecFROZEN));
481 env.close();
482 env(pay(bob, alice, USD(1)), ter(tecPATH_DRY));
483 env.close();
484 env(check::create(gw1, alice, USD(50)), ter(tecFROZEN));
485 env.close();
486 env(pay(gw1, alice, USD(1)), ter(tecPATH_DRY));
487 env.close();
488
489 // Clear that freeze.
490 env(trust(alice, USD(0), tfClearFreeze));
491 env.close();
492 }
493
494 // Expired expiration.
495 env(check::create(alice, bob, USD(50)),
496 expiration(env.now()),
497 ter(tecEXPIRED));
498 env.close();
499
500 using namespace std::chrono_literals;
501 env(check::create(alice, bob, USD(50)), expiration(env.now() + 1s));
502 env.close();
503
504 // Insufficient reserve.
505 Account const cheri{"cheri"};
506 env.fund(env.current()->fees().accountReserve(1) - drops(1), cheri);
507 env.close();
508
509 env(check::create(cheri, bob, USD(50)),
510 fee(drops(env.current()->fees().base)),
512 env.close();
513
514 env(pay(bob, cheri, drops(env.current()->fees().base + 1)));
515 env.close();
516
517 env(check::create(cheri, bob, USD(50)));
518 env.close();
519 }
520
521 void
523 {
524 // Explore many of the valid ways to cash a check for XRP.
525 testcase("Cash XRP");
526
527 using namespace test::jtx;
528
529 Account const alice{"alice"};
530 Account const bob{"bob"};
531
532 Env env{*this, features};
533
534 XRPAmount const baseFeeDrops{env.current()->fees().base};
535 STAmount const startBalance{XRP(300).value()};
536 env.fund(startBalance, alice, bob);
537 env.close();
538 {
539 // Basic XRP check.
540 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
541 env(check::create(alice, bob, XRP(10)));
542 env.close();
543 env.require(balance(alice, startBalance - drops(baseFeeDrops)));
544 env.require(balance(bob, startBalance));
545 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
546 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
547 BEAST_EXPECT(ownerCount(env, alice) == 1);
548 BEAST_EXPECT(ownerCount(env, bob) == 0);
549
550 env(check::cash(bob, chkId, XRP(10)));
551 env.close();
552 env.require(
553 balance(alice, startBalance - XRP(10) - drops(baseFeeDrops)));
554 env.require(
555 balance(bob, startBalance + XRP(10) - drops(baseFeeDrops)));
556 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
557 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
558 BEAST_EXPECT(ownerCount(env, alice) == 0);
559 BEAST_EXPECT(ownerCount(env, bob) == 0);
560
561 // Make alice's and bob's balances easy to think about.
562 env(pay(env.master, alice, XRP(10) + drops(baseFeeDrops)));
563 env(pay(bob, env.master, XRP(10) - drops(baseFeeDrops * 2)));
564 env.close();
565 env.require(balance(alice, startBalance));
566 env.require(balance(bob, startBalance));
567 }
568 {
569 // Write a check that chews into alice's reserve.
570 STAmount const reserve{env.current()->fees().reserve};
571 STAmount const checkAmount{
572 startBalance - reserve - drops(baseFeeDrops)};
573 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
574 env(check::create(alice, bob, checkAmount));
575 env.close();
576
577 // bob tries to cash for more than the check amount.
578 env(check::cash(bob, chkId, checkAmount + drops(1)),
579 ter(tecPATH_PARTIAL));
580 env.close();
581 env(check::cash(
582 bob, chkId, check::DeliverMin(checkAmount + drops(1))),
583 ter(tecPATH_PARTIAL));
584 env.close();
585
586 // bob cashes exactly the check amount. This is successful
587 // because one unit of alice's reserve is released when the
588 // check is consumed.
589 env(check::cash(bob, chkId, check::DeliverMin(checkAmount)));
590 verifyDeliveredAmount(env, drops(checkAmount.mantissa()));
591 env.require(balance(alice, reserve));
592 env.require(balance(
593 bob, startBalance + checkAmount - drops(baseFeeDrops * 3)));
594 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
595 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
596 BEAST_EXPECT(ownerCount(env, alice) == 0);
597 BEAST_EXPECT(ownerCount(env, bob) == 0);
598
599 // Make alice's and bob's balances easy to think about.
600 env(pay(env.master, alice, checkAmount + drops(baseFeeDrops)));
601 env(pay(bob, env.master, checkAmount - drops(baseFeeDrops * 4)));
602 env.close();
603 env.require(balance(alice, startBalance));
604 env.require(balance(bob, startBalance));
605 }
606 {
607 // Write a check that goes one drop past what alice can pay.
608 STAmount const reserve{env.current()->fees().reserve};
609 STAmount const checkAmount{
610 startBalance - reserve - drops(baseFeeDrops - 1)};
611 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
612 env(check::create(alice, bob, checkAmount));
613 env.close();
614
615 // bob tries to cash for exactly the check amount. Fails because
616 // alice is one drop shy of funding the check.
617 env(check::cash(bob, chkId, checkAmount), ter(tecPATH_PARTIAL));
618 env.close();
619
620 // bob decides to get what he can from the bounced check.
621 env(check::cash(bob, chkId, check::DeliverMin(drops(1))));
622 verifyDeliveredAmount(env, drops(checkAmount.mantissa() - 1));
623 env.require(balance(alice, reserve));
624 env.require(balance(
625 bob, startBalance + checkAmount - drops(baseFeeDrops * 2 + 1)));
626 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
627 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
628 BEAST_EXPECT(ownerCount(env, alice) == 0);
629 BEAST_EXPECT(ownerCount(env, bob) == 0);
630
631 // Make alice's and bob's balances easy to think about.
632 env(pay(env.master, alice, checkAmount + drops(baseFeeDrops - 1)));
633 env(pay(
634 bob, env.master, checkAmount - drops(baseFeeDrops * 3 + 1)));
635 env.close();
636 env.require(balance(alice, startBalance));
637 env.require(balance(bob, startBalance));
638 }
639 }
640
641 void
643 {
644 // Explore many of the valid ways to cash a check for an IOU.
645 testcase("Cash IOU");
646
647 using namespace test::jtx;
648
649 Account const gw{"gateway"};
650 Account const alice{"alice"};
651 Account const bob{"bob"};
652 IOU const USD{gw["USD"]};
653 {
654 // Simple IOU check cashed with Amount (with failures).
655 Env env{*this, features};
656
657 env.fund(XRP(1000), gw, alice, bob);
658 env.close();
659
660 // alice writes the check before she gets the funds.
661 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
662 env(check::create(alice, bob, USD(10)));
663 env.close();
664
665 // bob attempts to cash the check. Should fail.
666 env(check::cash(bob, chkId1, USD(10)), ter(tecPATH_PARTIAL));
667 env.close();
668
669 // alice gets almost enough funds. bob tries and fails again.
670 env(trust(alice, USD(20)));
671 env.close();
672 env(pay(gw, alice, USD(9.5)));
673 env.close();
674 env(check::cash(bob, chkId1, USD(10)), ter(tecPATH_PARTIAL));
675 env.close();
676
677 // alice gets the last of the necessary funds. bob tries again
678 // and fails because he hasn't got a trust line for USD.
679 env(pay(gw, alice, USD(0.5)));
680 env.close();
681
682 // bob sets up the trust line, but not at a high enough limit.
683 env(trust(bob, USD(9.5)));
684 env.close();
685
686 // bob sets the trust line limit high enough but asks for more
687 // than the check's SendMax.
688 env(trust(bob, USD(10.5)));
689 env.close();
690 env(check::cash(bob, chkId1, USD(10.5)), ter(tecPATH_PARTIAL));
691 env.close();
692
693 // bob asks for exactly the check amount and the check clears.
694 env(check::cash(bob, chkId1, USD(10)));
695 env.close();
696 env.require(balance(alice, USD(0)));
697 env.require(balance(bob, USD(10)));
698 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
699 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
700 BEAST_EXPECT(ownerCount(env, alice) == 1);
701 BEAST_EXPECT(ownerCount(env, bob) == 1);
702
703 // bob tries to cash the same check again, which fails.
704 env(check::cash(bob, chkId1, USD(10)), ter(tecNO_ENTRY));
705 env.close();
706
707 // bob pays alice USD(7) so he can try another case.
708 env(pay(bob, alice, USD(7)));
709 env.close();
710
711 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
712 env(check::create(alice, bob, USD(7)));
713 env.close();
714 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
715 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
716
717 // bob cashes the check for less than the face amount. That works,
718 // consumes the check, and bob receives as much as he asked for.
719 env(check::cash(bob, chkId2, USD(5)));
720 env.close();
721 env.require(balance(alice, USD(2)));
722 env.require(balance(bob, USD(8)));
723 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
724 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
725 BEAST_EXPECT(ownerCount(env, alice) == 1);
726 BEAST_EXPECT(ownerCount(env, bob) == 1);
727
728 // alice writes two checks for USD(2), although she only has USD(2).
729 uint256 const chkId3{getCheckIndex(alice, env.seq(alice))};
730 env(check::create(alice, bob, USD(2)));
731 env.close();
732 uint256 const chkId4{getCheckIndex(alice, env.seq(alice))};
733 env(check::create(alice, bob, USD(2)));
734 env.close();
735 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
736 BEAST_EXPECT(checksOnAccount(env, bob).size() == 2);
737
738 // bob cashes the second check for the face amount.
739 env(check::cash(bob, chkId4, USD(2)));
740 env.close();
741 env.require(balance(alice, USD(0)));
742 env.require(balance(bob, USD(10)));
743 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
744 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
745 BEAST_EXPECT(ownerCount(env, alice) == 2);
746 BEAST_EXPECT(ownerCount(env, bob) == 1);
747
748 // bob is not allowed to cash the last check for USD(0), he must
749 // use check::cancel instead.
750 env(check::cash(bob, chkId3, USD(0)), ter(temBAD_AMOUNT));
751 env.close();
752 env.require(balance(alice, USD(0)));
753 env.require(balance(bob, USD(10)));
754 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
755 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
756 BEAST_EXPECT(ownerCount(env, alice) == 2);
757 BEAST_EXPECT(ownerCount(env, bob) == 1);
758
759 // Automatic trust lines are enabled. But one aspect of
760 // automatic trust lines is that they allow the account
761 // cashing a check to exceed their trust line limit. Show
762 // that at work.
763 //
764 // bob's trust line limit is currently USD(10.5). Show that
765 // a payment to bob cannot exceed that trust line, but cashing
766 // a check can.
767
768 // Payment of 20 USD fails.
769 env(pay(gw, bob, USD(20)), ter(tecPATH_PARTIAL));
770 env.close();
771
772 uint256 const chkId20{getCheckIndex(gw, env.seq(gw))};
773 env(check::create(gw, bob, USD(20)));
774 env.close();
775
776 // However cashing a check for 20 USD succeeds.
777 env(check::cash(bob, chkId20, USD(20)));
778 env.close();
779 env.require(balance(bob, USD(30)));
780
781 // Clean up this most recent experiment so the rest of the
782 // tests work.
783 env(pay(bob, gw, USD(20)));
784
785 // ... so bob cancels alice's remaining check.
786 env(check::cancel(bob, chkId3));
787 env.close();
788 env.require(balance(alice, USD(0)));
789 env.require(balance(bob, USD(10)));
790 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
791 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
792 BEAST_EXPECT(ownerCount(env, alice) == 1);
793 BEAST_EXPECT(ownerCount(env, bob) == 1);
794 }
795 {
796 // Simple IOU check cashed with DeliverMin (with failures).
797 Env env{*this, features};
798
799 env.fund(XRP(1000), gw, alice, bob);
800 env.close();
801
802 env(trust(alice, USD(20)));
803 env(trust(bob, USD(20)));
804 env.close();
805 env(pay(gw, alice, USD(8)));
806 env.close();
807
808 // alice creates several checks ahead of time.
809 uint256 const chkId9{getCheckIndex(alice, env.seq(alice))};
810 env(check::create(alice, bob, USD(9)));
811 env.close();
812 uint256 const chkId8{getCheckIndex(alice, env.seq(alice))};
813 env(check::create(alice, bob, USD(8)));
814 env.close();
815 uint256 const chkId7{getCheckIndex(alice, env.seq(alice))};
816 env(check::create(alice, bob, USD(7)));
817 env.close();
818 uint256 const chkId6{getCheckIndex(alice, env.seq(alice))};
819 env(check::create(alice, bob, USD(6)));
820 env.close();
821
822 // bob attempts to cash a check for the amount on the check.
823 // Should fail, since alice doesn't have the funds.
824 env(check::cash(bob, chkId9, check::DeliverMin(USD(9))),
825 ter(tecPATH_PARTIAL));
826 env.close();
827
828 // bob sets a DeliverMin of 7 and gets all that alice has.
829 env(check::cash(bob, chkId9, check::DeliverMin(USD(7))));
830 verifyDeliveredAmount(env, USD(8));
831 env.require(balance(alice, USD(0)));
832 env.require(balance(bob, USD(8)));
833 BEAST_EXPECT(checksOnAccount(env, alice).size() == 3);
834 BEAST_EXPECT(checksOnAccount(env, bob).size() == 3);
835 BEAST_EXPECT(ownerCount(env, alice) == 4);
836 BEAST_EXPECT(ownerCount(env, bob) == 1);
837
838 // bob pays alice USD(7) so he can use another check.
839 env(pay(bob, alice, USD(7)));
840 env.close();
841
842 // Using DeliverMin for the SendMax value of the check (and no
843 // transfer fees) should work just like setting Amount.
844 env(check::cash(bob, chkId7, check::DeliverMin(USD(7))));
845 verifyDeliveredAmount(env, USD(7));
846 env.require(balance(alice, USD(0)));
847 env.require(balance(bob, USD(8)));
848 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
849 BEAST_EXPECT(checksOnAccount(env, bob).size() == 2);
850 BEAST_EXPECT(ownerCount(env, alice) == 3);
851 BEAST_EXPECT(ownerCount(env, bob) == 1);
852
853 // bob pays alice USD(8) so he can use the last two checks.
854 env(pay(bob, alice, USD(8)));
855 env.close();
856
857 // alice has USD(8). If bob uses the check for USD(6) and uses a
858 // DeliverMin of 4, he should get the SendMax value of the check.
859 env(check::cash(bob, chkId6, check::DeliverMin(USD(4))));
860 verifyDeliveredAmount(env, USD(6));
861 env.require(balance(alice, USD(2)));
862 env.require(balance(bob, USD(6)));
863 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
864 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
865 BEAST_EXPECT(ownerCount(env, alice) == 2);
866 BEAST_EXPECT(ownerCount(env, bob) == 1);
867
868 // bob cashes the last remaining check setting a DeliverMin.
869 // of exactly alice's remaining USD.
870 env(check::cash(bob, chkId8, check::DeliverMin(USD(2))));
871 verifyDeliveredAmount(env, USD(2));
872 env.require(balance(alice, USD(0)));
873 env.require(balance(bob, USD(8)));
874 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
875 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
876 BEAST_EXPECT(ownerCount(env, alice) == 1);
877 BEAST_EXPECT(ownerCount(env, bob) == 1);
878 }
879 {
880 // Examine the effects of the asfRequireAuth flag.
881 Env env(*this, features);
882
883 env.fund(XRP(1000), gw, alice, bob);
884 env(fset(gw, asfRequireAuth));
885 env.close();
886 env(trust(gw, alice["USD"](100)), txflags(tfSetfAuth));
887 env(trust(alice, USD(20)));
888 env.close();
889 env(pay(gw, alice, USD(8)));
890 env.close();
891
892 // alice writes a check to bob for USD. bob can't cash it
893 // because he is not authorized to hold gw["USD"].
894 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
895 env(check::create(alice, bob, USD(7)));
896 env.close();
897
898 env(check::cash(bob, chkId, USD(7)), ter(tecNO_AUTH));
899 env.close();
900
901 // Now give bob a trustline for USD. bob still can't cash the
902 // check because he is not authorized.
903 env(trust(bob, USD(5)));
904 env.close();
905
906 env(check::cash(bob, chkId, USD(7)), ter(tecNO_AUTH));
907 env.close();
908
909 // bob gets authorization to hold gw["USD"].
910 env(trust(gw, bob["USD"](1)), txflags(tfSetfAuth));
911 env.close();
912
913 // Two possible outcomes here depending on whether cashing a
914 // check can build a trust line:
915 // o If it can't build a trust line, then since bob set his
916 // limit low, he cashes the check with a DeliverMin and hits
917 // his trust limit.
918 // o If it can build a trust line, then the check is allowed to
919 // exceed the trust limit and bob gets the full transfer.
920 env(check::cash(bob, chkId, check::DeliverMin(USD(4))));
921 STAmount const bobGot = USD(7);
922 verifyDeliveredAmount(env, bobGot);
923 env.require(balance(alice, USD(8) - bobGot));
924 env.require(balance(bob, bobGot));
925
926 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
927 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
928 BEAST_EXPECT(ownerCount(env, alice) == 1);
929 BEAST_EXPECT(ownerCount(env, bob) == 1);
930 }
931
932 // Use a regular key and also multisign to cash a check.
933 {
934 Env env{*this, features};
935 env.fund(XRP(1000), gw, alice, bob);
936 env.close();
937
938 // alice creates her checks ahead of time.
939 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
940 env(check::create(alice, bob, USD(1)));
941 env.close();
942
943 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
944 env(check::create(alice, bob, USD(2)));
945 env.close();
946
947 env(trust(alice, USD(20)));
948 env(trust(bob, USD(20)));
949 env.close();
950 env(pay(gw, alice, USD(8)));
951 env.close();
952
953 // Give bob a regular key and signers
954 Account const bobby{"bobby", KeyType::secp256k1};
955 env(regkey(bob, bobby));
956 env.close();
957
958 Account const bogie{"bogie", KeyType::secp256k1};
959 Account const demon{"demon", KeyType::ed25519};
960 env(signers(bob, 2, {{bogie, 1}, {demon, 1}}), sig(bobby));
961 env.close();
962
963 BEAST_EXPECT(ownerCount(env, bob) == 2);
964
965 // bob uses his regular key to cash a check.
966 env(check::cash(bob, chkId1, (USD(1))), sig(bobby));
967 env.close();
968 env.require(balance(alice, USD(7)));
969 env.require(balance(bob, USD(1)));
970 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
971 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
972 BEAST_EXPECT(ownerCount(env, alice) == 2);
973 BEAST_EXPECT(ownerCount(env, bob) == 2);
974
975 // bob uses multisigning to cash a check.
976 XRPAmount const baseFeeDrops{env.current()->fees().base};
977 env(check::cash(bob, chkId2, (USD(2))),
978 msig(bogie, demon),
979 fee(3 * baseFeeDrops));
980 env.close();
981 env.require(balance(alice, USD(5)));
982 env.require(balance(bob, USD(3)));
983 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
984 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
985 BEAST_EXPECT(ownerCount(env, alice) == 1);
986 BEAST_EXPECT(ownerCount(env, bob) == 2);
987 }
988 }
989
990 void
992 {
993 // Look at behavior when the issuer charges a transfer fee.
994 testcase("Cash with transfer fee");
995
996 using namespace test::jtx;
997
998 Account const gw{"gateway"};
999 Account const alice{"alice"};
1000 Account const bob{"bob"};
1001 IOU const USD{gw["USD"]};
1002
1003 Env env{*this, features};
1004
1005 env.fund(XRP(1000), gw, alice, bob);
1006 env.close();
1007
1008 env(trust(alice, USD(1000)));
1009 env(trust(bob, USD(1000)));
1010 env.close();
1011 env(pay(gw, alice, USD(1000)));
1012 env.close();
1013
1014 // Set gw's transfer rate and see the consequences when cashing a check.
1015 env(rate(gw, 1.25));
1016 env.close();
1017
1018 // alice writes a check with a SendMax of USD(125). The most bob
1019 // can get is USD(100) because of the transfer rate.
1020 uint256 const chkId125{getCheckIndex(alice, env.seq(alice))};
1021 env(check::create(alice, bob, USD(125)));
1022 env.close();
1023
1024 // alice writes another check that won't get cashed until the transfer
1025 // rate changes so we can see the rate applies when the check is
1026 // cashed, not when it is created.
1027 uint256 const chkId120{getCheckIndex(alice, env.seq(alice))};
1028 env(check::create(alice, bob, USD(120)));
1029 env.close();
1030
1031 // bob attempts to cash the check for face value. Should fail.
1032 env(check::cash(bob, chkId125, USD(125)), ter(tecPATH_PARTIAL));
1033 env.close();
1034 env(check::cash(bob, chkId125, check::DeliverMin(USD(101))),
1035 ter(tecPATH_PARTIAL));
1036 env.close();
1037
1038 // bob decides that he'll accept anything USD(75) or up.
1039 // He gets USD(100).
1040 env(check::cash(bob, chkId125, check::DeliverMin(USD(75))));
1041 verifyDeliveredAmount(env, USD(100));
1042 env.require(balance(alice, USD(1000 - 125)));
1043 env.require(balance(bob, USD(0 + 100)));
1044 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
1045 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
1046
1047 // Adjust gw's rate...
1048 env(rate(gw, 1.2));
1049 env.close();
1050
1051 // bob cashes the second check for less than the face value. The new
1052 // rate applies to the actual value transferred.
1053 env(check::cash(bob, chkId120, USD(50)));
1054 env.close();
1055 env.require(balance(alice, USD(1000 - 125 - 60)));
1056 env.require(balance(bob, USD(0 + 100 + 50)));
1057 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
1058 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
1059 }
1060
1061 void
1063 {
1064 // Look at the eight possible cases for Quality In/Out.
1065 testcase("Cash quality");
1066
1067 using namespace test::jtx;
1068
1069 Account const gw{"gateway"};
1070 Account const alice{"alice"};
1071 Account const bob{"bob"};
1072 IOU const USD{gw["USD"]};
1073
1074 Env env{*this, features};
1075
1076 env.fund(XRP(1000), gw, alice, bob);
1077 env.close();
1078
1079 env(trust(alice, USD(1000)));
1080 env(trust(bob, USD(1000)));
1081 env.close();
1082 env(pay(gw, alice, USD(1000)));
1083 env.close();
1084
1085 //
1086 // Quality effects on transfers between two non-issuers.
1087 //
1088
1089 // Provide lambdas that return a qualityInPercent and qualityOutPercent.
1090 auto qIn = [](double percent) { return qualityInPercent(percent); };
1091 auto qOut = [](double percent) { return qualityOutPercent(percent); };
1092
1093 // There are two test lambdas: one for a Payment and one for a Check.
1094 // This shows whether a Payment and a Check behave the same.
1095 auto testNonIssuerQPay = [&env, &alice, &bob, &USD](
1096 Account const& truster,
1097 IOU const& iou,
1098 auto const& inOrOut,
1099 double pct,
1100 double amount) {
1101 // Capture bob's and alice's balances so we can test at the end.
1102 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1103 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
1104
1105 // Set the modified quality.
1106 env(trust(truster, iou(1000)), inOrOut(pct));
1107 env.close();
1108
1109 env(pay(alice, bob, USD(amount)), sendmax(USD(10)));
1110 env.close();
1111 env.require(balance(alice, aliceStart - USD(10)));
1112 env.require(balance(bob, bobStart + USD(10)));
1113
1114 // Return the quality to the unmodified state so it doesn't
1115 // interfere with upcoming tests.
1116 env(trust(truster, iou(1000)), inOrOut(0));
1117 env.close();
1118 };
1119
1120 auto testNonIssuerQCheck = [&env, &alice, &bob, &USD](
1121 Account const& truster,
1122 IOU const& iou,
1123 auto const& inOrOut,
1124 double pct,
1125 double amount) {
1126 // Capture bob's and alice's balances so we can test at the end.
1127 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1128 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
1129
1130 // Set the modified quality.
1131 env(trust(truster, iou(1000)), inOrOut(pct));
1132 env.close();
1133
1134 uint256 const chkId = getCheckIndex(alice, env.seq(alice));
1135 env(check::create(alice, bob, USD(10)));
1136 env.close();
1137
1138 env(check::cash(bob, chkId, USD(amount)));
1139 env.close();
1140 env.require(balance(alice, aliceStart - USD(10)));
1141 env.require(balance(bob, bobStart + USD(10)));
1142
1143 // Return the quality to the unmodified state so it doesn't
1144 // interfere with upcoming tests.
1145 env(trust(truster, iou(1000)), inOrOut(0));
1146 env.close();
1147 };
1148
1149 // pct amount
1150 testNonIssuerQPay(alice, gw["USD"], qIn, 50, 10);
1151 testNonIssuerQCheck(alice, gw["USD"], qIn, 50, 10);
1152
1153 // This is the only case where the Quality affects the outcome.
1154 testNonIssuerQPay(bob, gw["USD"], qIn, 50, 5);
1155 testNonIssuerQCheck(bob, gw["USD"], qIn, 50, 5);
1156
1157 testNonIssuerQPay(gw, alice["USD"], qIn, 50, 10);
1158 testNonIssuerQCheck(gw, alice["USD"], qIn, 50, 10);
1159
1160 testNonIssuerQPay(gw, bob["USD"], qIn, 50, 10);
1161 testNonIssuerQCheck(gw, bob["USD"], qIn, 50, 10);
1162
1163 testNonIssuerQPay(alice, gw["USD"], qOut, 200, 10);
1164 testNonIssuerQCheck(alice, gw["USD"], qOut, 200, 10);
1165
1166 testNonIssuerQPay(bob, gw["USD"], qOut, 200, 10);
1167 testNonIssuerQCheck(bob, gw["USD"], qOut, 200, 10);
1168
1169 testNonIssuerQPay(gw, alice["USD"], qOut, 200, 10);
1170 testNonIssuerQCheck(gw, alice["USD"], qOut, 200, 10);
1171
1172 testNonIssuerQPay(gw, bob["USD"], qOut, 200, 10);
1173 testNonIssuerQCheck(gw, bob["USD"], qOut, 200, 10);
1174
1175 //
1176 // Quality effects on transfers between an issuer and a non-issuer.
1177 //
1178
1179 // There are two test lambdas for the same reason as before.
1180 auto testIssuerQPay = [&env, &gw, &alice, &USD](
1181 Account const& truster,
1182 IOU const& iou,
1183 auto const& inOrOut,
1184 double pct,
1185 double amt1,
1186 double max1,
1187 double amt2,
1188 double max2) {
1189 // Capture alice's balance so we can test at the end. It doesn't
1190 // make any sense to look at the balance of a gateway.
1191 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1192
1193 // Set the modified quality.
1194 env(trust(truster, iou(1000)), inOrOut(pct));
1195 env.close();
1196
1197 // alice pays gw.
1198 env(pay(alice, gw, USD(amt1)), sendmax(USD(max1)));
1199 env.close();
1200 env.require(balance(alice, aliceStart - USD(10)));
1201
1202 // gw pays alice.
1203 env(pay(gw, alice, USD(amt2)), sendmax(USD(max2)));
1204 env.close();
1205 env.require(balance(alice, aliceStart));
1206
1207 // Return the quality to the unmodified state so it doesn't
1208 // interfere with upcoming tests.
1209 env(trust(truster, iou(1000)), inOrOut(0));
1210 env.close();
1211 };
1212
1213 auto testIssuerQCheck = [&env, &gw, &alice, &USD](
1214 Account const& truster,
1215 IOU const& iou,
1216 auto const& inOrOut,
1217 double pct,
1218 double amt1,
1219 double max1,
1220 double amt2,
1221 double max2) {
1222 // Capture alice's balance so we can test at the end. It doesn't
1223 // make any sense to look at the balance of the issuer.
1224 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1225
1226 // Set the modified quality.
1227 env(trust(truster, iou(1000)), inOrOut(pct));
1228 env.close();
1229
1230 // alice writes check to gw. gw cashes.
1231 uint256 const chkAliceId{getCheckIndex(alice, env.seq(alice))};
1232 env(check::create(alice, gw, USD(max1)));
1233 env.close();
1234
1235 env(check::cash(gw, chkAliceId, USD(amt1)));
1236 env.close();
1237 env.require(balance(alice, aliceStart - USD(10)));
1238
1239 // gw writes check to alice. alice cashes.
1240 uint256 const chkGwId{getCheckIndex(gw, env.seq(gw))};
1241 env(check::create(gw, alice, USD(max2)));
1242 env.close();
1243
1244 env(check::cash(alice, chkGwId, USD(amt2)));
1245 env.close();
1246 env.require(balance(alice, aliceStart));
1247
1248 // Return the quality to the unmodified state so it doesn't
1249 // interfere with upcoming tests.
1250 env(trust(truster, iou(1000)), inOrOut(0));
1251 env.close();
1252 };
1253
1254 // The first case is the only one where the quality affects the outcome.
1255 // pct amt1 max1 amt2 max2
1256 testIssuerQPay(alice, gw["USD"], qIn, 50, 10, 10, 5, 10);
1257 testIssuerQCheck(alice, gw["USD"], qIn, 50, 10, 10, 5, 10);
1258
1259 testIssuerQPay(gw, alice["USD"], qIn, 50, 10, 10, 10, 10);
1260 testIssuerQCheck(gw, alice["USD"], qIn, 50, 10, 10, 10, 10);
1261
1262 testIssuerQPay(alice, gw["USD"], qOut, 200, 10, 10, 10, 10);
1263 testIssuerQCheck(alice, gw["USD"], qOut, 200, 10, 10, 10, 10);
1264
1265 testIssuerQPay(gw, alice["USD"], qOut, 200, 10, 10, 10, 10);
1266 testIssuerQCheck(gw, alice["USD"], qOut, 200, 10, 10, 10, 10);
1267 }
1268
1269 void
1271 {
1272 // Explore many of the ways to fail at cashing a check.
1273 testcase("Cash invalid");
1274
1275 using namespace test::jtx;
1276
1277 Account const gw{"gateway"};
1278 Account const alice{"alice"};
1279 Account const bob{"bob"};
1280 Account const zoe{"zoe"};
1281 IOU const USD{gw["USD"]};
1282
1283 Env env(*this, features);
1284
1285 env.fund(XRP(1000), gw, alice, bob, zoe);
1286 env.close();
1287
1288 // Now set up alice's trustline.
1289 env(trust(alice, USD(20)));
1290 env.close();
1291 env(pay(gw, alice, USD(20)));
1292 env.close();
1293
1294 // Now set up bob's trustline.
1295 env(trust(bob, USD(20)));
1296 env.close();
1297
1298 // bob tries to cash a non-existent check from alice.
1299 {
1300 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
1301 env(check::cash(bob, chkId, USD(20)), ter(tecNO_ENTRY));
1302 env.close();
1303 }
1304
1305 // alice creates her checks ahead of time.
1306 uint256 const chkIdU{getCheckIndex(alice, env.seq(alice))};
1307 env(check::create(alice, bob, USD(20)));
1308 env.close();
1309
1310 uint256 const chkIdX{getCheckIndex(alice, env.seq(alice))};
1311 env(check::create(alice, bob, XRP(10)));
1312 env.close();
1313
1314 using namespace std::chrono_literals;
1315 uint256 const chkIdExp{getCheckIndex(alice, env.seq(alice))};
1316 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
1317 env.close();
1318
1319 uint256 const chkIdFroz1{getCheckIndex(alice, env.seq(alice))};
1320 env(check::create(alice, bob, USD(1)));
1321 env.close();
1322
1323 uint256 const chkIdFroz2{getCheckIndex(alice, env.seq(alice))};
1324 env(check::create(alice, bob, USD(2)));
1325 env.close();
1326
1327 uint256 const chkIdFroz3{getCheckIndex(alice, env.seq(alice))};
1328 env(check::create(alice, bob, USD(3)));
1329 env.close();
1330
1331 uint256 const chkIdFroz4{getCheckIndex(alice, env.seq(alice))};
1332 env(check::create(alice, bob, USD(4)));
1333 env.close();
1334
1335 uint256 const chkIdNoDest1{getCheckIndex(alice, env.seq(alice))};
1336 env(check::create(alice, bob, USD(1)));
1337 env.close();
1338
1339 uint256 const chkIdHasDest2{getCheckIndex(alice, env.seq(alice))};
1340 env(check::create(alice, bob, USD(2)), dest_tag(7));
1341 env.close();
1342
1343 // Same set of failing cases for both IOU and XRP check cashing.
1344 auto failingCases = [&env, &gw, &alice, &bob](
1345 uint256 const& chkId, STAmount const& amount) {
1346 // Bad fee.
1347 env(check::cash(bob, chkId, amount),
1348 fee(drops(-10)),
1349 ter(temBAD_FEE));
1350 env.close();
1351
1352 // Bad flags.
1353 env(check::cash(bob, chkId, amount),
1354 txflags(tfImmediateOrCancel),
1355 ter(temINVALID_FLAG));
1356 env.close();
1357
1358 // Missing both Amount and DeliverMin.
1359 {
1360 Json::Value tx{check::cash(bob, chkId, amount)};
1361 tx.removeMember(sfAmount.jsonName);
1362 env(tx, ter(temMALFORMED));
1363 env.close();
1364 }
1365 // Both Amount and DeliverMin present.
1366 {
1367 Json::Value tx{check::cash(bob, chkId, amount)};
1368 tx[sfDeliverMin.jsonName] = amount.getJson(JsonOptions::none);
1369 env(tx, ter(temMALFORMED));
1370 env.close();
1371 }
1372
1373 // Negative or zero amount.
1374 {
1375 STAmount neg{amount};
1376 neg.negate();
1377 env(check::cash(bob, chkId, neg), ter(temBAD_AMOUNT));
1378 env.close();
1379 env(check::cash(bob, chkId, amount.zeroed()),
1380 ter(temBAD_AMOUNT));
1381 env.close();
1382 }
1383
1384 // Bad currency.
1385 if (!amount.native())
1386 {
1387 Issue const badIssue{badCurrency(), amount.getIssuer()};
1388 STAmount badAmount{amount};
1389 badAmount.setIssue(Issue{badCurrency(), amount.getIssuer()});
1390 env(check::cash(bob, chkId, badAmount), ter(temBAD_CURRENCY));
1391 env.close();
1392 }
1393
1394 // Not destination cashing check.
1395 env(check::cash(alice, chkId, amount), ter(tecNO_PERMISSION));
1396 env.close();
1397 env(check::cash(gw, chkId, amount), ter(tecNO_PERMISSION));
1398 env.close();
1399
1400 // Currency mismatch.
1401 {
1402 IOU const wrongCurrency{gw["EUR"]};
1403 STAmount badAmount{amount};
1404 badAmount.setIssue(wrongCurrency.issue());
1405 env(check::cash(bob, chkId, badAmount), ter(temMALFORMED));
1406 env.close();
1407 }
1408
1409 // Issuer mismatch.
1410 {
1411 IOU const wrongIssuer{alice["USD"]};
1412 STAmount badAmount{amount};
1413 badAmount.setIssue(wrongIssuer.issue());
1414 env(check::cash(bob, chkId, badAmount), ter(temMALFORMED));
1415 env.close();
1416 }
1417
1418 // Amount bigger than SendMax.
1419 env(check::cash(bob, chkId, amount + amount), ter(tecPATH_PARTIAL));
1420 env.close();
1421
1422 // DeliverMin bigger than SendMax.
1423 env(check::cash(bob, chkId, check::DeliverMin(amount + amount)),
1424 ter(tecPATH_PARTIAL));
1425 env.close();
1426 };
1427
1428 failingCases(chkIdX, XRP(10));
1429 failingCases(chkIdU, USD(20));
1430
1431 // Verify that those two checks really were cashable.
1432 env(check::cash(bob, chkIdU, USD(20)));
1433 env.close();
1434 env(check::cash(bob, chkIdX, check::DeliverMin(XRP(10))));
1435 verifyDeliveredAmount(env, XRP(10));
1436
1437 // Try to cash an expired check.
1438 env(check::cash(bob, chkIdExp, XRP(10)), ter(tecEXPIRED));
1439 env.close();
1440
1441 // Cancel the expired check. Anyone can cancel an expired check.
1442 env(check::cancel(zoe, chkIdExp));
1443 env.close();
1444
1445 // Can we cash a check with frozen currency?
1446 {
1447 env(pay(bob, alice, USD(20)));
1448 env.close();
1449 env.require(balance(alice, USD(20)));
1450 env.require(balance(bob, USD(0)));
1451
1452 // Global freeze
1453 env(fset(gw, asfGlobalFreeze));
1454 env.close();
1455
1456 env(check::cash(bob, chkIdFroz1, USD(1)), ter(tecPATH_PARTIAL));
1457 env.close();
1458 env(check::cash(bob, chkIdFroz1, check::DeliverMin(USD(0.5))),
1459 ter(tecPATH_PARTIAL));
1460 env.close();
1461
1462 env(fclear(gw, asfGlobalFreeze));
1463 env.close();
1464
1465 // No longer frozen. Success.
1466 env(check::cash(bob, chkIdFroz1, USD(1)));
1467 env.close();
1468 env.require(balance(alice, USD(19)));
1469 env.require(balance(bob, USD(1)));
1470
1471 // Freeze individual trustlines.
1472 env(trust(gw, alice["USD"](0), tfSetFreeze));
1473 env.close();
1474 env(check::cash(bob, chkIdFroz2, USD(2)), ter(tecPATH_PARTIAL));
1475 env.close();
1476 env(check::cash(bob, chkIdFroz2, check::DeliverMin(USD(1))),
1477 ter(tecPATH_PARTIAL));
1478 env.close();
1479
1480 // Clear that freeze. Now check cashing works.
1481 env(trust(gw, alice["USD"](0), tfClearFreeze));
1482 env.close();
1483 env(check::cash(bob, chkIdFroz2, USD(2)));
1484 env.close();
1485 env.require(balance(alice, USD(17)));
1486 env.require(balance(bob, USD(3)));
1487
1488 // Freeze bob's trustline. bob can't cash the check.
1489 env(trust(gw, bob["USD"](0), tfSetFreeze));
1490 env.close();
1491 env(check::cash(bob, chkIdFroz3, USD(3)), ter(tecFROZEN));
1492 env.close();
1493 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))),
1494 ter(tecFROZEN));
1495 env.close();
1496
1497 // Clear that freeze. Now check cashing works again.
1498 env(trust(gw, bob["USD"](0), tfClearFreeze));
1499 env.close();
1500 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))));
1501 verifyDeliveredAmount(env, USD(3));
1502 env.require(balance(alice, USD(14)));
1503 env.require(balance(bob, USD(6)));
1504
1505 // Set bob's freeze bit in the other direction. Check
1506 // cashing fails.
1507 env(trust(bob, USD(20), tfSetFreeze));
1508 env.close();
1509 env(check::cash(bob, chkIdFroz4, USD(4)), ter(terNO_LINE));
1510 env.close();
1511 env(check::cash(bob, chkIdFroz4, check::DeliverMin(USD(1))),
1512 ter(terNO_LINE));
1513 env.close();
1514
1515 // Clear bob's freeze bit and the check should be cashable.
1516 env(trust(bob, USD(20), tfClearFreeze));
1517 env.close();
1518 env(check::cash(bob, chkIdFroz4, USD(4)));
1519 env.close();
1520 env.require(balance(alice, USD(10)));
1521 env.require(balance(bob, USD(10)));
1522 }
1523 {
1524 // Set the RequireDest flag on bob's account (after the check
1525 // was created) then cash a check without a destination tag.
1526 env(fset(bob, asfRequireDest));
1527 env.close();
1528 env(check::cash(bob, chkIdNoDest1, USD(1)), ter(tecDST_TAG_NEEDED));
1529 env.close();
1530 env(check::cash(bob, chkIdNoDest1, check::DeliverMin(USD(0.5))),
1531 ter(tecDST_TAG_NEEDED));
1532 env.close();
1533
1534 // bob can cash a check with a destination tag.
1535 env(check::cash(bob, chkIdHasDest2, USD(2)));
1536 env.close();
1537 env.require(balance(alice, USD(8)));
1538 env.require(balance(bob, USD(12)));
1539
1540 // Clear the RequireDest flag on bob's account so he can
1541 // cash the check with no DestinationTag.
1542 env(fclear(bob, asfRequireDest));
1543 env.close();
1544 env(check::cash(bob, chkIdNoDest1, USD(1)));
1545 env.close();
1546 env.require(balance(alice, USD(7)));
1547 env.require(balance(bob, USD(13)));
1548 }
1549 }
1550
1551 void
1553 {
1554 // Explore many of the ways to cancel a check.
1555 testcase("Cancel valid");
1556
1557 using namespace test::jtx;
1558
1559 Account const gw{"gateway"};
1560 Account const alice{"alice"};
1561 Account const bob{"bob"};
1562 Account const zoe{"zoe"};
1563 IOU const USD{gw["USD"]};
1564
1565 {
1566 Env env{*this, features};
1567
1568 env.fund(XRP(1000), gw, alice, bob, zoe);
1569 env.close();
1570
1571 // alice creates her checks ahead of time.
1572 // Three ordinary checks with no expiration.
1573 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
1574 env(check::create(alice, bob, USD(10)));
1575 env.close();
1576
1577 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
1578 env(check::create(alice, bob, XRP(10)));
1579 env.close();
1580
1581 uint256 const chkId3{getCheckIndex(alice, env.seq(alice))};
1582 env(check::create(alice, bob, USD(10)));
1583 env.close();
1584
1585 // Three checks that expire in 10 minutes.
1586 using namespace std::chrono_literals;
1587 uint256 const chkIdNotExp1{getCheckIndex(alice, env.seq(alice))};
1588 env(check::create(alice, bob, XRP(10)),
1589 expiration(env.now() + 600s));
1590 env.close();
1591
1592 uint256 const chkIdNotExp2{getCheckIndex(alice, env.seq(alice))};
1593 env(check::create(alice, bob, USD(10)),
1594 expiration(env.now() + 600s));
1595 env.close();
1596
1597 uint256 const chkIdNotExp3{getCheckIndex(alice, env.seq(alice))};
1598 env(check::create(alice, bob, XRP(10)),
1599 expiration(env.now() + 600s));
1600 env.close();
1601
1602 // Three checks that expire in one second.
1603 uint256 const chkIdExp1{getCheckIndex(alice, env.seq(alice))};
1604 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
1605 env.close();
1606
1607 uint256 const chkIdExp2{getCheckIndex(alice, env.seq(alice))};
1608 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
1609 env.close();
1610
1611 uint256 const chkIdExp3{getCheckIndex(alice, env.seq(alice))};
1612 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
1613 env.close();
1614
1615 // Two checks to cancel using a regular key and using multisigning.
1616 uint256 const chkIdReg{getCheckIndex(alice, env.seq(alice))};
1617 env(check::create(alice, bob, USD(10)));
1618 env.close();
1619
1620 uint256 const chkIdMSig{getCheckIndex(alice, env.seq(alice))};
1621 env(check::create(alice, bob, XRP(10)));
1622 env.close();
1623 BEAST_EXPECT(checksOnAccount(env, alice).size() == 11);
1624 BEAST_EXPECT(ownerCount(env, alice) == 11);
1625
1626 // Creator, destination, and an outsider cancel the checks.
1627 env(check::cancel(alice, chkId1));
1628 env.close();
1629 BEAST_EXPECT(checksOnAccount(env, alice).size() == 10);
1630 BEAST_EXPECT(ownerCount(env, alice) == 10);
1631
1632 env(check::cancel(bob, chkId2));
1633 env.close();
1634 BEAST_EXPECT(checksOnAccount(env, alice).size() == 9);
1635 BEAST_EXPECT(ownerCount(env, alice) == 9);
1636
1637 env(check::cancel(zoe, chkId3), ter(tecNO_PERMISSION));
1638 env.close();
1639 BEAST_EXPECT(checksOnAccount(env, alice).size() == 9);
1640 BEAST_EXPECT(ownerCount(env, alice) == 9);
1641
1642 // Creator, destination, and an outsider cancel unexpired checks.
1643 env(check::cancel(alice, chkIdNotExp1));
1644 env.close();
1645 BEAST_EXPECT(checksOnAccount(env, alice).size() == 8);
1646 BEAST_EXPECT(ownerCount(env, alice) == 8);
1647
1648 env(check::cancel(bob, chkIdNotExp2));
1649 env.close();
1650 BEAST_EXPECT(checksOnAccount(env, alice).size() == 7);
1651 BEAST_EXPECT(ownerCount(env, alice) == 7);
1652
1653 env(check::cancel(zoe, chkIdNotExp3), ter(tecNO_PERMISSION));
1654 env.close();
1655 BEAST_EXPECT(checksOnAccount(env, alice).size() == 7);
1656 BEAST_EXPECT(ownerCount(env, alice) == 7);
1657
1658 // Creator, destination, and an outsider cancel expired checks.
1659 env(check::cancel(alice, chkIdExp1));
1660 env.close();
1661 BEAST_EXPECT(checksOnAccount(env, alice).size() == 6);
1662 BEAST_EXPECT(ownerCount(env, alice) == 6);
1663
1664 env(check::cancel(bob, chkIdExp2));
1665 env.close();
1666 BEAST_EXPECT(checksOnAccount(env, alice).size() == 5);
1667 BEAST_EXPECT(ownerCount(env, alice) == 5);
1668
1669 env(check::cancel(zoe, chkIdExp3));
1670 env.close();
1671 BEAST_EXPECT(checksOnAccount(env, alice).size() == 4);
1672 BEAST_EXPECT(ownerCount(env, alice) == 4);
1673
1674 // Use a regular key and also multisign to cancel checks.
1675 Account const alie{"alie", KeyType::ed25519};
1676 env(regkey(alice, alie));
1677 env.close();
1678
1679 Account const bogie{"bogie", KeyType::secp256k1};
1680 Account const demon{"demon", KeyType::ed25519};
1681 env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie));
1682 env.close();
1683
1684 // alice uses her regular key to cancel a check.
1685 env(check::cancel(alice, chkIdReg), sig(alie));
1686 env.close();
1687 BEAST_EXPECT(checksOnAccount(env, alice).size() == 3);
1688 BEAST_EXPECT(ownerCount(env, alice) == 4);
1689
1690 // alice uses multisigning to cancel a check.
1691 XRPAmount const baseFeeDrops{env.current()->fees().base};
1692 env(check::cancel(alice, chkIdMSig),
1693 msig(bogie, demon),
1694 fee(3 * baseFeeDrops));
1695 env.close();
1696 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
1697 BEAST_EXPECT(ownerCount(env, alice) == 3);
1698
1699 // Creator and destination cancel the remaining unexpired checks.
1700 env(check::cancel(alice, chkId3), sig(alice));
1701 env.close();
1702 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
1703 BEAST_EXPECT(ownerCount(env, alice) == 2);
1704
1705 env(check::cancel(bob, chkIdNotExp3));
1706 env.close();
1707 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
1708 BEAST_EXPECT(ownerCount(env, alice) == 1);
1709 }
1710 }
1711
1712 void
1714 {
1715 // Explore many of the ways to fail at canceling a check.
1716 testcase("Cancel invalid");
1717
1718 using namespace test::jtx;
1719
1720 Account const alice{"alice"};
1721 Account const bob{"bob"};
1722
1723 Env env{*this, features};
1724
1725 env.fund(XRP(1000), alice, bob);
1726 env.close();
1727
1728 // Bad fee.
1729 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
1730 fee(drops(-10)),
1731 ter(temBAD_FEE));
1732 env.close();
1733
1734 // Bad flags.
1735 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
1736 txflags(tfImmediateOrCancel),
1737 ter(temINVALID_FLAG));
1738 env.close();
1739
1740 // Non-existent check.
1741 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
1742 ter(tecNO_ENTRY));
1743 env.close();
1744 }
1745
1746 void
1748 {
1749 testcase("DeliveredAmount For CheckCash Txn");
1750
1751 using namespace test::jtx;
1752 Account const alice{"alice"};
1753 Account const bob{"bob"};
1754
1755 Env env{*this, features};
1756
1757 env.fund(XRP(1000), alice, bob);
1758 env.close();
1759
1760 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
1761 env(check::create(alice, bob, XRP(200)));
1762 env.close();
1763
1764 env(check::cash(bob, chkId, check::DeliverMin(XRP(100))));
1765
1766 // Get the hash for the most recent transaction.
1767 std::string const txHash{
1768 env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
1769
1770 env.close();
1771 Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta];
1772
1773 // DeliveredAmount and delivered_amount are present.
1774 BEAST_EXPECT(meta.isMember(sfDeliveredAmount.jsonName));
1775 BEAST_EXPECT(meta.isMember(jss::delivered_amount));
1776 }
1777
1778 void
1780 {
1781 testcase("With Tickets");
1782
1783 using namespace test::jtx;
1784
1785 Account const gw{"gw"};
1786 Account const alice{"alice"};
1787 Account const bob{"bob"};
1788 IOU const USD{gw["USD"]};
1789
1790 Env env{*this, features};
1791 env.fund(XRP(1000), gw, alice, bob);
1792 env.close();
1793
1794 // alice and bob grab enough tickets for all of the following
1795 // transactions. Note that once the tickets are acquired alice's
1796 // and bob's account sequence numbers should not advance.
1797 std::uint32_t aliceTicketSeq{env.seq(alice) + 1};
1798 env(ticket::create(alice, 10));
1799 std::uint32_t const aliceSeq{env.seq(alice)};
1800
1801 std::uint32_t bobTicketSeq{env.seq(bob) + 1};
1802 env(ticket::create(bob, 10));
1803 std::uint32_t const bobSeq{env.seq(bob)};
1804
1805 env.close();
1806 env.require(owners(alice, 10));
1807 env.require(owners(bob, 10));
1808
1809 // alice gets enough USD to write a few checks.
1810 env(trust(alice, USD(1000)), ticket::use(aliceTicketSeq++));
1811 env(trust(bob, USD(1000)), ticket::use(bobTicketSeq++));
1812 env.close();
1813 env.require(owners(alice, 10));
1814 env.require(owners(bob, 10));
1815
1816 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1817 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1818
1819 env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
1820 BEAST_EXPECT(env.seq(bob) == bobSeq);
1821
1822 env(pay(gw, alice, USD(900)));
1823 env.close();
1824
1825 // alice creates four checks; two XRP, two IOU. Bob will cash
1826 // one of each and cancel one of each.
1827 uint256 const chkIdXrp1{getCheckIndex(alice, aliceTicketSeq)};
1828 env(check::create(alice, bob, XRP(200)), ticket::use(aliceTicketSeq++));
1829
1830 uint256 const chkIdXrp2{getCheckIndex(alice, aliceTicketSeq)};
1831 env(check::create(alice, bob, XRP(300)), ticket::use(aliceTicketSeq++));
1832
1833 uint256 const chkIdUsd1{getCheckIndex(alice, aliceTicketSeq)};
1834 env(check::create(alice, bob, USD(200)), ticket::use(aliceTicketSeq++));
1835
1836 uint256 const chkIdUsd2{getCheckIndex(alice, aliceTicketSeq)};
1837 env(check::create(alice, bob, USD(300)), ticket::use(aliceTicketSeq++));
1838
1839 env.close();
1840 // Alice used four tickets but created four checks.
1841 env.require(owners(alice, 10));
1842 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1843 BEAST_EXPECT(checksOnAccount(env, alice).size() == 4);
1844 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1845
1846 env.require(owners(bob, 10));
1847 BEAST_EXPECT(env.seq(bob) == bobSeq);
1848
1849 // Bob cancels two of alice's checks.
1850 env(check::cancel(bob, chkIdXrp1), ticket::use(bobTicketSeq++));
1851 env(check::cancel(bob, chkIdUsd2), ticket::use(bobTicketSeq++));
1852 env.close();
1853
1854 env.require(owners(alice, 8));
1855 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1856 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
1857 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1858
1859 env.require(owners(bob, 8));
1860 BEAST_EXPECT(env.seq(bob) == bobSeq);
1861
1862 // Bob cashes alice's two remaining checks.
1863 env(check::cash(bob, chkIdXrp2, XRP(300)), ticket::use(bobTicketSeq++));
1864 env(check::cash(bob, chkIdUsd1, USD(200)), ticket::use(bobTicketSeq++));
1865 env.close();
1866
1867 env.require(owners(alice, 6));
1868 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1869 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
1870 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1871 env.require(balance(alice, USD(700)));
1872
1873 env.require(owners(bob, 6));
1874 BEAST_EXPECT(env.seq(bob) == bobSeq);
1875 env.require(balance(bob, USD(200)));
1876 }
1877
1878 void
1880 {
1881 // Explore automatic trust line creation when a check is cashed.
1882 //
1883
1884 testcase("Trust Line Creation");
1885
1886 using namespace test::jtx;
1887
1888 Env env{*this, features};
1889
1890 // An account that independently tracks its owner count.
1891 struct AccountOwns
1892 {
1894 Env const& env;
1895 Account const acct;
1896 std::size_t owners;
1897
1898 void
1899 verifyOwners(std::uint32_t line) const
1900 {
1901 suite.expect(
1902 ownerCount(env, acct) == owners,
1903 "Owner count mismatch",
1904 __FILE__,
1905 line);
1906 }
1907
1908 // Operators to make using the class more convenient.
1909 operator Account const() const
1910 {
1911 return acct;
1912 }
1913
1914 operator xrpl::AccountID() const
1915 {
1916 return acct.id();
1917 }
1918
1919 IOU
1920 operator[](std::string const& s) const
1921 {
1922 return acct[s];
1923 }
1924 };
1925
1926 AccountOwns alice{*this, env, "alice", 0};
1927 AccountOwns bob{*this, env, "bob", 0};
1928
1929 // Fund with noripple so the accounts do not have any flags set.
1930 env.fund(XRP(5000), noripple(alice, bob));
1931 env.close();
1932
1933 // Automatic trust line creation should fail if the check destination
1934 // can't afford the reserve for the trust line.
1935 {
1936 AccountOwns gw1{*this, env, "gw1", 0};
1937
1938 // Fund gw1 with noripple (even though that's atypical for a
1939 // gateway) so it does not have any flags set. We'll set flags
1940 // on gw1 later.
1941 env.fund(XRP(5000), noripple(gw1));
1942 env.close();
1943
1944 IOU const CK8 = gw1["CK8"];
1945 gw1.verifyOwners(__LINE__);
1946
1947 Account const yui{"yui"};
1948
1949 // Note the reserve in unit tests is 200 XRP, not 20. So here
1950 // we're just barely giving yui enough XRP to meet the
1951 // account reserve.
1952 env.fund(XRP(200), yui);
1953 env.close();
1954
1955 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
1956 env(check::create(gw1, yui, CK8(99)));
1957 env.close();
1958
1959 env(check::cash(yui, chkId, CK8(99)),
1961 env.close();
1962 alice.verifyOwners(__LINE__);
1963
1964 // Give yui enough XRP to meet the trust line's reserve. Cashing
1965 // the check succeeds and creates the trust line.
1966 env(pay(env.master, yui, XRP(51)));
1967 env.close();
1968 env(check::cash(yui, chkId, CK8(99)));
1969 verifyDeliveredAmount(env, CK8(99));
1970 env.close();
1971 BEAST_EXPECT(ownerCount(env, yui) == 1);
1972
1973 // The automatic trust line does not take a reserve from gw1.
1974 // Since gw1's check was consumed it has no owners.
1975 gw1.verifyOwners(__LINE__);
1976 }
1977
1978 // We'll be looking at the effects of various account root flags.
1979
1980 // Automatically create trust lines using
1981 // o Offers and
1982 // o Check cashing
1983 // Compare the resulting trust lines and expect them to be very similar.
1984
1985 // Lambda that compares two trust lines created by
1986 // o Offer crossing and
1987 // o Check cashing
1988 // between the same two accounts but with two different currencies.
1989 // The lambda expects the two trust lines to be largely similar.
1990 auto cmpTrustLines = [this, &env](
1991 Account const& acct1,
1992 Account const& acct2,
1993 IOU const& offerIou,
1994 IOU const& checkIou) {
1995 auto const offerLine =
1996 env.le(keylet::line(acct1, acct2, offerIou.currency));
1997 auto const checkLine =
1998 env.le(keylet::line(acct1, acct2, checkIou.currency));
1999 if (offerLine == nullptr || checkLine == nullptr)
2000 {
2001 BEAST_EXPECT(offerLine == nullptr && checkLine == nullptr);
2002 return;
2003 }
2004
2005 {
2006 // Compare the contents of required fields.
2007 BEAST_EXPECT(offerLine->at(sfFlags) == checkLine->at(sfFlags));
2008
2009 // Lambda that compares the contents of required STAmounts
2010 // without comparing the currency.
2011 auto cmpReqAmount =
2012 [this, offerLine, checkLine](SF_AMOUNT const& sfield) {
2013 STAmount const offerAmount = offerLine->at(sfield);
2014 STAmount const checkAmount = checkLine->at(sfield);
2015
2016 // Neither STAmount should be native.
2017 if (!BEAST_EXPECT(
2018 !offerAmount.native() && !checkAmount.native()))
2019 return;
2020
2021 BEAST_EXPECT(
2022 offerAmount.issue().account ==
2023 checkAmount.issue().account);
2024 BEAST_EXPECT(
2025 offerAmount.negative() == checkAmount.negative());
2026 BEAST_EXPECT(
2027 offerAmount.mantissa() == checkAmount.mantissa());
2028 BEAST_EXPECT(
2029 offerAmount.exponent() == checkAmount.exponent());
2030 };
2031 cmpReqAmount(sfBalance);
2032 cmpReqAmount(sfLowLimit);
2033 cmpReqAmount(sfHighLimit);
2034 }
2035 {
2036 // Lambda that compares the contents of optional fields.
2037 auto cmpOptField =
2038 [this, offerLine, checkLine](auto const& sfield) {
2039 // Expect both fields to either be present or absent.
2040 if (!BEAST_EXPECT(
2041 offerLine->isFieldPresent(sfield) ==
2042 checkLine->isFieldPresent(sfield)))
2043 return;
2044
2045 // If both fields are absent then there's nothing
2046 // further to check.
2047 if (!offerLine->isFieldPresent(sfield))
2048 return;
2049
2050 // Both optional fields are present so we can compare
2051 // them.
2052 BEAST_EXPECT(
2053 offerLine->at(sfield) == checkLine->at(sfield));
2054 };
2055 cmpOptField(sfLowNode);
2056 cmpOptField(sfLowQualityIn);
2057 cmpOptField(sfLowQualityOut);
2058
2059 cmpOptField(sfHighNode);
2060 cmpOptField(sfHighQualityIn);
2061 cmpOptField(sfHighQualityOut);
2062 }
2063 };
2064
2065 //----------- No account root flags, check written by issuer -----------
2066 {
2067 // No account root flags on any participant.
2068 // Automatic trust line from issuer to destination.
2069 AccountOwns gw1{*this, env, "gw1", 0};
2070
2071 BEAST_EXPECT((*env.le(gw1))[sfFlags] == 0);
2072 BEAST_EXPECT((*env.le(alice))[sfFlags] == 0);
2073 BEAST_EXPECT((*env.le(bob))[sfFlags] == 0);
2074
2075 // Use offers to automatically create the trust line.
2076 IOU const OF1 = gw1["OF1"];
2077 env(offer(gw1, XRP(98), OF1(98)));
2078 env.close();
2079 BEAST_EXPECT(
2080 env.le(keylet::line(gw1, alice, OF1.currency)) == nullptr);
2081 env(offer(alice, OF1(98), XRP(98)));
2082 ++alice.owners;
2083 env.close();
2084
2085 // Both offers should be consumed.
2086 // Since gw1's offer was consumed and the trust line was not
2087 // created by gw1, gw1's owner count should be 0.
2088 gw1.verifyOwners(__LINE__);
2089
2090 // alice's automatically created trust line bumps her owner count.
2091 alice.verifyOwners(__LINE__);
2092
2093 // Use check cashing to automatically create the trust line.
2094 IOU const CK1 = gw1["CK1"];
2095 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
2096 env(check::create(gw1, alice, CK1(98)));
2097 env.close();
2098 BEAST_EXPECT(
2099 env.le(keylet::line(gw1, alice, CK1.currency)) == nullptr);
2100 env(check::cash(alice, chkId, CK1(98)));
2101 ++alice.owners;
2102 verifyDeliveredAmount(env, CK1(98));
2103 env.close();
2104
2105 // gw1's check should be consumed.
2106 // Since gw1's check was consumed and the trust line was not
2107 // created by gw1, gw1's owner count should be 0.
2108 gw1.verifyOwners(__LINE__);
2109
2110 // alice's automatically created trust line bumps her owner count.
2111 alice.verifyOwners(__LINE__);
2112
2113 cmpTrustLines(gw1, alice, OF1, CK1);
2114 }
2115 //--------- No account root flags, check written by non-issuer ---------
2116 {
2117 // No account root flags on any participant.
2118 // Automatic trust line from non-issuer to non-issuer.
2119
2120 // Use offers to automatically create the trust line.
2121 // Transfer of assets using offers does not require rippling.
2122 // So bob's offer is successfully crossed which creates the
2123 // trust line.
2124 AccountOwns gw1{*this, env, "gw1", 0};
2125 IOU const OF1 = gw1["OF1"];
2126 env(offer(alice, XRP(97), OF1(97)));
2127 env.close();
2128 BEAST_EXPECT(
2129 env.le(keylet::line(alice, bob, OF1.currency)) == nullptr);
2130 env(offer(bob, OF1(97), XRP(97)));
2131 ++bob.owners;
2132 env.close();
2133
2134 // Both offers should be consumed.
2135 env.require(balance(alice, OF1(1)));
2136 env.require(balance(bob, OF1(97)));
2137
2138 // bob now has an owner count of 1 due to the new trust line.
2139 gw1.verifyOwners(__LINE__);
2140 alice.verifyOwners(__LINE__);
2141 bob.verifyOwners(__LINE__);
2142
2143 // Use check cashing to automatically create the trust line.
2144 //
2145 // However cashing a check (unlike crossing offers) requires
2146 // rippling through the currency's issuer. Since gw1 does not
2147 // have rippling enabled the check cash fails and bob does not
2148 // have a trust line created.
2149 IOU const CK1 = gw1["CK1"];
2150 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
2151 env(check::create(alice, bob, CK1(97)));
2152 env.close();
2153 BEAST_EXPECT(
2154 env.le(keylet::line(alice, bob, CK1.currency)) == nullptr);
2155 env(check::cash(bob, chkId, CK1(97)), ter(terNO_RIPPLE));
2156 env.close();
2157
2158 BEAST_EXPECT(
2159 env.le(keylet::line(gw1, bob, OF1.currency)) != nullptr);
2160 BEAST_EXPECT(
2161 env.le(keylet::line(gw1, bob, CK1.currency)) == nullptr);
2162
2163 // Delete alice's check since it is no longer needed.
2164 env(check::cancel(alice, chkId));
2165 env.close();
2166
2167 // No one's owner count should have changed.
2168 gw1.verifyOwners(__LINE__);
2169 alice.verifyOwners(__LINE__);
2170 bob.verifyOwners(__LINE__);
2171 }
2172
2173 //------------- lsfDefaultRipple, check written by issuer --------------
2174 {
2175 // gw1 enables rippling.
2176 // Automatic trust line from issuer to non-issuer should still work.
2177 AccountOwns gw1{*this, env, "gw1", 0};
2178 env(fset(gw1, asfDefaultRipple));
2179 env.close();
2180
2181 // Use offers to automatically create the trust line.
2182 IOU const OF2 = gw1["OF2"];
2183 env(offer(gw1, XRP(96), OF2(96)));
2184 env.close();
2185 BEAST_EXPECT(
2186 env.le(keylet::line(gw1, alice, OF2.currency)) == nullptr);
2187 env(offer(alice, OF2(96), XRP(96)));
2188 ++alice.owners;
2189 env.close();
2190
2191 // Both offers should be consumed.
2192 // Since gw1's offer was consumed and the trust line was not
2193 // created by gw1, gw1's owner count should still be 0.
2194 gw1.verifyOwners(__LINE__);
2195
2196 // alice's automatically created trust line bumps her owner count.
2197 alice.verifyOwners(__LINE__);
2198
2199 // Use check cashing to automatically create the trust line.
2200 IOU const CK2 = gw1["CK2"];
2201 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
2202 env(check::create(gw1, alice, CK2(96)));
2203 env.close();
2204 BEAST_EXPECT(
2205 env.le(keylet::line(gw1, alice, CK2.currency)) == nullptr);
2206 env(check::cash(alice, chkId, CK2(96)));
2207 ++alice.owners;
2208 verifyDeliveredAmount(env, CK2(96));
2209 env.close();
2210
2211 // gw1's check should be consumed.
2212 // Since gw1's check was consumed and the trust line was not
2213 // created by gw1, gw1's owner count should still be 0.
2214 gw1.verifyOwners(__LINE__);
2215
2216 // alice's automatically created trust line bumps her owner count.
2217 alice.verifyOwners(__LINE__);
2218
2219 cmpTrustLines(gw1, alice, OF2, CK2);
2220 }
2221 //----------- lsfDefaultRipple, check written by non-issuer ------------
2222 {
2223 // gw1 enabled rippling, so automatic trust line from non-issuer
2224 // to non-issuer should work.
2225
2226 // Use offers to automatically create the trust line.
2227 AccountOwns gw1{*this, env, "gw1", 0};
2228 IOU const OF2 = gw1["OF2"];
2229 env(offer(alice, XRP(95), OF2(95)));
2230 env.close();
2231 BEAST_EXPECT(
2232 env.le(keylet::line(alice, bob, OF2.currency)) == nullptr);
2233 env(offer(bob, OF2(95), XRP(95)));
2234 ++bob.owners;
2235 env.close();
2236
2237 // bob's owner count should increase due to the new trust line.
2238 gw1.verifyOwners(__LINE__);
2239 alice.verifyOwners(__LINE__);
2240 bob.verifyOwners(__LINE__);
2241
2242 // Use check cashing to automatically create the trust line.
2243 IOU const CK2 = gw1["CK2"];
2244 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
2245 env(check::create(alice, bob, CK2(95)));
2246 env.close();
2247 BEAST_EXPECT(
2248 env.le(keylet::line(alice, bob, CK2.currency)) == nullptr);
2249 env(check::cash(bob, chkId, CK2(95)));
2250 ++bob.owners;
2251 verifyDeliveredAmount(env, CK2(95));
2252 env.close();
2253
2254 // bob's owner count should increase due to the new trust line.
2255 gw1.verifyOwners(__LINE__);
2256 alice.verifyOwners(__LINE__);
2257 bob.verifyOwners(__LINE__);
2258
2259 cmpTrustLines(alice, bob, OF2, CK2);
2260 }
2261
2262 //-------------- lsfDepositAuth, check written by issuer ---------------
2263 {
2264 // Both offers and checks ignore the lsfDepositAuth flag, since
2265 // the destination signs the transaction that delivers their funds.
2266 // So setting lsfDepositAuth on all the participants should not
2267 // change any outcomes.
2268 //
2269 // Automatic trust line from issuer to non-issuer should still work.
2270 AccountOwns gw1{*this, env, "gw1", 0};
2271 env(fset(gw1, asfDepositAuth));
2272 env(fset(alice, asfDepositAuth));
2273 env(fset(bob, asfDepositAuth));
2274 env.close();
2275
2276 // Use offers to automatically create the trust line.
2277 IOU const OF3 = gw1["OF3"];
2278 env(offer(gw1, XRP(94), OF3(94)));
2279 env.close();
2280 BEAST_EXPECT(
2281 env.le(keylet::line(gw1, alice, OF3.currency)) == nullptr);
2282 env(offer(alice, OF3(94), XRP(94)));
2283 ++alice.owners;
2284 env.close();
2285
2286 // Both offers should be consumed.
2287 // Since gw1's offer was consumed and the trust line was not
2288 // created by gw1, gw1's owner count should still be 0.
2289 gw1.verifyOwners(__LINE__);
2290
2291 // alice's automatically created trust line bumps her owner count.
2292 alice.verifyOwners(__LINE__);
2293
2294 // Use check cashing to automatically create the trust line.
2295 IOU const CK3 = gw1["CK3"];
2296 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
2297 env(check::create(gw1, alice, CK3(94)));
2298 env.close();
2299 BEAST_EXPECT(
2300 env.le(keylet::line(gw1, alice, CK3.currency)) == nullptr);
2301 env(check::cash(alice, chkId, CK3(94)));
2302 ++alice.owners;
2303 verifyDeliveredAmount(env, CK3(94));
2304 env.close();
2305
2306 // gw1's check should be consumed.
2307 // Since gw1's check was consumed and the trust line was not
2308 // created by gw1, gw1's owner count should still be 0.
2309 gw1.verifyOwners(__LINE__);
2310
2311 // alice's automatically created trust line bumps her owner count.
2312 alice.verifyOwners(__LINE__);
2313
2314 cmpTrustLines(gw1, alice, OF3, CK3);
2315 }
2316 //------------ lsfDepositAuth, check written by non-issuer -------------
2317 {
2318 // The presence of the lsfDepositAuth flag should not affect
2319 // automatic trust line creation.
2320
2321 // Use offers to automatically create the trust line.
2322 AccountOwns gw1{*this, env, "gw1", 0};
2323 IOU const OF3 = gw1["OF3"];
2324 env(offer(alice, XRP(93), OF3(93)));
2325 env.close();
2326 BEAST_EXPECT(
2327 env.le(keylet::line(alice, bob, OF3.currency)) == nullptr);
2328 env(offer(bob, OF3(93), XRP(93)));
2329 ++bob.owners;
2330 env.close();
2331
2332 // bob's owner count should increase due to the new trust line.
2333 gw1.verifyOwners(__LINE__);
2334 alice.verifyOwners(__LINE__);
2335 bob.verifyOwners(__LINE__);
2336
2337 // Use check cashing to automatically create the trust line.
2338 IOU const CK3 = gw1["CK3"];
2339 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
2340 env(check::create(alice, bob, CK3(93)));
2341 env.close();
2342 BEAST_EXPECT(
2343 env.le(keylet::line(alice, bob, CK3.currency)) == nullptr);
2344 env(check::cash(bob, chkId, CK3(93)));
2345 ++bob.owners;
2346 verifyDeliveredAmount(env, CK3(93));
2347 env.close();
2348
2349 // bob's owner count should increase due to the new trust line.
2350 gw1.verifyOwners(__LINE__);
2351 alice.verifyOwners(__LINE__);
2352 bob.verifyOwners(__LINE__);
2353
2354 cmpTrustLines(alice, bob, OF3, CK3);
2355 }
2356
2357 //-------------- lsfGlobalFreeze, check written by issuer --------------
2358 {
2359 // Set lsfGlobalFreeze on gw1. That should stop any automatic
2360 // trust lines from being created.
2361 AccountOwns gw1{*this, env, "gw1", 0};
2362 env(fset(gw1, asfGlobalFreeze));
2363 env.close();
2364
2365 // Use offers to automatically create the trust line.
2366 IOU const OF4 = gw1["OF4"];
2367 env(offer(gw1, XRP(92), OF4(92)), ter(tecFROZEN));
2368 env.close();
2369 BEAST_EXPECT(
2370 env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr);
2371 env(offer(alice, OF4(92), XRP(92)), ter(tecFROZEN));
2372 env.close();
2373
2374 // No one's owner count should have changed.
2375 gw1.verifyOwners(__LINE__);
2376 alice.verifyOwners(__LINE__);
2377 bob.verifyOwners(__LINE__);
2378
2379 // Use check cashing to automatically create the trust line.
2380 IOU const CK4 = gw1["CK4"];
2381 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
2382 env(check::create(gw1, alice, CK4(92)), ter(tecFROZEN));
2383 env.close();
2384 BEAST_EXPECT(
2385 env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr);
2386 env(check::cash(alice, chkId, CK4(92)), ter(tecNO_ENTRY));
2387 env.close();
2388
2389 // No one's owner count should have changed.
2390 gw1.verifyOwners(__LINE__);
2391 alice.verifyOwners(__LINE__);
2392 bob.verifyOwners(__LINE__);
2393
2394 // Because gw1 has set lsfGlobalFreeze, neither trust line
2395 // is created.
2396 BEAST_EXPECT(
2397 env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr);
2398 BEAST_EXPECT(
2399 env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr);
2400 }
2401 //------------ lsfGlobalFreeze, check written by non-issuer ------------
2402 {
2403 // Since gw1 has the lsfGlobalFreeze flag set, there should be
2404 // no automatic trust line creation between non-issuers.
2405
2406 // Use offers to automatically create the trust line.
2407 AccountOwns gw1{*this, env, "gw1", 0};
2408 IOU const OF4 = gw1["OF4"];
2409 env(offer(alice, XRP(91), OF4(91)), ter(tecFROZEN));
2410 env.close();
2411 BEAST_EXPECT(
2412 env.le(keylet::line(alice, bob, OF4.currency)) == nullptr);
2413 env(offer(bob, OF4(91), XRP(91)), ter(tecFROZEN));
2414 env.close();
2415
2416 // No one's owner count should have changed.
2417 gw1.verifyOwners(__LINE__);
2418 alice.verifyOwners(__LINE__);
2419 bob.verifyOwners(__LINE__);
2420
2421 // Use check cashing to automatically create the trust line.
2422 IOU const CK4 = gw1["CK4"];
2423 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
2424 env(check::create(alice, bob, CK4(91)), ter(tecFROZEN));
2425 env.close();
2426 BEAST_EXPECT(
2427 env.le(keylet::line(alice, bob, CK4.currency)) == nullptr);
2428 env(check::cash(bob, chkId, CK4(91)), ter(tecNO_ENTRY));
2429 env.close();
2430
2431 // No one's owner count should have changed.
2432 gw1.verifyOwners(__LINE__);
2433 alice.verifyOwners(__LINE__);
2434 bob.verifyOwners(__LINE__);
2435
2436 // Because gw1 has set lsfGlobalFreeze, neither trust line
2437 // is created.
2438 BEAST_EXPECT(
2439 env.le(keylet::line(gw1, bob, OF4.currency)) == nullptr);
2440 BEAST_EXPECT(
2441 env.le(keylet::line(gw1, bob, CK4.currency)) == nullptr);
2442 }
2443
2444 //-------------- lsfRequireAuth, check written by issuer ---------------
2445
2446 // We want to test the lsfRequireAuth flag, but we can't set that
2447 // flag on an account that already has trust lines. So we'll fund
2448 // a new gateway and use that.
2449 {
2450 AccountOwns gw2{*this, env, "gw2", 0};
2451 env.fund(XRP(5000), gw2);
2452 env.close();
2453
2454 // Set lsfRequireAuth on gw2. That should stop any automatic
2455 // trust lines from being created.
2456 env(fset(gw2, asfRequireAuth));
2457 env.close();
2458
2459 // Use offers to automatically create the trust line.
2460 IOU const OF5 = gw2["OF5"];
2461 std::uint32_t gw2OfferSeq = {env.seq(gw2)};
2462 env(offer(gw2, XRP(92), OF5(92)));
2463 ++gw2.owners;
2464 env.close();
2465 BEAST_EXPECT(
2466 env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr);
2467 env(offer(alice, OF5(92), XRP(92)), ter(tecNO_LINE));
2468 env.close();
2469
2470 // gw2 should still own the offer, but no one else's owner
2471 // count should have changed.
2472 gw2.verifyOwners(__LINE__);
2473 alice.verifyOwners(__LINE__);
2474 bob.verifyOwners(__LINE__);
2475
2476 // Since we don't need it any more, remove gw2's offer.
2477 env(offer_cancel(gw2, gw2OfferSeq));
2478 --gw2.owners;
2479 env.close();
2480 gw2.verifyOwners(__LINE__);
2481
2482 // Use check cashing to automatically create the trust line.
2483 IOU const CK5 = gw2["CK5"];
2484 uint256 const chkId{getCheckIndex(gw2, env.seq(gw2))};
2485 env(check::create(gw2, alice, CK5(92)));
2486 ++gw2.owners;
2487 env.close();
2488 BEAST_EXPECT(
2489 env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr);
2490 env(check::cash(alice, chkId, CK5(92)), ter(tecNO_AUTH));
2491 env.close();
2492
2493 // gw2 should still own the check, but no one else's owner
2494 // count should have changed.
2495 gw2.verifyOwners(__LINE__);
2496 alice.verifyOwners(__LINE__);
2497 bob.verifyOwners(__LINE__);
2498
2499 // Because gw2 has set lsfRequireAuth, neither trust line
2500 // is created.
2501 BEAST_EXPECT(
2502 env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr);
2503 BEAST_EXPECT(
2504 env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr);
2505
2506 // Since we don't need it any more, remove gw2's check.
2507 env(check::cancel(gw2, chkId));
2508 --gw2.owners;
2509 env.close();
2510 gw2.verifyOwners(__LINE__);
2511 }
2512 //------------ lsfRequireAuth, check written by non-issuer -------------
2513 {
2514 // Since gw2 has the lsfRequireAuth flag set, there should be
2515 // no automatic trust line creation between non-issuers.
2516
2517 // Use offers to automatically create the trust line.
2518 AccountOwns gw2{*this, env, "gw2", 0};
2519 IOU const OF5 = gw2["OF5"];
2520 env(offer(alice, XRP(91), OF5(91)), ter(tecUNFUNDED_OFFER));
2521 env.close();
2522 env(offer(bob, OF5(91), XRP(91)), ter(tecNO_LINE));
2523 BEAST_EXPECT(
2524 env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr);
2525 env.close();
2526
2527 gw2.verifyOwners(__LINE__);
2528 alice.verifyOwners(__LINE__);
2529 bob.verifyOwners(__LINE__);
2530
2531 // Use check cashing to automatically create the trust line.
2532 IOU const CK5 = gw2["CK5"];
2533 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
2534 env(check::create(alice, bob, CK5(91)));
2535 env.close();
2536 BEAST_EXPECT(
2537 env.le(keylet::line(alice, bob, CK5.currency)) == nullptr);
2538 env(check::cash(bob, chkId, CK5(91)), ter(tecPATH_PARTIAL));
2539 env.close();
2540
2541 // Delete alice's check since it is no longer needed.
2542 env(check::cancel(alice, chkId));
2543 env.close();
2544
2545 // No one's owner count should have changed.
2546 gw2.verifyOwners(__LINE__);
2547 alice.verifyOwners(__LINE__);
2548 bob.verifyOwners(__LINE__);
2549
2550 // Because gw2 has set lsfRequireAuth, neither trust line
2551 // is created.
2552 BEAST_EXPECT(
2553 env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr);
2554 BEAST_EXPECT(
2555 env.le(keylet::line(gw2, bob, CK5.currency)) == nullptr);
2556 }
2557 }
2558
2559 void
2561 {
2562 testEnabled(features);
2563 testCreateValid(features);
2565 testCreateInvalid(features);
2566 testCashXRP(features);
2567 testCashIOU(features);
2568 testCashXferFee(features);
2569 testCashQuality(features);
2570 testCashInvalid(features);
2571 testCancelValid(features);
2572 testCancelInvalid(features);
2574 testWithTickets(features);
2575 }
2576
2577public:
2578 void
2579 run() override
2580 {
2581 using namespace test::jtx;
2582 auto const sa = testable_amendments();
2583 testWithFeats(sa);
2585 }
2586};
2587
2588BEAST_DEFINE_TESTSUITE(Check, app, xrpl);
2589
2590} // namespace xrpl
Represents a JSON value.
Definition json_value.h:131
Value removeMember(char const *key)
Remove and return the named member.
bool isMember(char const *key) const
Return true if the object has a member named key.
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:226
void testCreateInvalid(FeatureBitset features)
void testCreateDisallowIncoming(FeatureBitset features)
void testCashQuality(FeatureBitset features)
static uint256 getCheckIndex(AccountID const &account, std::uint32_t uSequence)
void verifyDeliveredAmount(test::jtx::Env &env, STAmount const &amount)
void testCreateValid(FeatureBitset features)
void testTrustLineCreation(FeatureBitset features)
void testCashInvalid(FeatureBitset features)
void testCancelInvalid(FeatureBitset features)
void testEnabled(FeatureBitset features)
void testCashIOU(FeatureBitset features)
void testWithTickets(FeatureBitset features)
void testCancelValid(FeatureBitset features)
void testWithFeats(FeatureBitset features)
void testCashXferFee(FeatureBitset features)
void run() override
Runs the suite.
void testDeliveredAmountForCheckCashTxn(FeatureBitset features)
static std::vector< std::shared_ptr< SLE const > > checksOnAccount(test::jtx::Env &env, test::jtx::Account account)
void testCashXRP(FeatureBitset features)
A currency issued by an account.
Definition Issue.h:14
AccountID account
Definition Issue.h:17
Issue const & issue() const
Definition STAmount.h:488
std::uint64_t mantissa() const noexcept
Definition STAmount.h:469
bool negative() const noexcept
Definition STAmount.h:463
bool native() const noexcept
Definition STAmount.h:450
int exponent() const noexcept
Definition STAmount.h:438
Immutable cryptographic account descriptor.
Definition Account.h:20
A transaction testing environment.
Definition Env.h:102
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:104
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:774
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
Definition Env.cpp:510
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:314
Set DestinationTag on a JTx.
dest_tag(std::uint32_t tag)
std::uint32_t const tag_
void operator()(Env &, JTx &jt) const
Set Expiration on a JTx.
expiration(NetClock::time_point const &expiry)
void operator()(Env &, JTx &jt) const
std::uint32_t const expiry_
Set SourceTag on a JTx.
void operator()(Env &, JTx &jt) const
source_tag(std::uint32_t tag)
std::uint32_t const tag_
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition Indexes.cpp:318
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:226
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
@ terNO_LINE
Definition TER.h:200
@ terNO_RIPPLE
Definition TER.h:205
constexpr std::uint32_t asfGlobalFreeze
Definition TxFlags.h:64
constexpr std::uint32_t asfRequireDest
Definition TxFlags.h:58
constexpr std::uint32_t tfImmediateOrCancel
Definition TxFlags.h:80
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:759
constexpr std::uint32_t asfDepositAuth
Definition TxFlags.h:66
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:29
constexpr std::uint32_t asfDefaultRipple
Definition TxFlags.h:65
constexpr std::uint32_t tfClearFreeze
Definition TxFlags.h:100
constexpr std::uint32_t tfSetfAuth
Definition TxFlags.h:96
constexpr std::uint32_t asfDisallowIncomingCheck
Definition TxFlags.h:72
constexpr std::uint32_t asfRequireAuth
Definition TxFlags.h:59
@ temBAD_CURRENCY
Definition TER.h:71
@ temBAD_EXPIRATION
Definition TER.h:72
@ temBAD_FEE
Definition TER.h:73
@ temINVALID_FLAG
Definition TER.h:92
@ temMALFORMED
Definition TER.h:68
@ temBAD_AMOUNT
Definition TER.h:70
@ temREDUNDANT
Definition TER.h:93
@ tecNO_LINE_INSUF_RESERVE
Definition TER.h:274
@ tecPATH_PARTIAL
Definition TER.h:264
@ tecNO_ENTRY
Definition TER.h:288
@ tecPATH_DRY
Definition TER.h:276
@ tecNO_AUTH
Definition TER.h:282
@ tecFROZEN
Definition TER.h:285
@ tecUNFUNDED_OFFER
Definition TER.h:266
@ tecEXPIRED
Definition TER.h:296
@ tecNO_LINE
Definition TER.h:283
@ tecINSUFFICIENT_RESERVE
Definition TER.h:289
@ tecNO_PERMISSION
Definition TER.h:287
@ tecDST_TAG_NEEDED
Definition TER.h:291
@ tecNO_DST
Definition TER.h:272
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr std::uint32_t tfSetFreeze
Definition TxFlags.h:99
@ tesSUCCESS
Definition TER.h:226
uint256 key
Definition Keylet.h:21
A field with a type known at compile time.
Definition SField.h:301
Execution context for applying a JSON transaction.
Definition JTx.h:26