20 #include <ripple/protocol/Feature.h>
21 #include <ripple/protocol/jss.h>
103 if (sle && sle->getType() == ltCHECK)
104 result.push_back(sle);
114 if (
auto const sleAccount = env.
le(account))
132 Json::Value const meta = env.
rpc(
"tx", txHash)[jss::result][jss::meta];
152 using namespace test::jtx;
153 Account
const alice{
"alice"};
159 env.fund(XRP(1000), alice);
163 env(check::create(env.master, alice, XRP(100)), ter(
temDISABLED));
166 env(check::cash(alice, checkId, XRP(100)), ter(
temDISABLED));
169 env(check::cancel(alice, checkId), ter(
temDISABLED));
175 Env env{*
this, features};
177 env.fund(XRP(1000), alice);
181 env(check::create(env.master, alice, XRP(100)));
184 env(check::cash(alice, checkId1, XRP(100)));
189 env(check::create(env.master, alice, XRP(100)));
192 env(check::cancel(alice, checkId2));
201 testcase(
"Create valid");
203 using namespace test::jtx;
205 Account
const gw{
"gateway"};
206 Account
const alice{
"alice"};
207 Account
const bob{
"bob"};
208 IOU
const USD{gw[
"USD"]};
210 Env env{*
this, features};
212 STAmount const startBalance{XRP(1000).value()};
213 env.fund(startBalance, gw, alice, bob);
218 auto writeTwoChecks = [&env, &USD,
this](
219 Account
const& from, Account
const& to) {
226 env(check::create(from, to, XRP(2000)));
229 env(check::create(from, to, USD(50)));
235 env.require(owners(from, fromOwnerCount + 2));
237 owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount));
240 writeTwoChecks(alice, bob);
241 writeTwoChecks(gw, alice);
242 writeTwoChecks(alice, gw);
248 using namespace std::chrono_literals;
251 env(check::create(alice, bob, USD(50)), expiration(env.now() + 1s));
254 env(check::create(alice, bob, USD(50)), source_tag(2));
256 env(check::create(alice, bob, USD(50)), dest_tag(3));
258 env(check::create(alice, bob, USD(50)), invoice_id(
uint256{4}));
260 env(check::create(alice, bob, USD(50)),
261 expiration(env.now() + 1s),
272 env(regkey(alice, alie));
277 env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie));
281 env(check::create(alice, bob, USD(50)), sig(alie));
287 XRPAmount const baseFeeDrops{env.current()->fees().base};
288 env(check::create(alice, bob, USD(50)),
290 fee(3 * baseFeeDrops));
300 testcase(
"Create invalid");
302 using namespace test::jtx;
304 Account
const gw1{
"gateway1"};
305 Account
const gwF{
"gatewayFrozen"};
306 Account
const alice{
"alice"};
307 Account
const bob{
"bob"};
308 IOU
const USD{gw1[
"USD"]};
310 Env env{*
this, features};
312 STAmount const startBalance{XRP(1000).value()};
313 env.fund(startBalance, gw1, gwF, alice, bob);
316 env(check::create(alice, bob, USD(50)),
322 env(check::create(alice, bob, USD(50)),
328 env(check::create(alice, alice, XRP(10)), ter(
temREDUNDANT));
332 env(check::create(alice, bob, drops(-1)), ter(
temBAD_AMOUNT));
335 env(check::create(alice, bob, drops(0)), ter(
temBAD_AMOUNT));
338 env(check::create(alice, bob, drops(1)));
347 env(check::create(alice, bob, USD(1)));
356 env(check::create(alice, bob, USD(50)),
362 Account
const bogie{
"bogie"};
363 env(check::create(alice, bogie, USD(50)), ter(
tecNO_DST));
373 env(check::create(alice, bob, USD(50)), dest_tag(11));
380 IOU
const USF{gwF[
"USF"]};
384 env(check::create(alice, bob, USF(50)), ter(
tecFROZEN));
390 env(check::create(alice, bob, USF(50)));
396 env.trust(USD(1000), alice);
397 env.trust(USD(1000), bob);
399 env(pay(gw1, alice, USD(25)));
400 env(pay(gw1, bob, USD(25)));
408 env(check::create(alice, bob, USD(50)), ter(
tecFROZEN));
412 env(check::create(bob, alice, USD(50)));
414 env(pay(bob, alice, USD(1)));
416 env(check::create(gw1, alice, USD(50)));
418 env(pay(gw1, alice, USD(1)));
424 env(check::create(alice, bob, USD(50)));
426 env(check::create(bob, alice, USD(50)));
428 env(check::create(gw1, alice, USD(50)));
436 env(check::create(alice, bob, USD(50)));
438 env(pay(alice, bob, USD(1)));
440 env(check::create(bob, alice, USD(50)), ter(
tecFROZEN));
444 env(check::create(gw1, alice, USD(50)), ter(
tecFROZEN));
455 env(check::create(alice, bob, USD(50)),
456 expiration(env.now()),
460 using namespace std::chrono_literals;
461 env(check::create(alice, bob, USD(50)), expiration(env.now() + 1s));
465 Account
const cheri{
"cheri"};
466 env.fund(env.current()->fees().accountReserve(1) - drops(1), cheri);
468 env(check::create(cheri, bob, USD(50)),
469 fee(drops(env.current()->fees().base)),
473 env(pay(bob, cheri, drops(env.current()->fees().base + 1)));
476 env(check::create(cheri, bob, USD(50)));
484 testcase(
"Cash XRP");
486 using namespace test::jtx;
488 Account
const alice{
"alice"};
489 Account
const bob{
"bob"};
491 Env env{*
this, features};
493 XRPAmount const baseFeeDrops{env.current()->fees().base};
494 STAmount const startBalance{XRP(300).value()};
495 env.fund(startBalance, alice, bob);
499 env(check::create(alice, bob, XRP(10)));
501 env.require(balance(alice, startBalance - drops(baseFeeDrops)));
502 env.require(balance(bob, startBalance));
508 env(check::cash(bob, chkId, XRP(10)));
511 balance(alice, startBalance - XRP(10) - drops(baseFeeDrops)));
513 balance(bob, startBalance + XRP(10) - drops(baseFeeDrops)));
520 env(pay(env.master, alice, XRP(10) + drops(baseFeeDrops)));
521 env(pay(bob, env.master, XRP(10) - drops(baseFeeDrops * 2)));
523 env.require(balance(alice, startBalance));
524 env.require(balance(bob, startBalance));
528 STAmount const reserve{env.current()->fees().accountReserve(0)};
530 startBalance - reserve - drops(baseFeeDrops)};
532 env(check::create(alice, bob, checkAmount));
536 env(check::cash(bob, chkId, checkAmount + drops(1)),
540 bob, chkId, check::DeliverMin(checkAmount + drops(1))),
547 env(check::cash(bob, chkId, check::DeliverMin(checkAmount)));
549 env.require(balance(alice, reserve));
551 bob, startBalance + checkAmount - drops(baseFeeDrops * 3)));
558 env(pay(env.master, alice, checkAmount + drops(baseFeeDrops)));
559 env(pay(bob, env.master, checkAmount - drops(baseFeeDrops * 4)));
561 env.require(balance(alice, startBalance));
562 env.require(balance(bob, startBalance));
566 STAmount const reserve{env.current()->fees().accountReserve(0)};
568 startBalance - reserve - drops(baseFeeDrops - 1)};
570 env(check::create(alice, bob, checkAmount));
579 env(check::cash(bob, chkId, check::DeliverMin(drops(1))));
581 env.require(balance(alice, reserve));
583 bob, startBalance + checkAmount - drops(baseFeeDrops * 2 + 1)));
590 env(pay(env.master, alice, checkAmount + drops(baseFeeDrops - 1)));
592 bob, env.master, checkAmount - drops(baseFeeDrops * 3 + 1)));
594 env.require(balance(alice, startBalance));
595 env.require(balance(bob, startBalance));
603 testcase(
"Cash IOU");
605 using namespace test::jtx;
607 bool const cashCheckMakesTrustLine =
610 Account
const gw{
"gateway"};
611 Account
const alice{
"alice"};
612 Account
const bob{
"bob"};
613 IOU
const USD{gw[
"USD"]};
616 Env env{*
this, features};
618 env.fund(XRP(1000), gw, alice, bob);
622 env(check::create(alice, bob, USD(10)));
630 env(trust(alice, USD(20)));
632 env(pay(gw, alice, USD(9.5)));
639 env(pay(gw, alice, USD(0.5)));
641 if (!cashCheckMakesTrustLine)
646 env(check::cash(bob, chkId1, USD(10)), ter(
tecNO_LINE));
651 env(trust(bob, USD(9.5)));
653 if (!cashCheckMakesTrustLine)
664 env(trust(bob, USD(10.5)));
670 env(check::cash(bob, chkId1, USD(10)));
672 env.require(balance(alice, USD(0)));
673 env.require(balance(bob, USD(10)));
680 env(check::cash(bob, chkId1, USD(10)), ter(
tecNO_ENTRY));
684 env(pay(bob, alice, USD(7)));
688 env(check::create(alice, bob, USD(7)));
695 env(check::cash(bob, chkId2, USD(5)));
697 env.require(balance(alice, USD(2)));
698 env.require(balance(bob, USD(8)));
706 env(check::create(alice, bob, USD(2)));
709 env(check::create(alice, bob, USD(2)));
715 env(check::cash(bob, chkId4, USD(2)));
717 env.require(balance(alice, USD(0)));
718 env.require(balance(bob, USD(10)));
728 env.require(balance(alice, USD(0)));
729 env.require(balance(bob, USD(10)));
735 if (cashCheckMakesTrustLine)
751 env(check::create(gw, bob, USD(20)));
755 env(check::cash(bob, chkId20, USD(20)));
757 env.require(balance(bob, USD(30)));
761 env(pay(bob, gw, USD(20)));
765 env(check::cancel(bob, chkId3));
767 env.require(balance(alice, USD(0)));
768 env.require(balance(bob, USD(10)));
776 Env env{*
this, features};
778 env.fund(XRP(1000), gw, alice, bob);
780 env(trust(alice, USD(20)));
781 env(trust(bob, USD(20)));
783 env(pay(gw, alice, USD(8)));
788 env(check::create(alice, bob, USD(9)));
791 env(check::create(alice, bob, USD(8)));
794 env(check::create(alice, bob, USD(7)));
797 env(check::create(alice, bob, USD(6)));
802 env(check::cash(bob, chkId9, check::DeliverMin(USD(9))),
807 env(check::cash(bob, chkId9, check::DeliverMin(USD(7))));
809 env.require(balance(alice, USD(0)));
810 env.require(balance(bob, USD(8)));
817 env(pay(bob, alice, USD(7)));
822 env(check::cash(bob, chkId7, check::DeliverMin(USD(7))));
824 env.require(balance(alice, USD(0)));
825 env.require(balance(bob, USD(8)));
832 env(pay(bob, alice, USD(8)));
837 env(check::cash(bob, chkId6, check::DeliverMin(USD(4))));
839 env.require(balance(alice, USD(2)));
840 env.require(balance(bob, USD(6)));
848 env(check::cash(bob, chkId8, check::DeliverMin(USD(2))));
850 env.require(balance(alice, USD(0)));
851 env.require(balance(bob, USD(8)));
859 Env env(*
this, features);
861 env.fund(XRP(1000), gw, alice, bob);
864 env(trust(gw, alice[
"USD"](100)), txflags(
tfSetfAuth));
865 env(trust(alice, USD(20)));
867 env(pay(gw, alice, USD(8)));
873 env(check::create(alice, bob, USD(7)));
876 env(check::cash(bob, chkId, USD(7)),
882 env(trust(bob, USD(5)));
885 env(check::cash(bob, chkId, USD(7)), ter(
tecNO_AUTH));
889 env(trust(gw, bob[
"USD"](1)), txflags(
tfSetfAuth));
894 if (!cashCheckMakesTrustLine)
910 env(check::cash(bob, chkId, check::DeliverMin(USD(4))));
911 STAmount const bobGot = cashCheckMakesTrustLine ? USD(7) : USD(5);
913 env.require(balance(alice, USD(8) - bobGot));
914 env.require(balance(bob, bobGot));
925 for (
auto const& testFeatures :
929 Env env{*
this, testFeatures};
931 env.fund(XRP(1000), gw, alice, bob);
935 env(check::create(alice, bob, USD(1)));
939 env(check::create(alice, bob, USD(2)));
942 env(trust(alice, USD(20)));
943 env(trust(bob, USD(20)));
945 env(pay(gw, alice, USD(8)));
950 env(regkey(bob, bobby));
955 env(signers(bob, 2, {{bogie, 1}, {demon, 1}}), sig(bobby));
960 int const signersCount = {
962 BEAST_EXPECT(
ownerCount(env, bob) == signersCount + 1);
965 env(check::cash(bob, chkId1, (USD(1))), sig(bobby));
967 env.require(balance(alice, USD(7)));
968 env.require(balance(bob, USD(1)));
972 BEAST_EXPECT(
ownerCount(env, bob) == signersCount + 1);
975 XRPAmount const baseFeeDrops{env.current()->fees().base};
976 env(check::cash(bob, chkId2, (USD(2))),
978 fee(3 * baseFeeDrops));
980 env.require(balance(alice, USD(5)));
981 env.require(balance(bob, USD(3)));
985 BEAST_EXPECT(
ownerCount(env, bob) == signersCount + 1);
993 testcase(
"Cash with transfer fee");
995 using namespace test::jtx;
997 Account
const gw{
"gateway"};
998 Account
const alice{
"alice"};
999 Account
const bob{
"bob"};
1000 IOU
const USD{gw[
"USD"]};
1002 Env env{*
this, features};
1004 env.fund(XRP(1000), gw, alice, bob);
1006 env(trust(alice, USD(1000)));
1007 env(trust(bob, USD(1000)));
1009 env(pay(gw, alice, USD(1000)));
1013 env(rate(gw, 1.25));
1019 env(check::create(alice, bob, USD(125)));
1026 env(check::create(alice, bob, USD(120)));
1032 env(check::cash(bob, chkId125, check::DeliverMin(USD(101))),
1038 env(check::cash(bob, chkId125, check::DeliverMin(USD(75))));
1040 env.require(balance(alice, USD(1000 - 125)));
1041 env.require(balance(bob, USD(0 + 100)));
1051 env(check::cash(bob, chkId120, USD(50)));
1053 env.require(balance(alice, USD(1000 - 125 - 60)));
1054 env.require(balance(bob, USD(0 + 100 + 50)));
1063 testcase(
"Cash quality");
1065 using namespace test::jtx;
1067 Account
const gw{
"gateway"};
1068 Account
const alice{
"alice"};
1069 Account
const bob{
"bob"};
1070 IOU
const USD{gw[
"USD"]};
1072 Env env{*
this, features};
1074 env.fund(XRP(1000), gw, alice, bob);
1076 env(trust(alice, USD(1000)));
1077 env(trust(bob, USD(1000)));
1079 env(pay(gw, alice, USD(1000)));
1087 auto qIn = [](
double percent) {
return qualityInPercent(percent); };
1088 auto qOut = [](
double percent) {
return qualityOutPercent(percent); };
1092 auto testNonIssuerQPay = [&env, &alice, &bob, &USD](
1093 Account
const& truster,
1095 auto const& inOrOut,
1099 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1100 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
1103 env(trust(truster, iou(1000)), inOrOut(pct));
1106 env(pay(alice, bob, USD(amount)), sendmax(USD(10)));
1108 env.require(balance(alice, aliceStart - USD(10)));
1109 env.require(balance(bob, bobStart + USD(10)));
1113 env(trust(truster, iou(1000)), inOrOut(0));
1117 auto testNonIssuerQCheck = [&env, &alice, &bob, &USD](
1118 Account
const& truster,
1120 auto const& inOrOut,
1124 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1125 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
1128 env(trust(truster, iou(1000)), inOrOut(pct));
1132 env(check::create(alice, bob, USD(10)));
1135 env(check::cash(bob, chkId, USD(amount)));
1137 env.require(balance(alice, aliceStart - USD(10)));
1138 env.require(balance(bob, bobStart + USD(10)));
1142 env(trust(truster, iou(1000)), inOrOut(0));
1147 testNonIssuerQPay(alice, gw[
"USD"], qIn, 50, 10);
1148 testNonIssuerQCheck(alice, gw[
"USD"], qIn, 50, 10);
1151 testNonIssuerQPay(bob, gw[
"USD"], qIn, 50, 5);
1152 testNonIssuerQCheck(bob, gw[
"USD"], qIn, 50, 5);
1154 testNonIssuerQPay(gw, alice[
"USD"], qIn, 50, 10);
1155 testNonIssuerQCheck(gw, alice[
"USD"], qIn, 50, 10);
1157 testNonIssuerQPay(gw, bob[
"USD"], qIn, 50, 10);
1158 testNonIssuerQCheck(gw, bob[
"USD"], qIn, 50, 10);
1160 testNonIssuerQPay(alice, gw[
"USD"], qOut, 200, 10);
1161 testNonIssuerQCheck(alice, gw[
"USD"], qOut, 200, 10);
1163 testNonIssuerQPay(bob, gw[
"USD"], qOut, 200, 10);
1164 testNonIssuerQCheck(bob, gw[
"USD"], qOut, 200, 10);
1166 testNonIssuerQPay(gw, alice[
"USD"], qOut, 200, 10);
1167 testNonIssuerQCheck(gw, alice[
"USD"], qOut, 200, 10);
1169 testNonIssuerQPay(gw, bob[
"USD"], qOut, 200, 10);
1170 testNonIssuerQCheck(gw, bob[
"USD"], qOut, 200, 10);
1177 auto testIssuerQPay = [&env, &gw, &alice, &USD](
1178 Account
const& truster,
1180 auto const& inOrOut,
1188 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1191 env(trust(truster, iou(1000)), inOrOut(pct));
1195 env(pay(alice, gw, USD(amt1)), sendmax(USD(max1)));
1197 env.require(balance(alice, aliceStart - USD(10)));
1200 env(pay(gw, alice, USD(amt2)), sendmax(USD(max2)));
1202 env.require(balance(alice, aliceStart));
1206 env(trust(truster, iou(1000)), inOrOut(0));
1210 auto testIssuerQCheck = [&env, &gw, &alice, &USD](
1211 Account
const& truster,
1213 auto const& inOrOut,
1221 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1224 env(trust(truster, iou(1000)), inOrOut(pct));
1229 env(check::create(alice, gw, USD(max1)));
1232 env(check::cash(gw, chkAliceId, USD(amt1)));
1234 env.require(balance(alice, aliceStart - USD(10)));
1238 env(check::create(gw, alice, USD(max2)));
1241 env(check::cash(alice, chkGwId, USD(amt2)));
1243 env.require(balance(alice, aliceStart));
1247 env(trust(truster, iou(1000)), inOrOut(0));
1253 testIssuerQPay(alice, gw[
"USD"], qIn, 50, 10, 10, 5, 10);
1254 testIssuerQCheck(alice, gw[
"USD"], qIn, 50, 10, 10, 5, 10);
1256 testIssuerQPay(gw, alice[
"USD"], qIn, 50, 10, 10, 10, 10);
1257 testIssuerQCheck(gw, alice[
"USD"], qIn, 50, 10, 10, 10, 10);
1259 testIssuerQPay(alice, gw[
"USD"], qOut, 200, 10, 10, 10, 10);
1260 testIssuerQCheck(alice, gw[
"USD"], qOut, 200, 10, 10, 10, 10);
1262 testIssuerQPay(gw, alice[
"USD"], qOut, 200, 10, 10, 10, 10);
1263 testIssuerQCheck(gw, alice[
"USD"], qOut, 200, 10, 10, 10, 10);
1270 testcase(
"Cash invalid");
1272 using namespace test::jtx;
1274 Account
const gw{
"gateway"};
1275 Account
const alice{
"alice"};
1276 Account
const bob{
"bob"};
1277 Account
const zoe{
"zoe"};
1278 IOU
const USD{gw[
"USD"]};
1280 Env env(*
this, features);
1282 env.fund(XRP(1000), gw, alice, bob, zoe);
1285 env(trust(alice, USD(20)));
1287 env(pay(gw, alice, USD(20)));
1294 env(check::create(alice, bob, USD(20)));
1302 env(check::cash(bob, chkId, USD(20)), ter(
tecNO_LINE));
1308 env(trust(bob, USD(20)));
1314 env(check::cash(bob, chkId, USD(20)), ter(
tecNO_ENTRY));
1320 env(check::create(alice, bob, USD(20)));
1324 env(check::create(alice, bob, XRP(10)));
1327 using namespace std::chrono_literals;
1329 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
1333 env(check::create(alice, bob, USD(1)));
1337 env(check::create(alice, bob, USD(2)));
1341 env(check::create(alice, bob, USD(3)));
1345 env(check::create(alice, bob, USD(4)));
1349 env(check::create(alice, bob, USD(1)));
1353 env(check::create(alice, bob, USD(2)), dest_tag(7));
1357 auto failingCases = [&env, &gw, &alice, &bob](
1360 env(check::cash(bob, chkId, amount),
1366 env(check::cash(bob, chkId, amount),
1392 env(check::cash(bob, chkId, amount.zeroed()),
1398 if (!amount.native())
1415 IOU
const wrongCurrency{gw[
"EUR"]};
1417 badAmount.
setIssue(wrongCurrency.issue());
1418 env(check::cash(bob, chkId, badAmount), ter(
temMALFORMED));
1424 IOU
const wrongIssuer{alice[
"USD"]};
1426 badAmount.
setIssue(wrongIssuer.issue());
1427 env(check::cash(bob, chkId, badAmount), ter(
temMALFORMED));
1436 env(check::cash(bob, chkId, check::DeliverMin(amount + amount)),
1441 failingCases(chkIdX, XRP(10));
1442 failingCases(chkIdU, USD(20));
1445 env(check::cash(bob, chkIdU, USD(20)));
1447 env(check::cash(bob, chkIdX, check::DeliverMin(XRP(10))));
1451 env(check::cash(bob, chkIdExp, XRP(10)), ter(
tecEXPIRED));
1455 env(check::cancel(zoe, chkIdExp));
1460 env(pay(bob, alice, USD(20)));
1462 env.require(balance(alice, USD(20)));
1463 env.require(balance(bob, USD(0)));
1471 env(check::cash(bob, chkIdFroz1, check::DeliverMin(USD(0.5))),
1479 env(check::cash(bob, chkIdFroz1, USD(1)));
1481 env.require(balance(alice, USD(19)));
1482 env.require(balance(bob, USD(1)));
1489 env(check::cash(bob, chkIdFroz2, check::DeliverMin(USD(1))),
1496 env(check::cash(bob, chkIdFroz2, USD(2)));
1498 env.require(balance(alice, USD(17)));
1499 env.require(balance(bob, USD(3)));
1504 env(check::cash(bob, chkIdFroz3, USD(3)), ter(
tecFROZEN));
1506 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))),
1513 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))));
1515 env.require(balance(alice, USD(14)));
1516 env.require(balance(bob, USD(6)));
1522 env(check::cash(bob, chkIdFroz4, USD(4)), ter(
terNO_LINE));
1524 env(check::cash(bob, chkIdFroz4, check::DeliverMin(USD(1))),
1531 env(check::cash(bob, chkIdFroz4, USD(4)));
1533 env.require(balance(alice, USD(10)));
1534 env.require(balance(bob, USD(10)));
1543 env(check::cash(bob, chkIdNoDest1, check::DeliverMin(USD(0.5))),
1548 env(check::cash(bob, chkIdHasDest2, USD(2)));
1550 env.require(balance(alice, USD(8)));
1551 env.require(balance(bob, USD(12)));
1557 env(check::cash(bob, chkIdNoDest1, USD(1)));
1559 env.require(balance(alice, USD(7)));
1560 env.require(balance(bob, USD(13)));
1568 testcase(
"Cancel valid");
1570 using namespace test::jtx;
1572 Account
const gw{
"gateway"};
1573 Account
const alice{
"alice"};
1574 Account
const bob{
"bob"};
1575 Account
const zoe{
"zoe"};
1576 IOU
const USD{gw[
"USD"]};
1580 for (
auto const& testFeatures :
1584 Env env{*
this, testFeatures};
1586 env.fund(XRP(1000), gw, alice, bob, zoe);
1591 env(check::create(alice, bob, USD(10)));
1595 env(check::create(alice, bob, XRP(10)));
1599 env(check::create(alice, bob, USD(10)));
1603 using namespace std::chrono_literals;
1605 env(check::create(alice, bob, XRP(10)),
1606 expiration(env.now() + 600s));
1610 env(check::create(alice, bob, USD(10)),
1611 expiration(env.now() + 600s));
1615 env(check::create(alice, bob, XRP(10)),
1616 expiration(env.now() + 600s));
1621 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
1625 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
1629 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
1634 env(check::create(alice, bob, USD(10)));
1638 env(check::create(alice, bob, XRP(10)));
1644 env(check::cancel(alice, chkId1));
1649 env(check::cancel(bob, chkId2));
1660 env(check::cancel(alice, chkIdNotExp1));
1665 env(check::cancel(bob, chkIdNotExp2));
1676 env(check::cancel(alice, chkIdExp1));
1681 env(check::cancel(bob, chkIdExp2));
1686 env(check::cancel(zoe, chkIdExp3));
1693 env(regkey(alice, alie));
1698 env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie));
1703 int const signersCount{
1707 env(check::cancel(alice, chkIdReg), sig(alie));
1710 BEAST_EXPECT(
ownerCount(env, alice) == signersCount + 3);
1713 XRPAmount const baseFeeDrops{env.current()->fees().base};
1714 env(check::cancel(alice, chkIdMSig),
1716 fee(3 * baseFeeDrops));
1719 BEAST_EXPECT(
ownerCount(env, alice) == signersCount + 2);
1722 env(check::cancel(alice, chkId3), sig(alice));
1725 BEAST_EXPECT(
ownerCount(env, alice) == signersCount + 1);
1727 env(check::cancel(bob, chkIdNotExp3));
1730 BEAST_EXPECT(
ownerCount(env, alice) == signersCount + 0);
1738 testcase(
"Cancel invalid");
1740 using namespace test::jtx;
1742 Account
const alice{
"alice"};
1743 Account
const bob{
"bob"};
1745 Env env{*
this, features};
1747 env.fund(XRP(1000), alice, bob);
1750 env(check::cancel(bob,
getCheckIndex(alice, env.seq(alice))),
1756 env(check::cancel(bob,
getCheckIndex(alice, env.seq(alice))),
1762 env(check::cancel(bob,
getCheckIndex(alice, env.seq(alice))),
1770 testcase(
"Fix1623 enable");
1772 using namespace test::jtx;
1774 auto testEnable = [
this](
1779 Account
const alice{
"alice"};
1780 Account
const bob{
"bob"};
1782 Env env{*
this, features};
1784 env.fund(XRP(1000), alice, bob);
1788 env(check::create(alice, bob, XRP(200)));
1791 env(check::cash(bob, chkId, check::DeliverMin(XRP(100))));
1801 env.rpc(
"tx", txHash)[jss::result][jss::meta];
1805 BEAST_EXPECT(meta.
isMember(jss::delivered_amount) == hasFields);
1809 testEnable(features -
fix1623,
false);
1810 testEnable(features,
true);
1816 testcase(
"With Tickets");
1818 using namespace test::jtx;
1820 Account
const gw{
"gw"};
1821 Account
const alice{
"alice"};
1822 Account
const bob{
"bob"};
1823 IOU
const USD{gw[
"USD"]};
1825 Env env{*
this, features};
1826 env.fund(XRP(1000), gw, alice, bob);
1833 env(ticket::create(alice, 10));
1837 env(ticket::create(bob, 10));
1841 env.require(owners(alice, 10));
1842 env.require(owners(bob, 10));
1845 env(trust(alice, USD(1000)), ticket::use(aliceTicketSeq++));
1846 env(trust(bob, USD(1000)), ticket::use(bobTicketSeq++));
1848 env.require(owners(alice, 10));
1849 env.require(owners(bob, 10));
1851 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1852 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1854 env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
1855 BEAST_EXPECT(env.seq(bob) == bobSeq);
1857 env(pay(gw, alice, USD(900)));
1863 env(check::create(alice, bob, XRP(200)), ticket::use(aliceTicketSeq++));
1866 env(check::create(alice, bob, XRP(300)), ticket::use(aliceTicketSeq++));
1869 env(check::create(alice, bob, USD(200)), ticket::use(aliceTicketSeq++));
1872 env(check::create(alice, bob, USD(300)), ticket::use(aliceTicketSeq++));
1876 env.require(owners(alice, 10));
1877 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1879 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1881 env.require(owners(bob, 10));
1882 BEAST_EXPECT(env.seq(bob) == bobSeq);
1885 env(check::cancel(bob, chkIdXrp1), ticket::use(bobTicketSeq++));
1886 env(check::cancel(bob, chkIdUsd2), ticket::use(bobTicketSeq++));
1889 env.require(owners(alice, 8));
1890 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1892 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1894 env.require(owners(bob, 8));
1895 BEAST_EXPECT(env.seq(bob) == bobSeq);
1898 env(check::cash(bob, chkIdXrp2, XRP(300)), ticket::use(bobTicketSeq++));
1899 env(check::cash(bob, chkIdUsd1, USD(200)), ticket::use(bobTicketSeq++));
1902 env.require(owners(alice, 6));
1903 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1905 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1906 env.require(balance(alice, USD(700)));
1907 env.require(balance(alice, drops(699
'999'940)));
1909 env.require(owners(bob, 6));
1910 BEAST_EXPECT(env.seq(bob) == bobSeq);
1911 env.require(balance(bob, USD(200)));
1912 env.require(balance(bob, drops(1
'299'999
'940)));
1916 testTrustLineCreation(FeatureBitset features)
1918 // Explore automatic trust line creation when a check is cashed.
1920 // This capability is enabled by the featureCheckCashMakesTrustLine
1921 // amendment. So this test executes only when that amendment is
1923 assert(features[featureCheckCashMakesTrustLine]);
1925 testcase("Trust Line Creation");
1927 using namespace test::jtx;
1929 Env env{*this, features};
1931 // An account that independently tracks its owner count.
1934 beast::unit_test::suite& suite;
1940 verifyOwners(std::uint32_t line) const
1943 ownerCount(env, acct) == owners,
1944 "Owner count mismatch",
1949 // Operators to make using the class more convenient.
1950 operator Account const() const
1955 operator ripple::AccountID() const
1961 operator[](std::string const& s) const
1967 AccountOwns alice{*this, env, "alice", 0};
1968 AccountOwns bob{*this, env, "bob", 0};
1970 // Fund with noripple so the accounts do not have any flags set.
1971 env.fund(XRP(5000), noripple(alice, bob));
1974 // Automatic trust line creation should fail if the check destination
1975 // can't afford the reserve
for the trust line.
1977 AccountOwns gw1{*this, env,
"gw1", 0};
1982 env.fund(XRP(5000), noripple(gw1));
1985 IOU
const CK8 = gw1[
"CK8"];
1986 gw1.verifyOwners(__LINE__);
1988 Account
const yui{
"yui"};
1993 env.fund(XRP(200), yui);
1997 env(check::create(gw1, yui, CK8(99)));
2000 env(check::cash(yui, chkId, CK8(99)),
2003 alice.verifyOwners(__LINE__);
2007 env(pay(env.master, yui, XRP(51)));
2009 env(check::cash(yui, chkId, CK8(99)));
2016 gw1.verifyOwners(__LINE__);
2031 auto cmpTrustLines = [
this, &env](
2032 Account
const& acct1,
2033 Account
const& acct2,
2034 IOU
const& offerIou,
2035 IOU
const& checkIou) {
2036 auto const offerLine =
2038 auto const checkLine =
2040 if (offerLine ==
nullptr || checkLine ==
nullptr)
2042 BEAST_EXPECT(offerLine ==
nullptr && checkLine ==
nullptr);
2053 [
this, offerLine, checkLine](
SF_AMOUNT const& sfield) {
2054 STAmount
const offerAmount = offerLine->at(sfield);
2055 STAmount
const checkAmount = checkLine->at(sfield);
2059 !offerAmount.native() && !checkAmount.native()))
2063 offerAmount.issue().account ==
2064 checkAmount.issue().account);
2066 offerAmount.negative() == checkAmount.negative());
2068 offerAmount.mantissa() == checkAmount.mantissa());
2070 offerAmount.exponent() == checkAmount.exponent());
2079 [
this, offerLine, checkLine](
auto const& sfield) {
2082 offerLine->isFieldPresent(sfield) ==
2083 checkLine->isFieldPresent(sfield)))
2088 if (!offerLine->isFieldPresent(sfield))
2094 offerLine->at(sfield) == checkLine->at(sfield));
2110 AccountOwns gw1{*
this, env,
"gw1", 0};
2112 BEAST_EXPECT((*env.le(gw1))[
sfFlags] == 0);
2113 BEAST_EXPECT((*env.le(alice))[
sfFlags] == 0);
2114 BEAST_EXPECT((*env.le(bob))[
sfFlags] == 0);
2117 IOU
const OF1 = gw1[
"OF1"];
2121 env.le(
keylet::line(gw1, alice, OF1.currency)) ==
nullptr);
2122 env(
offer(alice, OF1(98),
XRP(98)));
2129 gw1.verifyOwners(__LINE__);
2132 alice.verifyOwners(__LINE__);
2135 IOU
const CK1 = gw1[
"CK1"];
2137 env(check::create(gw1, alice, CK1(98)));
2140 env.le(
keylet::line(gw1, alice, CK1.currency)) ==
nullptr);
2141 env(check::cash(alice, chkId, CK1(98)));
2149 gw1.verifyOwners(__LINE__);
2152 alice.verifyOwners(__LINE__);
2154 cmpTrustLines(gw1, alice, OF1, CK1);
2165 AccountOwns gw1{*
this, env,
"gw1", 0};
2166 IOU
const OF1 = gw1[
"OF1"];
2167 env(
offer(alice,
XRP(97), OF1(97)));
2170 env.le(
keylet::line(alice, bob, OF1.currency)) ==
nullptr);
2176 env.require(balance(alice, OF1(1)));
2177 env.require(balance(bob, OF1(97)));
2180 gw1.verifyOwners(__LINE__);
2181 alice.verifyOwners(__LINE__);
2182 bob.verifyOwners(__LINE__);
2190 IOU
const CK1 = gw1[
"CK1"];
2192 env(check::create(alice, bob, CK1(97)));
2195 env.le(
keylet::line(alice, bob, CK1.currency)) ==
nullptr);
2196 env(check::cash(bob, chkId, CK1(97)), ter(
terNO_RIPPLE));
2200 env.le(
keylet::line(gw1, bob, OF1.currency)) !=
nullptr);
2202 env.le(
keylet::line(gw1, bob, CK1.currency)) ==
nullptr);
2205 env(check::cancel(alice, chkId));
2209 gw1.verifyOwners(__LINE__);
2210 alice.verifyOwners(__LINE__);
2211 bob.verifyOwners(__LINE__);
2218 AccountOwns gw1{*
this, env,
"gw1", 0};
2223 IOU
const OF2 = gw1[
"OF2"];
2227 env.le(
keylet::line(gw1, alice, OF2.currency)) ==
nullptr);
2228 env(
offer(alice, OF2(96),
XRP(96)));
2235 gw1.verifyOwners(__LINE__);
2238 alice.verifyOwners(__LINE__);
2241 IOU
const CK2 = gw1[
"CK2"];
2243 env(check::create(gw1, alice, CK2(96)));
2246 env.le(
keylet::line(gw1, alice, CK2.currency)) ==
nullptr);
2247 env(check::cash(alice, chkId, CK2(96)));
2255 gw1.verifyOwners(__LINE__);
2258 alice.verifyOwners(__LINE__);
2260 cmpTrustLines(gw1, alice, OF2, CK2);
2268 AccountOwns gw1{*
this, env,
"gw1", 0};
2269 IOU
const OF2 = gw1[
"OF2"];
2270 env(
offer(alice,
XRP(95), OF2(95)));
2273 env.le(
keylet::line(alice, bob, OF2.currency)) ==
nullptr);
2279 gw1.verifyOwners(__LINE__);
2280 alice.verifyOwners(__LINE__);
2281 bob.verifyOwners(__LINE__);
2284 IOU
const CK2 = gw1[
"CK2"];
2286 env(check::create(alice, bob, CK2(95)));
2289 env.le(
keylet::line(alice, bob, CK2.currency)) ==
nullptr);
2290 env(check::cash(bob, chkId, CK2(95)));
2296 gw1.verifyOwners(__LINE__);
2297 alice.verifyOwners(__LINE__);
2298 bob.verifyOwners(__LINE__);
2300 cmpTrustLines(alice, bob, OF2, CK2);
2311 AccountOwns gw1{*
this, env,
"gw1", 0};
2318 IOU
const OF3 = gw1[
"OF3"];
2322 env.le(
keylet::line(gw1, alice, OF3.currency)) ==
nullptr);
2323 env(
offer(alice, OF3(94),
XRP(94)));
2330 gw1.verifyOwners(__LINE__);
2333 alice.verifyOwners(__LINE__);
2336 IOU
const CK3 = gw1[
"CK3"];
2338 env(check::create(gw1, alice, CK3(94)));
2341 env.le(
keylet::line(gw1, alice, CK3.currency)) ==
nullptr);
2342 env(check::cash(alice, chkId, CK3(94)));
2350 gw1.verifyOwners(__LINE__);
2353 alice.verifyOwners(__LINE__);
2355 cmpTrustLines(gw1, alice, OF3, CK3);
2363 AccountOwns gw1{*
this, env,
"gw1", 0};
2364 IOU
const OF3 = gw1[
"OF3"];
2365 env(
offer(alice,
XRP(93), OF3(93)));
2368 env.le(
keylet::line(alice, bob, OF3.currency)) ==
nullptr);
2374 gw1.verifyOwners(__LINE__);
2375 alice.verifyOwners(__LINE__);
2376 bob.verifyOwners(__LINE__);
2379 IOU
const CK3 = gw1[
"CK3"];
2381 env(check::create(alice, bob, CK3(93)));
2384 env.le(
keylet::line(alice, bob, CK3.currency)) ==
nullptr);
2385 env(check::cash(bob, chkId, CK3(93)));
2391 gw1.verifyOwners(__LINE__);
2392 alice.verifyOwners(__LINE__);
2393 bob.verifyOwners(__LINE__);
2395 cmpTrustLines(alice, bob, OF3, CK3);
2402 AccountOwns gw1{*
this, env,
"gw1", 0};
2407 IOU
const OF4 = gw1[
"OF4"];
2411 env.le(
keylet::line(gw1, alice, OF4.currency)) ==
nullptr);
2416 gw1.verifyOwners(__LINE__);
2417 alice.verifyOwners(__LINE__);
2418 bob.verifyOwners(__LINE__);
2421 IOU
const CK4 = gw1[
"CK4"];
2423 env(check::create(gw1, alice, CK4(92)), ter(
tecFROZEN));
2426 env.le(
keylet::line(gw1, alice, CK4.currency)) ==
nullptr);
2427 env(check::cash(alice, chkId, CK4(92)), ter(
tecNO_ENTRY));
2431 gw1.verifyOwners(__LINE__);
2432 alice.verifyOwners(__LINE__);
2433 bob.verifyOwners(__LINE__);
2438 env.le(
keylet::line(gw1, alice, OF4.currency)) ==
nullptr);
2440 env.le(
keylet::line(gw1, alice, CK4.currency)) ==
nullptr);
2448 AccountOwns gw1{*
this, env,
"gw1", 0};
2449 IOU
const OF4 = gw1[
"OF4"];
2453 env.le(
keylet::line(alice, bob, OF4.currency)) ==
nullptr);
2458 gw1.verifyOwners(__LINE__);
2459 alice.verifyOwners(__LINE__);
2460 bob.verifyOwners(__LINE__);
2463 IOU
const CK4 = gw1[
"CK4"];
2465 env(check::create(alice, bob, CK4(91)), ter(
tecFROZEN));
2468 env.le(
keylet::line(alice, bob, CK4.currency)) ==
nullptr);
2469 env(check::cash(bob, chkId, CK4(91)), ter(
tecNO_ENTRY));
2473 gw1.verifyOwners(__LINE__);
2474 alice.verifyOwners(__LINE__);
2475 bob.verifyOwners(__LINE__);
2480 env.le(
keylet::line(gw1, bob, OF4.currency)) ==
nullptr);
2482 env.le(
keylet::line(gw1, bob, CK4.currency)) ==
nullptr);
2491 AccountOwns gw2{*
this, env,
"gw2", 0};
2492 env.fund(
XRP(5000), gw2);
2501 IOU
const OF5 = gw2[
"OF5"];
2507 env.le(
keylet::line(gw2, alice, OF5.currency)) ==
nullptr);
2513 gw2.verifyOwners(__LINE__);
2514 alice.verifyOwners(__LINE__);
2515 bob.verifyOwners(__LINE__);
2521 gw2.verifyOwners(__LINE__);
2524 IOU
const CK5 = gw2[
"CK5"];
2526 env(check::create(gw2, alice, CK5(92)));
2530 env.le(
keylet::line(gw2, alice, CK5.currency)) ==
nullptr);
2531 env(check::cash(alice, chkId, CK5(92)), ter(
tecNO_AUTH));
2536 gw2.verifyOwners(__LINE__);
2537 alice.verifyOwners(__LINE__);
2538 bob.verifyOwners(__LINE__);
2543 env.le(
keylet::line(gw2, alice, OF5.currency)) ==
nullptr);
2545 env.le(
keylet::line(gw2, alice, CK5.currency)) ==
nullptr);
2548 env(check::cancel(gw2, chkId));
2551 gw2.verifyOwners(__LINE__);
2559 AccountOwns gw2{*
this, env,
"gw2", 0};
2560 IOU
const OF5 = gw2[
"OF5"];
2565 env.le(
keylet::line(gw2, bob, OF5.currency)) ==
nullptr);
2568 gw2.verifyOwners(__LINE__);
2569 alice.verifyOwners(__LINE__);
2570 bob.verifyOwners(__LINE__);
2573 IOU
const CK5 = gw2[
"CK5"];
2575 env(check::create(alice, bob, CK5(91)));
2578 env.le(
keylet::line(alice, bob, CK5.currency)) ==
nullptr);
2583 env(check::cancel(alice, chkId));
2587 gw2.verifyOwners(__LINE__);
2588 alice.verifyOwners(__LINE__);
2589 bob.verifyOwners(__LINE__);
2594 env.le(
keylet::line(gw2, bob, OF5.currency)) ==
nullptr);
2596 env.le(
keylet::line(gw2, bob, CK5.currency)) ==
nullptr);
2621 using namespace test::jtx;
2622 auto const sa = supported_amendments();