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