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