21#include <test/jtx/trust.h>
22#include <test/jtx/xchain_bridge.h>
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/jss.h>
35 using namespace test::jtx;
42 Env env{*
this, features - featureMPTokensV1};
50 Env env{*
this, features};
98 {.maxAmt = 0xFFFF'FFFF'FFFF'FFF0,
117 using namespace test::jtx;
123 Env env{*
this, features};
138 Json::Value const result = env.rpc(
"tx", txHash)[jss::result];
140 result[sfMaximumAmount.getJsonName()] ==
"9223372036854775807");
149 using namespace test::jtx;
154 Env env{*
this, features - featureMPTokensV1};
156 auto const id =
makeMptID(env.seq(alice), alice);
159 env.enableFeature(featureMPTokensV1);
167 Env env{*
this, features};
168 MPTTester mptAlice(env, alice, {.holders = {bob}});
175 mptAlice.create({.ownerCount = 1});
184 mptAlice.authorize({.account = bob, .holderCount = 1});
187 mptAlice.pay(alice, bob, 100);
199 using namespace test::jtx;
204 Env env{*
this, features};
207 mptAlice.
create({.ownerCount = 1});
209 mptAlice.
destroy({.ownerCount = 0});
215 testcase(
"Validate authorize transaction");
217 using namespace test::jtx;
223 Env env{*
this, features - featureMPTokensV1};
224 MPTTester mptAlice(env, alice, {.holders = {bob}});
234 Env env{*
this, features};
235 MPTTester mptAlice(env, alice, {.holders = {bob}});
237 mptAlice.
create({.ownerCount = 1});
247 mptAlice.authorize({.holder = alice, .err =
temMALFORMED});
253 Env env{*
this, features};
254 MPTTester mptAlice(env, alice, {.holders = {bob}});
255 auto const id =
makeMptID(env.seq(alice), alice);
267 Env env{*
this, features};
268 MPTTester mptAlice(env, alice, {.holders = {bob}});
270 mptAlice.
create({.ownerCount = 1});
280 mptAlice.authorize({.holder = bob, .err =
tecNO_AUTH});
283 mptAlice.authorize({.account = bob, .holderCount = 1});
286 mptAlice.authorize({.account = bob, .err =
tecDUPLICATE});
292 mptAlice.pay(alice, bob, 100);
302 mptAlice.pay(bob, alice, 100);
319 Env env{*
this, features};
320 MPTTester mptAlice(env, alice, {.holders = {bob}});
332 mptAlice.authorize({.holder = cindy, .err =
tecNO_DST});
335 mptAlice.authorize({.account = bob, .holderCount = 1});
344 mptAlice.authorize({.holder = bob});
349 mptAlice.authorize({.holder = bob});
358 Env env{*
this, features};
359 auto const acctReserve = env.current()->fees().accountReserve(0);
360 auto const incReserve = env.current()->fees().increment;
368 .xrpHolders = acctReserve + (incReserve - 1)});
371 MPTTester mptAlice2(env, alice, {.fund =
false});
374 MPTTester mptAlice3(env, alice, {.fund =
false});
375 mptAlice3.
create({.ownerCount = 3});
378 mptAlice1.authorize({.account = bob, .holderCount = 1});
381 mptAlice2.authorize({.account = bob, .holderCount = 2});
387 env.master, bob,
drops(incReserve + incReserve + incReserve)));
390 mptAlice3.authorize({.account = bob, .holderCount = 3});
399 using namespace test::jtx;
404 Env env{*
this, features};
407 MPTTester mptAlice(env, alice, {.holders = {bob}});
409 mptAlice.
create({.ownerCount = 1});
412 mptAlice.authorize({.account = bob, .holderCount = 1});
421 Env env{*
this, features};
424 MPTTester mptAlice(env, alice, {.holders = {bob}});
429 mptAlice.authorize({.account = bob, .holderCount = 1});
432 mptAlice.authorize({.account = alice, .holder = bob});
448 Env env{*
this, features};
449 MPTTester mptAlice(env, alice, {.holders = {bob}});
451 mptAlice.
create({.ownerCount = 1});
454 mptAlice.authorize({.account = bob, .holderCount = 1});
457 mptAlice.destroy({.ownerCount = 0});
469 testcase(
"Validate set transaction");
471 using namespace test::jtx;
477 Env env{*
this, features - featureMPTokensV1};
478 MPTTester mptAlice(env, alice, {.holders = {bob}});
485 env.enableFeature(featureMPTokensV1);
487 mptAlice.create({.ownerCount = 1, .holderCount = 0});
489 mptAlice.authorize({.account = bob, .holderCount = 1});
516 Env env{*
this, features};
518 MPTTester mptAlice(env, alice, {.holders = {bob}});
520 mptAlice.
create({.ownerCount = 1});
554 Env env{*
this, features};
556 MPTTester mptAlice(env, alice, {.holders = {bob}});
565 mptAlice.create({.ownerCount = 1, .flags =
tfMPTCanLock});
586 testcase(
"Enabled set transaction");
588 using namespace test::jtx;
591 Env env{*
this, features};
595 MPTTester mptAlice(env, alice, {.holders = {bob}});
599 {.ownerCount = 1, .holderCount = 0, .flags =
tfMPTCanLock});
601 mptAlice.authorize({.account = bob, .holderCount = 1});
604 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
608 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
611 mptAlice.set({.account = alice, .flags =
tfMPTLock});
615 mptAlice.set({.account = alice, .flags =
tfMPTLock});
616 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
619 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
622 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
625 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
628 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
633 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
634 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
642 using namespace test::jtx;
651 Env env{*
this, features - featureMPTokensV1};
655 env.fund(
XRP(1'000), alice);
656 env.fund(
XRP(1'000), bob);
664 Env env{*
this, features - featureMPTokensV1};
667 auto const USD = alice[
"USD"];
669 env.fund(
XRP(1'000), alice);
670 env.fund(
XRP(1'000), carol);
674 jv[jss::secret] = alice.
name();
675 jv[jss::tx_json] =
pay(alice, carol, mpt);
676 jv[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
677 auto const jrr = env.rpc(
"json",
"submit",
to_string(jv));
678 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"temDISABLED");
683 Env env{*
this, features};
685 MPTTester mptAlice(env, alice, {.holders = {bob}});
687 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
688 auto const MPT = mptAlice[
"MPT"];
690 mptAlice.authorize({.account = bob});
693 env(
pay(alice, bob,
MPT(10)),
700 Env env{*
this, features};
704 MPTTester mptAlice(env, alice, {.holders = {carol}});
706 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
708 mptAlice.authorize({.account = carol});
712 auto const MPT = mptAlice[
"MPT"];
713 env(
pay(alice, carol,
MPT(100)),
716 env(
pay(alice, carol,
MPT(100)),
720 auto const USD = alice[
"USD"];
721 env(
pay(alice, carol, USD(100)),
724 env(
pay(alice, carol,
XRP(100)),
727 env(
pay(alice, carol, USD(100)),
730 env(
pay(alice, carol,
XRP(100)),
735 "MPT",
makeMptID(env.seq(alice) + 10, alice));
736 env(
pay(alice, carol, MPT1(100)),
745 Env env{*
this, features};
749 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
751 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
752 auto const MPT = mptAlice[
"MPT"];
754 mptAlice.authorize({.account = carol});
757 payment[jss::secret] = alice.
name();
758 payment[jss::tx_json] =
pay(alice, carol,
MPT(100));
760 payment[jss::build_path] =
true;
761 auto jrr = env.rpc(
"json",
"submit",
to_string(payment));
762 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
764 jrr[jss::result][jss::error_message] ==
765 "Field 'build_path' not allowed in this context.");
770 Env env{*
this, features};
772 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
774 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
775 auto const MPT = mptAlice[
"MPT"];
777 mptAlice.authorize({.account = bob});
778 mptAlice.authorize({.account = carol});
791 Env env{*
this, features};
793 MPTTester mptAlice(env, alice, {.holders = {bob}});
795 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
797 mptAlice.authorize({.account = bob});
806 Env env{*
this, features};
808 MPTTester mptAlice(env, alice, {.holders = {bob}});
810 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
812 mptAlice.authorize({.account = bob});
825 Env env{*
this, features};
827 MPTTester mptAlice(env, alice, {.holders = {bob}});
834 mptAlice.authorize({.account = bob});
842 Env env{*
this, features};
844 MPTTester mptAlice(env, alice, {.holders = {bob}});
852 mptAlice.authorize({.account = bob});
855 mptAlice.authorize({.account = alice, .holder = bob});
858 mptAlice.pay(alice, bob, 100);
871 Env env(*
this, features);
876 MPTTester mptAlice(env, alice, {.holders = {bob, cindy}});
879 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
882 mptAlice.authorize({.account = bob});
885 mptAlice.authorize({.account = cindy});
888 mptAlice.pay(alice, bob, 100);
895 mptAlice.pay(bob, alice, 10);
900 Env env{*
this, features};
902 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
919 Env env{*
this, features};
921 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
925 mptAlice.authorize({.account = bob});
926 mptAlice.authorize({.account = carol});
928 mptAlice.pay(alice, bob, 100);
939 Env env{*
this, features};
941 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
946 mptAlice.authorize({.account = bob});
947 mptAlice.authorize({.account = carol});
949 mptAlice.pay(alice, bob, 100);
950 mptAlice.pay(alice, carol, 100);
953 mptAlice.set({.account = alice, .flags =
tfMPTLock});
958 mptAlice.pay(alice, bob, 3);
960 mptAlice.pay(bob, alice, 4);
963 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
965 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
970 mptAlice.pay(alice, bob, 7);
972 mptAlice.pay(bob, alice, 8);
977 Env env{*
this, features};
979 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
983 {.transferFee = 10'000,
989 mptAlice.authorize({.account = bob});
990 mptAlice.authorize({.account = carol});
993 mptAlice.pay(alice, bob, 2'000);
996 mptAlice.pay(bob, alice, 1'000);
997 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 1'000));
1007 auto const MPT = mptAlice[
"MPT"];
1009 env(
pay(bob, carol,
MPT(100)),
1018 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 780));
1019 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 200));
1022 env(
pay(bob, carol,
MPT(100)),
1027 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 690));
1028 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 282));
1033 Env env{*
this, features};
1035 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1041 mptAlice.authorize({.account = bob});
1042 mptAlice.authorize({.account = carol});
1043 mptAlice.pay(alice, bob, 1'000);
1045 auto const MPT = mptAlice[
"MPT"];
1047 env(
pay(bob, carol,
MPT(100)),
1050 env(
pay(bob, alice,
MPT(100)),
1056 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 100));
1058 env(
pay(bob, carol,
MPT(100)),
1061 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 199));
1066 Env env{*
this, features};
1068 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1074 mptAlice.authorize({.account = bob});
1075 mptAlice.authorize({.account = carol});
1076 mptAlice.pay(alice, bob, 1'000);
1078 auto const MPT = mptAlice[
"MPT"];
1081 env(
pay(bob, alice,
MPT(100)),
1087 env(
pay(bob, alice,
MPT(100)),
1095 Env env{*
this, features};
1097 MPTTester mptAlice(env, alice, {.holders = {bob}});
1105 mptAlice.authorize({.account = bob});
1108 mptAlice.pay(alice, bob, 100);
1117 Env env{*
this, features};
1119 MPTTester mptAlice(env, alice, {.holders = {bob}});
1121 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1123 mptAlice.authorize({.account = bob});
1135 Env env{*
this, features};
1136 env.fund(
XRP(1'000), alice, bob);
1139 jv[jss::secret] = alice.
name();
1140 jv[jss::tx_json] =
pay(alice, bob, mpt);
1141 jv[jss::tx_json][jss::Amount][jss::value] =
1143 auto const jrr = env.rpc(
"json",
"submit",
to_string(jv));
1144 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1150 Env env{*
this, features};
1152 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1160 auto const MPT = mptAlice[
"MPT"];
1162 mptAlice.authorize({.account = bob});
1163 mptAlice.authorize({.account = carol});
1166 mptAlice.pay(alice, bob, 10'000);
1169 env(
pay(bob, carol,
MPT(10'000)),
1173 auto const meta = env.meta()->getJson(
1177 meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1178 [sfOutstandingAmount.fieldName] ==
"9990");
1181 meta[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1182 [sfMPTAmount.fieldName] ==
"9990");
1185 meta[2u][sfModifiedNode.fieldName][sfPreviousFields.fieldName]
1186 [sfMPTAmount.fieldName] ==
"10000");
1188 !meta[2u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1189 .isMember(sfMPTAmount.fieldName));
1193 env(
pay(bob, carol,
MPT(10'000)),
1200 Env env{*
this, features};
1202 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1209 auto const MPT = mptAlice[
"MPT"];
1211 mptAlice.authorize({.account = bob});
1212 mptAlice.authorize({.account = carol});
1225 BEAST_EXPECT(mptAlice.checkMPTokenOutstandingAmount(0));
1230 Env env{*
this, features};
1232 MPTTester mptAlice(env, alice, {.holders = {bob}});
1234 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1236 mptAlice.authorize({.account = bob});
1239 mptAlice.destroy({.ownerCount = 0});
1248 Env env{*
this, features};
1250 env.fund(
XRP(1'000), alice, bob);
1259 Env env{*
this, features};
1261 MPTTester mptAlice(env, alice, {.holders = {bob}});
1263 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1266 mptAlice.destroy({.ownerCount = 0});
1276 Env env{*
this, features};
1281 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1286 mptAlice.authorize({.account = bob});
1287 mptAlice.authorize({.account = carol});
1289 mptAlice.pay(alice, bob, 100);
1292 mptAlice.pay(bob, carol, 100);
1297 Env env{*
this, features};
1299 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1304 mptAlice.authorize({.account = bob});
1305 mptAlice.authorize({.account = carol});
1308 mptAlice.pay(alice, bob, 100);
1311 mptAlice.pay(bob, alice, 100);
1314 mptAlice.pay(alice, bob, 100);
1315 mptAlice.pay(bob, carol, 50);
1324 using namespace test::jtx;
1328 Account const dpIssuer(
"dpIssuer");
1330 const char credType[] =
"abcde";
1335 env.
fund(
XRP(50000), diana, dpIssuer);
1338 MPTTester mptAlice(env, alice, {.holders = {bob}});
1344 env(
pay(diana, bob,
XRP(500)));
1348 mptAlice.authorize({.account = bob});
1350 mptAlice.authorize({.account = alice, .holder = bob});
1365 mptAlice.pay(alice, bob, 100);
1375 std::string const credIdx = jv[jss::result][jss::index].asString();
1378 mptAlice.pay(alice, bob, 100,
tesSUCCESS, {{credIdx}});
1402 mptAlice.pay(alice, bob, 100,
tesSUCCESS, {{credIdx}});
1406 testcase(
"DepositPreauth disabled featureCredentials");
1411 "D007AE4B6E1274B4AF872588267B810C2F82716726351D1C7D38D3E5499FC6"
1414 env.
fund(
XRP(50000), diana, dpIssuer);
1417 MPTTester mptAlice(env, alice, {.holders = {bob}});
1423 env(
pay(diana, bob,
XRP(500)));
1427 mptAlice.authorize({.account = bob});
1429 mptAlice.authorize({.account = alice, .holder = bob});
1441 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1449 mptAlice.pay(alice, bob, 100);
1453 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1465 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1473 testcase(
"MPT Issue Invalid in Transaction");
1474 using namespace test::jtx;
1483 for (
auto const& e : format.getSOTemplate())
1489 e.sField().getName() != jss::Fee &&
1490 format.getName() != jss::SetFee)
1493 format.getName() + e.sField().fieldName);
1500 auto const USD = alice[
"USD"];
1503 STAmount mpt{issue, UINT64_C(100)};
1504 auto const jvb =
bridge(alice, USD, alice, USD);
1505 for (
auto const& feature : {features, features - featureMPTokensV1})
1507 Env env{*
this, feature};
1508 env.fund(
XRP(1'000), alice);
1509 env.fund(
XRP(1'000), carol);
1512 txWithAmounts.
erase(
1513 jv[jss::TransactionType].asString() + mptField);
1516 auto jtx = env.jt(jv);
1521 jrr[jss::result][jss::error] ==
"invalidTransaction");
1525 jv1[jss::secret] = alice.
name();
1526 jv1[jss::tx_json] = jv;
1527 jrr = env.rpc(
"json",
"submit",
to_string(jv1));
1528 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1530 jrr = env.rpc(
"json",
"sign",
to_string(jv1));
1531 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1533 auto toSFieldRef = [](
SField const& field) {
1536 auto setMPTFields = [&](
SField const& field,
1538 bool withAmount =
true) {
1540 jv[jss::Asset2] =
to_json(USD.issue());
1542 jv[field.fieldName] =
1544 if (field == sfAsset)
1546 else if (field == sfAsset2)
1556 auto ammCreate = [&](
SField const& field) {
1558 jv[jss::TransactionType] = jss::AMMCreate;
1559 jv[jss::Account] = alice.
human();
1560 jv[jss::Amount] = (field.fieldName == sfAmount.fieldName)
1563 jv[jss::Amount2] = (field.fieldName == sfAmount2.fieldName)
1566 jv[jss::TradingFee] = 0;
1567 test(jv, field.fieldName);
1569 ammCreate(sfAmount);
1570 ammCreate(sfAmount2);
1572 auto ammDeposit = [&](
SField const& field) {
1574 jv[jss::TransactionType] = jss::AMMDeposit;
1575 jv[jss::Account] = alice.
human();
1577 setMPTFields(field, jv);
1578 test(jv, field.fieldName);
1580 for (
SField const& field :
1581 {toSFieldRef(sfAmount),
1582 toSFieldRef(sfAmount2),
1583 toSFieldRef(sfEPrice),
1584 toSFieldRef(sfLPTokenOut),
1585 toSFieldRef(sfAsset),
1586 toSFieldRef(sfAsset2)})
1589 auto ammWithdraw = [&](
SField const& field) {
1591 jv[jss::TransactionType] = jss::AMMWithdraw;
1592 jv[jss::Account] = alice.
human();
1594 setMPTFields(field, jv);
1595 test(jv, field.fieldName);
1597 ammWithdraw(sfAmount);
1598 for (
SField const& field :
1599 {toSFieldRef(sfAmount2),
1600 toSFieldRef(sfEPrice),
1601 toSFieldRef(sfLPTokenIn),
1602 toSFieldRef(sfAsset),
1603 toSFieldRef(sfAsset2)})
1606 auto ammBid = [&](
SField const& field) {
1608 jv[jss::TransactionType] = jss::AMMBid;
1609 jv[jss::Account] = alice.
human();
1610 setMPTFields(field, jv);
1611 test(jv, field.fieldName);
1613 for (
SField const& field :
1614 {toSFieldRef(sfBidMin),
1615 toSFieldRef(sfBidMax),
1616 toSFieldRef(sfAsset),
1617 toSFieldRef(sfAsset2)})
1620 auto ammClawback = [&](
SField const& field) {
1622 jv[jss::TransactionType] = jss::AMMClawback;
1623 jv[jss::Account] = alice.
human();
1624 jv[jss::Holder] = carol.
human();
1625 setMPTFields(field, jv);
1626 test(jv, field.fieldName);
1628 for (
SField const& field :
1629 {toSFieldRef(sfAmount),
1630 toSFieldRef(sfAsset),
1631 toSFieldRef(sfAsset2)})
1634 auto ammDelete = [&](
SField const& field) {
1636 jv[jss::TransactionType] = jss::AMMDelete;
1637 jv[jss::Account] = alice.
human();
1638 setMPTFields(field, jv,
false);
1639 test(jv, field.fieldName);
1642 ammDelete(sfAsset2);
1644 auto ammVote = [&](
SField const& field) {
1646 jv[jss::TransactionType] = jss::AMMVote;
1647 jv[jss::Account] = alice.
human();
1648 jv[jss::TradingFee] = 100;
1649 setMPTFields(field, jv,
false);
1650 test(jv, field.fieldName);
1655 auto checkCash = [&](
SField const& field) {
1657 jv[jss::TransactionType] = jss::CheckCash;
1658 jv[jss::Account] = alice.
human();
1661 test(jv, field.fieldName);
1663 checkCash(sfAmount);
1664 checkCash(sfDeliverMin);
1668 jv[jss::TransactionType] = jss::CheckCreate;
1669 jv[jss::Account] = alice.
human();
1670 jv[jss::Destination] = carol.
human();
1672 test(jv, jss::SendMax.c_str());
1677 jv[jss::TransactionType] = jss::EscrowCreate;
1678 jv[jss::Account] = alice.
human();
1679 jv[jss::Destination] = carol.
human();
1681 test(jv, jss::Amount.c_str());
1686 test(jv, jss::TakerPays.c_str());
1687 jv =
offer(alice, mpt, USD(100));
1688 test(jv, jss::TakerGets.c_str());
1693 jv[jss::TransactionType] = jss::PaymentChannelCreate;
1694 jv[jss::Account] = alice.
human();
1695 jv[jss::Destination] = carol.
human();
1696 jv[jss::SettleDelay] = 1;
1699 test(jv, jss::Amount.c_str());
1704 jv[jss::TransactionType] = jss::PaymentChannelFund;
1705 jv[jss::Account] = alice.
human();
1708 test(jv, jss::Amount.c_str());
1713 jv[jss::TransactionType] = jss::PaymentChannelClaim;
1714 jv[jss::Account] = alice.
human();
1717 test(jv, jss::Amount.c_str());
1722 jv[jss::TransactionType] = jss::NFTokenCreateOffer;
1723 jv[jss::Account] = alice.
human();
1726 test(jv, jss::Amount.c_str());
1731 jv[jss::TransactionType] = jss::NFTokenAcceptOffer;
1732 jv[jss::Account] = alice.
human();
1733 jv[sfNFTokenBrokerFee.fieldName] =
1735 test(jv, sfNFTokenBrokerFee.fieldName);
1740 jv[jss::TransactionType] = jss::NFTokenMint;
1741 jv[jss::Account] = alice.
human();
1742 jv[sfNFTokenTaxon.fieldName] = 1;
1744 test(jv, jss::Amount.c_str());
1747 auto trustSet = [&](
SField const& field) {
1749 jv[jss::TransactionType] = jss::TrustSet;
1750 jv[jss::Account] = alice.
human();
1753 test(jv, field.fieldName);
1755 trustSet(sfLimitAmount);
1760 test(jv, jss::Amount.c_str());
1765 test(jv, jss::Amount.c_str());
1771 test(jv, sfSignatureReward.fieldName);
1785 test(jv, jss::Amount.c_str());
1800 for (
auto const& field :
1801 {sfAmount.fieldName, sfSignatureReward.fieldName})
1810 alice, jvb, alice, mpt,
XRP(10));
1811 for (
auto const& field :
1812 {sfAmount.fieldName, sfSignatureReward.fieldName})
1824 jv[jss::TransactionType] = tt;
1825 jv[jss::Account] = alice.
human();
1826 jv[sfXChainBridge.fieldName] = jvb;
1827 jv[sfSignatureReward.fieldName] =
1829 jv[sfMinAccountCreateAmount.fieldName] =
1833 auto reward =
STAmount{sfSignatureReward, mpt};
1834 auto minAmount =
STAmount{sfMinAccountCreateAmount, USD(10)};
1835 for (
SField const& field :
1837 std::ref(sfMinAccountCreateAmount)})
1840 jss::XChainCreateBridge,
1845 jss::XChainModifyBridge,
1849 reward =
STAmount{sfSignatureReward, USD(10)};
1850 minAmount =
STAmount{sfMinAccountCreateAmount, mpt};
1853 BEAST_EXPECT(txWithAmounts.
empty());
1860 testcase(
"Test synthetic fields from tx response");
1862 using namespace test::jtx;
1866 Env env{*
this, features};
1875 "E11F0E0CA14219922B7881F060B9CEE67CFBC87E4049A441ED2AE348FF8FAC"
1878 Json::Value const meta = env.rpc(
"tx", txHash)[jss::result][jss::meta];
1879 auto const id = meta[jss::mpt_issuance_id].
asString();
1881 BEAST_EXPECT(meta.
isMember(jss::mpt_issuance_id));
1884 id ==
"00000004AE123A8556F3CF91154711376AFB0F894F832B3D",
id);
1890 testcase(
"MPT clawback validations");
1891 using namespace test::jtx;
1895 Env env(*
this, features - featureMPTokensV1);
1899 env.
fund(
XRP(1000), alice, bob);
1902 auto const USD = alice[
"USD"];
1918 Env env(*
this, features);
1922 env.
fund(
XRP(1000), alice, bob);
1925 auto const USD = alice[
"USD"];
1952 Env env(*
this, features);
1956 MPTTester mptAlice(env, alice, {.holders = {bob}});
1964 mptAlice.create({.ownerCount = 1, .holderCount = 0});
1966 mptAlice.authorize({.account = bob});
1968 mptAlice.pay(alice, bob, 100);
1977 Env env(*
this, features);
1983 MPTTester mptAlice(env, alice, {.holders = {bob}});
2000 mptAlice.authorize({.account = bob});
2006 mptAlice.pay(alice, bob, 100);
2017 Env env(*
this, features);
2021 env.
fund(
XRP(1000), alice, bob);
2030 jv1[jss::secret] = alice.name();
2031 jv1[jss::tx_json] = jv;
2032 auto const jrr = env.
rpc(
"json",
"submit",
to_string(jv1));
2033 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
2041 using namespace test::jtx;
2044 Env env(*
this, features);
2048 MPTTester mptAlice(env, alice, {.holders = {bob}});
2055 mptAlice.authorize({.account = bob});
2058 mptAlice.pay(alice, bob, 100);
2060 mptAlice.claw(alice, bob, 1);
2062 mptAlice.claw(alice, bob, 1000);
2070 Env env(*
this, features);
2074 MPTTester mptAlice(env, alice, {.holders = {bob}});
2083 mptAlice.authorize({.account = bob});
2086 mptAlice.pay(alice, bob, 100);
2088 mptAlice.set({.account = alice, .flags =
tfMPTLock});
2090 mptAlice.claw(alice, bob, 100);
2095 Env env(*
this, features);
2099 MPTTester mptAlice(env, alice, {.holders = {bob}});
2108 mptAlice.authorize({.account = bob});
2111 mptAlice.pay(alice, bob, 100);
2113 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
2115 mptAlice.claw(alice, bob, 100);
2120 Env env(*
this, features);
2124 MPTTester mptAlice(env, alice, {.holders = {bob}});
2133 mptAlice.authorize({.account = bob});
2136 mptAlice.authorize({.account = alice, .holder = bob});
2139 mptAlice.pay(alice, bob, 100);
2145 mptAlice.claw(alice, bob, 100);
2152 using namespace test::jtx;
2166 Asset const assetMpt1Gw1{mpt1};
2167 Asset const assetMpt1Gw1a{mpt1a};
2168 Asset const assetMpt1Gw2{mpt2};
2169 Asset const assetMpt2Gw2{mpt3};
2173 BEAST_EXPECT(
equalTokens(assetCur1Gw1, assetCur1Gw1a));
2174 BEAST_EXPECT(
equalTokens(assetCur2Gw1, assetCur2Gw2));
2177 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw1));
2178 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw2));
2182 BEAST_EXPECT(
equalTokens(assetMpt1Gw1, assetMpt1Gw1a));
2184 BEAST_EXPECT(!
equalTokens(assetMpt1Gw1, assetMpt1Gw2));
2185 BEAST_EXPECT(!
equalTokens(assetMpt1Gw2, assetMpt2Gw2));
2188 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetMpt1Gw1));
2189 BEAST_EXPECT(!
equalTokens(assetMpt2Gw2, assetCur2Gw2));
2195 using namespace test::jtx;
2202 STAmount const amt3{asset3, 10'000};
2205 testcase(
"Test STAmount MPT arithmetics");
2206 using namespace std::string_literals;
2208 BEAST_EXPECT(res == amt3);
2210 res =
mulRound(amt1, amt2, asset3,
true);
2211 BEAST_EXPECT(res == amt3);
2214 BEAST_EXPECT(res == amt3);
2217 STAmount mptOverflow{asset2, UINT64_C(3037000500)};
2220 res =
multiply(mptOverflow, mptOverflow, asset3);
2221 fail(
"should throw runtime exception 1");
2225 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2228 mptOverflow =
STAmount{asset2, UINT64_C(2147483648)};
2229 uint64_t
const mantissa = (2ull << 32) + 2;
2233 fail(
"should throw runtime exception 2");
2237 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2242 testcase(
"Test MPTAmount arithmetics");
2245 BEAST_EXPECT((mptAmt1 += mptAmt2) ==
MPTAmount{200});
2246 BEAST_EXPECT(mptAmt1 == 200);
2247 BEAST_EXPECT((mptAmt1 -= mptAmt2) == mptAmt1);
2248 BEAST_EXPECT(mptAmt1 == mptAmt2);
2249 BEAST_EXPECT(mptAmt1 == 100);
2254 testcase(
"Test MPTIssue from/to Json");
2263 testcase(
"Test Asset from/to Json");
2269 "{\"mpt_issuance_id\":"
2270 "\"00000001A407AF5856CCF3C42619DAA925813FC955C72983\"}");
2279 using namespace test::jtx;
2320BEAST_DEFINE_TESTSUITE_PRIO(MPToken, tx,
ripple, 2);
Lightweight wrapper to tag static string.
std::string asString() const
Returns the unquoted string value.
bool isMember(const char *key) const
Return true if the object has a member named key.
testcase_t testcase
Memberspace for declaring test cases.
void fail(String const &reason, char const *file, int line)
Record a failure.
A currency issued by an account.
static MPTAmount minPositiveAmount()
Slice slice() const noexcept
Slice slice() const noexcept
void run() override
Runs the suite.
void testCreateValidation(FeatureBitset features)
void testClawback(FeatureBitset features)
void testTokensEquality()
void testAuthorizeValidation(FeatureBitset features)
void testSetValidation(FeatureBitset features)
void testClawbackValidation(FeatureBitset features)
void testDepositPreauth()
void testCreateEnabled(FeatureBitset features)
void testDestroyEnabled(FeatureBitset features)
void testPayment(FeatureBitset features)
void testHelperFunctions()
void testMPTInvalidInTx(FeatureBitset features)
void testAuthorizeEnabled(FeatureBitset features)
void testDestroyValidation(FeatureBitset features)
void testSetEnabled(FeatureBitset features)
void testTxJsonMetaFields(FeatureBitset features)
Immutable cryptographic account descriptor.
PublicKey const & pk() const
Return the public key.
AccountID id() const
Returns the Account ID.
std::string const & name() const
Return the name.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
void require(Args const &... args)
Check a set of requirements.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
void authorize(MPTAuthorize const &arg=MPTAuthorize{})
void set(MPTSet const &set={})
MPTID const & issuanceID() const
void create(MPTCreate const &arg=MPTCreate{})
void destroy(MPTDestroy const &arg=MPTDestroy{})
Converts to MPT Issue or STAmount.
Sets the DeliverMin on a JTx.
Sets the SendMax on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Json::Value create(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Json::Value accept(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Json::Value ledgerEntry(jtx::Env &env, jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Json::Value unauth(Account const &account, Account const &unauth)
Remove preauthorization for deposit.
Json::Value auth(Account const &account, Account const &auth)
Preauthorize for deposit.
Json::Value authCredentials(jtx::Account const &account, std::vector< AuthorizeCredentials > const &auth)
Json::Value create_account_attestation(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::AnyAmount const &rewardAmount, jtx::Account const &rewardAccount, bool wasLockingChainSend, std::uint64_t createCount, jtx::Account const &dst, jtx::signer const &signer)
Json::Value claim_attestation(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::Account const &rewardAccount, bool wasLockingChainSend, std::uint64_t claimID, std::optional< jtx::Account > const &dst, jtx::signer const &signer)
Json::Value bridge(Account const &lockingChainDoor, Issue const &lockingChainIssue, Account const &issuingChainDoor, Issue const &issuingChainIssue)
Json::Value claw(Account const &account, STAmount const &amount, std::optional< Account > const &mptHolder)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value sidechain_xchain_account_create(Account const &acc, Json::Value const &bridge, Account const &dst, AnyAmount const &amt, AnyAmount const &reward)
Json::Value xchain_claim(Account const &acc, Json::Value const &bridge, std::uint32_t claimID, AnyAmount const &amt, Account const &dst)
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Json::Value xchain_create_claim_id(Account const &acc, Json::Value const &bridge, STAmount const &reward, Account const &otherChainSource)
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Json::Value xchain_commit(Account const &acc, Json::Value const &bridge, std::uint32_t claimID, AnyAmount const &amt, std::optional< Account > const &dst)
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
constexpr std::uint32_t tfSingleAsset
constexpr bool equalTokens(Asset const &lhs, Asset const &rhs)
constexpr std::uint32_t asfDepositAuth
constexpr std::uint32_t const tfMPTCanTransfer
Asset assetFromJson(Json::Value const &jv)
constexpr std::uint32_t const tfMPTCanTrade
constexpr std::uint32_t const tfMPTUnlock
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
std::uint16_t constexpr maxTransferFee
The maximum token transfer fee allowed.
STAmount multiply(STAmount const &amount, Rate const &rate)
MPTIssue mptIssueFromJson(Json::Value const &jv)
Json::Value to_json(Asset const &asset)
constexpr std::uint32_t tfPartialPayment
std::string strHex(FwdIt begin, FwdIt end)
constexpr std::uint32_t const tfMPTUnauthorize
@ tecINSUFFICIENT_RESERVE
constexpr std::uint32_t const tfMPTLock
constexpr std::uint32_t tfNoRippleDirect
constexpr std::uint32_t tfLimitQuality
std::string to_string(base_uint< Bits, Tag > const &a)
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
constexpr std::uint32_t asfAllowTrustLineClawback
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
constexpr std::uint32_t const tfMPTCanEscrow
constexpr std::uint32_t const tfMPTRequireAuth
constexpr std::uint32_t const tfMPTCanLock
constexpr std::uint32_t const tfMPTCanClawback
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
A signer in a SignerList.