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