20 #include <ripple/protocol/Feature.h>
21 #include <ripple/protocol/jss.h>
105 if (sle && sle->getType() == ltCHECK)
106 result.push_back(sle);
116 if (
auto const sleAccount = env.
le(account))
134 Json::Value const meta = env.
rpc(
"tx", txHash)[jss::result][jss::meta];
154 using namespace test::jtx;
155 Account
const alice{
"alice"};
161 env.fund(XRP(1000), alice);
165 env(check::create(env.master, alice, XRP(100)), ter(
temDISABLED));
168 env(check::cash(alice, checkId, XRP(100)), ter(
temDISABLED));
171 env(check::cancel(alice, checkId), ter(
temDISABLED));
177 Env env{*
this, features};
179 env.fund(XRP(1000), alice);
183 env(check::create(env.master, alice, XRP(100)));
186 env(check::cash(alice, checkId1, XRP(100)));
191 env(check::create(env.master, alice, XRP(100)));
194 env(check::cancel(alice, checkId2));
203 testcase(
"Create valid");
205 using namespace test::jtx;
207 Account
const gw{
"gateway"};
208 Account
const alice{
"alice"};
209 Account
const bob{
"bob"};
210 IOU
const USD{gw[
"USD"]};
212 Env env{*
this, features};
214 STAmount const startBalance{XRP(1000).value()};
215 env.fund(startBalance, gw, alice, bob);
220 auto writeTwoChecks = [&env, &USD,
this](
221 Account
const& from, Account
const& to) {
228 env(check::create(from, to, XRP(2000)));
231 env(check::create(from, to, USD(50)));
237 env.require(owners(from, fromOwnerCount + 2));
239 owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount));
242 writeTwoChecks(alice, bob);
243 writeTwoChecks(gw, alice);
244 writeTwoChecks(alice, gw);
250 using namespace std::chrono_literals;
253 env(check::create(alice, bob, USD(50)), expiration(env.now() + 1s));
256 env(check::create(alice, bob, USD(50)), source_tag(2));
258 env(check::create(alice, bob, USD(50)), dest_tag(3));
260 env(check::create(alice, bob, USD(50)), invoice_id(
uint256{4}));
262 env(check::create(alice, bob, USD(50)),
263 expiration(env.now() + 1s),
274 env(regkey(alice, alie));
279 env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie));
283 env(check::create(alice, bob, USD(50)), sig(alie));
289 XRPAmount const baseFeeDrops{env.current()->fees().base};
290 env(check::create(alice, bob, USD(50)),
292 fee(3 * baseFeeDrops));
301 testcase(
"Create valid with disallow incoming");
303 using namespace test::jtx;
308 Account
const alice{
"alice"};
309 env.fund(XRP(10000), alice);
312 auto const sle = env.le(alice);
313 uint32_t flags = sle->getFlags();
317 Account
const gw{
"gateway"};
318 Account
const alice{
"alice"};
319 Account
const bob{
"bob"};
320 IOU
const USD{gw[
"USD"]};
324 STAmount const startBalance{XRP(1000).value()};
325 env.fund(startBalance, gw, alice, bob);
331 auto writeTwoChecksDI = [&env, &USD,
this](
341 env(check::create(from, to, XRP(2000)), ter(expected));
344 env(check::create(from, to, USD(50)), ter(expected));
353 env.require(owners(from, fromOwnerCount + 2));
355 owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount));
362 env.require(owners(from, fromOwnerCount));
363 env.require(owners(to, to == from ? fromOwnerCount : toOwnerCount));
396 testcase(
"Create invalid");
398 using namespace test::jtx;
400 Account
const gw1{
"gateway1"};
401 Account
const gwF{
"gatewayFrozen"};
402 Account
const alice{
"alice"};
403 Account
const bob{
"bob"};
404 IOU
const USD{gw1[
"USD"]};
406 Env env{*
this, features};
408 STAmount const startBalance{XRP(1000).value()};
409 env.fund(startBalance, gw1, gwF, alice, bob);
412 env(check::create(alice, bob, USD(50)),
418 env(check::create(alice, bob, USD(50)),
424 env(check::create(alice, alice, XRP(10)), ter(
temREDUNDANT));
428 env(check::create(alice, bob, drops(-1)), ter(
temBAD_AMOUNT));
431 env(check::create(alice, bob, drops(0)), ter(
temBAD_AMOUNT));
434 env(check::create(alice, bob, drops(1)));
443 env(check::create(alice, bob, USD(1)));
452 env(check::create(alice, bob, USD(50)),
458 Account
const bogie{
"bogie"};
459 env(check::create(alice, bogie, USD(50)), ter(
tecNO_DST));
469 env(check::create(alice, bob, USD(50)), dest_tag(11));
476 IOU
const USF{gwF[
"USF"]};
480 env(check::create(alice, bob, USF(50)), ter(
tecFROZEN));
486 env(check::create(alice, bob, USF(50)));
492 env.trust(USD(1000), alice);
493 env.trust(USD(1000), bob);
495 env(pay(gw1, alice, USD(25)));
496 env(pay(gw1, bob, USD(25)));
504 env(check::create(alice, bob, USD(50)), ter(
tecFROZEN));
508 env(check::create(bob, alice, USD(50)));
510 env(pay(bob, alice, USD(1)));
512 env(check::create(gw1, alice, USD(50)));
514 env(pay(gw1, alice, USD(1)));
520 env(check::create(alice, bob, USD(50)));
522 env(check::create(bob, alice, USD(50)));
524 env(check::create(gw1, alice, USD(50)));
532 env(check::create(alice, bob, USD(50)));
534 env(pay(alice, bob, USD(1)));
536 env(check::create(bob, alice, USD(50)), ter(
tecFROZEN));
540 env(check::create(gw1, alice, USD(50)), ter(
tecFROZEN));
551 env(check::create(alice, bob, USD(50)),
552 expiration(env.now()),
556 using namespace std::chrono_literals;
557 env(check::create(alice, bob, USD(50)), expiration(env.now() + 1s));
561 Account
const cheri{
"cheri"};
562 env.fund(env.current()->fees().accountReserve(1) - drops(1), cheri);
564 env(check::create(cheri, bob, USD(50)),
565 fee(drops(env.current()->fees().base)),
569 env(pay(bob, cheri, drops(env.current()->fees().base + 1)));
572 env(check::create(cheri, bob, USD(50)));
580 testcase(
"Cash XRP");
582 using namespace test::jtx;
584 Account
const alice{
"alice"};
585 Account
const bob{
"bob"};
587 Env env{*
this, features};
589 XRPAmount const baseFeeDrops{env.current()->fees().base};
590 STAmount const startBalance{XRP(300).value()};
591 env.fund(startBalance, alice, bob);
595 env(check::create(alice, bob, XRP(10)));
597 env.require(balance(alice, startBalance - drops(baseFeeDrops)));
598 env.require(balance(bob, startBalance));
604 env(check::cash(bob, chkId, XRP(10)));
607 balance(alice, startBalance - XRP(10) - drops(baseFeeDrops)));
609 balance(bob, startBalance + XRP(10) - drops(baseFeeDrops)));
616 env(pay(env.master, alice, XRP(10) + drops(baseFeeDrops)));
617 env(pay(bob, env.master, XRP(10) - drops(baseFeeDrops * 2)));
619 env.require(balance(alice, startBalance));
620 env.require(balance(bob, startBalance));
624 STAmount const reserve{env.current()->fees().accountReserve(0)};
626 startBalance - reserve - drops(baseFeeDrops)};
628 env(check::create(alice, bob, checkAmount));
632 env(check::cash(bob, chkId, checkAmount + drops(1)),
636 bob, chkId, check::DeliverMin(checkAmount + drops(1))),
643 env(check::cash(bob, chkId, check::DeliverMin(checkAmount)));
645 env.require(balance(alice, reserve));
647 bob, startBalance + checkAmount - drops(baseFeeDrops * 3)));
654 env(pay(env.master, alice, checkAmount + drops(baseFeeDrops)));
655 env(pay(bob, env.master, checkAmount - drops(baseFeeDrops * 4)));
657 env.require(balance(alice, startBalance));
658 env.require(balance(bob, startBalance));
662 STAmount const reserve{env.current()->fees().accountReserve(0)};
664 startBalance - reserve - drops(baseFeeDrops - 1)};
666 env(check::create(alice, bob, checkAmount));
675 env(check::cash(bob, chkId, check::DeliverMin(drops(1))));
677 env.require(balance(alice, reserve));
679 bob, startBalance + checkAmount - drops(baseFeeDrops * 2 + 1)));
686 env(pay(env.master, alice, checkAmount + drops(baseFeeDrops - 1)));
688 bob, env.master, checkAmount - drops(baseFeeDrops * 3 + 1)));
690 env.require(balance(alice, startBalance));
691 env.require(balance(bob, startBalance));
699 testcase(
"Cash IOU");
701 using namespace test::jtx;
703 bool const cashCheckMakesTrustLine =
706 Account
const gw{
"gateway"};
707 Account
const alice{
"alice"};
708 Account
const bob{
"bob"};
709 IOU
const USD{gw[
"USD"]};
712 Env env{*
this, features};
714 env.fund(XRP(1000), gw, alice, bob);
718 env(check::create(alice, bob, USD(10)));
726 env(trust(alice, USD(20)));
728 env(pay(gw, alice, USD(9.5)));
735 env(pay(gw, alice, USD(0.5)));
737 if (!cashCheckMakesTrustLine)
742 env(check::cash(bob, chkId1, USD(10)), ter(
tecNO_LINE));
747 env(trust(bob, USD(9.5)));
749 if (!cashCheckMakesTrustLine)
760 env(trust(bob, USD(10.5)));
766 env(check::cash(bob, chkId1, USD(10)));
768 env.require(balance(alice, USD(0)));
769 env.require(balance(bob, USD(10)));
776 env(check::cash(bob, chkId1, USD(10)), ter(
tecNO_ENTRY));
780 env(pay(bob, alice, USD(7)));
784 env(check::create(alice, bob, USD(7)));
791 env(check::cash(bob, chkId2, USD(5)));
793 env.require(balance(alice, USD(2)));
794 env.require(balance(bob, USD(8)));
802 env(check::create(alice, bob, USD(2)));
805 env(check::create(alice, bob, USD(2)));
811 env(check::cash(bob, chkId4, USD(2)));
813 env.require(balance(alice, USD(0)));
814 env.require(balance(bob, USD(10)));
824 env.require(balance(alice, USD(0)));
825 env.require(balance(bob, USD(10)));
831 if (cashCheckMakesTrustLine)
847 env(check::create(gw, bob, USD(20)));
851 env(check::cash(bob, chkId20, USD(20)));
853 env.require(balance(bob, USD(30)));
857 env(pay(bob, gw, USD(20)));
861 env(check::cancel(bob, chkId3));
863 env.require(balance(alice, USD(0)));
864 env.require(balance(bob, USD(10)));
872 Env env{*
this, features};
874 env.fund(XRP(1000), gw, alice, bob);
876 env(trust(alice, USD(20)));
877 env(trust(bob, USD(20)));
879 env(pay(gw, alice, USD(8)));
884 env(check::create(alice, bob, USD(9)));
887 env(check::create(alice, bob, USD(8)));
890 env(check::create(alice, bob, USD(7)));
893 env(check::create(alice, bob, USD(6)));
898 env(check::cash(bob, chkId9, check::DeliverMin(USD(9))),
903 env(check::cash(bob, chkId9, check::DeliverMin(USD(7))));
905 env.require(balance(alice, USD(0)));
906 env.require(balance(bob, USD(8)));
913 env(pay(bob, alice, USD(7)));
918 env(check::cash(bob, chkId7, check::DeliverMin(USD(7))));
920 env.require(balance(alice, USD(0)));
921 env.require(balance(bob, USD(8)));
928 env(pay(bob, alice, USD(8)));
933 env(check::cash(bob, chkId6, check::DeliverMin(USD(4))));
935 env.require(balance(alice, USD(2)));
936 env.require(balance(bob, USD(6)));
944 env(check::cash(bob, chkId8, check::DeliverMin(USD(2))));
946 env.require(balance(alice, USD(0)));
947 env.require(balance(bob, USD(8)));
955 Env env(*
this, features);
957 env.fund(XRP(1000), gw, alice, bob);
960 env(trust(gw, alice[
"USD"](100)), txflags(
tfSetfAuth));
961 env(trust(alice, USD(20)));
963 env(pay(gw, alice, USD(8)));
969 env(check::create(alice, bob, USD(7)));
972 env(check::cash(bob, chkId, USD(7)),
978 env(trust(bob, USD(5)));
981 env(check::cash(bob, chkId, USD(7)), ter(
tecNO_AUTH));
985 env(trust(gw, bob[
"USD"](1)), txflags(
tfSetfAuth));
990 if (!cashCheckMakesTrustLine)
1006 env(check::cash(bob, chkId, check::DeliverMin(USD(4))));
1007 STAmount const bobGot = cashCheckMakesTrustLine ? USD(7) : USD(5);
1009 env.require(balance(alice, USD(8) - bobGot));
1010 env.require(balance(bob, bobGot));
1021 for (
auto const& testFeatures :
1025 Env env{*
this, testFeatures};
1027 env.fund(XRP(1000), gw, alice, bob);
1031 env(check::create(alice, bob, USD(1)));
1035 env(check::create(alice, bob, USD(2)));
1038 env(trust(alice, USD(20)));
1039 env(trust(bob, USD(20)));
1041 env(pay(gw, alice, USD(8)));
1046 env(regkey(bob, bobby));
1051 env(signers(bob, 2, {{bogie, 1}, {demon, 1}}), sig(bobby));
1056 int const signersCount = {
1058 BEAST_EXPECT(
ownerCount(env, bob) == signersCount + 1);
1061 env(check::cash(bob, chkId1, (USD(1))), sig(bobby));
1063 env.require(balance(alice, USD(7)));
1064 env.require(balance(bob, USD(1)));
1068 BEAST_EXPECT(
ownerCount(env, bob) == signersCount + 1);
1071 XRPAmount const baseFeeDrops{env.current()->fees().base};
1072 env(check::cash(bob, chkId2, (USD(2))),
1074 fee(3 * baseFeeDrops));
1076 env.require(balance(alice, USD(5)));
1077 env.require(balance(bob, USD(3)));
1081 BEAST_EXPECT(
ownerCount(env, bob) == signersCount + 1);
1089 testcase(
"Cash with transfer fee");
1091 using namespace test::jtx;
1093 Account
const gw{
"gateway"};
1094 Account
const alice{
"alice"};
1095 Account
const bob{
"bob"};
1096 IOU
const USD{gw[
"USD"]};
1098 Env env{*
this, features};
1100 env.fund(XRP(1000), gw, alice, bob);
1102 env(trust(alice, USD(1000)));
1103 env(trust(bob, USD(1000)));
1105 env(pay(gw, alice, USD(1000)));
1109 env(rate(gw, 1.25));
1115 env(check::create(alice, bob, USD(125)));
1122 env(check::create(alice, bob, USD(120)));
1128 env(check::cash(bob, chkId125, check::DeliverMin(USD(101))),
1134 env(check::cash(bob, chkId125, check::DeliverMin(USD(75))));
1136 env.require(balance(alice, USD(1000 - 125)));
1137 env.require(balance(bob, USD(0 + 100)));
1147 env(check::cash(bob, chkId120, USD(50)));
1149 env.require(balance(alice, USD(1000 - 125 - 60)));
1150 env.require(balance(bob, USD(0 + 100 + 50)));
1159 testcase(
"Cash quality");
1161 using namespace test::jtx;
1163 Account
const gw{
"gateway"};
1164 Account
const alice{
"alice"};
1165 Account
const bob{
"bob"};
1166 IOU
const USD{gw[
"USD"]};
1168 Env env{*
this, features};
1170 env.fund(XRP(1000), gw, alice, bob);
1172 env(trust(alice, USD(1000)));
1173 env(trust(bob, USD(1000)));
1175 env(pay(gw, alice, USD(1000)));
1183 auto qIn = [](
double percent) {
return qualityInPercent(percent); };
1184 auto qOut = [](
double percent) {
return qualityOutPercent(percent); };
1188 auto testNonIssuerQPay = [&env, &alice, &bob, &USD](
1189 Account
const& truster,
1191 auto const& inOrOut,
1195 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1196 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
1199 env(trust(truster, iou(1000)), inOrOut(pct));
1202 env(pay(alice, bob, USD(amount)), sendmax(USD(10)));
1204 env.require(balance(alice, aliceStart - USD(10)));
1205 env.require(balance(bob, bobStart + USD(10)));
1209 env(trust(truster, iou(1000)), inOrOut(0));
1213 auto testNonIssuerQCheck = [&env, &alice, &bob, &USD](
1214 Account
const& truster,
1216 auto const& inOrOut,
1220 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1221 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
1224 env(trust(truster, iou(1000)), inOrOut(pct));
1228 env(check::create(alice, bob, USD(10)));
1231 env(check::cash(bob, chkId, USD(amount)));
1233 env.require(balance(alice, aliceStart - USD(10)));
1234 env.require(balance(bob, bobStart + USD(10)));
1238 env(trust(truster, iou(1000)), inOrOut(0));
1243 testNonIssuerQPay(alice, gw[
"USD"], qIn, 50, 10);
1244 testNonIssuerQCheck(alice, gw[
"USD"], qIn, 50, 10);
1247 testNonIssuerQPay(bob, gw[
"USD"], qIn, 50, 5);
1248 testNonIssuerQCheck(bob, gw[
"USD"], qIn, 50, 5);
1250 testNonIssuerQPay(gw, alice[
"USD"], qIn, 50, 10);
1251 testNonIssuerQCheck(gw, alice[
"USD"], qIn, 50, 10);
1253 testNonIssuerQPay(gw, bob[
"USD"], qIn, 50, 10);
1254 testNonIssuerQCheck(gw, bob[
"USD"], qIn, 50, 10);
1256 testNonIssuerQPay(alice, gw[
"USD"], qOut, 200, 10);
1257 testNonIssuerQCheck(alice, gw[
"USD"], qOut, 200, 10);
1259 testNonIssuerQPay(bob, gw[
"USD"], qOut, 200, 10);
1260 testNonIssuerQCheck(bob, gw[
"USD"], qOut, 200, 10);
1262 testNonIssuerQPay(gw, alice[
"USD"], qOut, 200, 10);
1263 testNonIssuerQCheck(gw, alice[
"USD"], qOut, 200, 10);
1265 testNonIssuerQPay(gw, bob[
"USD"], qOut, 200, 10);
1266 testNonIssuerQCheck(gw, bob[
"USD"], qOut, 200, 10);
1273 auto testIssuerQPay = [&env, &gw, &alice, &USD](
1274 Account
const& truster,
1276 auto const& inOrOut,
1284 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1287 env(trust(truster, iou(1000)), inOrOut(pct));
1291 env(pay(alice, gw, USD(amt1)), sendmax(USD(max1)));
1293 env.require(balance(alice, aliceStart - USD(10)));
1296 env(pay(gw, alice, USD(amt2)), sendmax(USD(max2)));
1298 env.require(balance(alice, aliceStart));
1302 env(trust(truster, iou(1000)), inOrOut(0));
1306 auto testIssuerQCheck = [&env, &gw, &alice, &USD](
1307 Account
const& truster,
1309 auto const& inOrOut,
1317 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
1320 env(trust(truster, iou(1000)), inOrOut(pct));
1325 env(check::create(alice, gw, USD(max1)));
1328 env(check::cash(gw, chkAliceId, USD(amt1)));
1330 env.require(balance(alice, aliceStart - USD(10)));
1334 env(check::create(gw, alice, USD(max2)));
1337 env(check::cash(alice, chkGwId, USD(amt2)));
1339 env.require(balance(alice, aliceStart));
1343 env(trust(truster, iou(1000)), inOrOut(0));
1349 testIssuerQPay(alice, gw[
"USD"], qIn, 50, 10, 10, 5, 10);
1350 testIssuerQCheck(alice, gw[
"USD"], qIn, 50, 10, 10, 5, 10);
1352 testIssuerQPay(gw, alice[
"USD"], qIn, 50, 10, 10, 10, 10);
1353 testIssuerQCheck(gw, alice[
"USD"], qIn, 50, 10, 10, 10, 10);
1355 testIssuerQPay(alice, gw[
"USD"], qOut, 200, 10, 10, 10, 10);
1356 testIssuerQCheck(alice, gw[
"USD"], qOut, 200, 10, 10, 10, 10);
1358 testIssuerQPay(gw, alice[
"USD"], qOut, 200, 10, 10, 10, 10);
1359 testIssuerQCheck(gw, alice[
"USD"], qOut, 200, 10, 10, 10, 10);
1366 testcase(
"Cash invalid");
1368 using namespace test::jtx;
1370 Account
const gw{
"gateway"};
1371 Account
const alice{
"alice"};
1372 Account
const bob{
"bob"};
1373 Account
const zoe{
"zoe"};
1374 IOU
const USD{gw[
"USD"]};
1376 Env env(*
this, features);
1378 env.fund(XRP(1000), gw, alice, bob, zoe);
1381 env(trust(alice, USD(20)));
1383 env(pay(gw, alice, USD(20)));
1390 env(check::create(alice, bob, USD(20)));
1398 env(check::cash(bob, chkId, USD(20)), ter(
tecNO_LINE));
1404 env(trust(bob, USD(20)));
1410 env(check::cash(bob, chkId, USD(20)), ter(
tecNO_ENTRY));
1416 env(check::create(alice, bob, USD(20)));
1420 env(check::create(alice, bob, XRP(10)));
1423 using namespace std::chrono_literals;
1425 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
1429 env(check::create(alice, bob, USD(1)));
1433 env(check::create(alice, bob, USD(2)));
1437 env(check::create(alice, bob, USD(3)));
1441 env(check::create(alice, bob, USD(4)));
1445 env(check::create(alice, bob, USD(1)));
1449 env(check::create(alice, bob, USD(2)), dest_tag(7));
1453 auto failingCases = [&env, &gw, &alice, &bob](
1456 env(check::cash(bob, chkId, amount),
1462 env(check::cash(bob, chkId, amount),
1488 env(check::cash(bob, chkId, amount.zeroed()),
1494 if (!amount.native())
1511 IOU
const wrongCurrency{gw[
"EUR"]};
1513 badAmount.
setIssue(wrongCurrency.issue());
1514 env(check::cash(bob, chkId, badAmount), ter(
temMALFORMED));
1520 IOU
const wrongIssuer{alice[
"USD"]};
1522 badAmount.
setIssue(wrongIssuer.issue());
1523 env(check::cash(bob, chkId, badAmount), ter(
temMALFORMED));
1532 env(check::cash(bob, chkId, check::DeliverMin(amount + amount)),
1537 failingCases(chkIdX, XRP(10));
1538 failingCases(chkIdU, USD(20));
1541 env(check::cash(bob, chkIdU, USD(20)));
1543 env(check::cash(bob, chkIdX, check::DeliverMin(XRP(10))));
1547 env(check::cash(bob, chkIdExp, XRP(10)), ter(
tecEXPIRED));
1551 env(check::cancel(zoe, chkIdExp));
1556 env(pay(bob, alice, USD(20)));
1558 env.require(balance(alice, USD(20)));
1559 env.require(balance(bob, USD(0)));
1567 env(check::cash(bob, chkIdFroz1, check::DeliverMin(USD(0.5))),
1575 env(check::cash(bob, chkIdFroz1, USD(1)));
1577 env.require(balance(alice, USD(19)));
1578 env.require(balance(bob, USD(1)));
1585 env(check::cash(bob, chkIdFroz2, check::DeliverMin(USD(1))),
1592 env(check::cash(bob, chkIdFroz2, USD(2)));
1594 env.require(balance(alice, USD(17)));
1595 env.require(balance(bob, USD(3)));
1600 env(check::cash(bob, chkIdFroz3, USD(3)), ter(
tecFROZEN));
1602 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))),
1609 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))));
1611 env.require(balance(alice, USD(14)));
1612 env.require(balance(bob, USD(6)));
1618 env(check::cash(bob, chkIdFroz4, USD(4)), ter(
terNO_LINE));
1620 env(check::cash(bob, chkIdFroz4, check::DeliverMin(USD(1))),
1627 env(check::cash(bob, chkIdFroz4, USD(4)));
1629 env.require(balance(alice, USD(10)));
1630 env.require(balance(bob, USD(10)));
1639 env(check::cash(bob, chkIdNoDest1, check::DeliverMin(USD(0.5))),
1644 env(check::cash(bob, chkIdHasDest2, USD(2)));
1646 env.require(balance(alice, USD(8)));
1647 env.require(balance(bob, USD(12)));
1653 env(check::cash(bob, chkIdNoDest1, USD(1)));
1655 env.require(balance(alice, USD(7)));
1656 env.require(balance(bob, USD(13)));
1664 testcase(
"Cancel valid");
1666 using namespace test::jtx;
1668 Account
const gw{
"gateway"};
1669 Account
const alice{
"alice"};
1670 Account
const bob{
"bob"};
1671 Account
const zoe{
"zoe"};
1672 IOU
const USD{gw[
"USD"]};
1676 for (
auto const& testFeatures :
1680 Env env{*
this, testFeatures};
1682 env.fund(XRP(1000), gw, alice, bob, zoe);
1687 env(check::create(alice, bob, USD(10)));
1691 env(check::create(alice, bob, XRP(10)));
1695 env(check::create(alice, bob, USD(10)));
1699 using namespace std::chrono_literals;
1701 env(check::create(alice, bob, XRP(10)),
1702 expiration(env.now() + 600s));
1706 env(check::create(alice, bob, USD(10)),
1707 expiration(env.now() + 600s));
1711 env(check::create(alice, bob, XRP(10)),
1712 expiration(env.now() + 600s));
1717 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
1721 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
1725 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
1730 env(check::create(alice, bob, USD(10)));
1734 env(check::create(alice, bob, XRP(10)));
1740 env(check::cancel(alice, chkId1));
1745 env(check::cancel(bob, chkId2));
1756 env(check::cancel(alice, chkIdNotExp1));
1761 env(check::cancel(bob, chkIdNotExp2));
1772 env(check::cancel(alice, chkIdExp1));
1777 env(check::cancel(bob, chkIdExp2));
1782 env(check::cancel(zoe, chkIdExp3));
1789 env(regkey(alice, alie));
1794 env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie));
1799 int const signersCount{
1803 env(check::cancel(alice, chkIdReg), sig(alie));
1806 BEAST_EXPECT(
ownerCount(env, alice) == signersCount + 3);
1809 XRPAmount const baseFeeDrops{env.current()->fees().base};
1810 env(check::cancel(alice, chkIdMSig),
1812 fee(3 * baseFeeDrops));
1815 BEAST_EXPECT(
ownerCount(env, alice) == signersCount + 2);
1818 env(check::cancel(alice, chkId3), sig(alice));
1821 BEAST_EXPECT(
ownerCount(env, alice) == signersCount + 1);
1823 env(check::cancel(bob, chkIdNotExp3));
1826 BEAST_EXPECT(
ownerCount(env, alice) == signersCount + 0);
1834 testcase(
"Cancel invalid");
1836 using namespace test::jtx;
1838 Account
const alice{
"alice"};
1839 Account
const bob{
"bob"};
1841 Env env{*
this, features};
1843 env.fund(XRP(1000), alice, bob);
1846 env(check::cancel(bob,
getCheckIndex(alice, env.seq(alice))),
1852 env(check::cancel(bob,
getCheckIndex(alice, env.seq(alice))),
1858 env(check::cancel(bob,
getCheckIndex(alice, env.seq(alice))),
1866 testcase(
"Fix1623 enable");
1868 using namespace test::jtx;
1870 auto testEnable = [
this](
1875 Account
const alice{
"alice"};
1876 Account
const bob{
"bob"};
1878 Env env{*
this, features};
1880 env.fund(XRP(1000), alice, bob);
1884 env(check::create(alice, bob, XRP(200)));
1887 env(check::cash(bob, chkId, check::DeliverMin(XRP(100))));
1897 env.rpc(
"tx", txHash)[jss::result][jss::meta];
1901 BEAST_EXPECT(meta.
isMember(jss::delivered_amount) == hasFields);
1905 testEnable(features -
fix1623,
false);
1906 testEnable(features,
true);
1912 testcase(
"With Tickets");
1914 using namespace test::jtx;
1916 Account
const gw{
"gw"};
1917 Account
const alice{
"alice"};
1918 Account
const bob{
"bob"};
1919 IOU
const USD{gw[
"USD"]};
1921 Env env{*
this, features};
1922 env.fund(XRP(1000), gw, alice, bob);
1929 env(ticket::create(alice, 10));
1933 env(ticket::create(bob, 10));
1937 env.require(owners(alice, 10));
1938 env.require(owners(bob, 10));
1941 env(trust(alice, USD(1000)), ticket::use(aliceTicketSeq++));
1942 env(trust(bob, USD(1000)), ticket::use(bobTicketSeq++));
1944 env.require(owners(alice, 10));
1945 env.require(owners(bob, 10));
1947 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1948 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1950 env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
1951 BEAST_EXPECT(env.seq(bob) == bobSeq);
1953 env(pay(gw, alice, USD(900)));
1959 env(check::create(alice, bob, XRP(200)), ticket::use(aliceTicketSeq++));
1962 env(check::create(alice, bob, XRP(300)), ticket::use(aliceTicketSeq++));
1965 env(check::create(alice, bob, USD(200)), ticket::use(aliceTicketSeq++));
1968 env(check::create(alice, bob, USD(300)), ticket::use(aliceTicketSeq++));
1972 env.require(owners(alice, 10));
1973 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1975 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1977 env.require(owners(bob, 10));
1978 BEAST_EXPECT(env.seq(bob) == bobSeq);
1981 env(check::cancel(bob, chkIdXrp1), ticket::use(bobTicketSeq++));
1982 env(check::cancel(bob, chkIdUsd2), ticket::use(bobTicketSeq++));
1985 env.require(owners(alice, 8));
1986 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1988 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1990 env.require(owners(bob, 8));
1991 BEAST_EXPECT(env.seq(bob) == bobSeq);
1994 env(check::cash(bob, chkIdXrp2, XRP(300)), ticket::use(bobTicketSeq++));
1995 env(check::cash(bob, chkIdUsd1, USD(200)), ticket::use(bobTicketSeq++));
1998 env.require(owners(alice, 6));
1999 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
2001 BEAST_EXPECT(env.seq(alice) == aliceSeq);
2002 env.require(balance(alice, USD(700)));
2003 env.require(balance(alice, drops(699
'999'940)));
2005 env.require(owners(bob, 6));
2006 BEAST_EXPECT(env.seq(bob) == bobSeq);
2007 env.require(balance(bob, USD(200)));
2008 env.require(balance(bob, drops(1
'299'999
'940)));
2012 testTrustLineCreation(FeatureBitset features)
2014 // Explore automatic trust line creation when a check is cashed.
2016 // This capability is enabled by the featureCheckCashMakesTrustLine
2017 // amendment. So this test executes only when that amendment is
2019 assert(features[featureCheckCashMakesTrustLine]);
2021 testcase("Trust Line Creation");
2023 using namespace test::jtx;
2025 Env env{*this, features};
2027 // An account that independently tracks its owner count.
2030 beast::unit_test::suite& suite;
2036 verifyOwners(std::uint32_t line) const
2039 ownerCount(env, acct) == owners,
2040 "Owner count mismatch",
2045 // Operators to make using the class more convenient.
2046 operator Account const() const
2051 operator ripple::AccountID() const
2057 operator[](std::string const& s) const
2063 AccountOwns alice{*this, env, "alice", 0};
2064 AccountOwns bob{*this, env, "bob", 0};
2066 // Fund with noripple so the accounts do not have any flags set.
2067 env.fund(XRP(5000), noripple(alice, bob));
2070 // Automatic trust line creation should fail if the check destination
2071 // can't afford the reserve
for the trust line.
2073 AccountOwns gw1{*this, env,
"gw1", 0};
2078 env.fund(XRP(5000), noripple(gw1));
2081 IOU
const CK8 = gw1[
"CK8"];
2082 gw1.verifyOwners(__LINE__);
2084 Account
const yui{
"yui"};
2089 env.fund(XRP(200), yui);
2093 env(check::create(gw1, yui, CK8(99)));
2096 env(check::cash(yui, chkId, CK8(99)),
2099 alice.verifyOwners(__LINE__);
2103 env(pay(env.master, yui, XRP(51)));
2105 env(check::cash(yui, chkId, CK8(99)));
2112 gw1.verifyOwners(__LINE__);
2127 auto cmpTrustLines = [
this, &env](
2128 Account
const& acct1,
2129 Account
const& acct2,
2130 IOU
const& offerIou,
2131 IOU
const& checkIou) {
2132 auto const offerLine =
2134 auto const checkLine =
2136 if (offerLine ==
nullptr || checkLine ==
nullptr)
2138 BEAST_EXPECT(offerLine ==
nullptr && checkLine ==
nullptr);
2149 [
this, offerLine, checkLine](
SF_AMOUNT const& sfield) {
2150 STAmount
const offerAmount = offerLine->at(sfield);
2151 STAmount
const checkAmount = checkLine->at(sfield);
2155 !offerAmount.native() && !checkAmount.native()))
2159 offerAmount.issue().account ==
2160 checkAmount.issue().account);
2162 offerAmount.negative() == checkAmount.negative());
2164 offerAmount.mantissa() == checkAmount.mantissa());
2166 offerAmount.exponent() == checkAmount.exponent());
2175 [
this, offerLine, checkLine](
auto const& sfield) {
2178 offerLine->isFieldPresent(sfield) ==
2179 checkLine->isFieldPresent(sfield)))
2184 if (!offerLine->isFieldPresent(sfield))
2190 offerLine->at(sfield) == checkLine->at(sfield));
2206 AccountOwns gw1{*
this, env,
"gw1", 0};
2208 BEAST_EXPECT((*env.le(gw1))[
sfFlags] == 0);
2209 BEAST_EXPECT((*env.le(alice))[
sfFlags] == 0);
2210 BEAST_EXPECT((*env.le(bob))[
sfFlags] == 0);
2213 IOU
const OF1 = gw1[
"OF1"];
2217 env.le(
keylet::line(gw1, alice, OF1.currency)) ==
nullptr);
2218 env(
offer(alice, OF1(98),
XRP(98)));
2225 gw1.verifyOwners(__LINE__);
2228 alice.verifyOwners(__LINE__);
2231 IOU
const CK1 = gw1[
"CK1"];
2233 env(check::create(gw1, alice, CK1(98)));
2236 env.le(
keylet::line(gw1, alice, CK1.currency)) ==
nullptr);
2237 env(check::cash(alice, chkId, CK1(98)));
2245 gw1.verifyOwners(__LINE__);
2248 alice.verifyOwners(__LINE__);
2250 cmpTrustLines(gw1, alice, OF1, CK1);
2261 AccountOwns gw1{*
this, env,
"gw1", 0};
2262 IOU
const OF1 = gw1[
"OF1"];
2263 env(
offer(alice,
XRP(97), OF1(97)));
2266 env.le(
keylet::line(alice, bob, OF1.currency)) ==
nullptr);
2272 env.require(balance(alice, OF1(1)));
2273 env.require(balance(bob, OF1(97)));
2276 gw1.verifyOwners(__LINE__);
2277 alice.verifyOwners(__LINE__);
2278 bob.verifyOwners(__LINE__);
2286 IOU
const CK1 = gw1[
"CK1"];
2288 env(check::create(alice, bob, CK1(97)));
2291 env.le(
keylet::line(alice, bob, CK1.currency)) ==
nullptr);
2292 env(check::cash(bob, chkId, CK1(97)), ter(
terNO_RIPPLE));
2296 env.le(
keylet::line(gw1, bob, OF1.currency)) !=
nullptr);
2298 env.le(
keylet::line(gw1, bob, CK1.currency)) ==
nullptr);
2301 env(check::cancel(alice, chkId));
2305 gw1.verifyOwners(__LINE__);
2306 alice.verifyOwners(__LINE__);
2307 bob.verifyOwners(__LINE__);
2314 AccountOwns gw1{*
this, env,
"gw1", 0};
2319 IOU
const OF2 = gw1[
"OF2"];
2323 env.le(
keylet::line(gw1, alice, OF2.currency)) ==
nullptr);
2324 env(
offer(alice, OF2(96),
XRP(96)));
2331 gw1.verifyOwners(__LINE__);
2334 alice.verifyOwners(__LINE__);
2337 IOU
const CK2 = gw1[
"CK2"];
2339 env(check::create(gw1, alice, CK2(96)));
2342 env.le(
keylet::line(gw1, alice, CK2.currency)) ==
nullptr);
2343 env(check::cash(alice, chkId, CK2(96)));
2351 gw1.verifyOwners(__LINE__);
2354 alice.verifyOwners(__LINE__);
2356 cmpTrustLines(gw1, alice, OF2, CK2);
2364 AccountOwns gw1{*
this, env,
"gw1", 0};
2365 IOU
const OF2 = gw1[
"OF2"];
2366 env(
offer(alice,
XRP(95), OF2(95)));
2369 env.le(
keylet::line(alice, bob, OF2.currency)) ==
nullptr);
2375 gw1.verifyOwners(__LINE__);
2376 alice.verifyOwners(__LINE__);
2377 bob.verifyOwners(__LINE__);
2380 IOU
const CK2 = gw1[
"CK2"];
2382 env(check::create(alice, bob, CK2(95)));
2385 env.le(
keylet::line(alice, bob, CK2.currency)) ==
nullptr);
2386 env(check::cash(bob, chkId, CK2(95)));
2392 gw1.verifyOwners(__LINE__);
2393 alice.verifyOwners(__LINE__);
2394 bob.verifyOwners(__LINE__);
2396 cmpTrustLines(alice, bob, OF2, CK2);
2407 AccountOwns gw1{*
this, env,
"gw1", 0};
2414 IOU
const OF3 = gw1[
"OF3"];
2418 env.le(
keylet::line(gw1, alice, OF3.currency)) ==
nullptr);
2419 env(
offer(alice, OF3(94),
XRP(94)));
2426 gw1.verifyOwners(__LINE__);
2429 alice.verifyOwners(__LINE__);
2432 IOU
const CK3 = gw1[
"CK3"];
2434 env(check::create(gw1, alice, CK3(94)));
2437 env.le(
keylet::line(gw1, alice, CK3.currency)) ==
nullptr);
2438 env(check::cash(alice, chkId, CK3(94)));
2446 gw1.verifyOwners(__LINE__);
2449 alice.verifyOwners(__LINE__);
2451 cmpTrustLines(gw1, alice, OF3, CK3);
2459 AccountOwns gw1{*
this, env,
"gw1", 0};
2460 IOU
const OF3 = gw1[
"OF3"];
2461 env(
offer(alice,
XRP(93), OF3(93)));
2464 env.le(
keylet::line(alice, bob, OF3.currency)) ==
nullptr);
2470 gw1.verifyOwners(__LINE__);
2471 alice.verifyOwners(__LINE__);
2472 bob.verifyOwners(__LINE__);
2475 IOU
const CK3 = gw1[
"CK3"];
2477 env(check::create(alice, bob, CK3(93)));
2480 env.le(
keylet::line(alice, bob, CK3.currency)) ==
nullptr);
2481 env(check::cash(bob, chkId, CK3(93)));
2487 gw1.verifyOwners(__LINE__);
2488 alice.verifyOwners(__LINE__);
2489 bob.verifyOwners(__LINE__);
2491 cmpTrustLines(alice, bob, OF3, CK3);
2498 AccountOwns gw1{*
this, env,
"gw1", 0};
2503 IOU
const OF4 = gw1[
"OF4"];
2507 env.le(
keylet::line(gw1, alice, OF4.currency)) ==
nullptr);
2512 gw1.verifyOwners(__LINE__);
2513 alice.verifyOwners(__LINE__);
2514 bob.verifyOwners(__LINE__);
2517 IOU
const CK4 = gw1[
"CK4"];
2519 env(check::create(gw1, alice, CK4(92)), ter(
tecFROZEN));
2522 env.le(
keylet::line(gw1, alice, CK4.currency)) ==
nullptr);
2523 env(check::cash(alice, chkId, CK4(92)), ter(
tecNO_ENTRY));
2527 gw1.verifyOwners(__LINE__);
2528 alice.verifyOwners(__LINE__);
2529 bob.verifyOwners(__LINE__);
2534 env.le(
keylet::line(gw1, alice, OF4.currency)) ==
nullptr);
2536 env.le(
keylet::line(gw1, alice, CK4.currency)) ==
nullptr);
2544 AccountOwns gw1{*
this, env,
"gw1", 0};
2545 IOU
const OF4 = gw1[
"OF4"];
2549 env.le(
keylet::line(alice, bob, OF4.currency)) ==
nullptr);
2554 gw1.verifyOwners(__LINE__);
2555 alice.verifyOwners(__LINE__);
2556 bob.verifyOwners(__LINE__);
2559 IOU
const CK4 = gw1[
"CK4"];
2561 env(check::create(alice, bob, CK4(91)), ter(
tecFROZEN));
2564 env.le(
keylet::line(alice, bob, CK4.currency)) ==
nullptr);
2565 env(check::cash(bob, chkId, CK4(91)), ter(
tecNO_ENTRY));
2569 gw1.verifyOwners(__LINE__);
2570 alice.verifyOwners(__LINE__);
2571 bob.verifyOwners(__LINE__);
2576 env.le(
keylet::line(gw1, bob, OF4.currency)) ==
nullptr);
2578 env.le(
keylet::line(gw1, bob, CK4.currency)) ==
nullptr);
2587 AccountOwns gw2{*
this, env,
"gw2", 0};
2588 env.fund(
XRP(5000), gw2);
2597 IOU
const OF5 = gw2[
"OF5"];
2603 env.le(
keylet::line(gw2, alice, OF5.currency)) ==
nullptr);
2609 gw2.verifyOwners(__LINE__);
2610 alice.verifyOwners(__LINE__);
2611 bob.verifyOwners(__LINE__);
2617 gw2.verifyOwners(__LINE__);
2620 IOU
const CK5 = gw2[
"CK5"];
2622 env(check::create(gw2, alice, CK5(92)));
2626 env.le(
keylet::line(gw2, alice, CK5.currency)) ==
nullptr);
2627 env(check::cash(alice, chkId, CK5(92)), ter(
tecNO_AUTH));
2632 gw2.verifyOwners(__LINE__);
2633 alice.verifyOwners(__LINE__);
2634 bob.verifyOwners(__LINE__);
2639 env.le(
keylet::line(gw2, alice, OF5.currency)) ==
nullptr);
2641 env.le(
keylet::line(gw2, alice, CK5.currency)) ==
nullptr);
2644 env(check::cancel(gw2, chkId));
2647 gw2.verifyOwners(__LINE__);
2655 AccountOwns gw2{*
this, env,
"gw2", 0};
2656 IOU
const OF5 = gw2[
"OF5"];
2661 env.le(
keylet::line(gw2, bob, OF5.currency)) ==
nullptr);
2664 gw2.verifyOwners(__LINE__);
2665 alice.verifyOwners(__LINE__);
2666 bob.verifyOwners(__LINE__);
2669 IOU
const CK5 = gw2[
"CK5"];
2671 env(check::create(alice, bob, CK5(91)));
2674 env.le(
keylet::line(alice, bob, CK5.currency)) ==
nullptr);
2679 env(check::cancel(alice, chkId));
2683 gw2.verifyOwners(__LINE__);
2684 alice.verifyOwners(__LINE__);
2685 bob.verifyOwners(__LINE__);
2690 env.le(
keylet::line(gw2, bob, OF5.currency)) ==
nullptr);
2692 env.le(
keylet::line(gw2, bob, CK5.currency)) ==
nullptr);
2718 using namespace test::jtx;
2719 auto const sa = supported_amendments();