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 xrpl {
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 bool const largeMantissa = features[featureSingleAssetVault] ||
563 features[featureLendingProtocol];
564
565 // alice cannot create escrow for 1/10 iou - precision loss
566 env(escrow::create(alice, bob, USD(1)),
568 escrow::finish_time(env.now() + 1s),
569 fee(baseFee * 150),
570 ter(largeMantissa ? (TER)tesSUCCESS : (TER)tecPRECISION_LOSS));
571 env.close();
572 }
573 }
574
575 void
577 {
578 testcase("IOU Finish Preclaim");
579 using namespace test::jtx;
580 using namespace std::literals;
581
582 // tecNO_AUTH: requireAuth set: dest not authorized
583 {
584 Env env{*this, features};
585 auto const baseFee = env.current()->fees().base;
586 auto const alice = Account("alice");
587 auto const bob = Account("bob");
588 auto const gw = Account{"gateway"};
589 auto const USD = gw["USD"];
590 auto const aliceUSD = alice["USD"];
591 auto const bobUSD = bob["USD"];
592 env.fund(XRP(5000), alice, bob, gw);
594 env(fset(gw, asfRequireAuth));
595 env.close();
596 env(trust(gw, aliceUSD(10'000)), txflags(tfSetfAuth));
597 env(trust(gw, bobUSD(10'000)), txflags(tfSetfAuth));
598 env.trust(USD(10'000), alice, bob);
599 env.close();
600 env(pay(gw, alice, USD(10'000)));
601 env(pay(gw, bob, USD(10'000)));
602 env.close();
603
604 auto const seq1 = env.seq(alice);
605 env(escrow::create(alice, bob, USD(1)),
607 escrow::finish_time(env.now() + 1s),
608 fee(baseFee * 150),
609 ter(tesSUCCESS));
610 env.close();
611
612 env(pay(bob, gw, USD(10'000)));
613 env(trust(gw, bobUSD(0)), txflags(tfSetfAuth));
614 env(trust(bob, USD(0)));
615 env.close();
616
617 env.trust(USD(10'000), bob);
618 env.close();
619
620 // bob cannot finish because he is not authorized
621 env(escrow::finish(bob, alice, seq1),
624 fee(baseFee * 150),
625 ter(tecNO_AUTH));
626 env.close();
627 }
628
629 // tecFROZEN: issuer has deep frozen the dest
630 {
631 Env env{*this, features};
632 auto const baseFee = env.current()->fees().base;
633 auto const alice = Account("alice");
634 auto const bob = Account("bob");
635 auto const gw = Account{"gateway"};
636 auto const USD = gw["USD"];
637 env.fund(XRP(5000), alice, bob, gw);
639 env.close();
640 env.trust(USD(10'000), alice, bob);
641 env.close();
642 env(pay(gw, alice, USD(10'000)));
643 env(pay(gw, bob, USD(10'000)));
644 env.close();
645
646 auto const seq1 = env.seq(alice);
647 env(escrow::create(alice, bob, USD(1)),
649 escrow::finish_time(env.now() + 1s),
650 fee(baseFee * 150),
651 ter(tesSUCCESS));
652 env.close();
653
654 // set freeze on bob trustline
655 env(trust(gw, USD(10'000), bob, tfSetFreeze | tfSetDeepFreeze));
656
657 // bob cannot finish because of deep freeze
658 env(escrow::finish(bob, alice, seq1),
661 fee(baseFee * 150),
662 ter(tecFROZEN));
663 env.close();
664 }
665 }
666
667 void
669 {
670 testcase("IOU Finish Do Apply");
671 using namespace test::jtx;
672 using namespace std::literals;
673
674 // tecNO_LINE_INSUF_RESERVE: insufficient reserve to create line
675 {
676 Env env{*this, features};
677 auto const baseFee = env.current()->fees().base;
678 auto const acctReserve = env.current()->fees().reserve;
679 auto const incReserve = env.current()->fees().increment;
680 auto const alice = Account("alice");
681 auto const bob = Account("bob");
682 auto const gw = Account{"gateway"};
683 auto const USD = gw["USD"];
684 env.fund(XRP(5000), alice, gw);
685 env.fund(acctReserve + (incReserve - 1), bob);
686 env.close();
688 env.close();
689 env.trust(USD(10'000), alice);
690 env.close();
691 env(pay(gw, alice, USD(10'000)));
692 env.close();
693
694 auto const seq1 = env.seq(alice);
695 env(escrow::create(alice, bob, USD(1)),
697 escrow::finish_time(env.now() + 1s),
698 fee(baseFee * 150),
699 ter(tesSUCCESS));
700 env.close();
701
702 // bob cannot finish because insufficient reserve to create line
703 env(escrow::finish(bob, alice, seq1),
706 fee(baseFee * 150),
708 env.close();
709 }
710
711 // tecNO_LINE: alice submits; finish IOU not created
712 {
713 Env env{*this, features};
714 auto const baseFee = env.current()->fees().base;
715 auto const alice = Account("alice");
716 auto const bob = Account("bob");
717 auto const gw = Account{"gateway"};
718 auto const USD = gw["USD"];
719 env.fund(XRP(5000), alice, bob, gw);
720 env.close();
722 env.close();
723 env.trust(USD(10'000), alice);
724 env.close();
725 env(pay(gw, alice, USD(10'000)));
726 env.close();
727
728 auto const seq1 = env.seq(alice);
729 env(escrow::create(alice, bob, USD(1)),
731 escrow::finish_time(env.now() + 1s),
732 fee(baseFee * 150),
733 ter(tesSUCCESS));
734 env.close();
735
736 // alice cannot finish because bob does not have a trustline
737 env(escrow::finish(alice, alice, seq1),
740 fee(baseFee * 150),
741 ter(tecNO_LINE));
742 env.close();
743 }
744
745 // tecLIMIT_EXCEEDED: alice submits; IOU Limit < balance + amount
746 {
747 Env env{*this, features};
748 auto const baseFee = env.current()->fees().base;
749 auto const alice = Account("alice");
750 auto const bob = Account("bob");
751 auto const gw = Account{"gateway"};
752 auto const USD = gw["USD"];
753 env.fund(XRP(5000), alice, bob, gw);
754 env.close();
756 env.close();
757 env.trust(USD(1000), alice, bob);
758 env.close();
759 env(pay(gw, alice, USD(1000)));
760 env.close();
761
762 auto const seq1 = env.seq(alice);
763 env(escrow::create(alice, bob, USD(5)),
765 escrow::finish_time(env.now() + 1s),
766 fee(baseFee * 150),
767 ter(tesSUCCESS));
768 env.close();
769
770 env.trust(USD(1), bob);
771 env.close();
772
773 // alice cannot finish because bobs limit is too low
774 env(escrow::finish(alice, alice, seq1),
777 fee(baseFee * 150),
779 env.close();
780 }
781
782 // tesSUCCESS: bob submits; IOU Limit < balance + amount
783 {
784 Env env{*this, features};
785 auto const baseFee = env.current()->fees().base;
786 auto const alice = Account("alice");
787 auto const bob = Account("bob");
788 auto const gw = Account{"gateway"};
789 auto const USD = gw["USD"];
790 env.fund(XRP(5000), alice, bob, gw);
791 env.close();
793 env.close();
794 env.trust(USD(1000), alice, bob);
795 env.close();
796 env(pay(gw, alice, USD(1000)));
797 env.close();
798
799 auto const seq1 = env.seq(alice);
800 env(escrow::create(alice, bob, USD(5)),
802 escrow::finish_time(env.now() + 1s),
803 fee(baseFee * 150),
804 ter(tesSUCCESS));
805 env.close();
806
807 env.trust(USD(1), bob);
808 env.close();
809
810 // bob can finish even if bobs limit is too low
811 auto const bobPreLimit = env.limit(bob, USD);
812
813 env(escrow::finish(bob, alice, seq1),
816 fee(baseFee * 150),
817 ter(tesSUCCESS));
818 env.close();
819
820 // bobs limit is not changed
821 BEAST_EXPECT(env.limit(bob, USD) == bobPreLimit);
822 }
823 }
824
825 void
827 {
828 testcase("IOU Cancel Preclaim");
829 using namespace test::jtx;
830 using namespace std::literals;
831
832 // tecNO_AUTH: requireAuth set: account not authorized
833 {
834 Env env{*this, features};
835 auto const baseFee = env.current()->fees().base;
836 auto const alice = Account("alice");
837 auto const bob = Account("bob");
838 auto const gw = Account{"gateway"};
839 auto const USD = gw["USD"];
840 auto const aliceUSD = alice["USD"];
841 auto const bobUSD = bob["USD"];
842 env.fund(XRP(5000), alice, bob, gw);
844 env(fset(gw, asfRequireAuth));
845 env.close();
846 env(trust(gw, aliceUSD(10'000)), txflags(tfSetfAuth));
847 env(trust(gw, bobUSD(10'000)), txflags(tfSetfAuth));
848 env.trust(USD(10'000), alice, bob);
849 env.close();
850 env(pay(gw, alice, USD(10'000)));
851 env(pay(gw, bob, USD(10'000)));
852 env.close();
853
854 auto const seq1 = env.seq(alice);
855 env(escrow::create(alice, bob, USD(1)),
856 escrow::finish_time(env.now() + 1s),
857 escrow::cancel_time(env.now() + 2s),
858 fee(baseFee),
859 ter(tesSUCCESS));
860 env.close();
861
862 env(pay(alice, gw, USD(9'999)));
863 env(trust(gw, aliceUSD(0)), txflags(tfSetfAuth));
864 env(trust(alice, USD(0)));
865 env.close();
866
867 env.trust(USD(10'000), alice);
868 env.close();
869
870 // alice cannot cancel because she is not authorized
871 env(escrow::cancel(bob, alice, seq1),
872 fee(baseFee),
873 ter(tecNO_AUTH));
874 env.close();
875 }
876 }
877
878 void
880 {
881 testcase("IOU Balances");
882
883 using namespace jtx;
884 using namespace std::chrono;
885
886 Env env{*this, features};
887 auto const baseFee = env.current()->fees().base;
888 auto const alice = Account("alice");
889 auto const bob = Account("bob");
890 auto const gw = Account{"gateway"};
891 auto const USD = gw["USD"];
892 env.fund(XRP(5000), alice, bob, gw);
894 env.close();
895 env.trust(USD(10'000), alice, bob);
896 env.close();
897 env(pay(gw, alice, USD(5'000)));
898 env(pay(gw, bob, USD(5'000)));
899 env.close();
900
901 auto const outstandingUSD = USD(10'000);
902
903 // Create & Finish Escrow
904 auto const seq1 = env.seq(alice);
905 {
906 auto const preAliceUSD = env.balance(alice, USD);
907 auto const preBobUSD = env.balance(bob, USD);
908 env(escrow::create(alice, bob, USD(1'000)),
910 escrow::finish_time(env.now() + 1s),
911 fee(baseFee * 150),
912 ter(tesSUCCESS));
913 env.close();
914
915 BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD - USD(1'000));
916 BEAST_EXPECT(env.balance(bob, USD) == preBobUSD);
917 BEAST_EXPECT(
918 issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000));
919 BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(1'000));
920 }
921 {
922 auto const preAliceUSD = env.balance(alice, USD);
923 auto const preBobUSD = env.balance(bob, USD);
924 env(escrow::finish(bob, alice, seq1),
927 fee(baseFee * 150),
928 ter(tesSUCCESS));
929 env.close();
930
931 BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD);
932 BEAST_EXPECT(env.balance(bob, USD) == preBobUSD + USD(1'000));
933 BEAST_EXPECT(issuerBalance(env, gw, USD) == outstandingUSD);
934 BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(0));
935 }
936
937 // Create & Cancel Escrow
938 auto const seq2 = env.seq(alice);
939 {
940 auto const preAliceUSD = env.balance(alice, USD);
941 auto const preBobUSD = env.balance(bob, USD);
942 env(escrow::create(alice, bob, USD(1'000)),
944 escrow::finish_time(env.now() + 1s),
945 escrow::cancel_time(env.now() + 2s),
946 fee(baseFee * 150),
947 ter(tesSUCCESS));
948 env.close();
949
950 BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD - USD(1'000));
951 BEAST_EXPECT(env.balance(bob, USD) == preBobUSD);
952 BEAST_EXPECT(
953 issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000));
954 BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(1'000));
955 }
956 {
957 auto const preAliceUSD = env.balance(alice, USD);
958 auto const preBobUSD = env.balance(bob, USD);
959 env(escrow::cancel(bob, alice, seq2), ter(tesSUCCESS));
960 env.close();
961
962 BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD + USD(1'000));
963 BEAST_EXPECT(env.balance(bob, USD) == preBobUSD);
964 BEAST_EXPECT(issuerBalance(env, gw, USD) == outstandingUSD);
965 BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(0));
966 }
967 }
968
969 void
971 {
972 using namespace jtx;
973 using namespace std::chrono;
974
975 auto const alice = Account("alice");
976 auto const bob = Account("bob");
977 auto const carol = Account("carol");
978 auto const gw = Account{"gateway"};
979 auto const USD = gw["USD"];
980 {
981 testcase("IOU Metadata to self");
982
983 Env env{*this, features};
984 env.fund(XRP(5000), alice, bob, carol, gw);
986 env.close();
987 env.trust(USD(10'000), alice, bob, carol);
988 env.close();
989 env(pay(gw, alice, USD(5000)));
990 env(pay(gw, bob, USD(5000)));
991 env(pay(gw, carol, USD(5000)));
992 env.close();
993 auto const aseq = env.seq(alice);
994 auto const bseq = env.seq(bob);
995
996 env(escrow::create(alice, alice, USD(1'000)),
997 escrow::finish_time(env.now() + 1s),
998 escrow::cancel_time(env.now() + 500s));
999 BEAST_EXPECT(
1000 (*env.meta())[sfTransactionResult] ==
1001 static_cast<std::uint8_t>(tesSUCCESS));
1002 env.close(5s);
1003 auto const aa = env.le(keylet::escrow(alice.id(), aseq));
1004 BEAST_EXPECT(aa);
1005 {
1006 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1007 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
1008 BEAST_EXPECT(
1009 std::find(aod.begin(), aod.end(), aa) != aod.end());
1010 }
1011
1012 {
1013 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1014 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4);
1015 BEAST_EXPECT(
1016 std::find(iod.begin(), iod.end(), aa) != iod.end());
1017 }
1018
1019 env(escrow::create(bob, bob, USD(1'000)),
1020 escrow::finish_time(env.now() + 1s),
1021 escrow::cancel_time(env.now() + 2s));
1022 BEAST_EXPECT(
1023 (*env.meta())[sfTransactionResult] ==
1024 static_cast<std::uint8_t>(tesSUCCESS));
1025 env.close(5s);
1026 auto const bb = env.le(keylet::escrow(bob.id(), bseq));
1027 BEAST_EXPECT(bb);
1028
1029 {
1030 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1031 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1032 BEAST_EXPECT(
1033 std::find(bod.begin(), bod.end(), bb) != bod.end());
1034 }
1035
1036 {
1037 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1038 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 5);
1039 BEAST_EXPECT(
1040 std::find(iod.begin(), iod.end(), bb) != iod.end());
1041 }
1042
1043 env.close(5s);
1044 env(escrow::finish(alice, alice, aseq));
1045 {
1046 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1047 BEAST_EXPECT(
1048 (*env.meta())[sfTransactionResult] ==
1049 static_cast<std::uint8_t>(tesSUCCESS));
1050
1051 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1052 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1053 BEAST_EXPECT(
1054 std::find(aod.begin(), aod.end(), aa) == aod.end());
1055
1056 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1057 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1058 BEAST_EXPECT(
1059 std::find(bod.begin(), bod.end(), bb) != bod.end());
1060
1061 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1062 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4);
1063 BEAST_EXPECT(
1064 std::find(iod.begin(), iod.end(), bb) != iod.end());
1065 }
1066
1067 env.close(5s);
1068 env(escrow::cancel(bob, bob, bseq));
1069 {
1070 BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq)));
1071 BEAST_EXPECT(
1072 (*env.meta())[sfTransactionResult] ==
1073 static_cast<std::uint8_t>(tesSUCCESS));
1074
1075 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1076 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1077 BEAST_EXPECT(
1078 std::find(bod.begin(), bod.end(), bb) == bod.end());
1079
1080 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1081 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3);
1082 BEAST_EXPECT(
1083 std::find(iod.begin(), iod.end(), bb) == iod.end());
1084 }
1085 }
1086 {
1087 testcase("IOU Metadata to other");
1088
1089 Env env{*this, features};
1090 env.fund(XRP(5000), alice, bob, carol, gw);
1092 env.close();
1093 env.trust(USD(10'000), alice, bob, carol);
1094 env.close();
1095 env(pay(gw, alice, USD(5000)));
1096 env(pay(gw, bob, USD(5000)));
1097 env(pay(gw, carol, USD(5000)));
1098 env.close();
1099 auto const aseq = env.seq(alice);
1100 auto const bseq = env.seq(bob);
1101
1102 env(escrow::create(alice, bob, USD(1'000)),
1103 escrow::finish_time(env.now() + 1s));
1104 BEAST_EXPECT(
1105 (*env.meta())[sfTransactionResult] ==
1106 static_cast<std::uint8_t>(tesSUCCESS));
1107 env.close(5s);
1108 env(escrow::create(bob, carol, USD(1'000)),
1109 escrow::finish_time(env.now() + 1s),
1110 escrow::cancel_time(env.now() + 2s));
1111 BEAST_EXPECT(
1112 (*env.meta())[sfTransactionResult] ==
1113 static_cast<std::uint8_t>(tesSUCCESS));
1114 env.close(5s);
1115
1116 auto const ab = env.le(keylet::escrow(alice.id(), aseq));
1117 BEAST_EXPECT(ab);
1118
1119 auto const bc = env.le(keylet::escrow(bob.id(), bseq));
1120 BEAST_EXPECT(bc);
1121
1122 {
1123 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1124 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
1125 BEAST_EXPECT(
1126 std::find(aod.begin(), aod.end(), ab) != aod.end());
1127
1128 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1129 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 3);
1130 BEAST_EXPECT(
1131 std::find(bod.begin(), bod.end(), ab) != bod.end());
1132 BEAST_EXPECT(
1133 std::find(bod.begin(), bod.end(), bc) != bod.end());
1134
1135 xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1136 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2);
1137 BEAST_EXPECT(
1138 std::find(cod.begin(), cod.end(), bc) != cod.end());
1139
1140 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1141 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 5);
1142 BEAST_EXPECT(
1143 std::find(iod.begin(), iod.end(), ab) != iod.end());
1144 BEAST_EXPECT(
1145 std::find(iod.begin(), iod.end(), bc) != iod.end());
1146 }
1147
1148 env.close(5s);
1149 env(escrow::finish(alice, alice, aseq));
1150 {
1151 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1152 BEAST_EXPECT(env.le(keylet::escrow(bob.id(), bseq)));
1153
1154 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1155 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1156 BEAST_EXPECT(
1157 std::find(aod.begin(), aod.end(), ab) == aod.end());
1158
1159 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1160 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1161 BEAST_EXPECT(
1162 std::find(bod.begin(), bod.end(), ab) == bod.end());
1163 BEAST_EXPECT(
1164 std::find(bod.begin(), bod.end(), bc) != bod.end());
1165
1166 xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1167 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2);
1168
1169 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1170 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4);
1171 BEAST_EXPECT(
1172 std::find(iod.begin(), iod.end(), ab) == iod.end());
1173 BEAST_EXPECT(
1174 std::find(iod.begin(), iod.end(), bc) != iod.end());
1175 }
1176
1177 env.close(5s);
1178 env(escrow::cancel(bob, bob, bseq));
1179 {
1180 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1181 BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq)));
1182
1183 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1184 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1185 BEAST_EXPECT(
1186 std::find(aod.begin(), aod.end(), ab) == aod.end());
1187
1188 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
1189 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1190 BEAST_EXPECT(
1191 std::find(bod.begin(), bod.end(), ab) == bod.end());
1192 BEAST_EXPECT(
1193 std::find(bod.begin(), bod.end(), bc) == bod.end());
1194
1195 xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1196 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1197
1198 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1199 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3);
1200 BEAST_EXPECT(
1201 std::find(iod.begin(), iod.end(), ab) == iod.end());
1202 BEAST_EXPECT(
1203 std::find(iod.begin(), iod.end(), bc) == iod.end());
1204 }
1205 }
1206
1207 {
1208 testcase("IOU Metadata to issuer");
1209
1210 Env env{*this, features};
1211 env.fund(XRP(5000), alice, carol, gw);
1213 env.close();
1214 env.trust(USD(10'000), alice, carol);
1215 env.close();
1216 env(pay(gw, alice, USD(5000)));
1217 env(pay(gw, carol, USD(5000)));
1218 env.close();
1219 auto const aseq = env.seq(alice);
1220
1221 env(escrow::create(alice, gw, USD(1'000)),
1222 escrow::finish_time(env.now() + 1s));
1223
1224 BEAST_EXPECT(
1225 (*env.meta())[sfTransactionResult] ==
1226 static_cast<std::uint8_t>(tesSUCCESS));
1227 env.close(5s);
1228 env(escrow::create(gw, carol, USD(1'000)),
1229 escrow::finish_time(env.now() + 1s),
1230 escrow::cancel_time(env.now() + 2s),
1232 env.close(5s);
1233
1234 auto const ag = env.le(keylet::escrow(alice.id(), aseq));
1235 BEAST_EXPECT(ag);
1236
1237 {
1238 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1239 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
1240 BEAST_EXPECT(
1241 std::find(aod.begin(), aod.end(), ag) != aod.end());
1242
1243 xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1244 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1245
1246 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1247 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3);
1248 BEAST_EXPECT(
1249 std::find(iod.begin(), iod.end(), ag) != iod.end());
1250 }
1251
1252 env.close(5s);
1253 env(escrow::finish(alice, alice, aseq));
1254 {
1255 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1256
1257 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1258 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1259 BEAST_EXPECT(
1260 std::find(aod.begin(), aod.end(), ag) == aod.end());
1261
1262 xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1263 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1264
1265 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
1266 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 2);
1267 BEAST_EXPECT(
1268 std::find(iod.begin(), iod.end(), ag) == iod.end());
1269 }
1270 }
1271 }
1272
1273 void
1275 {
1276 testcase("IOU RippleState");
1277 using namespace test::jtx;
1278 using namespace std::literals;
1279
1280 struct TestAccountData
1281 {
1282 Account src;
1283 Account dst;
1284 Account gw;
1285 bool hasTrustline;
1286 bool negative;
1287 };
1288
1290 // src > dst && src > issuer && dst no trustline
1291 {Account("alice2"), Account("bob0"), Account{"gw0"}, false, true},
1292 // src < dst && src < issuer && dst no trustline
1293 {Account("carol0"), Account("dan1"), Account{"gw1"}, false, false},
1294 // dst > src && dst > issuer && dst no trustline
1295 {Account("dan1"), Account("alice2"), Account{"gw0"}, false, true},
1296 // dst < src && dst < issuer && dst no trustline
1297 {Account("bob0"), Account("carol0"), Account{"gw1"}, false, false},
1298 // src > dst && src > issuer && dst has trustline
1299 {Account("alice2"), Account("bob0"), Account{"gw0"}, true, true},
1300 // src < dst && src < issuer && dst has trustline
1301 {Account("carol0"), Account("dan1"), Account{"gw1"}, true, false},
1302 // dst > src && dst > issuer && dst has trustline
1303 {Account("dan1"), Account("alice2"), Account{"gw0"}, true, true},
1304 // dst < src && dst < issuer && dst has trustline
1305 {Account("bob0"), Account("carol0"), Account{"gw1"}, true, false},
1306 }};
1307
1308 for (auto const& t : tests)
1309 {
1310 Env env{*this, features};
1311 auto const baseFee = env.current()->fees().base;
1312 auto const USD = t.gw["USD"];
1313 env.fund(XRP(5000), t.src, t.dst, t.gw);
1314 env(fset(t.gw, asfAllowTrustLineLocking));
1315 env.close();
1316
1317 if (t.hasTrustline)
1318 env.trust(USD(100'000), t.src, t.dst);
1319 else
1320 env.trust(USD(100'000), t.src);
1321 env.close();
1322
1323 env(pay(t.gw, t.src, USD(10'000)));
1324 if (t.hasTrustline)
1325 env(pay(t.gw, t.dst, USD(10'000)));
1326 env.close();
1327
1328 // src can create escrow
1329 auto const seq1 = env.seq(t.src);
1330 auto const delta = USD(1'000);
1331 env(escrow::create(t.src, t.dst, delta),
1333 escrow::finish_time(env.now() + 1s),
1334 fee(baseFee * 150));
1335 env.close();
1336
1337 // dst can finish escrow
1338 auto const preSrc = env.balance(t.src, USD);
1339 auto const preDst = env.balance(t.dst, USD);
1340
1341 env(escrow::finish(t.dst, t.src, seq1),
1344 fee(baseFee * 150));
1345 env.close();
1346
1347 BEAST_EXPECT(env.balance(t.src, USD) == preSrc);
1348 BEAST_EXPECT(env.balance(t.dst, USD) == preDst + delta);
1349 }
1350 }
1351
1352 void
1354 {
1355 testcase("IOU Gateway");
1356 using namespace test::jtx;
1357 using namespace std::literals;
1358
1359 struct TestAccountData
1360 {
1361 Account src;
1362 Account dst;
1363 bool hasTrustline;
1364 };
1365
1366 // issuer is source
1367 {
1368 auto const gw = Account{"gateway"};
1369 auto const alice = Account{"alice"};
1370 Env env{*this, features};
1371 auto const baseFee = env.current()->fees().base;
1372 auto const USD = gw["USD"];
1373 env.fund(XRP(5000), alice, gw);
1375 env.close();
1376 env.trust(USD(100'000), alice);
1377 env.close();
1378
1379 env(pay(gw, alice, USD(10'000)));
1380 env.close();
1381
1382 // issuer cannot create escrow
1383 env(escrow::create(gw, alice, USD(1'000)),
1385 escrow::finish_time(env.now() + 1s),
1386 fee(baseFee * 150),
1388 env.close();
1389 }
1390
1391 std::array<TestAccountData, 4> gwDstTests = {{
1392 // src > dst && src > issuer && dst has trustline
1393 {Account("alice2"), Account{"gw0"}, true},
1394 // src < dst && src < issuer && dst has trustline
1395 {Account("carol0"), Account{"gw1"}, true},
1396 // dst > src && dst > issuer && dst has trustline
1397 {Account("dan1"), Account{"gw0"}, true},
1398 // dst < src && dst < issuer && dst has trustline
1399 {Account("bob0"), Account{"gw1"}, true},
1400 }};
1401
1402 // issuer is destination
1403 for (auto const& t : gwDstTests)
1404 {
1405 Env env{*this, features};
1406 auto const baseFee = env.current()->fees().base;
1407 auto const USD = t.dst["USD"];
1408 env.fund(XRP(5000), t.dst, t.src);
1409 env(fset(t.dst, asfAllowTrustLineLocking));
1410 env.close();
1411
1412 env.trust(USD(100'000), t.src);
1413 env.close();
1414
1415 env(pay(t.dst, t.src, USD(10'000)));
1416 env.close();
1417
1418 // issuer can receive escrow
1419 auto const seq1 = env.seq(t.src);
1420 auto const preSrc = env.balance(t.src, USD);
1421 env(escrow::create(t.src, t.dst, USD(1'000)),
1423 escrow::finish_time(env.now() + 1s),
1424 fee(baseFee * 150));
1425 env.close();
1426
1427 // issuer can finish escrow, no dest trustline
1428 env(escrow::finish(t.dst, t.src, seq1),
1431 fee(baseFee * 150));
1432 env.close();
1433 auto const preAmount = 10'000;
1434 BEAST_EXPECT(preSrc == USD(preAmount));
1435 auto const postAmount = 9000;
1436 BEAST_EXPECT(env.balance(t.src, USD) == USD(postAmount));
1437 BEAST_EXPECT(env.balance(t.dst, USD) == USD(0));
1438 }
1439
1440 // issuer is source and destination
1441 {
1442 auto const gw = Account{"gateway"};
1443 auto const USD = gw["USD"];
1444 Env env{*this, features};
1445 auto const baseFee = env.current()->fees().base;
1446 env.fund(XRP(5000), gw);
1448 env.close();
1449
1450 // issuer cannot receive escrow
1451 env(escrow::create(gw, gw, USD(1'000)),
1453 escrow::finish_time(env.now() + 1s),
1454 fee(baseFee * 150),
1456 env.close();
1457 }
1458 }
1459
1460 void
1462 {
1463 testcase("IOU Locked Rate");
1464 using namespace test::jtx;
1465 using namespace std::literals;
1466
1467 auto const alice = Account("alice");
1468 auto const bob = Account("bob");
1469 auto const carol = Account("carol");
1470 auto const gw = Account{"gateway"};
1471 auto const USD = gw["USD"];
1472
1473 // test locked rate
1474 {
1475 Env env{*this, features};
1476 auto const baseFee = env.current()->fees().base;
1477 env.fund(XRP(10'000), alice, bob, gw);
1479 env(rate(gw, 1.25));
1480 env.close();
1481 env.trust(USD(100'000), alice);
1482 env.trust(USD(100'000), bob);
1483 env.close();
1484 env(pay(gw, alice, USD(10'000)));
1485 env(pay(gw, bob, USD(10'000)));
1486 env.close();
1487
1488 // alice can create escrow w/ xfer rate
1489 auto const preAlice = env.balance(alice, USD);
1490 auto const seq1 = env.seq(alice);
1491 auto const delta = USD(125);
1492 env(escrow::create(alice, bob, delta),
1494 escrow::finish_time(env.now() + 1s),
1495 fee(baseFee * 150));
1496 env.close();
1497 auto const transferRate = escrow::rate(env, alice, seq1);
1498 BEAST_EXPECT(
1499 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
1500
1501 // bob can finish escrow
1502 env(escrow::finish(bob, alice, seq1),
1505 fee(baseFee * 150));
1506 env.close();
1507
1508 BEAST_EXPECT(env.balance(alice, USD) == preAlice - delta);
1509 BEAST_EXPECT(env.balance(bob, USD) == USD(10'100));
1510 }
1511 // test rate change - higher
1512 {
1513 Env env{*this, features};
1514 auto const baseFee = env.current()->fees().base;
1515 env.fund(XRP(10'000), alice, bob, gw);
1517 env(rate(gw, 1.25));
1518 env.close();
1519 env.trust(USD(100'000), alice);
1520 env.trust(USD(100'000), bob);
1521 env.close();
1522 env(pay(gw, alice, USD(10'000)));
1523 env(pay(gw, bob, USD(10'000)));
1524 env.close();
1525
1526 // alice can create escrow w/ xfer rate
1527 auto const preAlice = env.balance(alice, USD);
1528 auto const seq1 = env.seq(alice);
1529 auto const delta = USD(125);
1530 env(escrow::create(alice, bob, delta),
1532 escrow::finish_time(env.now() + 1s),
1533 fee(baseFee * 150));
1534 env.close();
1535 auto transferRate = escrow::rate(env, alice, seq1);
1536 BEAST_EXPECT(
1537 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
1538
1539 // issuer changes rate higher
1540 env(rate(gw, 1.26));
1541 env.close();
1542
1543 // bob can finish escrow - rate unchanged
1544 env(escrow::finish(bob, alice, seq1),
1547 fee(baseFee * 150));
1548 env.close();
1549
1550 BEAST_EXPECT(env.balance(alice, USD) == preAlice - delta);
1551 BEAST_EXPECT(env.balance(bob, USD) == USD(10'100));
1552 }
1553
1554 // test rate change - lower
1555 {
1556 Env env{*this, features};
1557 auto const baseFee = env.current()->fees().base;
1558 env.fund(XRP(10'000), alice, bob, gw);
1560 env(rate(gw, 1.25));
1561 env.close();
1562 env.trust(USD(100'000), alice);
1563 env.trust(USD(100'000), bob);
1564 env.close();
1565 env(pay(gw, alice, USD(10'000)));
1566 env(pay(gw, bob, USD(10'000)));
1567 env.close();
1568
1569 // alice can create escrow w/ xfer rate
1570 auto const preAlice = env.balance(alice, USD);
1571 auto const seq1 = env.seq(alice);
1572 auto const delta = USD(125);
1573 env(escrow::create(alice, bob, delta),
1575 escrow::finish_time(env.now() + 1s),
1576 fee(baseFee * 150));
1577 env.close();
1578 auto transferRate = escrow::rate(env, alice, seq1);
1579 BEAST_EXPECT(
1580 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
1581
1582 // issuer changes rate lower
1583 env(rate(gw, 1.00));
1584 env.close();
1585
1586 // bob can finish escrow - rate changed
1587 env(escrow::finish(bob, alice, seq1),
1590 fee(baseFee * 150));
1591 env.close();
1592
1593 BEAST_EXPECT(env.balance(alice, USD) == preAlice - delta);
1594 BEAST_EXPECT(env.balance(bob, USD) == USD(10125));
1595 }
1596
1597 // test cancel doesn't charge rate
1598 {
1599 Env env{*this, features};
1600 auto const baseFee = env.current()->fees().base;
1601 env.fund(XRP(10'000), alice, bob, gw);
1603 env(rate(gw, 1.25));
1604 env.close();
1605 env.trust(USD(100'000), alice);
1606 env.trust(USD(100'000), bob);
1607 env.close();
1608 env(pay(gw, alice, USD(10'000)));
1609 env(pay(gw, bob, USD(10'000)));
1610 env.close();
1611
1612 // alice can create escrow w/ xfer rate
1613 auto const preAlice = env.balance(alice, USD);
1614 auto const seq1 = env.seq(alice);
1615 auto const delta = USD(125);
1616 env(escrow::create(alice, bob, delta),
1617 escrow::finish_time(env.now() + 1s),
1618 escrow::cancel_time(env.now() + 3s),
1619 fee(baseFee));
1620 env.close();
1621 auto transferRate = escrow::rate(env, alice, seq1);
1622 BEAST_EXPECT(
1623 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
1624
1625 // issuer changes rate lower
1626 env(rate(gw, 1.00));
1627 env.close();
1628
1629 // alice can cancel escrow - rate is not charged
1630 env(escrow::cancel(alice, alice, seq1), fee(baseFee));
1631 env.close();
1632
1633 BEAST_EXPECT(env.balance(alice, USD) == preAlice);
1634 BEAST_EXPECT(env.balance(bob, USD) == USD(10000));
1635 }
1636 }
1637
1638 void
1640 {
1641 testcase("IOU Limit");
1642 using namespace test::jtx;
1643 using namespace std::literals;
1644
1645 auto const alice = Account("alice");
1646 auto const bob = Account("bob");
1647 auto const gw = Account{"gateway"};
1648 auto const USD = gw["USD"];
1649
1650 // test LimitAmount
1651 {
1652 Env env{*this, features};
1653 auto const baseFee = env.current()->fees().base;
1654 env.fund(XRP(1'000), alice, bob, gw);
1656 env.close();
1657 env.trust(USD(10'000), alice, bob);
1658 env.close();
1659 env(pay(gw, alice, USD(1'000)));
1660 env(pay(gw, bob, USD(1'000)));
1661 env.close();
1662
1663 // alice can create escrow
1664 auto seq1 = env.seq(alice);
1665 auto const delta = USD(125);
1666 env(escrow::create(alice, bob, delta),
1668 escrow::finish_time(env.now() + 1s),
1669 fee(baseFee * 150));
1670 env.close();
1671
1672 // bob can finish
1673 auto const preBobLimit = env.limit(bob, USD);
1674 env(escrow::finish(bob, alice, seq1),
1677 fee(baseFee * 150));
1678 env.close();
1679 auto const postBobLimit = env.limit(bob, USD);
1680 // bobs limit is NOT changed
1681 BEAST_EXPECT(postBobLimit == preBobLimit);
1682 }
1683 }
1684
1685 void
1687 {
1688 testcase("IOU Require Auth");
1689 using namespace test::jtx;
1690 using namespace std::literals;
1691
1692 auto const alice = Account("alice");
1693 auto const bob = Account("bob");
1694 auto const carol = Account("carol");
1695 auto const gw = Account{"gateway"};
1696 auto const USD = gw["USD"];
1697
1698 auto const aliceUSD = alice["USD"];
1699 auto const bobUSD = bob["USD"];
1700
1701 Env env{*this, features};
1702 auto const baseFee = env.current()->fees().base;
1703 env.fund(XRP(1'000), alice, bob, gw);
1705 env(fset(gw, asfRequireAuth));
1706 env.close();
1707 env(trust(gw, aliceUSD(10'000)), txflags(tfSetfAuth));
1708 env(trust(alice, USD(10'000)));
1709 env(trust(bob, USD(10'000)));
1710 env.close();
1711 env(pay(gw, alice, USD(1'000)));
1712 env.close();
1713
1714 // alice cannot create escrow - fails without auth
1715 auto seq1 = env.seq(alice);
1716 auto const delta = USD(125);
1717 env(escrow::create(alice, bob, delta),
1719 escrow::finish_time(env.now() + 1s),
1720 fee(baseFee * 150),
1721 ter(tecNO_AUTH));
1722 env.close();
1723
1724 // set auth on bob
1725 env(trust(gw, bobUSD(10'000)), txflags(tfSetfAuth));
1726 env(trust(bob, USD(10'000)));
1727 env.close();
1728 env(pay(gw, bob, USD(1'000)));
1729 env.close();
1730
1731 // alice can create escrow - bob has auth
1732 seq1 = env.seq(alice);
1733 env(escrow::create(alice, bob, delta),
1735 escrow::finish_time(env.now() + 1s),
1736 fee(baseFee * 150));
1737 env.close();
1738
1739 // bob can finish
1740 env(escrow::finish(bob, alice, seq1),
1743 fee(baseFee * 150));
1744 env.close();
1745 }
1746
1747 void
1749 {
1750 testcase("IOU Freeze");
1751 using namespace test::jtx;
1752 using namespace std::literals;
1753
1754 auto const alice = Account("alice");
1755 auto const bob = Account("bob");
1756 auto const carol = Account("carol");
1757 auto const gw = Account{"gateway"};
1758 auto const USD = gw["USD"];
1759
1760 // test Global Freeze
1761 {
1762 Env env{*this, features};
1763 auto const baseFee = env.current()->fees().base;
1764 env.fund(XRP(10'000), alice, bob, gw);
1766 env.close();
1767 env.trust(USD(100'000), alice);
1768 env.trust(USD(100'000), bob);
1769 env.close();
1770 env(pay(gw, alice, USD(10'000)));
1771 env(pay(gw, bob, USD(10'000)));
1772 env.close();
1773 env(fset(gw, asfGlobalFreeze));
1774 env.close();
1775
1776 // setup transaction
1777 auto seq1 = env.seq(alice);
1778 auto const delta = USD(125);
1779
1780 // create escrow fails - frozen trustline
1781 env(escrow::create(alice, bob, delta),
1783 escrow::finish_time(env.now() + 1s),
1784 fee(baseFee * 150),
1785 ter(tecFROZEN));
1786 env.close();
1787
1788 // clear global freeze
1789 env(fclear(gw, asfGlobalFreeze));
1790 env.close();
1791
1792 // create escrow success
1793 seq1 = env.seq(alice);
1794 env(escrow::create(alice, bob, delta),
1796 escrow::finish_time(env.now() + 1s),
1797 fee(baseFee * 150));
1798 env.close();
1799
1800 // set global freeze
1801 env(fset(gw, asfGlobalFreeze));
1802 env.close();
1803
1804 // bob finish escrow success regardless of frozen assets
1805 env(escrow::finish(bob, alice, seq1),
1808 fee(baseFee * 150));
1809 env.close();
1810
1811 // clear global freeze
1812 env(fclear(gw, asfGlobalFreeze));
1813 env.close();
1814
1815 // create escrow success
1816 seq1 = env.seq(alice);
1817 env(escrow::create(alice, bob, delta),
1819 escrow::cancel_time(env.now() + 1s),
1820 fee(baseFee * 150));
1821 env.close();
1822
1823 // set global freeze
1824 env(fset(gw, asfGlobalFreeze));
1825 env.close();
1826
1827 // bob cancel escrow success regardless of frozen assets
1828 env(escrow::cancel(bob, alice, seq1), fee(baseFee));
1829 env.close();
1830 }
1831
1832 // test Individual Freeze
1833 {
1834 // Env Setup
1835 Env env{*this, features};
1836 auto const baseFee = env.current()->fees().base;
1837 env.fund(XRP(10'000), alice, bob, gw);
1839 env.close();
1840 env(trust(alice, USD(100'000)));
1841 env(trust(bob, USD(100'000)));
1842 env.close();
1843 env(pay(gw, alice, USD(10'000)));
1844 env(pay(gw, bob, USD(10'000)));
1845 env.close();
1846
1847 // set freeze on alice trustline
1848 env(trust(gw, USD(10'000), alice, tfSetFreeze));
1849 env.close();
1850
1851 // setup transaction
1852 auto seq1 = env.seq(alice);
1853 auto const delta = USD(125);
1854
1855 // create escrow fails - frozen trustline
1856 env(escrow::create(alice, bob, delta),
1858 escrow::finish_time(env.now() + 1s),
1859 fee(baseFee * 150),
1860 ter(tecFROZEN));
1861 env.close();
1862
1863 // clear freeze on alice trustline
1864 env(trust(gw, USD(10'000), alice, tfClearFreeze));
1865 env.close();
1866
1867 // create escrow success
1868 seq1 = env.seq(alice);
1869 env(escrow::create(alice, bob, delta),
1871 escrow::finish_time(env.now() + 1s),
1872 fee(baseFee * 150));
1873 env.close();
1874
1875 // set freeze on bob trustline
1876 env(trust(gw, USD(10'000), bob, tfSetFreeze));
1877 env.close();
1878
1879 // bob finish escrow success regardless of frozen assets
1880 env(escrow::finish(bob, alice, seq1),
1883 fee(baseFee * 150));
1884 env.close();
1885
1886 // reset freeze on bob and alice trustline
1887 env(trust(gw, USD(10'000), alice, tfClearFreeze));
1888 env(trust(gw, USD(10'000), bob, tfClearFreeze));
1889 env.close();
1890
1891 // create escrow success
1892 seq1 = env.seq(alice);
1893 env(escrow::create(alice, bob, delta),
1895 escrow::cancel_time(env.now() + 1s),
1896 fee(baseFee * 150));
1897 env.close();
1898
1899 // set freeze on bob trustline
1900 env(trust(gw, USD(10'000), bob, tfSetFreeze));
1901 env.close();
1902
1903 // bob cancel escrow success regardless of frozen assets
1904 env(escrow::cancel(bob, alice, seq1), fee(baseFee));
1905 env.close();
1906 }
1907
1908 // test Deep Freeze
1909 {
1910 // Env Setup
1911 Env env{*this, features};
1912 auto const baseFee = env.current()->fees().base;
1913 env.fund(XRP(10'000), alice, bob, gw);
1915 env.close();
1916 env(trust(alice, USD(100'000)));
1917 env(trust(bob, USD(100'000)));
1918 env.close();
1919 env(pay(gw, alice, USD(10'000)));
1920 env(pay(gw, bob, USD(10'000)));
1921 env.close();
1922
1923 // set freeze on alice trustline
1924 env(trust(gw, USD(10'000), alice, tfSetFreeze | tfSetDeepFreeze));
1925 env.close();
1926
1927 // setup transaction
1928 auto seq1 = env.seq(alice);
1929 auto const delta = USD(125);
1930
1931 // create escrow fails - frozen trustline
1932 env(escrow::create(alice, bob, delta),
1934 escrow::finish_time(env.now() + 1s),
1935 fee(baseFee * 150),
1936 ter(tecFROZEN));
1937 env.close();
1938
1939 // clear freeze on alice trustline
1940 env(trust(
1941 gw, USD(10'000), alice, tfClearFreeze | tfClearDeepFreeze));
1942 env.close();
1943
1944 // create escrow success
1945 seq1 = env.seq(alice);
1946 env(escrow::create(alice, bob, delta),
1948 escrow::finish_time(env.now() + 1s),
1949 fee(baseFee * 150));
1950 env.close();
1951
1952 // set freeze on bob trustline
1953 env(trust(gw, USD(10'000), bob, tfSetFreeze | tfSetDeepFreeze));
1954 env.close();
1955
1956 // bob finish escrow fails because of deep frozen assets
1957 env(escrow::finish(bob, alice, seq1),
1960 fee(baseFee * 150),
1961 ter(tecFROZEN));
1962 env.close();
1963
1964 // reset freeze on alice and bob trustline
1965 env(trust(
1966 gw, USD(10'000), alice, tfClearFreeze | tfClearDeepFreeze));
1967 env(trust(gw, USD(10'000), bob, tfClearFreeze | tfClearDeepFreeze));
1968 env.close();
1969
1970 // create escrow success
1971 seq1 = env.seq(alice);
1972 env(escrow::create(alice, bob, delta),
1974 escrow::cancel_time(env.now() + 1s),
1975 fee(baseFee * 150));
1976 env.close();
1977
1978 // set freeze on bob trustline
1979 env(trust(gw, USD(10'000), bob, tfSetFreeze | tfSetDeepFreeze));
1980 env.close();
1981
1982 // bob cancel escrow fails because of deep frozen assets
1983 env(escrow::cancel(bob, alice, seq1),
1984 fee(baseFee),
1985 ter(tesSUCCESS));
1986 env.close();
1987 }
1988 }
1989 void
1991 {
1992 testcase("IOU Insufficient Funds");
1993 using namespace test::jtx;
1994 using namespace std::literals;
1995
1996 auto const alice = Account("alice");
1997 auto const bob = Account("bob");
1998 auto const carol = Account("carol");
1999 auto const gw = Account{"gateway"};
2000 auto const USD = gw["USD"];
2001 {
2002 // test tecPATH_PARTIAL
2003 // ie. has 10'000, escrow 1'000 then try to pay 10'000
2004 Env env{*this, features};
2005 auto const baseFee = env.current()->fees().base;
2006 env.fund(XRP(10'000), alice, bob, gw);
2008 env.close();
2009 env.trust(USD(100'000), alice);
2010 env.trust(USD(100'000), bob);
2011 env.close();
2012 env(pay(gw, alice, USD(10'000)));
2013 env(pay(gw, bob, USD(10'000)));
2014 env.close();
2015
2016 // create escrow success
2017 auto const delta = USD(1'000);
2018 env(escrow::create(alice, bob, delta),
2020 escrow::finish_time(env.now() + 1s),
2021 fee(baseFee * 150));
2022 env.close();
2023 env(pay(alice, gw, USD(10'000)), ter(tecPATH_PARTIAL));
2024 }
2025 {
2026 // test tecINSUFFICIENT_FUNDS
2027 // ie. has 10'000 escrow 1'000 then try to escrow 10'000
2028 Env env{*this, features};
2029 auto const baseFee = env.current()->fees().base;
2030 env.fund(XRP(10'000), alice, bob, gw);
2032 env.close();
2033 env.trust(USD(100'000), alice);
2034 env.trust(USD(100'000), bob);
2035 env.close();
2036 env(pay(gw, alice, USD(10'000)));
2037 env(pay(gw, bob, USD(10'000)));
2038 env.close();
2039
2040 auto const delta = USD(1'000);
2041 env(escrow::create(alice, bob, delta),
2043 escrow::finish_time(env.now() + 1s),
2044 fee(baseFee * 150));
2045 env.close();
2046
2047 env(escrow::create(alice, bob, USD(10'000)),
2049 escrow::finish_time(env.now() + 1s),
2050 fee(baseFee * 150),
2052 env.close();
2053 }
2054 }
2055
2056 void
2058 {
2059 testcase("IOU Precision Loss");
2060 using namespace test::jtx;
2061 using namespace std::literals;
2062
2063 auto const alice = Account("alice");
2064 auto const bob = Account("bob");
2065 auto const gw = Account{"gateway"};
2066 auto const USD = gw["USD"];
2067
2068 // test min create precision loss
2069 {
2070 Env env(*this, features);
2071 auto const baseFee = env.current()->fees().base;
2072 env.fund(XRP(10'000), alice, bob, gw);
2074 env.close();
2075 env.trust(USD(100000000000000000), alice);
2076 env.trust(USD(100000000000000000), bob);
2077 env.close();
2078 env(pay(gw, alice, USD(10000000000000000)));
2079 env(pay(gw, bob, USD(1)));
2080 env.close();
2081
2082 bool const largeMantissa = features[featureSingleAssetVault] ||
2083 features[featureLendingProtocol];
2084
2085 // alice cannot create escrow for 1/10 iou - precision loss
2086 env(escrow::create(alice, bob, USD(1)),
2088 escrow::finish_time(env.now() + 1s),
2089 fee(baseFee * 150),
2090 ter(largeMantissa ? (TER)tesSUCCESS : (TER)tecPRECISION_LOSS));
2091 env.close();
2092
2093 auto const seq1 = env.seq(alice);
2094 // alice can create escrow for 1'000 iou
2095 env(escrow::create(alice, bob, USD(1'000)),
2097 escrow::finish_time(env.now() + 1s),
2098 fee(baseFee * 150));
2099 env.close();
2100
2101 // bob finish escrow success
2102 env(escrow::finish(bob, alice, seq1),
2105 fee(baseFee * 150));
2106 env.close();
2107 }
2108 }
2109
2110 void
2112 {
2113 testcase("MPT Enablement");
2114
2115 using namespace jtx;
2116 using namespace std::chrono;
2117
2118 for (bool const withTokenEscrow : {false, true})
2119 {
2120 auto const amend =
2121 withTokenEscrow ? features : features - featureTokenEscrow;
2122 Env env{*this, amend};
2123 auto const baseFee = env.current()->fees().base;
2124 auto const alice = Account("alice");
2125 auto const bob = Account("bob");
2126 auto const gw = Account("gw");
2127 env.fund(XRP(5000), bob);
2128
2129 MPTTester mptGw(env, gw, {.holders = {alice}});
2130 mptGw.create(
2131 {.ownerCount = 1,
2132 .holderCount = 0,
2133 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2134 mptGw.authorize({.account = alice});
2135 auto const MPT = mptGw["MPT"];
2136 env(pay(gw, alice, MPT(10'000)));
2137 env.close();
2138
2139 auto const createResult =
2140 withTokenEscrow ? ter(tesSUCCESS) : ter(temBAD_AMOUNT);
2141 auto const finishResult =
2142 withTokenEscrow ? ter(tesSUCCESS) : ter(tecNO_TARGET);
2143
2144 auto const seq1 = env.seq(alice);
2145 env(escrow::create(alice, bob, MPT(1'000)),
2147 escrow::finish_time(env.now() + 1s),
2148 fee(baseFee * 150),
2149 createResult);
2150 env.close();
2151 env(escrow::finish(bob, alice, seq1),
2154 fee(baseFee * 150),
2155 finishResult);
2156 env.close();
2157 auto const seq2 = env.seq(alice);
2158 env(escrow::create(alice, bob, MPT(1'000)),
2160 escrow::finish_time(env.now() + 1s),
2161 escrow::cancel_time(env.now() + 2s),
2162 fee(baseFee * 150),
2163 createResult);
2164 env.close();
2165 env(escrow::cancel(bob, alice, seq2), finishResult);
2166 env.close();
2167 }
2168 }
2169
2170 void
2172 {
2173 testcase("MPT Create Preflight");
2174 using namespace test::jtx;
2175 using namespace std::literals;
2176
2177 for (bool const withMPT : {true, false})
2178 {
2179 auto const amend =
2180 withMPT ? features : features - featureMPTokensV1;
2181 Env env{*this, amend};
2182 auto const baseFee = env.current()->fees().base;
2183 auto const alice = Account("alice");
2184 auto const bob = Account("bob");
2185 auto const gw = Account("gw");
2186 env.fund(XRP(1'000), alice, bob, gw);
2187
2188 Json::Value jv = escrow::create(alice, bob, XRP(1));
2189 jv.removeMember(jss::Amount);
2190 jv[jss::Amount][jss::mpt_issuance_id] =
2191 "00000004A407AF5856CCF3C42619DAA925813FC955C72983";
2192 jv[jss::Amount][jss::value] = "-1";
2193
2194 auto const result = withMPT ? ter(temBAD_AMOUNT) : ter(temDISABLED);
2195 env(jv,
2197 escrow::finish_time(env.now() + 1s),
2198 fee(baseFee * 150),
2199 result);
2200 env.close();
2201 }
2202
2203 // temBAD_AMOUNT: amount < 0
2204 {
2205 Env env{*this, features};
2206 auto const baseFee = env.current()->fees().base;
2207 auto const alice = Account("alice");
2208 auto const bob = Account("bob");
2209 auto const gw = Account("gw");
2210
2211 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2212 mptGw.create(
2213 {.ownerCount = 1,
2214 .holderCount = 0,
2215 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2216 mptGw.authorize({.account = alice});
2217 mptGw.authorize({.account = bob});
2218 auto const MPT = mptGw["MPT"];
2219 env(pay(gw, alice, MPT(10'000)));
2220 env(pay(gw, bob, MPT(10'000)));
2221 env.close();
2222
2223 env(escrow::create(alice, bob, MPT(-1)),
2225 escrow::finish_time(env.now() + 1s),
2226 fee(baseFee * 150),
2228 env.close();
2229 }
2230 }
2231
2232 void
2234 {
2235 testcase("MPT Create Preclaim");
2236 using namespace test::jtx;
2237 using namespace std::literals;
2238
2239 // tecNO_PERMISSION: issuer is the same as the account
2240 {
2241 Env env{*this, features};
2242 auto const baseFee = env.current()->fees().base;
2243 auto const alice = Account("alice");
2244 auto const gw = Account("gw");
2245
2246 MPTTester mptGw(env, gw, {.holders = {alice}});
2247 mptGw.create(
2248 {.ownerCount = 1,
2249 .holderCount = 0,
2250 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2251 mptGw.authorize({.account = alice});
2252 auto const MPT = mptGw["MPT"];
2253 env(pay(gw, alice, MPT(10'000)));
2254 env.close();
2255
2256 env(escrow::create(gw, alice, MPT(1)),
2258 escrow::finish_time(env.now() + 1s),
2259 fee(baseFee * 150),
2261 env.close();
2262 }
2263
2264 // tecOBJECT_NOT_FOUND: mpt does not exist
2265 {
2266 Env env{*this, features};
2267 auto const baseFee = env.current()->fees().base;
2268 auto const alice = Account("alice");
2269 auto const bob = Account("bob");
2270 auto const gw = Account("gw");
2271 env.fund(XRP(10'000), alice, bob, gw);
2272 env.close();
2273
2274 auto const mpt = xrpl::test::jtx::MPT(
2275 alice.name(), makeMptID(env.seq(alice), alice));
2276 Json::Value jv = escrow::create(alice, bob, mpt(2));
2277 jv[jss::Amount][jss::mpt_issuance_id] =
2278 "00000004A407AF5856CCF3C42619DAA925813FC955C72983";
2279 env(jv,
2281 escrow::finish_time(env.now() + 1s),
2282 fee(baseFee * 150),
2284 env.close();
2285 }
2286
2287 // tecNO_PERMISSION: tfMPTCanEscrow is not enabled
2288 {
2289 Env env{*this, features};
2290 auto const baseFee = env.current()->fees().base;
2291 auto const alice = Account("alice");
2292 auto const bob = Account("bob");
2293 auto const gw = Account("gw");
2294
2295 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2296 mptGw.create(
2297 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
2298 mptGw.authorize({.account = alice});
2299 mptGw.authorize({.account = bob});
2300 auto const MPT = mptGw["MPT"];
2301 env(pay(gw, alice, MPT(10'000)));
2302 env(pay(gw, bob, MPT(10'000)));
2303 env.close();
2304
2305 env(escrow::create(alice, bob, MPT(3)),
2307 escrow::finish_time(env.now() + 1s),
2308 fee(baseFee * 150),
2310 env.close();
2311 }
2312
2313 // tecOBJECT_NOT_FOUND: account does not have the mpt
2314 {
2315 Env env{*this, features};
2316 auto const baseFee = env.current()->fees().base;
2317 auto const alice = Account("alice");
2318 auto const bob = Account("bob");
2319 auto const gw = Account("gw");
2320
2321 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2322 mptGw.create(
2323 {.ownerCount = 1,
2324 .holderCount = 0,
2325 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2326 auto const MPT = mptGw["MPT"];
2327
2328 env(escrow::create(alice, bob, MPT(4)),
2330 escrow::finish_time(env.now() + 1s),
2331 fee(baseFee * 150),
2333 env.close();
2334 }
2335
2336 // tecNO_AUTH: requireAuth set: account not authorized
2337 {
2338 Env env{*this, features};
2339 auto const baseFee = env.current()->fees().base;
2340 auto const alice = Account("alice");
2341 auto const bob = Account("bob");
2342 auto const gw = Account("gw");
2343
2344 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2345 mptGw.create(
2346 {.ownerCount = 1,
2347 .holderCount = 0,
2348 .flags =
2350 mptGw.authorize({.account = alice});
2351 mptGw.authorize({.account = gw, .holder = alice});
2352 auto const MPT = mptGw["MPT"];
2353 env(pay(gw, alice, MPT(10'000)));
2354 env.close();
2355
2356 // unauthorize account
2357 mptGw.authorize(
2358 {.account = gw, .holder = alice, .flags = tfMPTUnauthorize});
2359
2360 env(escrow::create(alice, bob, MPT(5)),
2362 escrow::finish_time(env.now() + 1s),
2363 fee(baseFee * 150),
2364 ter(tecNO_AUTH));
2365 env.close();
2366 }
2367
2368 // tecNO_AUTH: requireAuth set: dest not authorized
2369 {
2370 Env env{*this, features};
2371 auto const baseFee = env.current()->fees().base;
2372 auto const alice = Account("alice");
2373 auto const bob = Account("bob");
2374 auto const gw = Account("gw");
2375
2376 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2377 mptGw.create(
2378 {.ownerCount = 1,
2379 .holderCount = 0,
2380 .flags =
2382 mptGw.authorize({.account = alice});
2383 mptGw.authorize({.account = gw, .holder = alice});
2384 mptGw.authorize({.account = bob});
2385 mptGw.authorize({.account = gw, .holder = bob});
2386 auto const MPT = mptGw["MPT"];
2387 env(pay(gw, alice, MPT(10'000)));
2388 env(pay(gw, bob, MPT(10'000)));
2389 env.close();
2390
2391 // unauthorize dest
2392 mptGw.authorize(
2393 {.account = gw, .holder = bob, .flags = tfMPTUnauthorize});
2394
2395 env(escrow::create(alice, bob, MPT(6)),
2397 escrow::finish_time(env.now() + 1s),
2398 fee(baseFee * 150),
2399 ter(tecNO_AUTH));
2400 env.close();
2401 }
2402
2403 // tecLOCKED: issuer has locked the account
2404 {
2405 Env env{*this, features};
2406 auto const baseFee = env.current()->fees().base;
2407 auto const alice = Account("alice");
2408 auto const bob = Account("bob");
2409 auto const gw = Account("gw");
2410
2411 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2412 mptGw.create(
2413 {.ownerCount = 1,
2414 .holderCount = 0,
2416 mptGw.authorize({.account = alice});
2417 mptGw.authorize({.account = bob});
2418 auto const MPT = mptGw["MPT"];
2419 env(pay(gw, alice, MPT(10'000)));
2420 env(pay(gw, bob, MPT(10'000)));
2421 env.close();
2422
2423 // lock account
2424 mptGw.set({.account = gw, .holder = alice, .flags = tfMPTLock});
2425
2426 env(escrow::create(alice, bob, MPT(7)),
2428 escrow::finish_time(env.now() + 1s),
2429 fee(baseFee * 150),
2430 ter(tecLOCKED));
2431 env.close();
2432 }
2433
2434 // tecLOCKED: issuer has locked the dest
2435 {
2436 Env env{*this, features};
2437 auto const baseFee = env.current()->fees().base;
2438 auto const alice = Account("alice");
2439 auto const bob = Account("bob");
2440 auto const gw = Account("gw");
2441
2442 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2443 mptGw.create(
2444 {.ownerCount = 1,
2445 .holderCount = 0,
2447 mptGw.authorize({.account = alice});
2448 mptGw.authorize({.account = bob});
2449 auto const MPT = mptGw["MPT"];
2450 env(pay(gw, alice, MPT(10'000)));
2451 env(pay(gw, bob, MPT(10'000)));
2452 env.close();
2453
2454 // lock dest
2455 mptGw.set({.account = gw, .holder = bob, .flags = tfMPTLock});
2456
2457 env(escrow::create(alice, bob, MPT(8)),
2459 escrow::finish_time(env.now() + 1s),
2460 fee(baseFee * 150),
2461 ter(tecLOCKED));
2462 env.close();
2463 }
2464
2465 // tecNO_AUTH: mpt cannot be transferred
2466 {
2467 Env env{*this, features};
2468 auto const baseFee = env.current()->fees().base;
2469 auto const alice = Account("alice");
2470 auto const bob = Account("bob");
2471 auto const gw = Account("gw");
2472
2473 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2474 mptGw.create(
2475 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow});
2476 mptGw.authorize({.account = alice});
2477 mptGw.authorize({.account = bob});
2478 auto const MPT = mptGw["MPT"];
2479 env(pay(gw, alice, MPT(10'000)));
2480 env(pay(gw, bob, MPT(10'000)));
2481 env.close();
2482
2483 env(escrow::create(alice, bob, MPT(9)),
2485 escrow::finish_time(env.now() + 1s),
2486 fee(baseFee * 150),
2487 ter(tecNO_AUTH));
2488 env.close();
2489 }
2490
2491 // tecINSUFFICIENT_FUNDS: spendable amount is zero
2492 {
2493 Env env{*this, features};
2494 auto const baseFee = env.current()->fees().base;
2495 auto const alice = Account("alice");
2496 auto const bob = Account("bob");
2497 auto const gw = Account("gw");
2498
2499 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2500 mptGw.create(
2501 {.ownerCount = 1,
2502 .holderCount = 0,
2503 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2504 mptGw.authorize({.account = alice});
2505 mptGw.authorize({.account = bob});
2506 auto const MPT = mptGw["MPT"];
2507 env(pay(gw, bob, MPT(10)));
2508 env.close();
2509
2510 env(escrow::create(alice, bob, MPT(11)),
2512 escrow::finish_time(env.now() + 1s),
2513 fee(baseFee * 150),
2515 env.close();
2516 }
2517
2518 // tecINSUFFICIENT_FUNDS: spendable amount is less than the amount
2519 {
2520 Env env{*this, features};
2521 auto const baseFee = env.current()->fees().base;
2522 auto const alice = Account("alice");
2523 auto const bob = Account("bob");
2524 auto const gw = Account("gw");
2525
2526 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2527 mptGw.create(
2528 {.ownerCount = 1,
2529 .holderCount = 0,
2530 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2531 mptGw.authorize({.account = alice});
2532 mptGw.authorize({.account = bob});
2533 auto const MPT = mptGw["MPT"];
2534 env(pay(gw, alice, MPT(10)));
2535 env(pay(gw, bob, MPT(10)));
2536 env.close();
2537
2538 env(escrow::create(alice, bob, MPT(11)),
2540 escrow::finish_time(env.now() + 1s),
2541 fee(baseFee * 150),
2543 env.close();
2544 }
2545 }
2546
2547 void
2549 {
2550 testcase("MPT Finish Preclaim");
2551 using namespace test::jtx;
2552 using namespace std::literals;
2553
2554 // tecNO_AUTH: requireAuth set: dest not authorized
2555 {
2556 Env env{*this, features};
2557 auto const baseFee = env.current()->fees().base;
2558 auto const alice = Account("alice");
2559 auto const bob = Account("bob");
2560 auto const gw = Account("gw");
2561
2562 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2563 mptGw.create(
2564 {.ownerCount = 1,
2565 .holderCount = 0,
2566 .flags =
2568 mptGw.authorize({.account = alice});
2569 mptGw.authorize({.account = gw, .holder = alice});
2570 mptGw.authorize({.account = bob});
2571 mptGw.authorize({.account = gw, .holder = bob});
2572 auto const MPT = mptGw["MPT"];
2573 env(pay(gw, alice, MPT(10'000)));
2574 env(pay(gw, bob, MPT(10'000)));
2575 env.close();
2576
2577 auto const seq1 = env.seq(alice);
2578 env(escrow::create(alice, bob, MPT(10)),
2580 escrow::finish_time(env.now() + 1s),
2581 fee(baseFee * 150),
2582 ter(tesSUCCESS));
2583 env.close();
2584
2585 // unauthorize dest
2586 mptGw.authorize(
2587 {.account = gw, .holder = bob, .flags = tfMPTUnauthorize});
2588
2589 env(escrow::finish(bob, alice, seq1),
2592 fee(baseFee * 150),
2593 ter(tecNO_AUTH));
2594 env.close();
2595 }
2596
2597 // tecOBJECT_NOT_FOUND: MPT issuance does not exist
2598 {
2599 Env env{*this, features};
2600 auto const baseFee = env.current()->fees().base;
2601 auto const alice = Account("alice");
2602 auto const bob = Account("bob");
2603 env.fund(XRP(10'000), alice, bob);
2604 env.close();
2605
2606 auto const seq1 = env.seq(alice);
2607 env.app().openLedger().modify(
2608 [&](OpenView& view, beast::Journal j) {
2609 Sandbox sb(&view, tapNONE);
2610 auto sleNew =
2612 MPTIssue const mpt{
2613 MPTIssue{makeMptID(1, AccountID(0x4985601))}};
2614 STAmount amt(mpt, 10);
2615 sleNew->setAccountID(sfDestination, bob);
2616 sleNew->setFieldAmount(sfAmount, amt);
2617 sb.insert(sleNew);
2618 sb.apply(view);
2619 return true;
2620 });
2621
2622 env(escrow::finish(bob, alice, seq1),
2625 fee(baseFee * 150),
2627 env.close();
2628 }
2629
2630 // tecLOCKED: issuer has locked the dest
2631 {
2632 Env env{*this, features};
2633 auto const baseFee = env.current()->fees().base;
2634 auto const alice = Account("alice");
2635 auto const bob = Account("bob");
2636 auto const gw = Account("gw");
2637
2638 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2639 mptGw.create(
2640 {.ownerCount = 1,
2641 .holderCount = 0,
2643 mptGw.authorize({.account = alice});
2644 mptGw.authorize({.account = bob});
2645 auto const MPT = mptGw["MPT"];
2646 env(pay(gw, alice, MPT(10'000)));
2647 env(pay(gw, bob, MPT(10'000)));
2648 env.close();
2649
2650 auto const seq1 = env.seq(alice);
2651 env(escrow::create(alice, bob, MPT(8)),
2653 escrow::finish_time(env.now() + 1s),
2654 fee(baseFee * 150),
2655 ter(tesSUCCESS));
2656 env.close();
2657
2658 // lock dest
2659 mptGw.set({.account = gw, .holder = bob, .flags = tfMPTLock});
2660
2661 env(escrow::finish(bob, alice, seq1),
2664 fee(baseFee * 150),
2665 ter(tecLOCKED));
2666 env.close();
2667 }
2668 }
2669
2670 void
2672 {
2673 testcase("MPT Finish Do Apply");
2674 using namespace test::jtx;
2675 using namespace std::literals;
2676
2677 // tecINSUFFICIENT_RESERVE: insufficient reserve to create MPT
2678 {
2679 Env env{*this, features};
2680 auto const baseFee = env.current()->fees().base;
2681 auto const acctReserve = env.current()->fees().reserve;
2682 auto const incReserve = env.current()->fees().increment;
2683
2684 auto const alice = Account("alice");
2685 auto const bob = Account("bob");
2686 auto const gw = Account("gw");
2687 env.fund(acctReserve + (incReserve - 1), bob);
2688 env.close();
2689
2690 MPTTester mptGw(env, gw, {.holders = {alice}});
2691 mptGw.create(
2692 {.ownerCount = 1,
2693 .holderCount = 0,
2694 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2695 mptGw.authorize({.account = alice});
2696 auto const MPT = mptGw["MPT"];
2697 env(pay(gw, alice, MPT(10'000)));
2698 env.close();
2699
2700 auto const seq1 = env.seq(alice);
2701 env(escrow::create(alice, bob, MPT(10)),
2703 escrow::finish_time(env.now() + 1s),
2704 fee(baseFee * 150),
2705 ter(tesSUCCESS));
2706 env.close();
2707
2708 env(escrow::finish(bob, alice, seq1),
2711 fee(baseFee * 150),
2713 env.close();
2714 }
2715
2716 // tesSUCCESS: bob submits; finish MPT created
2717 {
2718 Env env{*this, features};
2719 auto const baseFee = env.current()->fees().base;
2720 auto const alice = Account("alice");
2721 auto const bob = Account("bob");
2722 auto const gw = Account("gw");
2723 env.fund(XRP(10'000), bob);
2724 env.close();
2725
2726 MPTTester mptGw(env, gw, {.holders = {alice}});
2727 mptGw.create(
2728 {.ownerCount = 1,
2729 .holderCount = 0,
2730 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2731 mptGw.authorize({.account = alice});
2732 auto const MPT = mptGw["MPT"];
2733 env(pay(gw, alice, MPT(10'000)));
2734 env.close();
2735
2736 auto const seq1 = env.seq(alice);
2737 env(escrow::create(alice, bob, MPT(10)),
2739 escrow::finish_time(env.now() + 1s),
2740 fee(baseFee * 150),
2741 ter(tesSUCCESS));
2742 env.close();
2743
2744 env(escrow::finish(bob, alice, seq1),
2747 fee(baseFee * 150),
2748 ter(tesSUCCESS));
2749 env.close();
2750 }
2751
2752 // tecNO_PERMISSION: carol submits; finish MPT not created
2753 {
2754 Env env{*this, features};
2755 auto const baseFee = env.current()->fees().base;
2756 auto const alice = Account("alice");
2757 auto const bob = Account("bob");
2758 auto const carol = Account("carol");
2759 auto const gw = Account("gw");
2760 env.fund(XRP(10'000), bob, carol);
2761 env.close();
2762
2763 MPTTester mptGw(env, gw, {.holders = {alice}});
2764 mptGw.create(
2765 {.ownerCount = 1,
2766 .holderCount = 0,
2767 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2768 mptGw.authorize({.account = alice});
2769 auto const MPT = mptGw["MPT"];
2770 env(pay(gw, alice, MPT(10'000)));
2771 env.close();
2772
2773 auto const seq1 = env.seq(alice);
2774 env(escrow::create(alice, bob, MPT(10)),
2776 escrow::finish_time(env.now() + 1s),
2777 fee(baseFee * 150),
2778 ter(tesSUCCESS));
2779 env.close();
2780
2781 env(escrow::finish(carol, alice, seq1),
2784 fee(baseFee * 150),
2786 env.close();
2787 }
2788 }
2789
2790 void
2792 {
2793 testcase("MPT Cancel Preclaim");
2794 using namespace test::jtx;
2795 using namespace std::literals;
2796
2797 // tecNO_AUTH: requireAuth set: account not authorized
2798 {
2799 Env env{*this, features};
2800 auto const baseFee = env.current()->fees().base;
2801 auto const alice = Account("alice");
2802 auto const bob = Account("bob");
2803 auto const gw = Account("gw");
2804
2805 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
2806 mptGw.create(
2807 {.ownerCount = 1,
2808 .holderCount = 0,
2809 .flags =
2811 mptGw.authorize({.account = alice});
2812 mptGw.authorize({.account = gw, .holder = alice});
2813 mptGw.authorize({.account = bob});
2814 mptGw.authorize({.account = gw, .holder = bob});
2815 auto const MPT = mptGw["MPT"];
2816 env(pay(gw, alice, MPT(10'000)));
2817 env(pay(gw, bob, MPT(10'000)));
2818 env.close();
2819
2820 auto const seq1 = env.seq(alice);
2821 env(escrow::create(alice, bob, MPT(10)),
2822 escrow::cancel_time(env.now() + 2s),
2824 fee(baseFee * 150),
2825 ter(tesSUCCESS));
2826 env.close();
2827
2828 // unauthorize account
2829 mptGw.authorize(
2830 {.account = gw, .holder = alice, .flags = tfMPTUnauthorize});
2831
2832 env(escrow::cancel(bob, alice, seq1), ter(tecNO_AUTH));
2833 env.close();
2834 }
2835
2836 // tecOBJECT_NOT_FOUND: MPT issuance does not exist
2837 {
2838 Env env{*this, features};
2839 auto const baseFee = env.current()->fees().base;
2840 auto const alice = Account("alice");
2841 auto const bob = Account("bob");
2842 env.fund(XRP(10'000), alice, bob);
2843
2844 auto const seq1 = env.seq(alice);
2845 env.app().openLedger().modify(
2846 [&](OpenView& view, beast::Journal j) {
2847 Sandbox sb(&view, tapNONE);
2848 auto sleNew =
2850 MPTIssue const mpt{
2851 MPTIssue{makeMptID(1, AccountID(0x4985601))}};
2852 STAmount amt(mpt, 10);
2853 sleNew->setAccountID(sfDestination, bob);
2854 sleNew->setFieldAmount(sfAmount, amt);
2855 sb.insert(sleNew);
2856 sb.apply(view);
2857 return true;
2858 });
2859
2860 env(escrow::cancel(bob, alice, seq1),
2861 fee(baseFee),
2863 env.close();
2864 }
2865 }
2866
2867 void
2869 {
2870 testcase("MPT Balances");
2871
2872 using namespace jtx;
2873 using namespace std::chrono;
2874
2875 Env env{*this, features};
2876 auto const baseFee = env.current()->fees().base;
2877 auto const alice = Account("alice");
2878 auto const bob = Account("bob");
2879 auto const carol = Account("carol");
2880 auto const gw = Account("gw");
2881 env.fund(XRP(5000), bob);
2882
2883 MPTTester mptGw(env, gw, {.holders = {alice, carol}});
2884 mptGw.create(
2885 {.ownerCount = 1,
2886 .holderCount = 0,
2887 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
2888 mptGw.authorize({.account = alice});
2889 mptGw.authorize({.account = carol});
2890 auto const MPT = mptGw["MPT"];
2891 env(pay(gw, alice, MPT(10'000)));
2892 env(pay(gw, carol, MPT(10'000)));
2893 env.close();
2894
2895 auto outstandingMPT = env.balance(gw, MPT);
2896
2897 // Create & Finish Escrow
2898 auto const seq1 = env.seq(alice);
2899 {
2900 auto const preAliceMPT = env.balance(alice, MPT);
2901 auto const preBobMPT = env.balance(bob, MPT);
2902 env(escrow::create(alice, bob, MPT(1'000)),
2904 escrow::finish_time(env.now() + 1s),
2905 fee(baseFee * 150),
2906 ter(tesSUCCESS));
2907 env.close();
2908
2909 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
2910 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
2911 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
2912 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
2913 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2914 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1'000);
2915 }
2916 {
2917 auto const preAliceMPT = env.balance(alice, MPT);
2918 auto const preBobMPT = env.balance(bob, MPT);
2919 env(escrow::finish(bob, alice, seq1),
2922 fee(baseFee * 150),
2923 ter(tesSUCCESS));
2924 env.close();
2925
2926 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT);
2927 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
2928 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT + MPT(1'000));
2929 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
2930 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2931 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
2932 }
2933
2934 // Create & Cancel Escrow
2935 auto const seq2 = env.seq(alice);
2936 {
2937 auto const preAliceMPT = env.balance(alice, MPT);
2938 auto const preBobMPT = env.balance(bob, MPT);
2939 env(escrow::create(alice, bob, MPT(1'000)),
2941 escrow::finish_time(env.now() + 1s),
2942 escrow::cancel_time(env.now() + 2s),
2943 fee(baseFee * 150),
2944 ter(tesSUCCESS));
2945 env.close();
2946
2947 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
2948 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
2949 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
2950 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
2951 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2952 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1'000);
2953 }
2954 {
2955 auto const preAliceMPT = env.balance(alice, MPT);
2956 auto const preBobMPT = env.balance(bob, MPT);
2957 env(escrow::cancel(bob, alice, seq2), ter(tesSUCCESS));
2958 env.close();
2959
2960 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT + MPT(1'000));
2961 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
2962 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
2963 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
2964 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2965 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
2966 }
2967
2968 // Self Escrow Create & Finish
2969 {
2970 auto const seq = env.seq(alice);
2971 auto const preAliceMPT = env.balance(alice, MPT);
2972 env(escrow::create(alice, alice, MPT(1'000)),
2974 escrow::finish_time(env.now() + 1s),
2975 fee(baseFee * 150),
2976 ter(tesSUCCESS));
2977 env.close();
2978
2979 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
2980 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
2981 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2982 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1'000);
2983
2984 env(escrow::finish(alice, alice, seq),
2987 fee(baseFee * 150),
2988 ter(tesSUCCESS));
2989 env.close();
2990
2991 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT);
2992 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
2993 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
2994 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
2995 }
2996
2997 // Self Escrow Create & Cancel
2998 {
2999 auto const seq = env.seq(alice);
3000 auto const preAliceMPT = env.balance(alice, MPT);
3001 env(escrow::create(alice, alice, MPT(1'000)),
3003 escrow::finish_time(env.now() + 1s),
3004 escrow::cancel_time(env.now() + 2s),
3005 fee(baseFee * 150),
3006 ter(tesSUCCESS));
3007 env.close();
3008
3009 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
3010 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
3011 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3012 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1'000);
3013
3014 env(escrow::cancel(alice, alice, seq), ter(tesSUCCESS));
3015 env.close();
3016
3017 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT);
3018 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3019 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3020 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3021 }
3022
3023 // Multiple Escrows
3024 {
3025 auto const preAliceMPT = env.balance(alice, MPT);
3026 auto const preBobMPT = env.balance(bob, MPT);
3027 auto const preCarolMPT = env.balance(carol, MPT);
3028 env(escrow::create(alice, bob, MPT(1'000)),
3030 escrow::finish_time(env.now() + 1s),
3031 fee(baseFee * 150),
3032 ter(tesSUCCESS));
3033 env.close();
3034
3035 env(escrow::create(carol, bob, MPT(1'000)),
3037 escrow::finish_time(env.now() + 1s),
3038 fee(baseFee * 150),
3039 ter(tesSUCCESS));
3040 env.close();
3041
3042 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
3043 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
3044 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
3045 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3046 BEAST_EXPECT(env.balance(carol, MPT) == preCarolMPT - MPT(1'000));
3047 BEAST_EXPECT(mptEscrowed(env, carol, MPT) == 1'000);
3048 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3049 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 2'000);
3050 }
3051
3052 // Max MPT Amount Issued (Escrow 1 MPT)
3053 {
3054 Env env{*this, features};
3055 auto const baseFee = env.current()->fees().base;
3056 auto const alice = Account("alice");
3057 auto const bob = Account("bob");
3058 auto const gw = Account("gw");
3059
3060 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3061 mptGw.create(
3062 {.ownerCount = 1,
3063 .holderCount = 0,
3064 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3065 mptGw.authorize({.account = alice});
3066 mptGw.authorize({.account = bob});
3067 auto const MPT = mptGw["MPT"];
3068 env(pay(gw, alice, MPT(maxMPTokenAmount)));
3069 env.close();
3070
3071 auto const preAliceMPT = env.balance(alice, MPT);
3072 auto const preBobMPT = env.balance(bob, MPT);
3073 auto const outstandingMPT = env.balance(gw, MPT);
3074
3075 auto const seq1 = env.seq(alice);
3076 env(escrow::create(alice, bob, MPT(1)),
3078 escrow::finish_time(env.now() + 1s),
3079 fee(baseFee * 150));
3080 env.close();
3081
3082 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1));
3083 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1);
3084 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
3085 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3086 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3087 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 1);
3088
3089 env(escrow::finish(bob, alice, seq1),
3092 fee(baseFee * 150),
3093 ter(tesSUCCESS));
3094 env.close();
3095
3096 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1));
3097 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3098 BEAST_EXPECT(!env.le(keylet::mptoken(MPT.mpt(), alice))
3099 ->isFieldPresent(sfLockedAmount));
3100 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT + MPT(1));
3101 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3102 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3103 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3104 BEAST_EXPECT(!env.le(keylet::mptIssuance(MPT.mpt()))
3105 ->isFieldPresent(sfLockedAmount));
3106 }
3107
3108 // Max MPT Amount Issued (Escrow Max MPT)
3109 {
3110 Env env{*this, features};
3111 auto const baseFee = env.current()->fees().base;
3112 auto const alice = Account("alice");
3113 auto const bob = Account("bob");
3114 auto const gw = Account("gw");
3115
3116 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3117 mptGw.create(
3118 {.ownerCount = 1,
3119 .holderCount = 0,
3120 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3121 mptGw.authorize({.account = alice});
3122 mptGw.authorize({.account = bob});
3123 auto const MPT = mptGw["MPT"];
3124 env(pay(gw, alice, MPT(maxMPTokenAmount)));
3125 env.close();
3126
3127 auto const preAliceMPT = env.balance(alice, MPT);
3128 auto const preBobMPT = env.balance(bob, MPT);
3129 auto const outstandingMPT = env.balance(gw, MPT);
3130
3131 // Escrow Max MPT - 10
3132 auto const seq1 = env.seq(alice);
3133 env(escrow::create(alice, bob, MPT(maxMPTokenAmount - 10)),
3135 escrow::finish_time(env.now() + 1s),
3136 fee(baseFee * 150));
3137 env.close();
3138
3139 // Escrow 10 MPT
3140 auto const seq2 = env.seq(alice);
3141 env(escrow::create(alice, bob, MPT(10)),
3143 escrow::finish_time(env.now() + 1s),
3144 fee(baseFee * 150));
3145 env.close();
3146
3147 BEAST_EXPECT(
3148 env.balance(alice, MPT) == preAliceMPT - MPT(maxMPTokenAmount));
3149 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == maxMPTokenAmount);
3150 BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT);
3151 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3152 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3153 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == maxMPTokenAmount);
3154
3155 env(escrow::finish(bob, alice, seq1),
3158 fee(baseFee * 150),
3159 ter(tesSUCCESS));
3160 env.close();
3161
3162 env(escrow::finish(bob, alice, seq2),
3165 fee(baseFee * 150),
3166 ter(tesSUCCESS));
3167 env.close();
3168
3169 BEAST_EXPECT(
3170 env.balance(alice, MPT) == preAliceMPT - MPT(maxMPTokenAmount));
3171 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3172 BEAST_EXPECT(
3173 env.balance(bob, MPT) == preBobMPT + MPT(maxMPTokenAmount));
3174 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3175 BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT);
3176 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3177 }
3178 }
3179
3180 void
3182 {
3183 using namespace jtx;
3184 using namespace std::chrono;
3185
3186 auto const alice = Account("alice");
3187 auto const bob = Account("bob");
3188 auto const carol = Account("carol");
3189 auto const gw = Account{"gateway"};
3190 {
3191 testcase("MPT Metadata to self");
3192
3193 Env env{*this, features};
3194 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3195 mptGw.create(
3196 {.ownerCount = 1,
3197 .holderCount = 0,
3198 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3199 mptGw.authorize({.account = alice});
3200 mptGw.authorize({.account = bob});
3201 auto const MPT = mptGw["MPT"];
3202 env(pay(gw, alice, MPT(10'000)));
3203 env(pay(gw, bob, MPT(10'000)));
3204 env.close();
3205 auto const aseq = env.seq(alice);
3206 auto const bseq = env.seq(bob);
3207
3208 env(escrow::create(alice, alice, MPT(1'000)),
3209 escrow::finish_time(env.now() + 1s),
3210 escrow::cancel_time(env.now() + 500s));
3211 BEAST_EXPECT(
3212 (*env.meta())[sfTransactionResult] ==
3213 static_cast<std::uint8_t>(tesSUCCESS));
3214 env.close(5s);
3215 auto const aa = env.le(keylet::escrow(alice.id(), aseq));
3216 BEAST_EXPECT(aa);
3217 {
3218 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3219 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
3220 BEAST_EXPECT(
3221 std::find(aod.begin(), aod.end(), aa) != aod.end());
3222 }
3223
3224 {
3225 xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id()));
3226 BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 1);
3227 BEAST_EXPECT(
3228 std::find(iod.begin(), iod.end(), aa) == iod.end());
3229 }
3230
3231 env(escrow::create(bob, bob, MPT(1'000)),
3232 escrow::finish_time(env.now() + 1s),
3233 escrow::cancel_time(env.now() + 2s));
3234 BEAST_EXPECT(
3235 (*env.meta())[sfTransactionResult] ==
3236 static_cast<std::uint8_t>(tesSUCCESS));
3237 env.close(5s);
3238 auto const bb = env.le(keylet::escrow(bob.id(), bseq));
3239 BEAST_EXPECT(bb);
3240
3241 {
3242 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3243 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
3244 BEAST_EXPECT(
3245 std::find(bod.begin(), bod.end(), bb) != bod.end());
3246 }
3247
3248 env.close(5s);
3249 env(escrow::finish(alice, alice, aseq));
3250 {
3251 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
3252 BEAST_EXPECT(
3253 (*env.meta())[sfTransactionResult] ==
3254 static_cast<std::uint8_t>(tesSUCCESS));
3255
3256 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3257 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
3258 BEAST_EXPECT(
3259 std::find(aod.begin(), aod.end(), aa) == aod.end());
3260
3261 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3262 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
3263 BEAST_EXPECT(
3264 std::find(bod.begin(), bod.end(), bb) != bod.end());
3265 }
3266
3267 env.close(5s);
3268 env(escrow::cancel(bob, bob, bseq));
3269 {
3270 BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq)));
3271 BEAST_EXPECT(
3272 (*env.meta())[sfTransactionResult] ==
3273 static_cast<std::uint8_t>(tesSUCCESS));
3274
3275 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3276 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
3277 BEAST_EXPECT(
3278 std::find(bod.begin(), bod.end(), bb) == bod.end());
3279 }
3280 }
3281
3282 {
3283 testcase("MPT Metadata to other");
3284
3285 Env env{*this, features};
3286 MPTTester mptGw(env, gw, {.holders = {alice, bob, carol}});
3287 mptGw.create(
3288 {.ownerCount = 1,
3289 .holderCount = 0,
3290 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3291 mptGw.authorize({.account = alice});
3292 mptGw.authorize({.account = bob});
3293 mptGw.authorize({.account = carol});
3294 auto const MPT = mptGw["MPT"];
3295 env(pay(gw, alice, MPT(10'000)));
3296 env(pay(gw, bob, MPT(10'000)));
3297 env(pay(gw, carol, MPT(10'000)));
3298 env.close();
3299 auto const aseq = env.seq(alice);
3300 auto const bseq = env.seq(bob);
3301
3302 env(escrow::create(alice, bob, MPT(1'000)),
3303 escrow::finish_time(env.now() + 1s));
3304 BEAST_EXPECT(
3305 (*env.meta())[sfTransactionResult] ==
3306 static_cast<std::uint8_t>(tesSUCCESS));
3307 env.close(5s);
3308 env(escrow::create(bob, carol, MPT(1'000)),
3309 escrow::finish_time(env.now() + 1s),
3310 escrow::cancel_time(env.now() + 2s));
3311 BEAST_EXPECT(
3312 (*env.meta())[sfTransactionResult] ==
3313 static_cast<std::uint8_t>(tesSUCCESS));
3314 env.close(5s);
3315
3316 auto const ab = env.le(keylet::escrow(alice.id(), aseq));
3317 BEAST_EXPECT(ab);
3318
3319 auto const bc = env.le(keylet::escrow(bob.id(), bseq));
3320 BEAST_EXPECT(bc);
3321
3322 {
3323 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3324 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2);
3325 BEAST_EXPECT(
3326 std::find(aod.begin(), aod.end(), ab) != aod.end());
3327
3328 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3329 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 3);
3330 BEAST_EXPECT(
3331 std::find(bod.begin(), bod.end(), ab) != bod.end());
3332 BEAST_EXPECT(
3333 std::find(bod.begin(), bod.end(), bc) != bod.end());
3334
3335 xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
3336 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2);
3337 BEAST_EXPECT(
3338 std::find(cod.begin(), cod.end(), bc) != cod.end());
3339 }
3340
3341 env.close(5s);
3342 env(escrow::finish(alice, alice, aseq));
3343 {
3344 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
3345 BEAST_EXPECT(env.le(keylet::escrow(bob.id(), bseq)));
3346
3347 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3348 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
3349 BEAST_EXPECT(
3350 std::find(aod.begin(), aod.end(), ab) == aod.end());
3351
3352 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3353 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
3354 BEAST_EXPECT(
3355 std::find(bod.begin(), bod.end(), ab) == bod.end());
3356 BEAST_EXPECT(
3357 std::find(bod.begin(), bod.end(), bc) != bod.end());
3358
3359 xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
3360 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2);
3361 }
3362
3363 env.close(5s);
3364 env(escrow::cancel(bob, bob, bseq));
3365 {
3366 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
3367 BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq)));
3368
3369 xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
3370 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
3371 BEAST_EXPECT(
3372 std::find(aod.begin(), aod.end(), ab) == aod.end());
3373
3374 xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id()));
3375 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
3376 BEAST_EXPECT(
3377 std::find(bod.begin(), bod.end(), ab) == bod.end());
3378 BEAST_EXPECT(
3379 std::find(bod.begin(), bod.end(), bc) == bod.end());
3380
3381 xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
3382 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
3383 }
3384 }
3385 }
3386
3387 void
3389 {
3390 testcase("MPT Gateway Balances");
3391 using namespace test::jtx;
3392 using namespace std::literals;
3393
3394 // issuer is dest; alice w/ authorization
3395 {
3396 Env env{*this, features};
3397 auto const baseFee = env.current()->fees().base;
3398 auto const alice = Account("alice");
3399 auto const gw = Account("gw");
3400
3401 MPTTester mptGw(env, gw, {.holders = {alice}});
3402 mptGw.create(
3403 {.ownerCount = 1,
3404 .holderCount = 0,
3405 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3406 mptGw.authorize({.account = alice});
3407 auto const MPT = mptGw["MPT"];
3408 env(pay(gw, alice, MPT(10'000)));
3409 env.close();
3410
3411 // issuer can be destination
3412 auto const seq1 = env.seq(alice);
3413 auto const preAliceMPT = env.balance(alice, MPT);
3414 auto const preOutstanding = env.balance(gw, MPT);
3415 auto const preEscrowed = issuerMPTEscrowed(env, MPT);
3416 BEAST_EXPECT(preOutstanding == MPT(-10'000));
3417 BEAST_EXPECT(preEscrowed == 0);
3418
3419 env(escrow::create(alice, gw, MPT(1'000)),
3421 escrow::finish_time(env.now() + 1s),
3422 fee(baseFee * 150));
3423 env.close();
3424
3425 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
3426 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 1'000);
3427 BEAST_EXPECT(env.balance(gw, MPT) == preOutstanding);
3428 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == preEscrowed + 1'000);
3429
3430 // issuer (dest) can finish escrow
3431 env(escrow::finish(gw, alice, seq1),
3434 fee(baseFee * 150));
3435 env.close();
3436
3437 BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1'000));
3438 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3439 BEAST_EXPECT(env.balance(gw, MPT) == preOutstanding + MPT(1'000));
3440 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == preEscrowed);
3441 }
3442 }
3443
3444 void
3446 {
3447 testcase("MPT Locked Rate");
3448 using namespace test::jtx;
3449 using namespace std::literals;
3450
3451 auto const alice = Account("alice");
3452 auto const bob = Account("bob");
3453 auto const carol = Account("carol");
3454 auto const gw = Account{"gateway"};
3455 auto const USD = gw["USD"];
3456
3457 // test locked rate: finish
3458 {
3459 Env env{*this, features};
3460 auto const baseFee = env.current()->fees().base;
3461 auto const alice = Account("alice");
3462 auto const bob = Account("bob");
3463 auto const gw = Account("gw");
3464
3465 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3466 mptGw.create(
3467 {.transferFee = 25000,
3468 .ownerCount = 1,
3469 .holderCount = 0,
3470 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3471 mptGw.authorize({.account = alice});
3472 mptGw.authorize({.account = bob});
3473 auto const MPT = mptGw["MPT"];
3474 env(pay(gw, alice, MPT(10'000)));
3475 env(pay(gw, bob, MPT(10'000)));
3476 env.close();
3477
3478 // alice can create escrow w/ xfer rate
3479 auto const preAlice = env.balance(alice, MPT);
3480 auto const seq1 = env.seq(alice);
3481 auto const delta = MPT(125);
3482 env(escrow::create(alice, bob, MPT(125)),
3484 escrow::finish_time(env.now() + 1s),
3485 fee(baseFee * 150));
3486 env.close();
3487 auto const transferRate = escrow::rate(env, alice, seq1);
3488 BEAST_EXPECT(
3489 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
3490
3491 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 125);
3492 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 125);
3493 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-20'000));
3494
3495 // bob can finish escrow
3496 env(escrow::finish(bob, alice, seq1),
3499 fee(baseFee * 150));
3500 env.close();
3501
3502 BEAST_EXPECT(env.balance(alice, MPT) == preAlice - delta);
3503 BEAST_EXPECT(env.balance(bob, MPT) == MPT(10'100));
3504
3505 auto const escrowedWithFix =
3506 env.current()->rules().enabled(fixTokenEscrowV1) ? 0 : 25;
3507 auto const outstandingWithFix =
3508 env.current()->rules().enabled(fixTokenEscrowV1) ? MPT(19'975)
3509 : MPT(20'000);
3510 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == escrowedWithFix);
3511 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == escrowedWithFix);
3512 BEAST_EXPECT(env.balance(gw, MPT) == -outstandingWithFix);
3513 }
3514
3515 // test locked rate: cancel
3516 {
3517 Env env{*this, features};
3518 auto const baseFee = env.current()->fees().base;
3519 auto const alice = Account("alice");
3520 auto const bob = Account("bob");
3521 auto const gw = Account("gw");
3522
3523 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3524 mptGw.create(
3525 {.transferFee = 25000,
3526 .ownerCount = 1,
3527 .holderCount = 0,
3528 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3529 mptGw.authorize({.account = alice});
3530 mptGw.authorize({.account = bob});
3531 auto const MPT = mptGw["MPT"];
3532 env(pay(gw, alice, MPT(10'000)));
3533 env(pay(gw, bob, MPT(10'000)));
3534 env.close();
3535
3536 // alice can create escrow w/ xfer rate
3537 auto const preAlice = env.balance(alice, MPT);
3538 auto const preBob = env.balance(bob, MPT);
3539 auto const seq1 = env.seq(alice);
3540 auto const delta = MPT(125);
3541 env(escrow::create(alice, bob, MPT(125)),
3543 escrow::finish_time(env.now() + 1s),
3544 escrow::cancel_time(env.now() + 3s),
3545 fee(baseFee * 150));
3546 env.close();
3547 auto const transferRate = escrow::rate(env, alice, seq1);
3548 BEAST_EXPECT(
3549 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
3550
3551 // alice can cancel escrow
3552 env(escrow::cancel(alice, alice, seq1), fee(baseFee));
3553 env.close();
3554
3555 BEAST_EXPECT(env.balance(alice, MPT) == preAlice);
3556 BEAST_EXPECT(env.balance(bob, MPT) == preBob);
3557 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-20'000));
3558 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3559 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3560 }
3561
3562 // test locked rate: issuer is destination
3563 {
3564 Env env{*this, features};
3565 auto const baseFee = env.current()->fees().base;
3566 auto const alice = Account("alice");
3567 auto const bob = Account("bob");
3568 auto const gw = Account("gw");
3569
3570 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3571 mptGw.create(
3572 {.transferFee = 25000,
3573 .ownerCount = 1,
3574 .holderCount = 0,
3575 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3576 mptGw.authorize({.account = alice});
3577 mptGw.authorize({.account = bob});
3578 auto const MPT = mptGw["MPT"];
3579 env(pay(gw, alice, MPT(10'000)));
3580 env(pay(gw, bob, MPT(10'000)));
3581 env.close();
3582
3583 // alice can create escrow w/ xfer rate
3584 auto const preAlice = env.balance(alice, MPT);
3585 auto const seq1 = env.seq(alice);
3586 auto const delta = MPT(125);
3587 env(escrow::create(alice, gw, MPT(125)),
3589 escrow::finish_time(env.now() + 1s),
3590 fee(baseFee * 150));
3591 env.close();
3592 auto const transferRate = escrow::rate(env, alice, seq1);
3593 BEAST_EXPECT(
3594 transferRate.value == std::uint32_t(1'000'000'000 * 1.25));
3595
3596 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 125);
3597 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 125);
3598 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-20'000));
3599
3600 // bob can finish escrow
3601 env(escrow::finish(gw, alice, seq1),
3604 fee(baseFee * 150));
3605 env.close();
3606
3607 BEAST_EXPECT(env.balance(alice, MPT) == preAlice - delta);
3608 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3609 BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0);
3610 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-19'875));
3611 }
3612 }
3613
3614 void
3616 {
3617 testcase("MPT Require Auth");
3618 using namespace test::jtx;
3619 using namespace std::literals;
3620
3621 Env env{*this, features};
3622 auto const baseFee = env.current()->fees().base;
3623 auto const alice = Account("alice");
3624 auto const bob = Account("bob");
3625 auto const gw = Account("gw");
3626
3627 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3628 mptGw.create(
3629 {.ownerCount = 1,
3630 .holderCount = 0,
3632 mptGw.authorize({.account = alice});
3633 mptGw.authorize({.account = gw, .holder = alice});
3634 mptGw.authorize({.account = bob});
3635 mptGw.authorize({.account = gw, .holder = bob});
3636 auto const MPT = mptGw["MPT"];
3637 env(pay(gw, alice, MPT(10'000)));
3638 env.close();
3639
3640 auto seq = env.seq(alice);
3641 auto const delta = MPT(125);
3642 // alice can create escrow - is authorized
3643 env(escrow::create(alice, bob, MPT(100)),
3645 escrow::finish_time(env.now() + 1s),
3646 fee(baseFee * 150));
3647 env.close();
3648
3649 // bob can finish escrow - is authorized
3650 env(escrow::finish(bob, alice, seq),
3653 fee(baseFee * 150));
3654 env.close();
3655 }
3656
3657 void
3659 {
3660 testcase("MPT Lock");
3661 using namespace test::jtx;
3662 using namespace std::literals;
3663
3664 Env env{*this, features};
3665 auto const baseFee = env.current()->fees().base;
3666 auto const alice = Account("alice");
3667 auto const bob = Account("bob");
3668 auto const gw = Account("gw");
3669
3670 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3671 mptGw.create(
3672 {.ownerCount = 1,
3673 .holderCount = 0,
3675 mptGw.authorize({.account = alice});
3676 mptGw.authorize({.account = bob});
3677 auto const MPT = mptGw["MPT"];
3678 env(pay(gw, alice, MPT(10'000)));
3679 env(pay(gw, bob, MPT(10'000)));
3680 env.close();
3681
3682 // alice create escrow
3683 auto seq1 = env.seq(alice);
3684 env(escrow::create(alice, bob, MPT(100)),
3686 escrow::finish_time(env.now() + 1s),
3687 escrow::cancel_time(env.now() + 2s),
3688 fee(baseFee * 150));
3689 env.close();
3690
3691 // lock account & dest
3692 mptGw.set({.account = gw, .holder = alice, .flags = tfMPTLock});
3693 mptGw.set({.account = gw, .holder = bob, .flags = tfMPTLock});
3694
3695 // bob cannot finish
3696 env(escrow::finish(bob, alice, seq1),
3699 fee(baseFee * 150),
3700 ter(tecLOCKED));
3701 env.close();
3702
3703 // bob can cancel
3704 env(escrow::cancel(bob, alice, seq1));
3705 env.close();
3706 }
3707
3708 void
3710 {
3711 testcase("MPT Can Transfer");
3712 using namespace test::jtx;
3713 using namespace std::literals;
3714
3715 Env env{*this, features};
3716 auto const baseFee = env.current()->fees().base;
3717 auto const alice = Account("alice");
3718 auto const bob = Account("bob");
3719 auto const gw = Account("gw");
3720
3721 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3722 mptGw.create(
3723 {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow});
3724 mptGw.authorize({.account = alice});
3725 mptGw.authorize({.account = bob});
3726 auto const MPT = mptGw["MPT"];
3727 env(pay(gw, alice, MPT(10'000)));
3728 env(pay(gw, bob, MPT(10'000)));
3729 env.close();
3730
3731 // alice cannot create escrow to non issuer
3732 env(escrow::create(alice, bob, MPT(100)),
3734 escrow::finish_time(env.now() + 1s),
3735 escrow::cancel_time(env.now() + 2s),
3736 fee(baseFee * 150),
3737 ter(tecNO_AUTH));
3738 env.close();
3739
3740 // Escrow Create & Finish
3741 {
3742 // alice an create escrow to issuer
3743 auto seq = env.seq(alice);
3744 env(escrow::create(alice, gw, MPT(100)),
3746 escrow::finish_time(env.now() + 1s),
3747 fee(baseFee * 150));
3748 env.close();
3749
3750 // gw can finish
3751 env(escrow::finish(gw, alice, seq),
3754 fee(baseFee * 150));
3755 env.close();
3756 }
3757
3758 // Escrow Create & Cancel
3759 {
3760 // alice an create escrow to issuer
3761 auto seq = env.seq(alice);
3762 env(escrow::create(alice, gw, MPT(100)),
3764 escrow::finish_time(env.now() + 1s),
3765 escrow::cancel_time(env.now() + 2s),
3766 fee(baseFee * 150));
3767 env.close();
3768
3769 // alice can cancel
3770 env(escrow::cancel(alice, alice, seq));
3771 env.close();
3772 }
3773 }
3774
3775 void
3777 {
3778 testcase("MPT Destroy");
3779 using namespace test::jtx;
3780 using namespace std::literals;
3781
3782 // tecHAS_OBLIGATIONS: issuer cannot destroy issuance
3783 {
3784 Env env{*this, features};
3785 auto const baseFee = env.current()->fees().base;
3786 auto const alice = Account("alice");
3787 auto const bob = Account("bob");
3788 auto const gw = Account("gw");
3789
3790 MPTTester mptGw(env, gw, {.holders = {alice, bob}});
3791 mptGw.create(
3792 {.ownerCount = 1,
3793 .holderCount = 0,
3794 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3795 mptGw.authorize({.account = alice});
3796 mptGw.authorize({.account = bob});
3797 auto const MPT = mptGw["MPT"];
3798 env(pay(gw, alice, MPT(10'000)));
3799 env(pay(gw, bob, MPT(10'000)));
3800 env.close();
3801
3802 auto const seq1 = env.seq(alice);
3803 env(escrow::create(alice, bob, MPT(10)),
3805 escrow::finish_time(env.now() + 1s),
3806 fee(baseFee * 150));
3807 env.close();
3808
3809 env(pay(alice, gw, MPT(10'000)), ter(tecPATH_PARTIAL));
3810 env(pay(alice, gw, MPT(9'990)));
3811 env(pay(bob, gw, MPT(10'000)));
3812 BEAST_EXPECT(env.balance(alice, MPT) == MPT(0));
3813 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 10);
3814 BEAST_EXPECT(env.balance(bob, MPT) == MPT(0));
3815 BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0);
3816 BEAST_EXPECT(env.balance(gw, MPT) == MPT(-10));
3817 mptGw.authorize({.account = bob, .flags = tfMPTUnauthorize});
3818 mptGw.destroy(
3819 {.id = mptGw.issuanceID(),
3820 .ownerCount = 1,
3821 .err = tecHAS_OBLIGATIONS});
3822
3823 env(escrow::finish(bob, alice, seq1),
3826 fee(baseFee * 150),
3827 ter(tesSUCCESS));
3828 env.close();
3829
3830 env(pay(bob, gw, MPT(10)));
3831 mptGw.destroy({.id = mptGw.issuanceID(), .ownerCount = 0});
3832 }
3833
3834 // tecHAS_OBLIGATIONS: holder cannot destroy mptoken
3835 {
3836 Env env{*this, features};
3837 auto const baseFee = env.current()->fees().base;
3838 auto const alice = Account("alice");
3839 auto const bob = Account("bob");
3840 auto const gw = Account("gw");
3841 env.fund(XRP(10'000), bob);
3842 env.close();
3843
3844 MPTTester mptGw(env, gw, {.holders = {alice}});
3845 mptGw.create(
3846 {.ownerCount = 1,
3847 .holderCount = 0,
3848 .flags = tfMPTCanEscrow | tfMPTCanTransfer});
3849 mptGw.authorize({.account = alice});
3850 auto const MPT = mptGw["MPT"];
3851 env(pay(gw, alice, MPT(10'000)));
3852 env.close();
3853
3854 auto const seq1 = env.seq(alice);
3855 env(escrow::create(alice, bob, MPT(10)),
3857 escrow::finish_time(env.now() + 1s),
3858 fee(baseFee * 150),
3859 ter(tesSUCCESS));
3860 env.close();
3861
3862 env(pay(alice, gw, MPT(9'990)));
3863 env.close();
3864
3865 BEAST_EXPECT(env.balance(alice, MPT) == MPT(0));
3866 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 10);
3867 mptGw.authorize(
3868 {.account = alice,
3869 .flags = tfMPTUnauthorize,
3870 .err = tecHAS_OBLIGATIONS});
3871
3872 env(escrow::finish(bob, alice, seq1),
3875 fee(baseFee * 150),
3876 ter(tesSUCCESS));
3877 env.close();
3878
3879 BEAST_EXPECT(env.balance(alice, MPT) == MPT(0));
3880 BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0);
3881 mptGw.authorize({.account = alice, .flags = tfMPTUnauthorize});
3882 BEAST_EXPECT(!env.le(keylet::mptoken(MPT.mpt(), alice)));
3883 }
3884 }
3885
3886 void
3888 {
3889 testIOUEnablement(features);
3890 testIOUAllowLockingFlag(features);
3891 testIOUCreatePreflight(features);
3892 testIOUCreatePreclaim(features);
3893 testIOUFinishPreclaim(features);
3894 testIOUFinishDoApply(features);
3895 testIOUCancelPreclaim(features);
3896 testIOUBalances(features);
3897 testIOUMetaAndOwnership(features);
3898 testIOURippleState(features);
3899 testIOUGateway(features);
3900 testIOULockedRate(features);
3901 testIOULimitAmount(features);
3902 testIOURequireAuth(features);
3903 testIOUFreeze(features);
3904 testIOUINSF(features);
3905 testIOUPrecisionLoss(features);
3906 }
3907
3908 void
3910 {
3911 testMPTEnablement(features);
3912 testMPTCreatePreflight(features);
3913 testMPTCreatePreclaim(features);
3914 testMPTFinishPreclaim(features);
3915 testMPTFinishDoApply(features);
3916 testMPTCancelPreclaim(features);
3917 testMPTBalances(features);
3918 testMPTMetaAndOwnership(features);
3919 testMPTGateway(features);
3920 testMPTLockedRate(features);
3921 testMPTRequireAuth(features);
3922 testMPTLock(features);
3923 testMPTCanTransfer(features);
3924 testMPTDestroy(features);
3925 }
3926
3927public:
3928 void
3929 run() override
3930 {
3931 using namespace test::jtx;
3933 for (FeatureBitset const& feats :
3934 {all - featureSingleAssetVault - featureLendingProtocol, all})
3935 {
3936 testIOUWithFeats(feats);
3937 testMPTWithFeats(feats);
3938 testMPTWithFeats(feats - fixTokenEscrowV1);
3939 }
3940 }
3941};
3942
3943BEAST_DEFINE_TESTSUITE(EscrowToken, app, xrpl);
3944
3945} // namespace test
3946} // namespace xrpl
Represents a JSON value.
Definition json_value.h:131
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 begin() const
Definition Dir.cpp:15
const_iterator end() const
Definition Dir.cpp:33
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
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:104
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition Env.cpp:260
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:272
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition Env.cpp:251
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition Env.cpp:303
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:774
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:314
NetClock::time_point now()
Returns the current network time.
Definition Env.h:267
Converts to IOU Issue or STAmount.
void create(MPTCreate const &arg=MPTCreate{})
Definition mpt.cpp:144
Converts to MPT Issue or STAmount.
xrpl::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 escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Definition Indexes.cpp:371
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:356
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:508
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:522
auto const finish_time
Set the "FinishAfter" time tag on a JTx.
Definition escrow.h:79
Json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount)
Definition escrow.cpp:14
auto const condition
Definition escrow.h:84
Rate rate(Env &env, Account const &account, std::uint32_t const &seq)
Definition escrow.cpp:50
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
std::array< std::uint8_t, 39 > const cb1
Definition escrow.h:52
auto const cancel_time
Set the "CancelAfter" time tag on a JTx.
Definition escrow.h:82
auto const fulfillment
Definition escrow.h:86
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
Definition escrow.cpp:26
std::array< std::uint8_t, 4 > const fb1
Definition escrow.h:50
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition trust.cpp:13
std::uint32_t ownerCount(Env const &env, Account const &account)
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
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:11
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition flags.h:102
FeatureBitset testable_amendments()
Definition Env.h:55
auto const amount
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition flags.cpp:10
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
constexpr std::uint32_t asfGlobalFreeze
Definition TxFlags.h:64
constexpr std::uint32_t const tfMPTCanTransfer
Definition TxFlags.h:133
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
constexpr std::uint32_t const tfMPTRequireAuth
Definition TxFlags.h:130
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
Definition Protocol.h:235
STAmount amountFromString(Asset const &asset, std::string const &amount)
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:29
constexpr std::uint32_t const tfMPTCanLock
Definition TxFlags.h:129
constexpr std::uint32_t tfClearFreeze
Definition TxFlags.h:100
TERSubset< CanCvtToTER > TER
Definition TER.h:630
constexpr std::uint32_t const tfMPTLock
Definition TxFlags.h:157
constexpr std::uint32_t tfClearDeepFreeze
Definition TxFlags.h:102
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition View.cpp:818
constexpr std::uint32_t tfSetDeepFreeze
Definition TxFlags.h:101
constexpr std::uint32_t const tfMPTUnauthorize
Definition TxFlags.h:153
constexpr std::uint32_t tfSetfAuth
Definition TxFlags.h:96
@ tapNONE
Definition ApplyView.h:12
constexpr std::uint32_t asfRequireAuth
Definition TxFlags.h:59
@ temBAD_CURRENCY
Definition TER.h:71
@ temBAD_FEE
Definition TER.h:73
@ temDISABLED
Definition TER.h:95
@ temBAD_AMOUNT
Definition TER.h:70
@ tecLOCKED
Definition TER.h:340
@ tecNO_LINE_INSUF_RESERVE
Definition TER.h:274
@ tecPATH_PARTIAL
Definition TER.h:264
@ tecNO_TARGET
Definition TER.h:286
@ tecOBJECT_NOT_FOUND
Definition TER.h:308
@ tecNO_AUTH
Definition TER.h:282
@ tecFROZEN
Definition TER.h:285
@ tecINSUFFICIENT_FUNDS
Definition TER.h:307
@ tecNO_LINE
Definition TER.h:283
@ tecPRECISION_LOSS
Definition TER.h:345
@ tecINSUFFICIENT_RESERVE
Definition TER.h:289
@ tecLIMIT_EXCEEDED
Definition TER.h:343
@ tecNO_PERMISSION
Definition TER.h:287
@ tecNO_ISSUER
Definition TER.h:281
@ tecHAS_OBLIGATIONS
Definition TER.h:299
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr std::uint32_t tfSetFreeze
Definition TxFlags.h:99
constexpr std::uint32_t const tfMPTCanEscrow
Definition TxFlags.h:131
constexpr std::uint32_t asfAllowTrustLineLocking
Definition TxFlags.h:76
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
Definition Indexes.cpp:152
@ tesSUCCESS
Definition TER.h:226
std::uint32_t value
Definition Rate.h:22
void testMPTCreatePreclaim(FeatureBitset features)
void testMPTFinishDoApply(FeatureBitset features)
void testMPTMetaAndOwnership(FeatureBitset features)
void testIOUBalances(FeatureBitset features)
void testIOUCreatePreclaim(FeatureBitset features)
void testMPTGateway(FeatureBitset features)
void testMPTCanTransfer(FeatureBitset features)
void testIOUFinishPreclaim(FeatureBitset features)
void run() override
Runs the suite.
void testIOUMetaAndOwnership(FeatureBitset features)
void testIOUPrecisionLoss(FeatureBitset features)
void testMPTLock(FeatureBitset features)
void testMPTCancelPreclaim(FeatureBitset features)
void testIOUEnablement(FeatureBitset features)
void testMPTBalances(FeatureBitset features)
void testMPTRequireAuth(FeatureBitset features)
void testIOUFinishDoApply(FeatureBitset features)
jtx::PrettyAmount issuerEscrowed(jtx::Env &env, jtx::Account const &account, Issue const &issue)
void testIOUFreeze(FeatureBitset features)
void testMPTEnablement(FeatureBitset features)
static uint64_t mptEscrowed(jtx::Env const &env, jtx::Account const &account, jtx::MPT const &mpt)
void testIOUCancelPreclaim(FeatureBitset features)
void testIOUGateway(FeatureBitset features)
static uint64_t issuerMPTEscrowed(jtx::Env const &env, jtx::MPT const &mpt)
void testIOULimitAmount(FeatureBitset features)
void testIOUAllowLockingFlag(FeatureBitset features)
void testMPTCreatePreflight(FeatureBitset features)
void testIOULockedRate(FeatureBitset features)
void testMPTFinishPreclaim(FeatureBitset features)
void testIOUINSF(FeatureBitset features)
jtx::PrettyAmount issuerBalance(jtx::Env &env, jtx::Account const &account, Issue const &issue)
void testIOUWithFeats(FeatureBitset features)
void testMPTLockedRate(FeatureBitset features)
void testMPTWithFeats(FeatureBitset features)
void testIOUCreatePreflight(FeatureBitset features)
void testIOURequireAuth(FeatureBitset features)
void testMPTDestroy(FeatureBitset features)
void testIOURippleState(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