rippled
Loading...
Searching...
No Matches
EscrowToken_test.cpp
1#include <test/jtx.h>
2
3#include <xrpld/app/tx/applySteps.h>
4
5#include <xrpl/ledger/Dir.h>
6#include <xrpl/ledger/Sandbox.h>
7#include <xrpl/protocol/Feature.h>
8#include <xrpl/protocol/Indexes.h>
9#include <xrpl/protocol/STAmount.h>
10#include <xrpl/protocol/TxFlags.h>
11#include <xrpl/protocol/jss.h>
12
13#include <algorithm>
14#include <iterator>
15
16namespace ripple {
17namespace test {
18
20{
21 static uint64_t
23 jtx::Env const& env,
24 jtx::Account const& account,
25 jtx::MPT const& mpt)
26 {
27 auto const sle = env.le(keylet::mptoken(mpt.mpt(), account));
28 if (sle && sle->isFieldPresent(sfLockedAmount))
29 return (*sle)[sfLockedAmount];
30 return 0;
31 }
32
33 static uint64_t
34 issuerMPTEscrowed(jtx::Env const& env, jtx::MPT const& mpt)
35 {
36 auto const sle = env.le(keylet::mptIssuance(mpt.mpt()));
37 if (sle && sle->isFieldPresent(sfLockedAmount))
38 return (*sle)[sfLockedAmount];
39 return 0;
40 }
41
44 jtx::Env& env,
45 jtx::Account const& account,
46 Issue const& issue)
47 {
48 Json::Value params;
49 params[jss::account] = account.human();
50 auto jrr = env.rpc("json", "gateway_balances", to_string(params));
51 auto const result = jrr[jss::result];
52 auto const obligations =
53 result[jss::obligations][to_string(issue.currency)];
54 if (obligations.isNull())
55 return {STAmount(issue, 0), account.name()};
56 STAmount const amount = amountFromString(issue, obligations.asString());
57 return {amount, account.name()};
58 }
59
62 jtx::Env& env,
63 jtx::Account const& account,
64 Issue const& issue)
65 {
66 Json::Value params;
67 params[jss::account] = account.human();
68 auto jrr = env.rpc("json", "gateway_balances", to_string(params));
69 auto const result = jrr[jss::result];
70 auto const locked = result[jss::locked][to_string(issue.currency)];
71 if (locked.isNull())
72 return {STAmount(issue, 0), account.name()};
73 STAmount const amount = amountFromString(issue, locked.asString());
74 return {amount, account.name()};
75 }
76
77 void
79 {
80 testcase("IOU Enablement");
81
82 using namespace jtx;
83 using namespace std::chrono;
84
85 for (bool const withTokenEscrow : {false, true})
86 {
87 auto const amend =
88 withTokenEscrow ? features : features - featureTokenEscrow;
89 Env env{*this, amend};
90 auto const baseFee = env.current()->fees().base;
91 auto const alice = Account("alice");
92 auto const bob = Account("bob");
93 auto const gw = Account{"gateway"};
94 auto const USD = gw["USD"];
95 env.fund(XRP(5000), alice, bob, gw);
97 env.close();
98 env.trust(USD(10'000), alice, bob);
99 env.close();
100 env(pay(gw, alice, USD(5000)));
101 env(pay(gw, bob, USD(5000)));
102 env.close();
103
104 auto const createResult =
105 withTokenEscrow ? ter(tesSUCCESS) : ter(temBAD_AMOUNT);
106 auto const finishResult =
107 withTokenEscrow ? ter(tesSUCCESS) : ter(tecNO_TARGET);
108
109 auto const seq1 = env.seq(alice);
110 env(escrow::create(alice, bob, USD(1'000)),
112 escrow::finish_time(env.now() + 1s),
113 fee(baseFee * 150),
114 createResult);
115 env.close();
116 env(escrow::finish(bob, alice, seq1),
119 fee(baseFee * 150),
120 finishResult);
121 env.close();
122
123 auto const seq2 = env.seq(alice);
124 env(escrow::create(alice, bob, USD(1'000)),
126 escrow::finish_time(env.now() + 1s),
127 escrow::cancel_time(env.now() + 2s),
128 fee(baseFee * 150),
129 createResult);
130 env.close();
131 env(escrow::cancel(bob, alice, seq2), finishResult);
132 env.close();
133 }
134
135 for (bool const withTokenEscrow : {false, true})
136 {
137 auto const amend =
138 withTokenEscrow ? features : features - featureTokenEscrow;
139 Env env{*this, amend};
140 auto const baseFee = env.current()->fees().base;
141 auto const alice = Account("alice");
142 auto const bob = Account("bob");
143 auto const gw = Account{"gateway"};
144 auto const USD = gw["USD"];
145 env.fund(XRP(5000), alice, bob, gw);
147 env.close();
148 env.trust(USD(10'000), alice, bob);
149 env.close();
150 env(pay(gw, alice, USD(5000)));
151 env(pay(gw, bob, USD(5000)));
152 env.close();
153
154 auto const seq1 = env.seq(alice);
155 env(escrow::finish(bob, alice, seq1),
158 fee(baseFee * 150),
160 env.close();
161
162 env(escrow::cancel(bob, alice, seq1), ter(tecNO_TARGET));
163 env.close();
164 }
165 }
166
167 void
169 {
170 testcase("IOU Allow Locking Flag");
171
172 using namespace jtx;
173 using namespace std::chrono;
174
175 Env env{*this, features};
176 auto const baseFee = env.current()->fees().base;
177 auto const alice = Account("alice");
178 auto const bob = Account("bob");
179 auto const gw = Account{"gateway"};
180 auto const USD = gw["USD"];
181 env.fund(XRP(5000), alice, bob, gw);
183 env.close();
184 env.trust(USD(10'000), alice, bob);
185 env.close();
186 env(pay(gw, alice, USD(5000)));
187 env(pay(gw, bob, USD(5000)));
188 env.close();
189
190 // Create Escrow #1 & #2
191 auto const seq1 = env.seq(alice);
192 env(escrow::create(alice, bob, USD(1'000)),
194 escrow::finish_time(env.now() + 1s),
195 fee(baseFee * 150),
196 ter(tesSUCCESS));
197 env.close();
198
199 auto const seq2 = env.seq(alice);
200 env(escrow::create(alice, bob, USD(1'000)),
201 escrow::finish_time(env.now() + 1s),
202 escrow::cancel_time(env.now() + 3s),
203 fee(baseFee),
204 ter(tesSUCCESS));
205 env.close();
206
207 // Clear the asfAllowTrustLineLocking flag
209 env.close();
210 env.require(nflags(gw, asfAllowTrustLineLocking));
211
212 // Cannot Create Escrow without asfAllowTrustLineLocking
213 env(escrow::create(alice, bob, USD(1'000)),
215 escrow::finish_time(env.now() + 1s),
216 fee(baseFee * 150),
218 env.close();
219
220 // Can finish the escrow created before the flag was cleared
221 env(escrow::finish(bob, alice, seq1),
224 fee(baseFee * 150),
225 ter(tesSUCCESS));
226 env.close();
227
228 // Can cancel the escrow created before the flag was cleared
229 env(escrow::cancel(bob, alice, seq2), ter(tesSUCCESS));
230 env.close();
231 }
232
233 void
235 {
236 testcase("IOU Create Preflight");
237 using namespace test::jtx;
238 using namespace std::literals;
239
240 // temBAD_FEE: Exercises invalid preflight1.
241 {
242 Env env{*this, features};
243 auto const alice = Account("alice");
244 auto const bob = Account("bob");
245 auto const gw = Account{"gateway"};
246 auto const USD = gw["USD"];
247 env.fund(XRP(5000), alice, bob, gw);
248
249 env(escrow::create(alice, bob, USD(1)),
250 escrow::finish_time(env.now() + 1s),
251 fee(XRP(-1)),
252 ter(temBAD_FEE));
253 env.close();
254 }
255
256 // temBAD_AMOUNT: amount <= 0
257 {
258 Env env{*this, features};
259 auto const baseFee = env.current()->fees().base;
260 auto const alice = Account("alice");
261 auto const bob = Account("bob");
262 auto const gw = Account{"gateway"};
263 auto const USD = gw["USD"];
264 env.fund(XRP(5000), alice, bob, gw);
265
266 env(escrow::create(alice, bob, USD(-1)),
268 escrow::finish_time(env.now() + 1s),
269 fee(baseFee * 150),
271 env.close();
272 }
273
274 // temBAD_CURRENCY: badCurrency() == amount.getCurrency()
275 {
276 Env env{*this, features};
277 auto const baseFee = env.current()->fees().base;
278 auto const alice = Account("alice");
279 auto const bob = Account("bob");
280 auto const gw = Account{"gateway"};
281 auto const BAD = IOU(gw, badCurrency());
282 env.fund(XRP(5000), alice, bob, gw);
283
284 env(escrow::create(alice, bob, BAD(1)),
286 escrow::finish_time(env.now() + 1s),
287 fee(baseFee * 150),
289 env.close();
290 }
291 }
292
293 void
295 {
296 testcase("IOU Create Preclaim");
297 using namespace test::jtx;
298 using namespace std::literals;
299
300 // tecNO_PERMISSION: issuer is the same as the account
301 {
302 Env env{*this, features};
303 auto const baseFee = env.current()->fees().base;
304 auto const alice = Account("alice");
305 auto const bob = Account("bob");
306 auto const gw = Account{"gateway"};
307 auto const USD = gw["USD"];
308 env.fund(XRP(5000), alice, bob, gw);
309
310 env(escrow::create(gw, alice, USD(1)),
312 escrow::finish_time(env.now() + 1s),
313 fee(baseFee * 150),
315 env.close();
316 }
317
318 // tecNO_ISSUER: Issuer does not exist
319 {
320 Env env{*this, features};
321 auto const baseFee = env.current()->fees().base;
322 auto const alice = Account("alice");
323 auto const bob = Account("bob");
324 auto const gw = Account{"gateway"};
325 auto const USD = gw["USD"];
326 env.fund(XRP(5000), alice, bob);
327 env.close();
328 env.memoize(gw);
329
330 env(escrow::create(alice, bob, USD(1)),
332 escrow::finish_time(env.now() + 1s),
333 fee(baseFee * 150),
335 env.close();
336 }
337
338 // tecNO_PERMISSION: asfAllowTrustLineLocking is not set
339 {
340 Env env{*this, features};
341 auto const baseFee = env.current()->fees().base;
342 auto const alice = Account("alice");
343 auto const bob = Account("bob");
344 auto const gw = Account{"gateway"};
345 auto const USD = gw["USD"];
346 env.fund(XRP(5000), alice, bob, gw);
347 env.close();
348 env.trust(USD(10'000), alice, bob);
349 env.close();
350 env(pay(gw, alice, USD(5000)));
351 env(pay(gw, bob, USD(5000)));
352 env.close();
353
354 env(escrow::create(gw, alice, USD(1)),
356 escrow::finish_time(env.now() + 1s),
357 fee(baseFee * 150),
359 env.close();
360 }
361
362 // tecNO_LINE: account does not have a trustline to the issuer
363 {
364 Env env{*this, features};
365 auto const baseFee = env.current()->fees().base;
366 auto const alice = Account("alice");
367 auto const bob = Account("bob");
368 auto const gw = Account{"gateway"};
369 auto const USD = gw["USD"];
370 env.fund(XRP(5000), alice, bob, gw);
372 env.close();
373 env(escrow::create(alice, bob, USD(1)),
375 escrow::finish_time(env.now() + 1s),
376 fee(baseFee * 150),
377 ter(tecNO_LINE));
378 env.close();
379 }
380
381 // tecNO_PERMISSION: Not testable
382 // tecNO_PERMISSION: Not testable
383 // tecNO_AUTH: requireAuth
384 {
385 Env env{*this, features};
386 auto const baseFee = env.current()->fees().base;
387 auto const alice = Account("alice");
388 auto const bob = Account("bob");
389 auto const gw = Account{"gateway"};
390 auto const USD = gw["USD"];
391 env.fund(XRP(5000), alice, bob, gw);
393 env(fset(gw, asfRequireAuth));
394 env.close();
395 env.trust(USD(10'000), alice, bob);
396 env.close();
397
398 env(escrow::create(alice, bob, USD(1)),
400 escrow::finish_time(env.now() + 1s),
401 fee(baseFee * 150),
402 ter(tecNO_AUTH));
403 env.close();
404 }
405
406 // tecNO_AUTH: requireAuth
407 {
408 Env env{*this, features};
409 auto const baseFee = env.current()->fees().base;
410 auto const alice = Account("alice");
411 auto const bob = Account("bob");
412 auto const gw = Account{"gateway"};
413 auto const USD = gw["USD"];
414 auto const aliceUSD = alice["USD"];
415 env.fund(XRP(5000), alice, bob, gw);
417 env(fset(gw, asfRequireAuth));
418 env.close();
419 env(trust(gw, aliceUSD(10'000)), txflags(tfSetfAuth));
420 env.trust(USD(10'000), alice, bob);
421 env.close();
422
423 env(escrow::create(alice, bob, USD(1)),
425 escrow::finish_time(env.now() + 1s),
426 fee(baseFee * 150),
427 ter(tecNO_AUTH));
428 env.close();
429 }
430
431 // tecFROZEN: account is frozen
432 {
433 // Env Setup
434 Env env{*this, features};
435 auto const alice = Account("alice");
436 auto const bob = Account("bob");
437 auto const gw = Account{"gateway"};
438 auto const USD = gw["USD"];
439 auto const baseFee = env.current()->fees().base;
440 env.fund(XRP(10'000), alice, bob, gw);
442 env.close();
443 env(trust(alice, USD(100'000)));
444 env(trust(bob, USD(100'000)));
445 env.close();
446 env(pay(gw, alice, USD(10'000)));
447 env(pay(gw, bob, USD(10'000)));
448 env.close();
449
450 // set freeze on alice trustline
451 env(trust(gw, USD(10'000), alice, tfSetFreeze));
452 env.close();
453
454 env(escrow::create(alice, bob, USD(1)),
456 escrow::finish_time(env.now() + 1s),
457 fee(baseFee * 150),
458 ter(tecFROZEN));
459 env.close();
460 }
461
462 // tecFROZEN: dest is frozen
463 {
464 // Env Setup
465 Env env{*this, features};
466 auto const alice = Account("alice");
467 auto const bob = Account("bob");
468 auto const gw = Account{"gateway"};
469 auto const USD = gw["USD"];
470 auto const baseFee = env.current()->fees().base;
471 env.fund(XRP(10'000), alice, bob, gw);
473 env.close();
474 env(trust(alice, USD(100'000)));
475 env(trust(bob, USD(100'000)));
476 env.close();
477 env(pay(gw, alice, USD(10'000)));
478 env(pay(gw, bob, USD(10'000)));
479 env.close();
480
481 // set freeze on bob trustline
482 env(trust(gw, USD(10'000), bob, tfSetFreeze));
483 env.close();
484
485 env(escrow::create(alice, bob, USD(1)),
487 escrow::finish_time(env.now() + 1s),
488 fee(baseFee * 150),
489 ter(tecFROZEN));
490 env.close();
491 }
492
493 // tecINSUFFICIENT_FUNDS
494 {
495 // Env Setup
496 Env env{*this, features};
497 auto const alice = Account("alice");
498 auto const bob = Account("bob");
499 auto const gw = Account{"gateway"};
500 auto const USD = gw["USD"];
501 auto const baseFee = env.current()->fees().base;
502 env.fund(XRP(10'000), alice, bob, gw);
504 env.close();
505 env(trust(alice, USD(100'000)));
506 env(trust(bob, USD(100'000)));
507 env.close();
508
509 env(escrow::create(alice, bob, USD(1)),
511 escrow::finish_time(env.now() + 1s),
512 fee(baseFee * 150),
514 env.close();
515 }
516
517 // tecINSUFFICIENT_FUNDS
518 {
519 // Env Setup
520 Env env{*this, features};
521 auto const alice = Account("alice");
522 auto const bob = Account("bob");
523 auto const gw = Account{"gateway"};
524 auto const USD = gw["USD"];
525 auto const baseFee = env.current()->fees().base;
526 env.fund(XRP(10'000), alice, bob, gw);
528 env.close();
529 env(trust(alice, USD(100'000)));
530 env(trust(bob, USD(100'000)));
531 env.close();
532 env(pay(gw, alice, USD(10'000)));
533 env(pay(gw, bob, USD(10'000)));
534 env.close();
535
536 env(escrow::create(alice, bob, USD(10'001)),
538 escrow::finish_time(env.now() + 1s),
539 fee(baseFee * 150),
541 env.close();
542 }
543
544 // tecPRECISION_LOSS
545 {
546 Env env{*this, features};
547 auto const alice = Account("alice");
548 auto const bob = Account("bob");
549 auto const gw = Account{"gateway"};
550 auto const USD = gw["USD"];
551 auto const baseFee = env.current()->fees().base;
552 env.fund(XRP(10'000), alice, bob, gw);
554 env.close();
555 env.trust(USD(100000000000000000), alice);
556 env.trust(USD(100000000000000000), bob);
557 env.close();
558 env(pay(gw, alice, USD(10000000000000000)));
559 env(pay(gw, bob, USD(1)));
560 env.close();
561
562 // alice cannot create escrow for 1/10 iou - precision loss
563 env(escrow::create(alice, bob, USD(1)),
565 escrow::finish_time(env.now() + 1s),
566 fee(baseFee * 150),
568 env.close();
569 }
570 }
571
572 void
574 {
575 testcase("IOU Finish Preclaim");
576 using namespace test::jtx;
577 using namespace std::literals;
578
579 // tecNO_AUTH: requireAuth set: dest not authorized
580 {
581 Env env{*this, features};
582 auto const baseFee = env.current()->fees().base;
583 auto const alice = Account("alice");
584 auto const bob = Account("bob");
585 auto const gw = Account{"gateway"};
586 auto const USD = gw["USD"];
587 auto const aliceUSD = alice["USD"];
588 auto const bobUSD = bob["USD"];
589 env.fund(XRP(5000), alice, bob, gw);
591 env(fset(gw, asfRequireAuth));
592 env.close();
593 env(trust(gw, aliceUSD(10'000)), txflags(tfSetfAuth));
594 env(trust(gw, bobUSD(10'000)), txflags(tfSetfAuth));
595 env.trust(USD(10'000), alice, bob);
596 env.close();
597 env(pay(gw, alice, USD(10'000)));
598 env(pay(gw, bob, USD(10'000)));
599 env.close();
600
601 auto const seq1 = env.seq(alice);
602 env(escrow::create(alice, bob, USD(1)),
604 escrow::finish_time(env.now() + 1s),
605 fee(baseFee * 150),
606 ter(tesSUCCESS));
607 env.close();
608
609 env(pay(bob, gw, USD(10'000)));
610 env(trust(gw, bobUSD(0)), txflags(tfSetfAuth));
611 env(trust(bob, USD(0)));
612 env.close();
613
614 env.trust(USD(10'000), bob);
615 env.close();
616
617 // bob cannot finish because he is not authorized
618 env(escrow::finish(bob, alice, seq1),
621 fee(baseFee * 150),
622 ter(tecNO_AUTH));
623 env.close();
624 }
625
626 // tecFROZEN: issuer has deep frozen the dest
627 {
628 Env env{*this, features};
629 auto const baseFee = env.current()->fees().base;
630 auto const alice = Account("alice");
631 auto const bob = Account("bob");
632 auto const gw = Account{"gateway"};
633 auto const USD = gw["USD"];
634 env.fund(XRP(5000), alice, bob, gw);
636 env.close();
637 env.trust(USD(10'000), alice, bob);
638 env.close();
639 env(pay(gw, alice, USD(10'000)));
640 env(pay(gw, bob, USD(10'000)));
641 env.close();
642
643 auto const seq1 = env.seq(alice);
644 env(escrow::create(alice, bob, USD(1)),
646 escrow::finish_time(env.now() + 1s),
647 fee(baseFee * 150),
648 ter(tesSUCCESS));
649 env.close();
650
651 // set freeze on bob trustline
652 env(trust(gw, USD(10'000), bob, tfSetFreeze | tfSetDeepFreeze));
653
654 // bob cannot finish because of deep freeze
655 env(escrow::finish(bob, alice, seq1),
658 fee(baseFee * 150),
659 ter(tecFROZEN));
660 env.close();
661 }
662 }
663
664 void
666 {
667 testcase("IOU Finish Do Apply");
668 using namespace test::jtx;
669 using namespace std::literals;
670
671 // tecNO_LINE_INSUF_RESERVE: insufficient reserve to create line
672 {
673 Env env{*this, features};
674 auto const baseFee = env.current()->fees().base;
675 auto const acctReserve = env.current()->fees().reserve;
676 auto const incReserve = env.current()->fees().increment;
677 auto const alice = Account("alice");
678 auto const bob = Account("bob");
679 auto const gw = Account{"gateway"};
680 auto const USD = gw["USD"];
681 env.fund(XRP(5000), alice, gw);
682 env.fund(acctReserve + (incReserve - 1), bob);
683 env.close();
685 env.close();
686 env.trust(USD(10'000), alice);
687 env.close();
688 env(pay(gw, alice, USD(10'000)));
689 env.close();
690
691 auto const seq1 = env.seq(alice);
692 env(escrow::create(alice, bob, USD(1)),
694 escrow::finish_time(env.now() + 1s),
695 fee(baseFee * 150),
696 ter(tesSUCCESS));
697 env.close();
698
699 // bob cannot finish because insufficient reserve to create line
700 env(escrow::finish(bob, alice, seq1),
703 fee(baseFee * 150),
705 env.close();
706 }
707
708 // tecNO_LINE: alice submits; finish IOU not created
709 {
710 Env env{*this, features};
711 auto const baseFee = env.current()->fees().base;
712 auto const alice = Account("alice");
713 auto const bob = Account("bob");
714 auto const gw = Account{"gateway"};
715 auto const USD = gw["USD"];
716 env.fund(XRP(5000), alice, bob, gw);
717 env.close();
719 env.close();
720 env.trust(USD(10'000), alice);
721 env.close();
722 env(pay(gw, alice, USD(10'000)));
723 env.close();
724
725 auto const seq1 = env.seq(alice);
726 env(escrow::create(alice, bob, USD(1)),
728 escrow::finish_time(env.now() + 1s),
729 fee(baseFee * 150),
730 ter(tesSUCCESS));
731 env.close();
732
733 // alice cannot finish because bob does not have a trustline
734 env(escrow::finish(alice, alice, seq1),
737 fee(baseFee * 150),
738 ter(tecNO_LINE));
739 env.close();
740 }
741
742 // tecLIMIT_EXCEEDED: alice submits; IOU Limit < balance + amount
743 {
744 Env env{*this, features};
745 auto const baseFee = env.current()->fees().base;
746 auto const alice = Account("alice");
747 auto const bob = Account("bob");
748 auto const gw = Account{"gateway"};
749 auto const USD = gw["USD"];
750 env.fund(XRP(5000), alice, bob, gw);
751 env.close();
753 env.close();
754 env.trust(USD(1000), alice, bob);
755 env.close();
756 env(pay(gw, alice, USD(1000)));
757 env.close();
758
759 auto const seq1 = env.seq(alice);
760 env(escrow::create(alice, bob, USD(5)),
762 escrow::finish_time(env.now() + 1s),
763 fee(baseFee * 150),
764 ter(tesSUCCESS));
765 env.close();
766
767 env.trust(USD(1), bob);
768 env.close();
769
770 // alice cannot finish because bobs limit is too low
771 env(escrow::finish(alice, alice, seq1),
774 fee(baseFee * 150),
776 env.close();
777 }
778
779 // tesSUCCESS: bob submits; IOU Limit < balance + amount
780 {
781 Env env{*this, features};
782 auto const baseFee = env.current()->fees().base;
783 auto const alice = Account("alice");
784 auto const bob = Account("bob");
785 auto const gw = Account{"gateway"};
786 auto const USD = gw["USD"];
787 env.fund(XRP(5000), alice, bob, gw);
788 env.close();
790 env.close();
791 env.trust(USD(1000), alice, bob);
792 env.close();
793 env(pay(gw, alice, USD(1000)));
794 env.close();
795
796 auto const seq1 = env.seq(alice);
797 env(escrow::create(alice, bob, USD(5)),
799 escrow::finish_time(env.now() + 1s),
800 fee(baseFee * 150),
801 ter(tesSUCCESS));
802 env.close();
803
804 env.trust(USD(1), bob);
805 env.close();
806
807 // bob can finish even if bobs limit is too low
808 auto const bobPreLimit = env.limit(bob, USD);
809
810 env(escrow::finish(bob, alice, seq1),
813 fee(baseFee * 150),
814 ter(tesSUCCESS));
815 env.close();
816
817 // bobs limit is not changed
818 BEAST_EXPECT(env.limit(bob, USD) == bobPreLimit);
819 }
820 }
821
822 void
824 {
825 testcase("IOU Cancel Preclaim");
826 using namespace test::jtx;
827 using namespace std::literals;
828
829 // tecNO_AUTH: requireAuth set: account not authorized
830 {
831 Env env{*this, features};
832 auto const baseFee = env.current()->fees().base;
833 auto const alice = Account("alice");
834 auto const bob = Account("bob");
835 auto const gw = Account{"gateway"};
836 auto const USD = gw["USD"];
837 auto const aliceUSD = alice["USD"];
838 auto const bobUSD = bob["USD"];
839 env.fund(XRP(5000), alice, bob, gw);
841 env(fset(gw, asfRequireAuth));
842 env.close();
843 env(trust(gw, aliceUSD(10'000)), txflags(tfSetfAuth));
844 env(trust(gw, bobUSD(10'000)), txflags(tfSetfAuth));
845 env.trust(USD(10'000), alice, bob);
846 env.close();
847 env(pay(gw, alice, USD(10'000)));
848 env(pay(gw, bob, USD(10'000)));
849 env.close();
850
851 auto const seq1 = env.seq(alice);
852 env(escrow::create(alice, bob, USD(1)),
853 escrow::finish_time(env.now() + 1s),
854 escrow::cancel_time(env.now() + 2s),
855 fee(baseFee),
856 ter(tesSUCCESS));
857 env.close();
858
859 env(pay(alice, gw, USD(9'999)));
860 env(trust(gw, aliceUSD(0)), txflags(tfSetfAuth));
861 env(trust(alice, USD(0)));
862 env.close();
863
864 env.trust(USD(10'000), alice);
865 env.close();
866
867 // alice cannot cancel because she is not authorized
868 env(escrow::cancel(bob, alice, seq1),
869 fee(baseFee),
870 ter(tecNO_AUTH));
871 env.close();
872 }
873 }
874
875 void
877 {
878 testcase("IOU Balances");
879
880 using namespace jtx;
881 using namespace std::chrono;
882
883 Env env{*this, features};
884 auto const baseFee = env.current()->fees().base;
885 auto const alice = Account("alice");
886 auto const bob = Account("bob");
887 auto const gw = Account{"gateway"};
888 auto const USD = gw["USD"];
889 env.fund(XRP(5000), alice, bob, gw);
891 env.close();
892 env.trust(USD(10'000), alice, bob);
893 env.close();
894 env(pay(gw, alice, USD(5'000)));
895 env(pay(gw, bob, USD(5'000)));
896 env.close();
897
898 auto const outstandingUSD = USD(10'000);
899
900 // Create & Finish Escrow
901 auto const seq1 = env.seq(alice);
902 {
903 auto const preAliceUSD = env.balance(alice, USD);
904 auto const preBobUSD = env.balance(bob, USD);
905 env(escrow::create(alice, bob, USD(1'000)),
907 escrow::finish_time(env.now() + 1s),
908 fee(baseFee * 150),
909 ter(tesSUCCESS));
910 env.close();
911
912 BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD - USD(1'000));
913 BEAST_EXPECT(env.balance(bob, USD) == preBobUSD);
914 BEAST_EXPECT(
915 issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000));
916 BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(1'000));
917 }
918 {
919 auto const preAliceUSD = env.balance(alice, USD);
920 auto const preBobUSD = env.balance(bob, USD);
921 env(escrow::finish(bob, alice, seq1),
924 fee(baseFee * 150),
925 ter(tesSUCCESS));
926 env.close();
927
928 BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD);
929 BEAST_EXPECT(env.balance(bob, USD) == preBobUSD + USD(1'000));
930 BEAST_EXPECT(issuerBalance(env, gw, USD) == outstandingUSD);
931 BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(0));
932 }
933
934 // Create & Cancel Escrow
935 auto const seq2 = env.seq(alice);
936 {
937 auto const preAliceUSD = env.balance(alice, USD);
938 auto const preBobUSD = env.balance(bob, USD);
939 env(escrow::create(alice, bob, USD(1'000)),
941 escrow::finish_time(env.now() + 1s),
942 escrow::cancel_time(env.now() + 2s),
943 fee(baseFee * 150),
944 ter(tesSUCCESS));
945 env.close();
946
947 BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD - USD(1'000));
948 BEAST_EXPECT(env.balance(bob, USD) == preBobUSD);
949 BEAST_EXPECT(
950 issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000));
951 BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(1'000));
952 }
953 {
954 auto const preAliceUSD = env.balance(alice, USD);
955 auto const preBobUSD = env.balance(bob, USD);
956 env(escrow::cancel(bob, alice, seq2), ter(tesSUCCESS));
957 env.close();
958
959 BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD + USD(1'000));
960 BEAST_EXPECT(env.balance(bob, USD) == preBobUSD);
961 BEAST_EXPECT(issuerBalance(env, gw, USD) == outstandingUSD);
962 BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(0));
963 }
964 }
965
966 void
968 {
969 using namespace jtx;
970 using namespace std::chrono;
971
972 auto const alice = Account("alice");
973 auto const bob = Account("bob");
974 auto const carol = Account("carol");
975 auto const gw = Account{"gateway"};
976 auto const USD = gw["USD"];
977 {
978 testcase("IOU Metadata to self");
979
980 Env env{*this, features};
981 env.fund(XRP(5000), alice, bob, carol, gw);
983 env.close();
984 env.trust(USD(10'000), alice, bob, carol);
985 env.close();
986 env(pay(gw, alice, USD(5000)));
987 env(pay(gw, bob, USD(5000)));
988 env(pay(gw, carol, USD(5000)));
989 env.close();
990 auto const aseq = env.seq(alice);
991 auto const bseq = env.seq(bob);
992
993 env(escrow::create(alice, alice, USD(1'000)),
994 escrow::finish_time(env.now() + 1s),
995 escrow::cancel_time(env.now() + 500s));
996 BEAST_EXPECT(
997 (*env.meta())[sfTransactionResult] ==
998 static_cast<std::uint8_t>(tesSUCCESS));
999 env.close(5s);
1000 auto const aa = env.le(keylet::escrow(alice.id(), aseq));
1001 BEAST_EXPECT(aa);
1002 {
1003 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1004 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
1005 BEAST_EXPECT(
1006 std::find(aod.begin(), aod.end(), aa) != aod.end());
1007 }
1008
1009 {
1010 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1011 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4);
1012 BEAST_EXPECT(
1013 std::find(iod.begin(), iod.end(), aa) != iod.end());
1014 }
1015
1016 env(escrow::create(bob, bob, USD(1'000)),
1017 escrow::finish_time(env.now() + 1s),
1018 escrow::cancel_time(env.now() + 2s));
1019 BEAST_EXPECT(
1020 (*env.meta())[sfTransactionResult] ==
1021 static_cast<std::uint8_t>(tesSUCCESS));
1022 env.close(5s);
1023 auto const bb = env.le(keylet::escrow(bob.id(), bseq));
1024 BEAST_EXPECT(bb);
1025
1026 {
1027 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1028 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1029 BEAST_EXPECT(
1030 std::find(bod.begin(), bod.end(), bb) != bod.end());
1031 }
1032
1033 {
1034 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1035 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 5);
1036 BEAST_EXPECT(
1037 std::find(iod.begin(), iod.end(), bb) != iod.end());
1038 }
1039
1040 env.close(5s);
1041 env(escrow::finish(alice, alice, aseq));
1042 {
1043 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1044 BEAST_EXPECT(
1045 (*env.meta())[sfTransactionResult] ==
1046 static_cast<std::uint8_t>(tesSUCCESS));
1047
1048 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1049 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1050 BEAST_EXPECT(
1051 std::find(aod.begin(), aod.end(), aa) == aod.end());
1052
1053 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1054 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1055 BEAST_EXPECT(
1056 std::find(bod.begin(), bod.end(), bb) != bod.end());
1057
1058 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1059 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4);
1060 BEAST_EXPECT(
1061 std::find(iod.begin(), iod.end(), bb) != iod.end());
1062 }
1063
1064 env.close(5s);
1065 env(escrow::cancel(bob, bob, bseq));
1066 {
1067 BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq)));
1068 BEAST_EXPECT(
1069 (*env.meta())[sfTransactionResult] ==
1070 static_cast<std::uint8_t>(tesSUCCESS));
1071
1072 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1073 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1074 BEAST_EXPECT(
1075 std::find(bod.begin(), bod.end(), bb) == bod.end());
1076
1077 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1078 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3);
1079 BEAST_EXPECT(
1080 std::find(iod.begin(), iod.end(), bb) == iod.end());
1081 }
1082 }
1083 {
1084 testcase("IOU Metadata to other");
1085
1086 Env env{*this, features};
1087 env.fund(XRP(5000), alice, bob, carol, gw);
1089 env.close();
1090 env.trust(USD(10'000), alice, bob, carol);
1091 env.close();
1092 env(pay(gw, alice, USD(5000)));
1093 env(pay(gw, bob, USD(5000)));
1094 env(pay(gw, carol, USD(5000)));
1095 env.close();
1096 auto const aseq = env.seq(alice);
1097 auto const bseq = env.seq(bob);
1098
1099 env(escrow::create(alice, bob, USD(1'000)),
1100 escrow::finish_time(env.now() + 1s));
1101 BEAST_EXPECT(
1102 (*env.meta())[sfTransactionResult] ==
1103 static_cast<std::uint8_t>(tesSUCCESS));
1104 env.close(5s);
1105 env(escrow::create(bob, carol, USD(1'000)),
1106 escrow::finish_time(env.now() + 1s),
1107 escrow::cancel_time(env.now() + 2s));
1108 BEAST_EXPECT(
1109 (*env.meta())[sfTransactionResult] ==
1110 static_cast<std::uint8_t>(tesSUCCESS));
1111 env.close(5s);
1112
1113 auto const ab = env.le(keylet::escrow(alice.id(), aseq));
1114 BEAST_EXPECT(ab);
1115
1116 auto const bc = env.le(keylet::escrow(bob.id(), bseq));
1117 BEAST_EXPECT(bc);
1118
1119 {
1120 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1121 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
1122 BEAST_EXPECT(
1123 std::find(aod.begin(), aod.end(), ab) != aod.end());
1124
1125 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1126 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 3);
1127 BEAST_EXPECT(
1128 std::find(bod.begin(), bod.end(), ab) != bod.end());
1129 BEAST_EXPECT(
1130 std::find(bod.begin(), bod.end(), bc) != bod.end());
1131
1132 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1133 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2);
1134 BEAST_EXPECT(
1135 std::find(cod.begin(), cod.end(), bc) != cod.end());
1136
1137 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1138 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 5);
1139 BEAST_EXPECT(
1140 std::find(iod.begin(), iod.end(), ab) != iod.end());
1141 BEAST_EXPECT(
1142 std::find(iod.begin(), iod.end(), bc) != iod.end());
1143 }
1144
1145 env.close(5s);
1146 env(escrow::finish(alice, alice, aseq));
1147 {
1148 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1149 BEAST_EXPECT(env.le(keylet::escrow(bob.id(), bseq)));
1150
1151 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1152 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1153 BEAST_EXPECT(
1154 std::find(aod.begin(), aod.end(), ab) == aod.end());
1155
1156 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1157 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1158 BEAST_EXPECT(
1159 std::find(bod.begin(), bod.end(), ab) == bod.end());
1160 BEAST_EXPECT(
1161 std::find(bod.begin(), bod.end(), bc) != bod.end());
1162
1163 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1164 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2);
1165
1166 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1167 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4);
1168 BEAST_EXPECT(
1169 std::find(iod.begin(), iod.end(), ab) == iod.end());
1170 BEAST_EXPECT(
1171 std::find(iod.begin(), iod.end(), bc) != iod.end());
1172 }
1173
1174 env.close(5s);
1175 env(escrow::cancel(bob, bob, bseq));
1176 {
1177 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1178 BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq)));
1179
1180 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1181 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1182 BEAST_EXPECT(
1183 std::find(aod.begin(), aod.end(), ab) == aod.end());
1184
1185 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1186 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1187 BEAST_EXPECT(
1188 std::find(bod.begin(), bod.end(), ab) == bod.end());
1189 BEAST_EXPECT(
1190 std::find(bod.begin(), bod.end(), bc) == bod.end());
1191
1192 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1193 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1194
1195 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1196 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3);
1197 BEAST_EXPECT(
1198 std::find(iod.begin(), iod.end(), ab) == iod.end());
1199 BEAST_EXPECT(
1200 std::find(iod.begin(), iod.end(), bc) == iod.end());
1201 }
1202 }
1203
1204 {
1205 testcase("IOU Metadata to issuer");
1206
1207 Env env{*this, features};
1208 env.fund(XRP(5000), alice, carol, gw);
1210 env.close();
1211 env.trust(USD(10'000), alice, carol);
1212 env.close();
1213 env(pay(gw, alice, USD(5000)));
1214 env(pay(gw, carol, USD(5000)));
1215 env.close();
1216 auto const aseq = env.seq(alice);
1217
1218 env(escrow::create(alice, gw, USD(1'000)),
1219 escrow::finish_time(env.now() + 1s));
1220
1221 BEAST_EXPECT(
1222 (*env.meta())[sfTransactionResult] ==
1223 static_cast<std::uint8_t>(tesSUCCESS));
1224 env.close(5s);
1225 env(escrow::create(gw, carol, USD(1'000)),
1226 escrow::finish_time(env.now() + 1s),
1227 escrow::cancel_time(env.now() + 2s),
1229 env.close(5s);
1230
1231 auto const ag = env.le(keylet::escrow(alice.id(), aseq));
1232 BEAST_EXPECT(ag);
1233
1234 {
1235 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1236 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
1237 BEAST_EXPECT(
1238 std::find(aod.begin(), aod.end(), ag) != aod.end());
1239
1240 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1241 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1242
1243 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1244 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3);
1245 BEAST_EXPECT(
1246 std::find(iod.begin(), iod.end(), ag) != iod.end());
1247 }
1248
1249 env.close(5s);
1250 env(escrow::finish(alice, alice, aseq));
1251 {
1252 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1253
1254 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1255 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1256 BEAST_EXPECT(
1257 std::find(aod.begin(), aod.end(), ag) == aod.end());
1258
1259 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1260 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1261
1262 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1263 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 2);
1264 BEAST_EXPECT(
1265 std::find(iod.begin(), iod.end(), ag) == iod.end());
1266 }
1267 }
1268 }
1269
1270 void
1272 {
1273 testcase("IOU RippleState");
1274 using namespace test::jtx;
1275 using namespace std::literals;
1276
1277 struct TestAccountData
1278 {
1279 Account src;
1280 Account dst;
1281 Account gw;
1282 bool hasTrustline;
1283 bool negative;
1284 };
1285
1287 // src > dst && src > issuer && dst no trustline
1288 {Account("alice2"), Account("bob0"), Account{"gw0"}, false, true},
1289 // src < dst && src < issuer && dst no trustline
1290 {Account("carol0"), Account("dan1"), Account{"gw1"}, false, false},
1291 // dst > src && dst > issuer && dst no trustline
1292 {Account("dan1"), Account("alice2"), Account{"gw0"}, false, true},
1293 // dst < src && dst < issuer && dst no trustline
1294 {Account("bob0"), Account("carol0"), Account{"gw1"}, false, false},
1295 // src > dst && src > issuer && dst has trustline
1296 {Account("alice2"), Account("bob0"), Account{"gw0"}, true, true},
1297 // src < dst && src < issuer && dst has trustline
1298 {Account("carol0"), Account("dan1"), Account{"gw1"}, true, false},
1299 // dst > src && dst > issuer && dst has trustline
1300 {Account("dan1"), Account("alice2"), Account{"gw0"}, true, true},
1301 // dst < src && dst < issuer && dst has trustline
1302 {Account("bob0"), Account("carol0"), Account{"gw1"}, true, false},
1303 }};
1304
1305 for (auto const& t : tests)
1306 {
1307 Env env{*this, features};
1308 auto const baseFee = env.current()->fees().base;
1309 auto const USD = t.gw["USD"];
1310 env.fund(XRP(5000), t.src, t.dst, t.gw);
1311 env(fset(t.gw, asfAllowTrustLineLocking));
1312 env.close();
1313
1314 if (t.hasTrustline)
1315 env.trust(USD(100'000), t.src, t.dst);
1316 else
1317 env.trust(USD(100'000), t.src);
1318 env.close();
1319
1320 env(pay(t.gw, t.src, USD(10'000)));
1321 if (t.hasTrustline)
1322 env(pay(t.gw, t.dst, USD(10'000)));
1323 env.close();
1324
1325 // src can create escrow
1326 auto const seq1 = env.seq(t.src);
1327 auto const delta = USD(1'000);
1328 env(escrow::create(t.src, t.dst, delta),
1330 escrow::finish_time(env.now() + 1s),
1331 fee(baseFee * 150));
1332 env.close();
1333
1334 // dst can finish escrow
1335 auto const preSrc = env.balance(t.src, USD);
1336 auto const preDst = env.balance(t.dst, USD);
1337
1338 env(escrow::finish(t.dst, t.src, seq1),
1341 fee(baseFee * 150));
1342 env.close();
1343
1344 BEAST_EXPECT(env.balance(t.src, USD) == preSrc);
1345 BEAST_EXPECT(env.balance(t.dst, USD) == preDst + delta);
1346 }
1347 }
1348
1349 void
1351 {
1352 testcase("IOU Gateway");
1353 using namespace test::jtx;
1354 using namespace std::literals;
1355
1356 struct TestAccountData
1357 {
1358 Account src;
1359 Account dst;
1360 bool hasTrustline;
1361 };
1362
1363 // issuer is source
1364 {
1365 auto const gw = Account{"gateway"};
1366 auto const alice = Account{"alice"};
1367 Env env{*this, features};
1368 auto const baseFee = env.current()->fees().base;
1369 auto const USD = gw["USD"];
1370 env.fund(XRP(5000), alice, gw);
1372 env.close();
1373 env.trust(USD(100'000), alice);
1374 env.close();
1375
1376 env(pay(gw, alice, USD(10'000)));
1377 env.close();
1378
1379 // issuer cannot create escrow
1380 env(escrow::create(gw, alice, USD(1'000)),
1382 escrow::finish_time(env.now() + 1s),
1383 fee(baseFee * 150),
1385 env.close();
1386 }
1387
1388 std::array<TestAccountData, 4> gwDstTests = {{
1389 // src > dst && src > issuer && dst has trustline
1390 {Account("alice2"), Account{"gw0"}, true},
1391 // src < dst && src < issuer && dst has trustline
1392 {Account("carol0"), Account{"gw1"}, true},
1393 // dst > src && dst > issuer && dst has trustline
1394 {Account("dan1"), Account{"gw0"}, true},
1395 // dst < src && dst < issuer && dst has trustline
1396 {Account("bob0"), Account{"gw1"}, true},
1397 }};
1398
1399 // issuer is destination
1400 for (auto const& t : gwDstTests)
1401 {
1402 Env env{*this, features};
1403 auto const baseFee = env.current()->fees().base;
1404 auto const USD = t.dst["USD"];
1405 env.fund(XRP(5000), t.dst, t.src);
1406 env(fset(t.dst, asfAllowTrustLineLocking));
1407 env.close();
1408
1409 env.trust(USD(100'000), t.src);
1410 env.close();
1411
1412 env(pay(t.dst, t.src, USD(10'000)));
1413 env.close();
1414
1415 // issuer can receive escrow
1416 auto const seq1 = env.seq(t.src);
1417 auto const preSrc = env.balance(t.src, USD);
1418 env(escrow::create(t.src, t.dst, USD(1'000)),
1420 escrow::finish_time(env.now() + 1s),
1421 fee(baseFee * 150));
1422 env.close();
1423
1424 // issuer can finish escrow, no dest trustline
1425 env(escrow::finish(t.dst, t.src, seq1),
1428 fee(baseFee * 150));
1429 env.close();
1430 auto const preAmount = 10'000;
1431 BEAST_EXPECT(preSrc == USD(preAmount));
1432 auto const postAmount = 9000;
1433 BEAST_EXPECT(env.balance(t.src, USD) == USD(postAmount));
1434 BEAST_EXPECT(env.balance(t.dst, USD) == USD(0));
1435 }
1436
1437 // issuer is source and destination
1438 {
1439 auto const gw = Account{"gateway"};
1440 auto const USD = gw["USD"];
1441 Env env{*this, features};
1442 auto const baseFee = env.current()->fees().base;
1443 env.fund(XRP(5000), gw);
1445 env.close();
1446
1447 // issuer cannot receive escrow
1448 env(escrow::create(gw, gw, USD(1'000)),
1450 escrow::finish_time(env.now() + 1s),
1451 fee(baseFee * 150),
1453 env.close();
1454 }
1455 }
1456
1457 void
1459 {
1460 testcase("IOU Locked Rate");
1461 using namespace test::jtx;
1462 using namespace std::literals;
1463
1464 auto const alice = Account("alice");
1465 auto const bob = Account("bob");
1466 auto const carol = Account("carol");
1467 auto const gw = Account{"gateway"};
1468 auto const USD = gw["USD"];
1469
1470 // test locked rate
1471 {
1472 Env env{*this, features};
1473 auto const baseFee = env.current()->fees().base;
1474 env.fund(XRP(10'000), alice, bob, gw);
1476 env(rate(gw, 1.25));
1477 env.close();
1478 env.trust(USD(100'000), alice);
1479 env.trust(USD(100'000), bob);
1480 env.close();
1481 env(pay(gw, alice, USD(10'000)));
1482 env(pay(gw, bob, USD(10'000)));
1483 env.close();
1484
1485 // alice can create escrow w/ xfer rate
1486 auto const preAlice = env.balance(alice, USD);
1487 auto const seq1 = env.seq(alice);
1488 auto const delta = USD(125);
1489 env(escrow::create(alice, bob, delta),
1491 escrow::finish_time(env.now() + 1s),
1492 fee(baseFee * 150));
1493 env.close();
1494 auto const transferRate = escrow::rate(env, alice, seq1);
1495 BEAST_EXPECT(
1496 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
1497
1498 // bob can finish escrow
1499 env(escrow::finish(bob, alice, seq1),
1502 fee(baseFee * 150));
1503 env.close();
1504
1505 BEAST_EXPECT(env.balance(alice, USD) == preAlice - delta);
1506 BEAST_EXPECT(env.balance(bob, USD) == USD(10'100));
1507 }
1508 // test rate change - higher
1509 {
1510 Env env{*this, features};
1511 auto const baseFee = env.current()->fees().base;
1512 env.fund(XRP(10'000), alice, bob, gw);
1514 env(rate(gw, 1.25));
1515 env.close();
1516 env.trust(USD(100'000), alice);
1517 env.trust(USD(100'000), bob);
1518 env.close();
1519 env(pay(gw, alice, USD(10'000)));
1520 env(pay(gw, bob, USD(10'000)));
1521 env.close();
1522
1523 // alice can create escrow w/ xfer rate
1524 auto const preAlice = env.balance(alice, USD);
1525 auto const seq1 = env.seq(alice);
1526 auto const delta = USD(125);
1527 env(escrow::create(alice, bob, delta),
1529 escrow::finish_time(env.now() + 1s),
1530 fee(baseFee * 150));
1531 env.close();
1532 auto transferRate = escrow::rate(env, alice, seq1);
1533 BEAST_EXPECT(
1534 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
1535
1536 // issuer changes rate higher
1537 env(rate(gw, 1.26));
1538 env.close();
1539
1540 // bob can finish escrow - rate unchanged
1541 env(escrow::finish(bob, alice, seq1),
1544 fee(baseFee * 150));
1545 env.close();
1546
1547 BEAST_EXPECT(env.balance(alice, USD) == preAlice - delta);
1548 BEAST_EXPECT(env.balance(bob, USD) == USD(10'100));
1549 }
1550
1551 // test rate change - lower
1552 {
1553 Env env{*this, features};
1554 auto const baseFee = env.current()->fees().base;
1555 env.fund(XRP(10'000), alice, bob, gw);
1557 env(rate(gw, 1.25));
1558 env.close();
1559 env.trust(USD(100'000), alice);
1560 env.trust(USD(100'000), bob);
1561 env.close();
1562 env(pay(gw, alice, USD(10'000)));
1563 env(pay(gw, bob, USD(10'000)));
1564 env.close();
1565
1566 // alice can create escrow w/ xfer rate
1567 auto const preAlice = env.balance(alice, USD);
1568 auto const seq1 = env.seq(alice);
1569 auto const delta = USD(125);
1570 env(escrow::create(alice, bob, delta),
1572 escrow::finish_time(env.now() + 1s),
1573 fee(baseFee * 150));
1574 env.close();
1575 auto transferRate = escrow::rate(env, alice, seq1);
1576 BEAST_EXPECT(
1577 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
1578
1579 // issuer changes rate lower
1580 env(rate(gw, 1.00));
1581 env.close();
1582
1583 // bob can finish escrow - rate changed
1584 env(escrow::finish(bob, alice, seq1),
1587 fee(baseFee * 150));
1588 env.close();
1589
1590 BEAST_EXPECT(env.balance(alice, USD) == preAlice - delta);
1591 BEAST_EXPECT(env.balance(bob, USD) == USD(10125));
1592 }
1593
1594 // test cancel doesnt charge rate
1595 {
1596 Env env{*this, features};
1597 auto const baseFee = env.current()->fees().base;
1598 env.fund(XRP(10'000), alice, bob, gw);
1600 env(rate(gw, 1.25));
1601 env.close();
1602 env.trust(USD(100'000), alice);
1603 env.trust(USD(100'000), bob);
1604 env.close();
1605 env(pay(gw, alice, USD(10'000)));
1606 env(pay(gw, bob, USD(10'000)));
1607 env.close();
1608
1609 // alice can create escrow w/ xfer rate
1610 auto const preAlice = env.balance(alice, USD);
1611 auto const seq1 = env.seq(alice);
1612 auto const delta = USD(125);
1613 env(escrow::create(alice, bob, delta),
1614 escrow::finish_time(env.now() + 1s),
1615 escrow::cancel_time(env.now() + 3s),
1616 fee(baseFee));
1617 env.close();
1618 auto transferRate = escrow::rate(env, alice, seq1);
1619 BEAST_EXPECT(
1620 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
1621
1622 // issuer changes rate lower
1623 env(rate(gw, 1.00));
1624 env.close();
1625
1626 // alice can cancel escrow - rate is not charged
1627 env(escrow::cancel(alice, alice, seq1), fee(baseFee));
1628 env.close();
1629
1630 BEAST_EXPECT(env.balance(alice, USD) == preAlice);
1631 BEAST_EXPECT(env.balance(bob, USD) == USD(10000));
1632 }
1633 }
1634
1635 void
1637 {
1638 testcase("IOU Limit");
1639 using namespace test::jtx;
1640 using namespace std::literals;
1641
1642 auto const alice = Account("alice");
1643 auto const bob = Account("bob");
1644 auto const gw = Account{"gateway"};
1645 auto const USD = gw["USD"];
1646
1647 // test LimitAmount
1648 {
1649 Env env{*this, features};
1650 auto const baseFee = env.current()->fees().base;
1651 env.fund(XRP(1'000), alice, bob, gw);
1653 env.close();
1654 env.trust(USD(10'000), alice, bob);
1655 env.close();
1656 env(pay(gw, alice, USD(1'000)));
1657 env(pay(gw, bob, USD(1'000)));
1658 env.close();
1659
1660 // alice can create escrow
1661 auto seq1 = env.seq(alice);
1662 auto const delta = USD(125);
1663 env(escrow::create(alice, bob, delta),
1665 escrow::finish_time(env.now() + 1s),
1666 fee(baseFee * 150));
1667 env.close();
1668
1669 // bob can finish
1670 auto const preBobLimit = env.limit(bob, USD);
1671 env(escrow::finish(bob, alice, seq1),
1674 fee(baseFee * 150));
1675 env.close();
1676 auto const postBobLimit = env.limit(bob, USD);
1677 // bobs limit is NOT changed
1678 BEAST_EXPECT(postBobLimit == preBobLimit);
1679 }
1680 }
1681
1682 void
1684 {
1685 testcase("IOU Require Auth");
1686 using namespace test::jtx;
1687 using namespace std::literals;
1688
1689 auto const alice = Account("alice");
1690 auto const bob = Account("bob");
1691 auto const carol = Account("carol");
1692 auto const gw = Account{"gateway"};
1693 auto const USD = gw["USD"];
1694
1695 auto const aliceUSD = alice["USD"];
1696 auto const bobUSD = bob["USD"];
1697
1698 Env env{*this, features};
1699 auto const baseFee = env.current()->fees().base;
1700 env.fund(XRP(1'000), alice, bob, gw);
1702 env(fset(gw, asfRequireAuth));
1703 env.close();
1704 env(trust(gw, aliceUSD(10'000)), txflags(tfSetfAuth));
1705 env(trust(alice, USD(10'000)));
1706 env(trust(bob, USD(10'000)));
1707 env.close();
1708 env(pay(gw, alice, USD(1'000)));
1709 env.close();
1710
1711 // alice cannot create escrow - fails without auth
1712 auto seq1 = env.seq(alice);
1713 auto const delta = USD(125);
1714 env(escrow::create(alice, bob, delta),
1716 escrow::finish_time(env.now() + 1s),
1717 fee(baseFee * 150),
1718 ter(tecNO_AUTH));
1719 env.close();
1720
1721 // set auth on bob
1722 env(trust(gw, bobUSD(10'000)), txflags(tfSetfAuth));
1723 env(trust(bob, USD(10'000)));
1724 env.close();
1725 env(pay(gw, bob, USD(1'000)));
1726 env.close();
1727
1728 // alice can create escrow - bob has auth
1729 seq1 = env.seq(alice);
1730 env(escrow::create(alice, bob, delta),
1732 escrow::finish_time(env.now() + 1s),
1733 fee(baseFee * 150));
1734 env.close();
1735
1736 // bob can finish
1737 env(escrow::finish(bob, alice, seq1),
1740 fee(baseFee * 150));
1741 env.close();
1742 }
1743
1744 void
1746 {
1747 testcase("IOU Freeze");
1748 using namespace test::jtx;
1749 using namespace std::literals;
1750
1751 auto const alice = Account("alice");
1752 auto const bob = Account("bob");
1753 auto const carol = Account("carol");
1754 auto const gw = Account{"gateway"};
1755 auto const USD = gw["USD"];
1756
1757 // test Global Freeze
1758 {
1759 Env env{*this, features};
1760 auto const baseFee = env.current()->fees().base;
1761 env.fund(XRP(10'000), alice, bob, gw);
1763 env.close();
1764 env.trust(USD(100'000), alice);
1765 env.trust(USD(100'000), bob);
1766 env.close();
1767 env(pay(gw, alice, USD(10'000)));
1768 env(pay(gw, bob, USD(10'000)));
1769 env.close();
1770 env(fset(gw, asfGlobalFreeze));
1771 env.close();
1772
1773 // setup transaction
1774 auto seq1 = env.seq(alice);
1775 auto const delta = USD(125);
1776
1777 // create escrow fails - frozen trustline
1778 env(escrow::create(alice, bob, delta),
1780 escrow::finish_time(env.now() + 1s),
1781 fee(baseFee * 150),
1782 ter(tecFROZEN));
1783 env.close();
1784
1785 // clear global freeze
1786 env(fclear(gw, asfGlobalFreeze));
1787 env.close();
1788
1789 // create escrow success
1790 seq1 = env.seq(alice);
1791 env(escrow::create(alice, bob, delta),
1793 escrow::finish_time(env.now() + 1s),
1794 fee(baseFee * 150));
1795 env.close();
1796
1797 // set global freeze
1798 env(fset(gw, asfGlobalFreeze));
1799 env.close();
1800
1801 // bob finish escrow success regardless of frozen assets
1802 env(escrow::finish(bob, alice, seq1),
1805 fee(baseFee * 150));
1806 env.close();
1807
1808 // clear global freeze
1809 env(fclear(gw, asfGlobalFreeze));
1810 env.close();
1811
1812 // create escrow success
1813 seq1 = env.seq(alice);
1814 env(escrow::create(alice, bob, delta),
1816 escrow::cancel_time(env.now() + 1s),
1817 fee(baseFee * 150));
1818 env.close();
1819
1820 // set global freeze
1821 env(fset(gw, asfGlobalFreeze));
1822 env.close();
1823
1824 // bob cancel escrow success regardless of frozen assets
1825 env(escrow::cancel(bob, alice, seq1), fee(baseFee));
1826 env.close();
1827 }
1828
1829 // test Individual Freeze
1830 {
1831 // Env Setup
1832 Env env{*this, features};
1833 auto const baseFee = env.current()->fees().base;
1834 env.fund(XRP(10'000), alice, bob, gw);
1836 env.close();
1837 env(trust(alice, USD(100'000)));
1838 env(trust(bob, USD(100'000)));
1839 env.close();
1840 env(pay(gw, alice, USD(10'000)));
1841 env(pay(gw, bob, USD(10'000)));
1842 env.close();
1843
1844 // set freeze on alice trustline
1845 env(trust(gw, USD(10'000), alice, tfSetFreeze));
1846 env.close();
1847
1848 // setup transaction
1849 auto seq1 = env.seq(alice);
1850 auto const delta = USD(125);
1851
1852 // create escrow fails - frozen trustline
1853 env(escrow::create(alice, bob, delta),
1855 escrow::finish_time(env.now() + 1s),
1856 fee(baseFee * 150),
1857 ter(tecFROZEN));
1858 env.close();
1859
1860 // clear freeze on alice trustline
1861 env(trust(gw, USD(10'000), alice, tfClearFreeze));
1862 env.close();
1863
1864 // create escrow success
1865 seq1 = env.seq(alice);
1866 env(escrow::create(alice, bob, delta),
1868 escrow::finish_time(env.now() + 1s),
1869 fee(baseFee * 150));
1870 env.close();
1871
1872 // set freeze on bob trustline
1873 env(trust(gw, USD(10'000), bob, tfSetFreeze));
1874 env.close();
1875
1876 // bob finish escrow success regardless of frozen assets
1877 env(escrow::finish(bob, alice, seq1),
1880 fee(baseFee * 150));
1881 env.close();
1882
1883 // reset freeze on bob and alice trustline
1884 env(trust(gw, USD(10'000), alice, tfClearFreeze));
1885 env(trust(gw, USD(10'000), bob, tfClearFreeze));
1886 env.close();
1887
1888 // create escrow success
1889 seq1 = env.seq(alice);
1890 env(escrow::create(alice, bob, delta),
1892 escrow::cancel_time(env.now() + 1s),
1893 fee(baseFee * 150));
1894 env.close();
1895
1896 // set freeze on bob trustline
1897 env(trust(gw, USD(10'000), bob, tfSetFreeze));
1898 env.close();
1899
1900 // bob cancel escrow success regardless of frozen assets
1901 env(escrow::cancel(bob, alice, seq1), fee(baseFee));
1902 env.close();
1903 }
1904
1905 // test Deep Freeze
1906 {
1907 // Env Setup
1908 Env env{*this, features};
1909 auto const baseFee = env.current()->fees().base;
1910 env.fund(XRP(10'000), alice, bob, gw);
1912 env.close();
1913 env(trust(alice, USD(100'000)));
1914 env(trust(bob, USD(100'000)));
1915 env.close();
1916 env(pay(gw, alice, USD(10'000)));
1917 env(pay(gw, bob, USD(10'000)));
1918 env.close();
1919
1920 // set freeze on alice trustline
1921 env(trust(gw, USD(10'000), alice, tfSetFreeze | tfSetDeepFreeze));
1922 env.close();
1923
1924 // setup transaction
1925 auto seq1 = env.seq(alice);
1926 auto const delta = USD(125);
1927
1928 // create escrow fails - frozen trustline
1929 env(escrow::create(alice, bob, delta),
1931 escrow::finish_time(env.now() + 1s),
1932 fee(baseFee * 150),
1933 ter(tecFROZEN));
1934 env.close();
1935
1936 // clear freeze on alice trustline
1937 env(trust(
1938 gw, USD(10'000), alice, tfClearFreeze | tfClearDeepFreeze));
1939 env.close();
1940
1941 // create escrow success
1942 seq1 = env.seq(alice);
1943 env(escrow::create(alice, bob, delta),
1945 escrow::finish_time(env.now() + 1s),
1946 fee(baseFee * 150));
1947 env.close();
1948
1949 // set freeze on bob trustline
1950 env(trust(gw, USD(10'000), bob, tfSetFreeze | tfSetDeepFreeze));
1951 env.close();
1952
1953 // bob finish escrow fails because of deep frozen assets
1954 env(escrow::finish(bob, alice, seq1),
1957 fee(baseFee * 150),
1958 ter(tecFROZEN));
1959 env.close();
1960
1961 // reset freeze on alice and bob trustline
1962 env(trust(
1963 gw, USD(10'000), alice, tfClearFreeze | tfClearDeepFreeze));
1964 env(trust(gw, USD(10'000), bob, tfClearFreeze | tfClearDeepFreeze));
1965 env.close();
1966
1967 // create escrow success
1968 seq1 = env.seq(alice);
1969 env(escrow::create(alice, bob, delta),
1971 escrow::cancel_time(env.now() + 1s),
1972 fee(baseFee * 150));
1973 env.close();
1974
1975 // set freeze on bob trustline
1976 env(trust(gw, USD(10'000), bob, tfSetFreeze | tfSetDeepFreeze));
1977 env.close();
1978
1979 // bob cancel escrow fails because of deep frozen assets
1980 env(escrow::cancel(bob, alice, seq1),
1981 fee(baseFee),
1982 ter(tesSUCCESS));
1983 env.close();
1984 }
1985 }
1986 void
1988 {
1989 testcase("IOU Insuficient Funds");
1990 using namespace test::jtx;
1991 using namespace std::literals;
1992
1993 auto const alice = Account("alice");
1994 auto const bob = Account("bob");
1995 auto const carol = Account("carol");
1996 auto const gw = Account{"gateway"};
1997 auto const USD = gw["USD"];
1998 {
1999 // test tecPATH_PARTIAL
2000 // ie. has 10'000, escrow 1'000 then try to pay 10'000
2001 Env env{*this, features};
2002 auto const baseFee = env.current()->fees().base;
2003 env.fund(XRP(10'000), alice, bob, gw);
2005 env.close();
2006 env.trust(USD(100'000), alice);
2007 env.trust(USD(100'000), bob);
2008 env.close();
2009 env(pay(gw, alice, USD(10'000)));
2010 env(pay(gw, bob, USD(10'000)));
2011 env.close();
2012
2013 // create escrow success
2014 auto const delta = USD(1'000);
2015 env(escrow::create(alice, bob, delta),
2017 escrow::finish_time(env.now() + 1s),
2018 fee(baseFee * 150));
2019 env.close();
2020 env(pay(alice, gw, USD(10'000)), ter(tecPATH_PARTIAL));
2021 }
2022 {
2023 // test tecINSUFFICIENT_FUNDS
2024 // ie. has 10'000 escrow 1'000 then try to escrow 10'000
2025 Env env{*this, features};
2026 auto const baseFee = env.current()->fees().base;
2027 env.fund(XRP(10'000), alice, bob, gw);
2029 env.close();
2030 env.trust(USD(100'000), alice);
2031 env.trust(USD(100'000), bob);
2032 env.close();
2033 env(pay(gw, alice, USD(10'000)));
2034 env(pay(gw, bob, USD(10'000)));
2035 env.close();
2036
2037 auto const delta = USD(1'000);
2038 env(escrow::create(alice, bob, delta),
2040 escrow::finish_time(env.now() + 1s),
2041 fee(baseFee * 150));
2042 env.close();
2043
2044 env(escrow::create(alice, bob, USD(10'000)),
2046 escrow::finish_time(env.now() + 1s),
2047 fee(baseFee * 150),
2049 env.close();
2050 }
2051 }
2052
2053 void
2055 {
2056 testcase("IOU Precision Loss");
2057 using namespace test::jtx;
2058 using namespace std::literals;
2059
2060 auto const alice = Account("alice");
2061 auto const bob = Account("bob");
2062 auto const gw = Account{"gateway"};
2063 auto const USD = gw["USD"];
2064
2065 // test min create precision loss
2066 {
2067 Env env(*this, features);
2068 auto const baseFee = env.current()->fees().base;
2069 env.fund(XRP(10'000), alice, bob, gw);
2071 env.close();
2072 env.trust(USD(100000000000000000), alice);
2073 env.trust(USD(100000000000000000), bob);
2074 env.close();
2075 env(pay(gw, alice, USD(10000000000000000)));
2076 env(pay(gw, bob, USD(1)));
2077 env.close();
2078
2079 // alice cannot create escrow for 1/10 iou - precision loss
2080 env(escrow::create(alice, bob, USD(1)),
2082 escrow::finish_time(env.now() + 1s),
2083 fee(baseFee * 150),
2085 env.close();
2086
2087 auto const seq1 = env.seq(alice);
2088 // alice can create escrow for 1'000 iou
2089 env(escrow::create(alice, bob, USD(1'000)),
2091 escrow::finish_time(env.now() + 1s),
2092 fee(baseFee * 150));
2093 env.close();
2094
2095 // bob finish escrow success
2096 env(escrow::finish(bob, alice, seq1),
2099 fee(baseFee * 150));
2100 env.close();
2101 }
2102 }
2103
2104 void
2106 {
2107 testcase("MPT Enablement");
2108
2109 using namespace jtx;
2110 using namespace std::chrono;
2111
2112 for (bool const withTokenEscrow : {false, true})
2113 {
2114 auto const amend =
2115 withTokenEscrow ? features : features - featureTokenEscrow;
2116 Env env{*this, amend};
2117 auto const baseFee = env.current()->fees().base;
2118 auto const alice = Account("alice");
2119 auto const bob = Account("bob");
2120 auto const gw = Account("gw");
2121 env.fund(XRP(5000), bob);
2122
2123 MPTTester mptGw(env, gw, {.holders = {alice}});
2124 mptGw.create(
2125 {.ownerCount = 1,
2126 .holderCount = 0,
2127 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2128 mptGw.authorize({.account = alice});
2129 auto const MPT = mptGw["MPT"];
2130 env(pay(gw, alice, MPT(10'000)));
2131 env.close();
2132
2133 auto const createResult =
2134 withTokenEscrow ? ter(tesSUCCESS) : ter(temBAD_AMOUNT);
2135 auto const finishResult =
2136 withTokenEscrow ? ter(tesSUCCESS) : ter(tecNO_TARGET);
2137
2138 auto const seq1 = env.seq(alice);
2139 env(escrow::create(alice, bob, MPT(1'000)),
2141 escrow::finish_time(env.now() + 1s),
2142 fee(baseFee * 150),
2143 createResult);
2144 env.close();
2145 env(escrow::finish(bob, alice, seq1),
2148 fee(baseFee * 150),
2149 finishResult);
2150 env.close();
2151 auto const seq2 = env.seq(alice);
2152 env(escrow::create(alice, bob, MPT(1'000)),
2154 escrow::finish_time(env.now() + 1s),
2155 escrow::cancel_time(env.now() + 2s),
2156 fee(baseFee * 150),
2157 createResult);
2158 env.close();
2159 env(escrow::cancel(bob, alice, seq2), finishResult);
2160 env.close();
2161 }
2162 }
2163
2164 void
2166 {
2167 testcase("MPT Create Preflight");
2168 using namespace test::jtx;
2169 using namespace std::literals;
2170
2171 for (bool const withMPT : {true, false})
2172 {
2173 auto const amend =
2174 withMPT ? features : features - featureMPTokensV1;
2175 Env env{*this, amend};
2176 auto const baseFee = env.current()->fees().base;
2177 auto const alice = Account("alice");
2178 auto const bob = Account("bob");
2179 auto const gw = Account("gw");
2180 env.fund(XRP(1'000), alice, bob, gw);
2181
2182 Json::Value jv = escrow::create(alice, bob, XRP(1));
2183 jv.removeMember(jss::Amount);
2184 jv[jss::Amount][jss::mpt_issuance_id] =
2185 "00000004A407AF5856CCF3C42619DAA925813FC955C72983";
2186 jv[jss::Amount][jss::value] = "-1";
2187
2188 auto const result = withMPT ? ter(temBAD_AMOUNT) : ter(temDISABLED);
2189 env(jv,
2191 escrow::finish_time(env.now() + 1s),
2192 fee(baseFee * 150),
2193 result);
2194 env.close();
2195 }
2196
2197 // temBAD_AMOUNT: amount < 0
2198 {
2199 Env env{*this, features};
2200 auto const baseFee = env.current()->fees().base;
2201 auto const alice = Account("alice");
2202 auto const bob = Account("bob");
2203 auto const gw = Account("gw");
2204
2205 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2206 mptGw.create(
2207 {.ownerCount = 1,
2208 .holderCount = 0,
2209 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2210 mptGw.authorize({.account = alice});
2211 mptGw.authorize({.account = bob});
2212 auto const MPT = mptGw["MPT"];
2213 env(pay(gw, alice, MPT(10'000)));
2214 env(pay(gw, bob, MPT(10'000)));
2215 env.close();
2216
2217 env(escrow::create(alice, bob, MPT(-1)),
2219 escrow::finish_time(env.now() + 1s),
2220 fee(baseFee * 150),
2222 env.close();
2223 }
2224 }
2225
2226 void
2228 {
2229 testcase("MPT Create Preclaim");
2230 using namespace test::jtx;
2231 using namespace std::literals;
2232
2233 // tecNO_PERMISSION: issuer is the same as the account
2234 {
2235 Env env{*this, features};
2236 auto const baseFee = env.current()->fees().base;
2237 auto const alice = Account("alice");
2238 auto const gw = Account("gw");
2239
2240 MPTTester mptGw(env, gw, {.holders = {alice}});
2241 mptGw.create(
2242 {.ownerCount = 1,
2243 .holderCount = 0,
2244 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2245 mptGw.authorize({.account = alice});
2246 auto const MPT = mptGw["MPT"];
2247 env(pay(gw, alice, MPT(10'000)));
2248 env.close();
2249
2250 env(escrow::create(gw, alice, MPT(1)),
2252 escrow::finish_time(env.now() + 1s),
2253 fee(baseFee * 150),
2255 env.close();
2256 }
2257
2258 // tecOBJECT_NOT_FOUND: mpt does not exist
2259 {
2260 Env env{*this, features};
2261 auto const baseFee = env.current()->fees().base;
2262 auto const alice = Account("alice");
2263 auto const bob = Account("bob");
2264 auto const gw = Account("gw");
2265 env.fund(XRP(10'000), alice, bob, gw);
2266 env.close();
2267
2268 auto const mpt = ripple::test::jtx::MPT(
2269 alice.name(), makeMptID(env.seq(alice), alice));
2270 Json::Value jv = escrow::create(alice, bob, mpt(2));
2271 jv[jss::Amount][jss::mpt_issuance_id] =
2272 "00000004A407AF5856CCF3C42619DAA925813FC955C72983";
2273 env(jv,
2275 escrow::finish_time(env.now() + 1s),
2276 fee(baseFee * 150),
2278 env.close();
2279 }
2280
2281 // tecNO_PERMISSION: tfMPTCanEscrow is not enabled
2282 {
2283 Env env{*this, features};
2284 auto const baseFee = env.current()->fees().base;
2285 auto const alice = Account("alice");
2286 auto const bob = Account("bob");
2287 auto const gw = Account("gw");
2288
2289 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2290 mptGw.create(
2291 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
2292 mptGw.authorize({.account = alice});
2293 mptGw.authorize({.account = bob});
2294 auto const MPT = mptGw["MPT"];
2295 env(pay(gw, alice, MPT(10'000)));
2296 env(pay(gw, bob, MPT(10'000)));
2297 env.close();
2298
2299 env(escrow::create(alice, bob, MPT(3)),
2301 escrow::finish_time(env.now() + 1s),
2302 fee(baseFee * 150),
2304 env.close();
2305 }
2306
2307 // tecOBJECT_NOT_FOUND: account does not have the mpt
2308 {
2309 Env env{*this, features};
2310 auto const baseFee = env.current()->fees().base;
2311 auto const alice = Account("alice");
2312 auto const bob = Account("bob");
2313 auto const gw = Account("gw");
2314
2315 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2316 mptGw.create(
2317 {.ownerCount = 1,
2318 .holderCount = 0,
2319 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2320 auto const MPT = mptGw["MPT"];
2321
2322 env(escrow::create(alice, bob, MPT(4)),
2324 escrow::finish_time(env.now() + 1s),
2325 fee(baseFee * 150),
2327 env.close();
2328 }
2329
2330 // tecNO_AUTH: requireAuth set: account not authorized
2331 {
2332 Env env{*this, features};
2333 auto const baseFee = env.current()->fees().base;
2334 auto const alice = Account("alice");
2335 auto const bob = Account("bob");
2336 auto const gw = Account("gw");
2337
2338 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2339 mptGw.create(
2340 {.ownerCount = 1,
2341 .holderCount = 0,
2342 .flags =
2344 mptGw.authorize({.account = alice});
2345 mptGw.authorize({.account = gw, .holder = alice});
2346 auto const MPT = mptGw["MPT"];
2347 env(pay(gw, alice, MPT(10'000)));
2348 env.close();
2349
2350 // unauthorize account
2351 mptGw.authorize(
2352 {.account = gw, .holder = alice, .flags = tfMPTUnauthorize});
2353
2354 env(escrow::create(alice, bob, MPT(5)),
2356 escrow::finish_time(env.now() + 1s),
2357 fee(baseFee * 150),
2358 ter(tecNO_AUTH));
2359 env.close();
2360 }
2361
2362 // tecNO_AUTH: requireAuth set: dest not authorized
2363 {
2364 Env env{*this, features};
2365 auto const baseFee = env.current()->fees().base;
2366 auto const alice = Account("alice");
2367 auto const bob = Account("bob");
2368 auto const gw = Account("gw");
2369
2370 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2371 mptGw.create(
2372 {.ownerCount = 1,
2373 .holderCount = 0,
2374 .flags =
2376 mptGw.authorize({.account = alice});
2377 mptGw.authorize({.account = gw, .holder = alice});
2378 mptGw.authorize({.account = bob});
2379 mptGw.authorize({.account = gw, .holder = bob});
2380 auto const MPT = mptGw["MPT"];
2381 env(pay(gw, alice, MPT(10'000)));
2382 env(pay(gw, bob, MPT(10'000)));
2383 env.close();
2384
2385 // unauthorize dest
2386 mptGw.authorize(
2387 {.account = gw, .holder = bob, .flags = tfMPTUnauthorize});
2388
2389 env(escrow::create(alice, bob, MPT(6)),
2391 escrow::finish_time(env.now() + 1s),
2392 fee(baseFee * 150),
2393 ter(tecNO_AUTH));
2394 env.close();
2395 }
2396
2397 // tecLOCKED: issuer has locked the account
2398 {
2399 Env env{*this, features};
2400 auto const baseFee = env.current()->fees().base;
2401 auto const alice = Account("alice");
2402 auto const bob = Account("bob");
2403 auto const gw = Account("gw");
2404
2405 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2406 mptGw.create(
2407 {.ownerCount = 1,
2408 .holderCount = 0,
2410 mptGw.authorize({.account = alice});
2411 mptGw.authorize({.account = bob});
2412 auto const MPT = mptGw["MPT"];
2413 env(pay(gw, alice, MPT(10'000)));
2414 env(pay(gw, bob, MPT(10'000)));
2415 env.close();
2416
2417 // lock account
2418 mptGw.set({.account = gw, .holder = alice, .flags = tfMPTLock});
2419
2420 env(escrow::create(alice, bob, MPT(7)),
2422 escrow::finish_time(env.now() + 1s),
2423 fee(baseFee * 150),
2424 ter(tecLOCKED));
2425 env.close();
2426 }
2427
2428 // tecLOCKED: issuer has locked the dest
2429 {
2430 Env env{*this, features};
2431 auto const baseFee = env.current()->fees().base;
2432 auto const alice = Account("alice");
2433 auto const bob = Account("bob");
2434 auto const gw = Account("gw");
2435
2436 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2437 mptGw.create(
2438 {.ownerCount = 1,
2439 .holderCount = 0,
2441 mptGw.authorize({.account = alice});
2442 mptGw.authorize({.account = bob});
2443 auto const MPT = mptGw["MPT"];
2444 env(pay(gw, alice, MPT(10'000)));
2445 env(pay(gw, bob, MPT(10'000)));
2446 env.close();
2447
2448 // lock dest
2449 mptGw.set({.account = gw, .holder = bob, .flags = tfMPTLock});
2450
2451 env(escrow::create(alice, bob, MPT(8)),
2453 escrow::finish_time(env.now() + 1s),
2454 fee(baseFee * 150),
2455 ter(tecLOCKED));
2456 env.close();
2457 }
2458
2459 // tecNO_AUTH: mpt cannot be transferred
2460 {
2461 Env env{*this, features};
2462 auto const baseFee = env.current()->fees().base;
2463 auto const alice = Account("alice");
2464 auto const bob = Account("bob");
2465 auto const gw = Account("gw");
2466
2467 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2468 mptGw.create(
2469 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow});
2470 mptGw.authorize({.account = alice});
2471 mptGw.authorize({.account = bob});
2472 auto const MPT = mptGw["MPT"];
2473 env(pay(gw, alice, MPT(10'000)));
2474 env(pay(gw, bob, MPT(10'000)));
2475 env.close();
2476
2477 env(escrow::create(alice, bob, MPT(9)),
2479 escrow::finish_time(env.now() + 1s),
2480 fee(baseFee * 150),
2481 ter(tecNO_AUTH));
2482 env.close();
2483 }
2484
2485 // tecINSUFFICIENT_FUNDS: spendable amount is zero
2486 {
2487 Env env{*this, features};
2488 auto const baseFee = env.current()->fees().base;
2489 auto const alice = Account("alice");
2490 auto const bob = Account("bob");
2491 auto const gw = Account("gw");
2492
2493 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2494 mptGw.create(
2495 {.ownerCount = 1,
2496 .holderCount = 0,
2497 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2498 mptGw.authorize({.account = alice});
2499 mptGw.authorize({.account = bob});
2500 auto const MPT = mptGw["MPT"];
2501 env(pay(gw, bob, MPT(10)));
2502 env.close();
2503
2504 env(escrow::create(alice, bob, MPT(11)),
2506 escrow::finish_time(env.now() + 1s),
2507 fee(baseFee * 150),
2509 env.close();
2510 }
2511
2512 // tecINSUFFICIENT_FUNDS: spendable amount is less than the amount
2513 {
2514 Env env{*this, features};
2515 auto const baseFee = env.current()->fees().base;
2516 auto const alice = Account("alice");
2517 auto const bob = Account("bob");
2518 auto const gw = Account("gw");
2519
2520 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2521 mptGw.create(
2522 {.ownerCount = 1,
2523 .holderCount = 0,
2524 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2525 mptGw.authorize({.account = alice});
2526 mptGw.authorize({.account = bob});
2527 auto const MPT = mptGw["MPT"];
2528 env(pay(gw, alice, MPT(10)));
2529 env(pay(gw, bob, MPT(10)));
2530 env.close();
2531
2532 env(escrow::create(alice, bob, MPT(11)),
2534 escrow::finish_time(env.now() + 1s),
2535 fee(baseFee * 150),
2537 env.close();
2538 }
2539 }
2540
2541 void
2543 {
2544 testcase("MPT Finish Preclaim");
2545 using namespace test::jtx;
2546 using namespace std::literals;
2547
2548 // tecNO_AUTH: requireAuth set: dest not authorized
2549 {
2550 Env env{*this, features};
2551 auto const baseFee = env.current()->fees().base;
2552 auto const alice = Account("alice");
2553 auto const bob = Account("bob");
2554 auto const gw = Account("gw");
2555
2556 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2557 mptGw.create(
2558 {.ownerCount = 1,
2559 .holderCount = 0,
2560 .flags =
2562 mptGw.authorize({.account = alice});
2563 mptGw.authorize({.account = gw, .holder = alice});
2564 mptGw.authorize({.account = bob});
2565 mptGw.authorize({.account = gw, .holder = bob});
2566 auto const MPT = mptGw["MPT"];
2567 env(pay(gw, alice, MPT(10'000)));
2568 env(pay(gw, bob, MPT(10'000)));
2569 env.close();
2570
2571 auto const seq1 = env.seq(alice);
2572 env(escrow::create(alice, bob, MPT(10)),
2574 escrow::finish_time(env.now() + 1s),
2575 fee(baseFee * 150),
2576 ter(tesSUCCESS));
2577 env.close();
2578
2579 // unauthorize dest
2580 mptGw.authorize(
2581 {.account = gw, .holder = bob, .flags = tfMPTUnauthorize});
2582
2583 env(escrow::finish(bob, alice, seq1),
2586 fee(baseFee * 150),
2587 ter(tecNO_AUTH));
2588 env.close();
2589 }
2590
2591 // tecOBJECT_NOT_FOUND: MPT issuance does not exist
2592 {
2593 Env env{*this, features};
2594 auto const baseFee = env.current()->fees().base;
2595 auto const alice = Account("alice");
2596 auto const bob = Account("bob");
2597 env.fund(XRP(10'000), alice, bob);
2598 env.close();
2599
2600 auto const seq1 = env.seq(alice);
2601 env.app().openLedger().modify(
2602 [&](OpenView& view, beast::Journal j) {
2603 Sandbox sb(&view, tapNONE);
2604 auto sleNew =
2606 MPTIssue const mpt{
2607 MPTIssue{makeMptID(1, AccountID(0x4985601))}};
2608 STAmount amt(mpt, 10);
2609 sleNew->setAccountID(sfDestination, bob);
2610 sleNew->setFieldAmount(sfAmount, amt);
2611 sb.insert(sleNew);
2612 sb.apply(view);
2613 return true;
2614 });
2615
2616 env(escrow::finish(bob, alice, seq1),
2619 fee(baseFee * 150),
2621 env.close();
2622 }
2623
2624 // tecLOCKED: issuer has locked the dest
2625 {
2626 Env env{*this, features};
2627 auto const baseFee = env.current()->fees().base;
2628 auto const alice = Account("alice");
2629 auto const bob = Account("bob");
2630 auto const gw = Account("gw");
2631
2632 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2633 mptGw.create(
2634 {.ownerCount = 1,
2635 .holderCount = 0,
2637 mptGw.authorize({.account = alice});
2638 mptGw.authorize({.account = bob});
2639 auto const MPT = mptGw["MPT"];
2640 env(pay(gw, alice, MPT(10'000)));
2641 env(pay(gw, bob, MPT(10'000)));
2642 env.close();
2643
2644 auto const seq1 = env.seq(alice);
2645 env(escrow::create(alice, bob, MPT(8)),
2647 escrow::finish_time(env.now() + 1s),
2648 fee(baseFee * 150),
2649 ter(tesSUCCESS));
2650 env.close();
2651
2652 // lock dest
2653 mptGw.set({.account = gw, .holder = bob, .flags = tfMPTLock});
2654
2655 env(escrow::finish(bob, alice, seq1),
2658 fee(baseFee * 150),
2659 ter(tecLOCKED));
2660 env.close();
2661 }
2662 }
2663
2664 void
2666 {
2667 testcase("MPT Finish Do Apply");
2668 using namespace test::jtx;
2669 using namespace std::literals;
2670
2671 // tecINSUFFICIENT_RESERVE: insufficient reserve to create MPT
2672 {
2673 Env env{*this, features};
2674 auto const baseFee = env.current()->fees().base;
2675 auto const acctReserve = env.current()->fees().reserve;
2676 auto const incReserve = env.current()->fees().increment;
2677
2678 auto const alice = Account("alice");
2679 auto const bob = Account("bob");
2680 auto const gw = Account("gw");
2681 env.fund(acctReserve + (incReserve - 1), bob);
2682 env.close();
2683
2684 MPTTester mptGw(env, gw, {.holders = {alice}});
2685 mptGw.create(
2686 {.ownerCount = 1,
2687 .holderCount = 0,
2688 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2689 mptGw.authorize({.account = alice});
2690 auto const MPT = mptGw["MPT"];
2691 env(pay(gw, alice, MPT(10'000)));
2692 env.close();
2693
2694 auto const seq1 = env.seq(alice);
2695 env(escrow::create(alice, bob, MPT(10)),
2697 escrow::finish_time(env.now() + 1s),
2698 fee(baseFee * 150),
2699 ter(tesSUCCESS));
2700 env.close();
2701
2702 env(escrow::finish(bob, alice, seq1),
2705 fee(baseFee * 150),
2707 env.close();
2708 }
2709
2710 // tesSUCCESS: bob submits; finish MPT created
2711 {
2712 Env env{*this, features};
2713 auto const baseFee = env.current()->fees().base;
2714 auto const alice = Account("alice");
2715 auto const bob = Account("bob");
2716 auto const gw = Account("gw");
2717 env.fund(XRP(10'000), bob);
2718 env.close();
2719
2720 MPTTester mptGw(env, gw, {.holders = {alice}});
2721 mptGw.create(
2722 {.ownerCount = 1,
2723 .holderCount = 0,
2724 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2725 mptGw.authorize({.account = alice});
2726 auto const MPT = mptGw["MPT"];
2727 env(pay(gw, alice, MPT(10'000)));
2728 env.close();
2729
2730 auto const seq1 = env.seq(alice);
2731 env(escrow::create(alice, bob, MPT(10)),
2733 escrow::finish_time(env.now() + 1s),
2734 fee(baseFee * 150),
2735 ter(tesSUCCESS));
2736 env.close();
2737
2738 env(escrow::finish(bob, alice, seq1),
2741 fee(baseFee * 150),
2742 ter(tesSUCCESS));
2743 env.close();
2744 }
2745
2746 // tecNO_PERMISSION: carol submits; finish MPT not created
2747 {
2748 Env env{*this, features};
2749 auto const baseFee = env.current()->fees().base;
2750 auto const alice = Account("alice");
2751 auto const bob = Account("bob");
2752 auto const carol = Account("carol");
2753 auto const gw = Account("gw");
2754 env.fund(XRP(10'000), bob, carol);
2755 env.close();
2756
2757 MPTTester mptGw(env, gw, {.holders = {alice}});
2758 mptGw.create(
2759 {.ownerCount = 1,
2760 .holderCount = 0,
2761 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2762 mptGw.authorize({.account = alice});
2763 auto const MPT = mptGw["MPT"];
2764 env(pay(gw, alice, MPT(10'000)));
2765 env.close();
2766
2767 auto const seq1 = env.seq(alice);
2768 env(escrow::create(alice, bob, MPT(10)),
2770 escrow::finish_time(env.now() + 1s),
2771 fee(baseFee * 150),
2772 ter(tesSUCCESS));
2773 env.close();
2774
2775 env(escrow::finish(carol, alice, seq1),
2778 fee(baseFee * 150),
2780 env.close();
2781 }
2782 }
2783
2784 void
2786 {
2787 testcase("MPT Cancel Preclaim");
2788 using namespace test::jtx;
2789 using namespace std::literals;
2790
2791 // tecNO_AUTH: requireAuth set: account not authorized
2792 {
2793 Env env{*this, features};
2794 auto const baseFee = env.current()->fees().base;
2795 auto const alice = Account("alice");
2796 auto const bob = Account("bob");
2797 auto const gw = Account("gw");
2798
2799 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2800 mptGw.create(
2801 {.ownerCount = 1,
2802 .holderCount = 0,
2803 .flags =
2805 mptGw.authorize({.account = alice});
2806 mptGw.authorize({.account = gw, .holder = alice});
2807 mptGw.authorize({.account = bob});
2808 mptGw.authorize({.account = gw, .holder = bob});
2809 auto const MPT = mptGw["MPT"];
2810 env(pay(gw, alice, MPT(10'000)));
2811 env(pay(gw, bob, MPT(10'000)));
2812 env.close();
2813
2814 auto const seq1 = env.seq(alice);
2815 env(escrow::create(alice, bob, MPT(10)),
2816 escrow::cancel_time(env.now() + 2s),
2818 fee(baseFee * 150),
2819 ter(tesSUCCESS));
2820 env.close();
2821
2822 // unauthorize account
2823 mptGw.authorize(
2824 {.account = gw, .holder = alice, .flags = tfMPTUnauthorize});
2825
2826 env(escrow::cancel(bob, alice, seq1), ter(tecNO_AUTH));
2827 env.close();
2828 }
2829
2830 // tecOBJECT_NOT_FOUND: MPT issuance does not exist
2831 {
2832 Env env{*this, features};
2833 auto const baseFee = env.current()->fees().base;
2834 auto const alice = Account("alice");
2835 auto const bob = Account("bob");
2836 env.fund(XRP(10'000), alice, bob);
2837
2838 auto const seq1 = env.seq(alice);
2839 env.app().openLedger().modify(
2840 [&](OpenView& view, beast::Journal j) {
2841 Sandbox sb(&view, tapNONE);
2842 auto sleNew =
2844 MPTIssue const mpt{
2845 MPTIssue{makeMptID(1, AccountID(0x4985601))}};
2846 STAmount amt(mpt, 10);
2847 sleNew->setAccountID(sfDestination, bob);
2848 sleNew->setFieldAmount(sfAmount, amt);
2849 sb.insert(sleNew);
2850 sb.apply(view);
2851 return true;
2852 });
2853
2854 env(escrow::cancel(bob, alice, seq1),
2855 fee(baseFee),
2857 env.close();
2858 }
2859 }
2860
2861 void
2863 {
2864 testcase("MPT Balances");
2865
2866 using namespace jtx;
2867 using namespace std::chrono;
2868
2869 Env env{*this, features};
2870 auto const baseFee = env.current()->fees().base;
2871 auto const alice = Account("alice");
2872 auto const bob = Account("bob");
2873 auto const carol = Account("carol");
2874 auto const gw = Account("gw");
2875 env.fund(XRP(5000), bob);
2876
2877 MPTTester mptGw(env, gw, {.holders = {alice, carol}});
2878 mptGw.create(
2879 {.ownerCount = 1,
2880 .holderCount = 0,
2881 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2882 mptGw.authorize({.account = alice});
2883 mptGw.authorize({.account = carol});
2884 auto const MPT = mptGw["MPT"];
2885 env(pay(gw, alice, MPT(10'000)));
2886 env(pay(gw, carol, MPT(10'000)));
2887 env.close();
2888
2889 auto outstandingMPT = env.balance(gw, MPT);
2890
2891 // Create & Finish Escrow
2892 auto const seq1 = env.seq(alice);
2893 {
2894 auto const preAliceMPT = env.balance(alice, MPT);
2895 auto const preBobMPT = env.balance(bob, MPT);
2896 env(escrow::create(alice, bob, MPT(1'000)),
2898 escrow::finish_time(env.now() + 1s),
2899 fee(baseFee * 150),
2900 ter(tesSUCCESS));
2901 env.close();
2902
2903 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
2904 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
2905 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
2906 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
2907 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2908 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1'000);
2909 }
2910 {
2911 auto const preAliceMPT = env.balance(alice, MPT);
2912 auto const preBobMPT = env.balance(bob, MPT);
2913 env(escrow::finish(bob, alice, seq1),
2916 fee(baseFee * 150),
2917 ter(tesSUCCESS));
2918 env.close();
2919
2920 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT);
2921 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
2922 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT + MPT(1'000));
2923 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
2924 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2925 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
2926 }
2927
2928 // Create & Cancel Escrow
2929 auto const seq2 = env.seq(alice);
2930 {
2931 auto const preAliceMPT = env.balance(alice, MPT);
2932 auto const preBobMPT = env.balance(bob, MPT);
2933 env(escrow::create(alice, bob, MPT(1'000)),
2935 escrow::finish_time(env.now() + 1s),
2936 escrow::cancel_time(env.now() + 2s),
2937 fee(baseFee * 150),
2938 ter(tesSUCCESS));
2939 env.close();
2940
2941 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
2942 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
2943 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
2944 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
2945 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2946 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1'000);
2947 }
2948 {
2949 auto const preAliceMPT = env.balance(alice, MPT);
2950 auto const preBobMPT = env.balance(bob, MPT);
2951 env(escrow::cancel(bob, alice, seq2), ter(tesSUCCESS));
2952 env.close();
2953
2954 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT + MPT(1'000));
2955 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
2956 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
2957 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
2958 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2959 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
2960 }
2961
2962 // Self Escrow Create & Finish
2963 {
2964 auto const seq = env.seq(alice);
2965 auto const preAliceMPT = env.balance(alice, MPT);
2966 env(escrow::create(alice, alice, MPT(1'000)),
2968 escrow::finish_time(env.now() + 1s),
2969 fee(baseFee * 150),
2970 ter(tesSUCCESS));
2971 env.close();
2972
2973 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
2974 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
2975 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2976 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1'000);
2977
2978 env(escrow::finish(alice, alice, seq),
2981 fee(baseFee * 150),
2982 ter(tesSUCCESS));
2983 env.close();
2984
2985 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT);
2986 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
2987 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2988 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
2989 }
2990
2991 // Self Escrow Create & Cancel
2992 {
2993 auto const seq = env.seq(alice);
2994 auto const preAliceMPT = env.balance(alice, MPT);
2995 env(escrow::create(alice, alice, MPT(1'000)),
2997 escrow::finish_time(env.now() + 1s),
2998 escrow::cancel_time(env.now() + 2s),
2999 fee(baseFee * 150),
3000 ter(tesSUCCESS));
3001 env.close();
3002
3003 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
3004 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
3005 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3006 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1'000);
3007
3008 env(escrow::cancel(alice, alice, seq), ter(tesSUCCESS));
3009 env.close();
3010
3011 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT);
3012 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3013 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3014 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3015 }
3016
3017 // Multiple Escrows
3018 {
3019 auto const preAliceMPT = env.balance(alice, MPT);
3020 auto const preBobMPT = env.balance(bob, MPT);
3021 auto const preCarolMPT = env.balance(carol, MPT);
3022 env(escrow::create(alice, bob, MPT(1'000)),
3024 escrow::finish_time(env.now() + 1s),
3025 fee(baseFee * 150),
3026 ter(tesSUCCESS));
3027 env.close();
3028
3029 env(escrow::create(carol, bob, MPT(1'000)),
3031 escrow::finish_time(env.now() + 1s),
3032 fee(baseFee * 150),
3033 ter(tesSUCCESS));
3034 env.close();
3035
3036 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
3037 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
3038 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
3039 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3040 BEAST_EXPECT(env.balance(carol, MPT) == preCarolMPT - MPT(1'000));
3041 BEAST_EXPECT(mptEscrowed(env, carol, MPT) == 1'000);
3042 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3043 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 2'000);
3044 }
3045
3046 // Max MPT Amount Issued (Escrow 1 MPT)
3047 {
3048 Env env{*this, features};
3049 auto const baseFee = env.current()->fees().base;
3050 auto const alice = Account("alice");
3051 auto const bob = Account("bob");
3052 auto const gw = Account("gw");
3053
3054 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3055 mptGw.create(
3056 {.ownerCount = 1,
3057 .holderCount = 0,
3058 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3059 mptGw.authorize({.account = alice});
3060 mptGw.authorize({.account = bob});
3061 auto const MPT = mptGw["MPT"];
3062 env(pay(gw, alice, MPT(maxMPTokenAmount)));
3063 env.close();
3064
3065 auto const preAliceMPT = env.balance(alice, MPT);
3066 auto const preBobMPT = env.balance(bob, MPT);
3067 auto const outstandingMPT = env.balance(gw, MPT);
3068
3069 auto const seq1 = env.seq(alice);
3070 env(escrow::create(alice, bob, MPT(1)),
3072 escrow::finish_time(env.now() + 1s),
3073 fee(baseFee * 150));
3074 env.close();
3075
3076 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1));
3077 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1);
3078 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
3079 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3080 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3081 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1);
3082
3083 env(escrow::finish(bob, alice, seq1),
3086 fee(baseFee * 150),
3087 ter(tesSUCCESS));
3088 env.close();
3089
3090 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1));
3091 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3092 BEAST_EXPECT(!env.le(keylet::mptoken(MPT.mpt(), alice))
3093 ->isFieldPresent(sfLockedAmount));
3094 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT + MPT(1));
3095 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3096 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3097 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3098 BEAST_EXPECT(!env.le(keylet::mptIssuance(MPT.mpt()))
3099 ->isFieldPresent(sfLockedAmount));
3100 }
3101
3102 // Max MPT Amount Issued (Escrow Max MPT)
3103 {
3104 Env env{*this, features};
3105 auto const baseFee = env.current()->fees().base;
3106 auto const alice = Account("alice");
3107 auto const bob = Account("bob");
3108 auto const gw = Account("gw");
3109
3110 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3111 mptGw.create(
3112 {.ownerCount = 1,
3113 .holderCount = 0,
3114 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3115 mptGw.authorize({.account = alice});
3116 mptGw.authorize({.account = bob});
3117 auto const MPT = mptGw["MPT"];
3118 env(pay(gw, alice, MPT(maxMPTokenAmount)));
3119 env.close();
3120
3121 auto const preAliceMPT = env.balance(alice, MPT);
3122 auto const preBobMPT = env.balance(bob, MPT);
3123 auto const outstandingMPT = env.balance(gw, MPT);
3124
3125 // Escrow Max MPT - 10
3126 auto const seq1 = env.seq(alice);
3127 env(escrow::create(alice, bob, MPT(maxMPTokenAmount - 10)),
3129 escrow::finish_time(env.now() + 1s),
3130 fee(baseFee * 150));
3131 env.close();
3132
3133 // Escrow 10 MPT
3134 auto const seq2 = env.seq(alice);
3135 env(escrow::create(alice, bob, MPT(10)),
3137 escrow::finish_time(env.now() + 1s),
3138 fee(baseFee * 150));
3139 env.close();
3140
3141 BEAST_EXPECT(
3142 env.balance(alice, MPT) == preAliceMPT - MPT(maxMPTokenAmount));
3143 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == maxMPTokenAmount);
3144 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
3145 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3146 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3147 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == maxMPTokenAmount);
3148
3149 env(escrow::finish(bob, alice, seq1),
3152 fee(baseFee * 150),
3153 ter(tesSUCCESS));
3154 env.close();
3155
3156 env(escrow::finish(bob, alice, seq2),
3159 fee(baseFee * 150),
3160 ter(tesSUCCESS));
3161 env.close();
3162
3163 BEAST_EXPECT(
3164 env.balance(alice, MPT) == preAliceMPT - MPT(maxMPTokenAmount));
3165 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3166 BEAST_EXPECT(
3167 env.balance(bob, MPT) == preBobMPT + MPT(maxMPTokenAmount));
3168 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3169 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3170 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3171 }
3172 }
3173
3174 void
3176 {
3177 using namespace jtx;
3178 using namespace std::chrono;
3179
3180 auto const alice = Account("alice");
3181 auto const bob = Account("bob");
3182 auto const carol = Account("carol");
3183 auto const gw = Account{"gateway"};
3184 {
3185 testcase("MPT Metadata to self");
3186
3187 Env env{*this, features};
3188 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3189 mptGw.create(
3190 {.ownerCount = 1,
3191 .holderCount = 0,
3192 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3193 mptGw.authorize({.account = alice});
3194 mptGw.authorize({.account = bob});
3195 auto const MPT = mptGw["MPT"];
3196 env(pay(gw, alice, MPT(10'000)));
3197 env(pay(gw, bob, MPT(10'000)));
3198 env.close();
3199 auto const aseq = env.seq(alice);
3200 auto const bseq = env.seq(bob);
3201
3202 env(escrow::create(alice, alice, MPT(1'000)),
3203 escrow::finish_time(env.now() + 1s),
3204 escrow::cancel_time(env.now() + 500s));
3205 BEAST_EXPECT(
3206 (*env.meta())[sfTransactionResult] ==
3207 static_cast<std::uint8_t>(tesSUCCESS));
3208 env.close(5s);
3209 auto const aa = env.le(keylet::escrow(alice.id(), aseq));
3210 BEAST_EXPECT(aa);
3211 {
3212 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3213 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
3214 BEAST_EXPECT(
3215 std::find(aod.begin(), aod.end(), aa) != aod.end());
3216 }
3217
3218 {
3219 ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
3220 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 1);
3221 BEAST_EXPECT(
3222 std::find(iod.begin(), iod.end(), aa) == iod.end());
3223 }
3224
3225 env(escrow::create(bob, bob, MPT(1'000)),
3226 escrow::finish_time(env.now() + 1s),
3227 escrow::cancel_time(env.now() + 2s));
3228 BEAST_EXPECT(
3229 (*env.meta())[sfTransactionResult] ==
3230 static_cast<std::uint8_t>(tesSUCCESS));
3231 env.close(5s);
3232 auto const bb = env.le(keylet::escrow(bob.id(), bseq));
3233 BEAST_EXPECT(bb);
3234
3235 {
3236 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3237 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
3238 BEAST_EXPECT(
3239 std::find(bod.begin(), bod.end(), bb) != bod.end());
3240 }
3241
3242 env.close(5s);
3243 env(escrow::finish(alice, alice, aseq));
3244 {
3245 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
3246 BEAST_EXPECT(
3247 (*env.meta())[sfTransactionResult] ==
3248 static_cast<std::uint8_t>(tesSUCCESS));
3249
3250 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3251 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
3252 BEAST_EXPECT(
3253 std::find(aod.begin(), aod.end(), aa) == aod.end());
3254
3255 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3256 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
3257 BEAST_EXPECT(
3258 std::find(bod.begin(), bod.end(), bb) != bod.end());
3259 }
3260
3261 env.close(5s);
3262 env(escrow::cancel(bob, bob, bseq));
3263 {
3264 BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq)));
3265 BEAST_EXPECT(
3266 (*env.meta())[sfTransactionResult] ==
3267 static_cast<std::uint8_t>(tesSUCCESS));
3268
3269 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3270 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
3271 BEAST_EXPECT(
3272 std::find(bod.begin(), bod.end(), bb) == bod.end());
3273 }
3274 }
3275
3276 {
3277 testcase("MPT Metadata to other");
3278
3279 Env env{*this, features};
3280 MPTTester mptGw(env, gw, {.holders = {alice, bob, carol}});
3281 mptGw.create(
3282 {.ownerCount = 1,
3283 .holderCount = 0,
3284 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3285 mptGw.authorize({.account = alice});
3286 mptGw.authorize({.account = bob});
3287 mptGw.authorize({.account = carol});
3288 auto const MPT = mptGw["MPT"];
3289 env(pay(gw, alice, MPT(10'000)));
3290 env(pay(gw, bob, MPT(10'000)));
3291 env(pay(gw, carol, MPT(10'000)));
3292 env.close();
3293 auto const aseq = env.seq(alice);
3294 auto const bseq = env.seq(bob);
3295
3296 env(escrow::create(alice, bob, MPT(1'000)),
3297 escrow::finish_time(env.now() + 1s));
3298 BEAST_EXPECT(
3299 (*env.meta())[sfTransactionResult] ==
3300 static_cast<std::uint8_t>(tesSUCCESS));
3301 env.close(5s);
3302 env(escrow::create(bob, carol, MPT(1'000)),
3303 escrow::finish_time(env.now() + 1s),
3304 escrow::cancel_time(env.now() + 2s));
3305 BEAST_EXPECT(
3306 (*env.meta())[sfTransactionResult] ==
3307 static_cast<std::uint8_t>(tesSUCCESS));
3308 env.close(5s);
3309
3310 auto const ab = env.le(keylet::escrow(alice.id(), aseq));
3311 BEAST_EXPECT(ab);
3312
3313 auto const bc = env.le(keylet::escrow(bob.id(), bseq));
3314 BEAST_EXPECT(bc);
3315
3316 {
3317 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3318 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
3319 BEAST_EXPECT(
3320 std::find(aod.begin(), aod.end(), ab) != aod.end());
3321
3322 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3323 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 3);
3324 BEAST_EXPECT(
3325 std::find(bod.begin(), bod.end(), ab) != bod.end());
3326 BEAST_EXPECT(
3327 std::find(bod.begin(), bod.end(), bc) != bod.end());
3328
3329 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
3330 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2);
3331 BEAST_EXPECT(
3332 std::find(cod.begin(), cod.end(), bc) != cod.end());
3333 }
3334
3335 env.close(5s);
3336 env(escrow::finish(alice, alice, aseq));
3337 {
3338 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
3339 BEAST_EXPECT(env.le(keylet::escrow(bob.id(), bseq)));
3340
3341 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3342 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
3343 BEAST_EXPECT(
3344 std::find(aod.begin(), aod.end(), ab) == aod.end());
3345
3346 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3347 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
3348 BEAST_EXPECT(
3349 std::find(bod.begin(), bod.end(), ab) == bod.end());
3350 BEAST_EXPECT(
3351 std::find(bod.begin(), bod.end(), bc) != bod.end());
3352
3353 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
3354 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2);
3355 }
3356
3357 env.close(5s);
3358 env(escrow::cancel(bob, bob, bseq));
3359 {
3360 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
3361 BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq)));
3362
3363 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3364 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
3365 BEAST_EXPECT(
3366 std::find(aod.begin(), aod.end(), ab) == aod.end());
3367
3368 ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3369 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
3370 BEAST_EXPECT(
3371 std::find(bod.begin(), bod.end(), ab) == bod.end());
3372 BEAST_EXPECT(
3373 std::find(bod.begin(), bod.end(), bc) == bod.end());
3374
3375 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
3376 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
3377 }
3378 }
3379 }
3380
3381 void
3383 {
3384 testcase("MPT Gateway Balances");
3385 using namespace test::jtx;
3386 using namespace std::literals;
3387
3388 // issuer is dest; alice w/ authorization
3389 {
3390 Env env{*this, features};
3391 auto const baseFee = env.current()->fees().base;
3392 auto const alice = Account("alice");
3393 auto const gw = Account("gw");
3394
3395 MPTTester mptGw(env, gw, {.holders = {alice}});
3396 mptGw.create(
3397 {.ownerCount = 1,
3398 .holderCount = 0,
3399 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3400 mptGw.authorize({.account = alice});
3401 auto const MPT = mptGw["MPT"];
3402 env(pay(gw, alice, MPT(10'000)));
3403 env.close();
3404
3405 // issuer can be destination
3406 auto const seq1 = env.seq(alice);
3407 auto const preAliceMPT = env.balance(alice, MPT);
3408 auto const preOutstanding = env.balance(gw, MPT);
3409 auto const preEscrowed = issuerMPTEscrowed(env, MPT);
3410 BEAST_EXPECT(preOutstanding == MPT(-10'000));
3411 BEAST_EXPECT(preEscrowed == 0);
3412
3413 env(escrow::create(alice, gw, MPT(1'000)),
3415 escrow::finish_time(env.now() + 1s),
3416 fee(baseFee * 150));
3417 env.close();
3418
3419 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
3420 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
3421 BEAST_EXPECT(env.balance(gw, MPT) == preOutstanding);
3422 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == preEscrowed + 1'000);
3423
3424 // issuer (dest) can finish escrow
3425 env(escrow::finish(gw, alice, seq1),
3428 fee(baseFee * 150));
3429 env.close();
3430
3431 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
3432 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3433 BEAST_EXPECT(env.balance(gw, MPT) == preOutstanding + MPT(1'000));
3434 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == preEscrowed);
3435 }
3436 }
3437
3438 void
3440 {
3441 testcase("MPT Locked Rate");
3442 using namespace test::jtx;
3443 using namespace std::literals;
3444
3445 auto const alice = Account("alice");
3446 auto const bob = Account("bob");
3447 auto const carol = Account("carol");
3448 auto const gw = Account{"gateway"};
3449 auto const USD = gw["USD"];
3450
3451 // test locked rate: finish
3452 {
3453 Env env{*this, features};
3454 auto const baseFee = env.current()->fees().base;
3455 auto const alice = Account("alice");
3456 auto const bob = Account("bob");
3457 auto const gw = Account("gw");
3458
3459 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3460 mptGw.create(
3461 {.transferFee = 25000,
3462 .ownerCount = 1,
3463 .holderCount = 0,
3464 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3465 mptGw.authorize({.account = alice});
3466 mptGw.authorize({.account = bob});
3467 auto const MPT = mptGw["MPT"];
3468 env(pay(gw, alice, MPT(10'000)));
3469 env(pay(gw, bob, MPT(10'000)));
3470 env.close();
3471
3472 // alice can create escrow w/ xfer rate
3473 auto const preAlice = env.balance(alice, MPT);
3474 auto const seq1 = env.seq(alice);
3475 auto const delta = MPT(125);
3476 env(escrow::create(alice, bob, MPT(125)),
3478 escrow::finish_time(env.now() + 1s),
3479 fee(baseFee * 150));
3480 env.close();
3481 auto const transferRate = escrow::rate(env, alice, seq1);
3482 BEAST_EXPECT(
3483 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
3484
3485 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 125);
3486 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 125);
3487 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-20'000));
3488
3489 // bob can finish escrow
3490 env(escrow::finish(bob, alice, seq1),
3493 fee(baseFee * 150));
3494 env.close();
3495
3496 BEAST_EXPECT(env.balance(alice, MPT) == preAlice - delta);
3497 BEAST_EXPECT(env.balance(bob, MPT) == MPT(10'100));
3498
3499 auto const escrowedWithFix =
3500 env.current()->rules().enabled(fixTokenEscrowV1) ? 0 : 25;
3501 auto const outstandingWithFix =
3502 env.current()->rules().enabled(fixTokenEscrowV1) ? MPT(19'975)
3503 : MPT(20'000);
3504 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == escrowedWithFix);
3505 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == escrowedWithFix);
3506 BEAST_EXPECT(env.balance(gw, MPT) == -outstandingWithFix);
3507 }
3508
3509 // test locked rate: cancel
3510 {
3511 Env env{*this, features};
3512 auto const baseFee = env.current()->fees().base;
3513 auto const alice = Account("alice");
3514 auto const bob = Account("bob");
3515 auto const gw = Account("gw");
3516
3517 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3518 mptGw.create(
3519 {.transferFee = 25000,
3520 .ownerCount = 1,
3521 .holderCount = 0,
3522 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3523 mptGw.authorize({.account = alice});
3524 mptGw.authorize({.account = bob});
3525 auto const MPT = mptGw["MPT"];
3526 env(pay(gw, alice, MPT(10'000)));
3527 env(pay(gw, bob, MPT(10'000)));
3528 env.close();
3529
3530 // alice can create escrow w/ xfer rate
3531 auto const preAlice = env.balance(alice, MPT);
3532 auto const preBob = env.balance(bob, MPT);
3533 auto const seq1 = env.seq(alice);
3534 auto const delta = MPT(125);
3535 env(escrow::create(alice, bob, MPT(125)),
3537 escrow::finish_time(env.now() + 1s),
3538 escrow::cancel_time(env.now() + 3s),
3539 fee(baseFee * 150));
3540 env.close();
3541 auto const transferRate = escrow::rate(env, alice, seq1);
3542 BEAST_EXPECT(
3543 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
3544
3545 // alice can cancel escrow
3546 env(escrow::cancel(alice, alice, seq1), fee(baseFee));
3547 env.close();
3548
3549 BEAST_EXPECT(env.balance(alice, MPT) == preAlice);
3550 BEAST_EXPECT(env.balance(bob, MPT) == preBob);
3551 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-20'000));
3552 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3553 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3554 }
3555
3556 // test locked rate: issuer is destination
3557 {
3558 Env env{*this, features};
3559 auto const baseFee = env.current()->fees().base;
3560 auto const alice = Account("alice");
3561 auto const bob = Account("bob");
3562 auto const gw = Account("gw");
3563
3564 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3565 mptGw.create(
3566 {.transferFee = 25000,
3567 .ownerCount = 1,
3568 .holderCount = 0,
3569 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3570 mptGw.authorize({.account = alice});
3571 mptGw.authorize({.account = bob});
3572 auto const MPT = mptGw["MPT"];
3573 env(pay(gw, alice, MPT(10'000)));
3574 env(pay(gw, bob, MPT(10'000)));
3575 env.close();
3576
3577 // alice can create escrow w/ xfer rate
3578 auto const preAlice = env.balance(alice, MPT);
3579 auto const seq1 = env.seq(alice);
3580 auto const delta = MPT(125);
3581 env(escrow::create(alice, gw, MPT(125)),
3583 escrow::finish_time(env.now() + 1s),
3584 fee(baseFee * 150));
3585 env.close();
3586 auto const transferRate = escrow::rate(env, alice, seq1);
3587 BEAST_EXPECT(
3588 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
3589
3590 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 125);
3591 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 125);
3592 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-20'000));
3593
3594 // bob can finish escrow
3595 env(escrow::finish(gw, alice, seq1),
3598 fee(baseFee * 150));
3599 env.close();
3600
3601 BEAST_EXPECT(env.balance(alice, MPT) == preAlice - delta);
3602 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3603 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3604 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-19'875));
3605 }
3606 }
3607
3608 void
3610 {
3611 testcase("MPT Require Auth");
3612 using namespace test::jtx;
3613 using namespace std::literals;
3614
3615 Env env{*this, features};
3616 auto const baseFee = env.current()->fees().base;
3617 auto const alice = Account("alice");
3618 auto const bob = Account("bob");
3619 auto const gw = Account("gw");
3620
3621 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3622 mptGw.create(
3623 {.ownerCount = 1,
3624 .holderCount = 0,
3626 mptGw.authorize({.account = alice});
3627 mptGw.authorize({.account = gw, .holder = alice});
3628 mptGw.authorize({.account = bob});
3629 mptGw.authorize({.account = gw, .holder = bob});
3630 auto const MPT = mptGw["MPT"];
3631 env(pay(gw, alice, MPT(10'000)));
3632 env.close();
3633
3634 auto seq = env.seq(alice);
3635 auto const delta = MPT(125);
3636 // alice can create escrow - is authorized
3637 env(escrow::create(alice, bob, MPT(100)),
3639 escrow::finish_time(env.now() + 1s),
3640 fee(baseFee * 150));
3641 env.close();
3642
3643 // bob can finish escrow - is authorized
3644 env(escrow::finish(bob, alice, seq),
3647 fee(baseFee * 150));
3648 env.close();
3649 }
3650
3651 void
3653 {
3654 testcase("MPT Lock");
3655 using namespace test::jtx;
3656 using namespace std::literals;
3657
3658 Env env{*this, features};
3659 auto const baseFee = env.current()->fees().base;
3660 auto const alice = Account("alice");
3661 auto const bob = Account("bob");
3662 auto const gw = Account("gw");
3663
3664 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3665 mptGw.create(
3666 {.ownerCount = 1,
3667 .holderCount = 0,
3669 mptGw.authorize({.account = alice});
3670 mptGw.authorize({.account = bob});
3671 auto const MPT = mptGw["MPT"];
3672 env(pay(gw, alice, MPT(10'000)));
3673 env(pay(gw, bob, MPT(10'000)));
3674 env.close();
3675
3676 // alice create escrow
3677 auto seq1 = env.seq(alice);
3678 env(escrow::create(alice, bob, MPT(100)),
3680 escrow::finish_time(env.now() + 1s),
3681 escrow::cancel_time(env.now() + 2s),
3682 fee(baseFee * 150));
3683 env.close();
3684
3685 // lock account & dest
3686 mptGw.set({.account = gw, .holder = alice, .flags = tfMPTLock});
3687 mptGw.set({.account = gw, .holder = bob, .flags = tfMPTLock});
3688
3689 // bob cannot finish
3690 env(escrow::finish(bob, alice, seq1),
3693 fee(baseFee * 150),
3694 ter(tecLOCKED));
3695 env.close();
3696
3697 // bob can cancel
3698 env(escrow::cancel(bob, alice, seq1));
3699 env.close();
3700 }
3701
3702 void
3704 {
3705 testcase("MPT Can Transfer");
3706 using namespace test::jtx;
3707 using namespace std::literals;
3708
3709 Env env{*this, features};
3710 auto const baseFee = env.current()->fees().base;
3711 auto const alice = Account("alice");
3712 auto const bob = Account("bob");
3713 auto const gw = Account("gw");
3714
3715 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3716 mptGw.create(
3717 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow});
3718 mptGw.authorize({.account = alice});
3719 mptGw.authorize({.account = bob});
3720 auto const MPT = mptGw["MPT"];
3721 env(pay(gw, alice, MPT(10'000)));
3722 env(pay(gw, bob, MPT(10'000)));
3723 env.close();
3724
3725 // alice cannot create escrow to non issuer
3726 env(escrow::create(alice, bob, MPT(100)),
3728 escrow::finish_time(env.now() + 1s),
3729 escrow::cancel_time(env.now() + 2s),
3730 fee(baseFee * 150),
3731 ter(tecNO_AUTH));
3732 env.close();
3733
3734 // Escrow Create & Finish
3735 {
3736 // alice an create escrow to issuer
3737 auto seq = env.seq(alice);
3738 env(escrow::create(alice, gw, MPT(100)),
3740 escrow::finish_time(env.now() + 1s),
3741 fee(baseFee * 150));
3742 env.close();
3743
3744 // gw can finish
3745 env(escrow::finish(gw, alice, seq),
3748 fee(baseFee * 150));
3749 env.close();
3750 }
3751
3752 // Escrow Create & Cancel
3753 {
3754 // alice an create escrow to issuer
3755 auto seq = env.seq(alice);
3756 env(escrow::create(alice, gw, MPT(100)),
3758 escrow::finish_time(env.now() + 1s),
3759 escrow::cancel_time(env.now() + 2s),
3760 fee(baseFee * 150));
3761 env.close();
3762
3763 // alice can cancel
3764 env(escrow::cancel(alice, alice, seq));
3765 env.close();
3766 }
3767 }
3768
3769 void
3771 {
3772 testcase("MPT Destroy");
3773 using namespace test::jtx;
3774 using namespace std::literals;
3775
3776 // tecHAS_OBLIGATIONS: issuer cannot destroy issuance
3777 {
3778 Env env{*this, features};
3779 auto const baseFee = env.current()->fees().base;
3780 auto const alice = Account("alice");
3781 auto const bob = Account("bob");
3782 auto const gw = Account("gw");
3783
3784 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3785 mptGw.create(
3786 {.ownerCount = 1,
3787 .holderCount = 0,
3788 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3789 mptGw.authorize({.account = alice});
3790 mptGw.authorize({.account = bob});
3791 auto const MPT = mptGw["MPT"];
3792 env(pay(gw, alice, MPT(10'000)));
3793 env(pay(gw, bob, MPT(10'000)));
3794 env.close();
3795
3796 auto const seq1 = env.seq(alice);
3797 env(escrow::create(alice, bob, MPT(10)),
3799 escrow::finish_time(env.now() + 1s),
3800 fee(baseFee * 150));
3801 env.close();
3802
3803 env(pay(alice, gw, MPT(10'000)), ter(tecPATH_PARTIAL));
3804 env(pay(alice, gw, MPT(9'990)));
3805 env(pay(bob, gw, MPT(10'000)));
3806 BEAST_EXPECT(env.balance(alice, MPT) == MPT(0));
3807 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 10);
3808 BEAST_EXPECT(env.balance(bob, MPT) == MPT(0));
3809 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3810 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-10));
3811 mptGw.authorize({.account = bob, .flags = tfMPTUnauthorize});
3812 mptGw.destroy(
3813 {.id = mptGw.issuanceID(),
3814 .ownerCount = 1,
3815 .err = tecHAS_OBLIGATIONS});
3816
3817 env(escrow::finish(bob, alice, seq1),
3820 fee(baseFee * 150),
3821 ter(tesSUCCESS));
3822 env.close();
3823
3824 env(pay(bob, gw, MPT(10)));
3825 mptGw.destroy({.id = mptGw.issuanceID(), .ownerCount = 0});
3826 }
3827
3828 // tecHAS_OBLIGATIONS: holder cannot destroy mptoken
3829 {
3830 Env env{*this, features};
3831 auto const baseFee = env.current()->fees().base;
3832 auto const alice = Account("alice");
3833 auto const bob = Account("bob");
3834 auto const gw = Account("gw");
3835 env.fund(XRP(10'000), bob);
3836 env.close();
3837
3838 MPTTester mptGw(env, gw, {.holders = {alice}});
3839 mptGw.create(
3840 {.ownerCount = 1,
3841 .holderCount = 0,
3842 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3843 mptGw.authorize({.account = alice});
3844 auto const MPT = mptGw["MPT"];
3845 env(pay(gw, alice, MPT(10'000)));
3846 env.close();
3847
3848 auto const seq1 = env.seq(alice);
3849 env(escrow::create(alice, bob, MPT(10)),
3851 escrow::finish_time(env.now() + 1s),
3852 fee(baseFee * 150),
3853 ter(tesSUCCESS));
3854 env.close();
3855
3856 env(pay(alice, gw, MPT(9'990)));
3857 env.close();
3858
3859 BEAST_EXPECT(env.balance(alice, MPT) == MPT(0));
3860 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 10);
3861 mptGw.authorize(
3862 {.account = alice,
3863 .flags = tfMPTUnauthorize,
3864 .err = tecHAS_OBLIGATIONS});
3865
3866 env(escrow::finish(bob, alice, seq1),
3869 fee(baseFee * 150),
3870 ter(tesSUCCESS));
3871 env.close();
3872
3873 BEAST_EXPECT(env.balance(alice, MPT) == MPT(0));
3874 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3875 mptGw.authorize({.account = alice, .flags = tfMPTUnauthorize});
3876 BEAST_EXPECT(!env.le(keylet::mptoken(MPT.mpt(), alice)));
3877 }
3878 }
3879
3880 void
3882 {
3883 testIOUEnablement(features);
3884 testIOUAllowLockingFlag(features);
3885 testIOUCreatePreflight(features);
3886 testIOUCreatePreclaim(features);
3887 testIOUFinishPreclaim(features);
3888 testIOUFinishDoApply(features);
3889 testIOUCancelPreclaim(features);
3890 testIOUBalances(features);
3891 testIOUMetaAndOwnership(features);
3892 testIOURippleState(features);
3893 testIOUGateway(features);
3894 testIOULockedRate(features);
3895 testIOULimitAmount(features);
3896 testIOURequireAuth(features);
3897 testIOUFreeze(features);
3898 testIOUINSF(features);
3899 testIOUPrecisionLoss(features);
3900 }
3901
3902 void
3904 {
3905 testMPTEnablement(features);
3906 testMPTCreatePreflight(features);
3907 testMPTCreatePreclaim(features);
3908 testMPTFinishPreclaim(features);
3909 testMPTFinishDoApply(features);
3910 testMPTCancelPreclaim(features);
3911 testMPTBalances(features);
3912 testMPTMetaAndOwnership(features);
3913 testMPTGateway(features);
3914 testMPTLockedRate(features);
3915 testMPTRequireAuth(features);
3916 testMPTLock(features);
3917 testMPTCanTransfer(features);
3918 testMPTDestroy(features);
3919 }
3920
3921public:
3922 void
3923 run() override
3924 {
3925 using namespace test::jtx;
3929 testMPTWithFeats(all - fixTokenEscrowV1);
3930 }
3931};
3932
3933BEAST_DEFINE_TESTSUITE(EscrowToken, app, ripple);
3934
3935} // namespace test
3936} // namespace ripple
Represents a JSON value.
Definition json_value.h:130
Value removeMember(char const *key)
Remove and return the named member.
A generic endpoint for log messages.
Definition Journal.h:41
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
A class that simplifies iterating ledger directory pages.
Definition Dir.h:22
const_iterator end() const
Definition Dir.cpp:33
const_iterator begin() const
Definition Dir.cpp:15
A currency issued by an account.
Definition Issue.h:14
Currency currency
Definition Issue.h:16
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:46
Discardable, editable view to a ledger.
Definition Sandbox.h:16
void apply(RawView &to)
Definition Sandbox.h:36
void insert(std::shared_ptr< SLE > const &sle) override
Insert a new state SLE.
Immutable cryptographic account descriptor.
Definition Account.h:20
A transaction testing environment.
Definition Env.h:102
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition Env.cpp:250
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:312
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:103
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition Env.cpp:302
NetClock::time_point now()
Returns the current network time.
Definition Env.h:265
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:772
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:271
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition Env.cpp:259
Converts to IOU Issue or STAmount.
void create(MPTCreate const &arg=MPTCreate{})
Definition mpt.cpp:68
Converts to MPT Issue or STAmount.
ripple::MPTID const & mpt() const
Set the fee on a JTx.
Definition fee.h:18
Match clear account flags.
Definition flags.h:126
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:16
Set the flags on a JTx.
Definition txflags.h:12
T distance(T... args)
T find(T... args)
T is_same_v
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:521
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:507
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Definition Indexes.cpp:370
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:355
std::array< std::uint8_t, 39 > const cb1
Definition escrow.h:52
Json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount)
Definition escrow.cpp:14
auto const finish_time
Set the "FinishAfter" time tag on a JTx.
Definition escrow.h:79
Rate rate(Env &env, Account const &account, std::uint32_t const &seq)
Definition escrow.cpp:50
auto const fulfillment
Definition escrow.h:86
Json::Value cancel(AccountID const &account, Account const &from, std::uint32_t seq)
Definition escrow.cpp:38
std::array< std::uint8_t, 39 > const cb2
Definition escrow.h:62
auto const cancel_time
Set the "CancelAfter" time tag on a JTx.
Definition escrow.h:82
std::array< std::uint8_t, 4 > const fb1
Definition escrow.h:50
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
Definition escrow.cpp:26
std::uint32_t ownerCount(Env const &env, Account const &account)
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition flags.h:102
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition trust.cpp:13
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition flags.cpp:10
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:11
FeatureBitset testable_amendments()
Definition Env.h:55
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition rate.cpp:13
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:29
constexpr std::uint32_t asfGlobalFreeze
Definition TxFlags.h:64
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr std::uint32_t tfSetDeepFreeze
Definition TxFlags.h:101
constexpr std::uint32_t asfAllowTrustLineLocking
Definition TxFlags.h:76
constexpr std::uint32_t const tfMPTCanTransfer
Definition TxFlags.h:133
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
Definition Protocol.h:100
constexpr std::uint32_t const tfMPTUnauthorize
Definition TxFlags.h:153
constexpr std::uint32_t tfSetfAuth
Definition TxFlags.h:96
constexpr std::uint32_t tfClearFreeze
Definition TxFlags.h:100
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition View.cpp:743
@ tecNO_LINE_INSUF_RESERVE
Definition TER.h:274
@ tecLIMIT_EXCEEDED
Definition TER.h:343
@ tecOBJECT_NOT_FOUND
Definition TER.h:308
@ tecNO_ISSUER
Definition TER.h:281
@ tecNO_TARGET
Definition TER.h:286
@ tecFROZEN
Definition TER.h:285
@ tecINSUFFICIENT_FUNDS
Definition TER.h:307
@ tecNO_PERMISSION
Definition TER.h:287
@ tecPRECISION_LOSS
Definition TER.h:345
@ tecHAS_OBLIGATIONS
Definition TER.h:299
@ tecPATH_PARTIAL
Definition TER.h:264
@ tecNO_LINE
Definition TER.h:283
@ tecINSUFFICIENT_RESERVE
Definition TER.h:289
@ tecNO_AUTH
Definition TER.h:282
@ tecLOCKED
Definition TER.h:340
constexpr std::uint32_t const tfMPTLock
Definition TxFlags.h:157
@ tesSUCCESS
Definition TER.h:226
constexpr std::uint32_t tfClearDeepFreeze
Definition TxFlags.h:102
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
STAmount amountFromString(Asset const &asset, std::string const &amount)
Definition STAmount.cpp:977
@ tapNONE
Definition ApplyView.h:12
constexpr std::uint32_t asfRequireAuth
Definition TxFlags.h:59
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
Definition Indexes.cpp:151
constexpr std::uint32_t const tfMPTCanEscrow
Definition TxFlags.h:131
constexpr std::uint32_t const tfMPTRequireAuth
Definition TxFlags.h:130
constexpr std::uint32_t tfSetFreeze
Definition TxFlags.h:99
constexpr std::uint32_t const tfMPTCanLock
Definition TxFlags.h:129
@ temBAD_AMOUNT
Definition TER.h:70
@ temBAD_FEE
Definition TER.h:73
@ temBAD_CURRENCY
Definition TER.h:71
@ temDISABLED
Definition TER.h:95
std::uint32_t value
Definition Rate.h:22
void testMPTBalances(FeatureBitset features)
void testIOUWithFeats(FeatureBitset features)
void testMPTLockedRate(FeatureBitset features)
void testIOUINSF(FeatureBitset features)
void testIOULimitAmount(FeatureBitset features)
void testIOURippleState(FeatureBitset features)
void testMPTFinishPreclaim(FeatureBitset features)
void testMPTGateway(FeatureBitset features)
void testIOULockedRate(FeatureBitset features)
static uint64_t issuerMPTEscrowed(jtx::Env const &env, jtx::MPT const &mpt)
static uint64_t mptEscrowed(jtx::Env const &env, jtx::Account const &account, jtx::MPT const &mpt)
void testIOUEnablement(FeatureBitset features)
void run() override
Runs the suite.
void testIOUFreeze(FeatureBitset features)
void testIOUAllowLockingFlag(FeatureBitset features)
void testMPTCreatePreclaim(FeatureBitset features)
void testIOUFinishDoApply(FeatureBitset features)
jtx::PrettyAmount issuerBalance(jtx::Env &env, jtx::Account const &account, Issue const &issue)
void testMPTRequireAuth(FeatureBitset features)
void testMPTCanTransfer(FeatureBitset features)
void testMPTCreatePreflight(FeatureBitset features)
void testMPTDestroy(FeatureBitset features)
void testMPTLock(FeatureBitset features)
void testIOUCreatePreclaim(FeatureBitset features)
void testIOUPrecisionLoss(FeatureBitset features)
void testIOUBalances(FeatureBitset features)
void testMPTCancelPreclaim(FeatureBitset features)
void testIOUGateway(FeatureBitset features)
void testMPTWithFeats(FeatureBitset features)
void testIOUFinishPreclaim(FeatureBitset features)
void testIOUCreatePreflight(FeatureBitset features)
void testMPTEnablement(FeatureBitset features)
void testMPTFinishDoApply(FeatureBitset features)
void testIOUMetaAndOwnership(FeatureBitset features)
void testIOURequireAuth(FeatureBitset features)
jtx::PrettyAmount issuerEscrowed(jtx::Env &env, jtx::Account const &account, Issue const &issue)
void testIOUCancelPreclaim(FeatureBitset features)
void testMPTMetaAndOwnership(FeatureBitset features)
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Set the sequence number on a JTx.
Definition seq.h:15
seq(autofill_t)
Definition seq.h:21