21#include <test/jtx/trust.h>
22#include <test/jtx/xchain_bridge.h>
24#include <xrpl/protocol/Feature.h>
25#include <xrpl/protocol/jss.h>
36 using namespace test::jtx;
43 Env env{*
this, features - featureMPTokensV1};
51 Env env{*
this, features};
99 {.maxAmt = 0xFFFF'FFFF'FFFF'FFF0,
118 using namespace test::jtx;
124 Env env{*
this, features};
139 Json::Value const result = env.rpc(
"tx", txHash)[jss::result];
141 result[sfMaximumAmount.getJsonName()] ==
"9223372036854775807");
150 using namespace test::jtx;
155 Env env{*
this, features - featureMPTokensV1};
157 auto const id =
makeMptID(env.seq(alice), alice);
160 env.enableFeature(featureMPTokensV1);
168 Env env{*
this, features};
169 MPTTester mptAlice(env, alice, {.holders = {bob}});
176 mptAlice.create({.ownerCount = 1});
185 mptAlice.authorize({.account = bob, .holderCount = 1});
188 mptAlice.pay(alice, bob, 100);
200 using namespace test::jtx;
205 Env env{*
this, features};
208 mptAlice.
create({.ownerCount = 1});
210 mptAlice.
destroy({.ownerCount = 0});
216 testcase(
"Validate authorize transaction");
218 using namespace test::jtx;
224 Env env{*
this, features - featureMPTokensV1};
225 MPTTester mptAlice(env, alice, {.holders = {bob}});
235 Env env{*
this, features};
236 MPTTester mptAlice(env, alice, {.holders = {bob}});
238 mptAlice.
create({.ownerCount = 1});
248 mptAlice.authorize({.holder = alice, .err =
temMALFORMED});
254 Env env{*
this, features};
255 MPTTester mptAlice(env, alice, {.holders = {bob}});
256 auto const id =
makeMptID(env.seq(alice), alice);
268 Env env{*
this, features};
269 MPTTester mptAlice(env, alice, {.holders = {bob}});
271 mptAlice.
create({.ownerCount = 1});
281 mptAlice.authorize({.holder = bob, .err =
tecNO_AUTH});
284 mptAlice.authorize({.account = bob, .holderCount = 1});
287 mptAlice.authorize({.account = bob, .err =
tecDUPLICATE});
293 mptAlice.pay(alice, bob, 100);
303 mptAlice.pay(bob, alice, 100);
320 Env env{*
this, features};
321 MPTTester mptAlice(env, alice, {.holders = {bob}});
333 mptAlice.authorize({.holder = cindy, .err =
tecNO_DST});
336 mptAlice.authorize({.account = bob, .holderCount = 1});
345 mptAlice.authorize({.holder = bob});
350 mptAlice.authorize({.holder = bob});
359 Env env{*
this, features};
360 auto const acctReserve = env.current()->fees().accountReserve(0);
361 auto const incReserve = env.current()->fees().increment;
369 .xrpHolders = acctReserve + (incReserve - 1)});
372 MPTTester mptAlice2(env, alice, {.fund =
false});
375 MPTTester mptAlice3(env, alice, {.fund =
false});
376 mptAlice3.
create({.ownerCount = 3});
379 mptAlice1.authorize({.account = bob, .holderCount = 1});
382 mptAlice2.authorize({.account = bob, .holderCount = 2});
388 env.master, bob,
drops(incReserve + incReserve + incReserve)));
391 mptAlice3.authorize({.account = bob, .holderCount = 3});
400 using namespace test::jtx;
405 Env env{*
this, features};
408 MPTTester mptAlice(env, alice, {.holders = {bob}});
410 mptAlice.
create({.ownerCount = 1});
413 mptAlice.authorize({.account = bob, .holderCount = 1});
422 Env env{*
this, features};
425 MPTTester mptAlice(env, alice, {.holders = {bob}});
430 mptAlice.authorize({.account = bob, .holderCount = 1});
433 mptAlice.authorize({.account = alice, .holder = bob});
449 Env env{*
this, features};
450 MPTTester mptAlice(env, alice, {.holders = {bob}});
452 mptAlice.
create({.ownerCount = 1});
455 mptAlice.authorize({.account = bob, .holderCount = 1});
458 mptAlice.destroy({.ownerCount = 0});
470 testcase(
"Validate set transaction");
472 using namespace test::jtx;
478 Env env{*
this, features - featureMPTokensV1};
479 MPTTester mptAlice(env, alice, {.holders = {bob}});
486 env.enableFeature(featureMPTokensV1);
488 mptAlice.create({.ownerCount = 1, .holderCount = 0});
490 mptAlice.authorize({.account = bob, .holderCount = 1});
517 Env env{*
this, features};
519 MPTTester mptAlice(env, alice, {.holders = {bob}});
521 mptAlice.
create({.ownerCount = 1});
555 Env env{*
this, features};
557 MPTTester mptAlice(env, alice, {.holders = {bob}});
566 mptAlice.create({.ownerCount = 1, .flags =
tfMPTCanLock});
587 testcase(
"Enabled set transaction");
589 using namespace test::jtx;
592 Env env{*
this, features};
596 MPTTester mptAlice(env, alice, {.holders = {bob}});
600 {.ownerCount = 1, .holderCount = 0, .flags =
tfMPTCanLock});
602 mptAlice.authorize({.account = bob, .holderCount = 1});
605 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
609 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
612 mptAlice.set({.account = alice, .flags =
tfMPTLock});
616 mptAlice.set({.account = alice, .flags =
tfMPTLock});
617 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
620 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
623 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
626 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
629 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
634 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
635 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
643 using namespace test::jtx;
652 Env env{*
this, features - featureMPTokensV1};
656 env.fund(
XRP(1'000), alice);
657 env.fund(
XRP(1'000), bob);
665 Env env{*
this, features - featureMPTokensV1};
668 auto const USD = alice[
"USD"];
670 env.fund(
XRP(1'000), alice);
671 env.fund(
XRP(1'000), carol);
675 jv[jss::secret] = alice.
name();
676 jv[jss::tx_json] =
pay(alice, carol, mpt);
677 jv[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
678 auto const jrr = env.rpc(
"json",
"submit",
to_string(jv));
679 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"temDISABLED");
684 Env env{*
this, features};
686 MPTTester mptAlice(env, alice, {.holders = {bob}});
688 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
689 auto const MPT = mptAlice[
"MPT"];
691 mptAlice.authorize({.account = bob});
694 env(
pay(alice, bob,
MPT(10)),
701 Env env{*
this, features};
705 MPTTester mptAlice(env, alice, {.holders = {carol}});
707 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
709 mptAlice.authorize({.account = carol});
713 auto const MPT = mptAlice[
"MPT"];
714 env(
pay(alice, carol,
MPT(100)),
717 env(
pay(alice, carol,
MPT(100)),
721 auto const USD = alice[
"USD"];
722 env(
pay(alice, carol, USD(100)),
725 env(
pay(alice, carol,
XRP(100)),
728 env(
pay(alice, carol, USD(100)),
731 env(
pay(alice, carol,
XRP(100)),
736 "MPT",
makeMptID(env.seq(alice) + 10, alice));
737 env(
pay(alice, carol, MPT1(100)),
746 Env env{*
this, features};
750 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
752 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
753 auto const MPT = mptAlice[
"MPT"];
755 mptAlice.authorize({.account = carol});
758 payment[jss::secret] = alice.
name();
759 payment[jss::tx_json] =
pay(alice, carol,
MPT(100));
761 payment[jss::build_path] =
true;
762 auto jrr = env.rpc(
"json",
"submit",
to_string(payment));
763 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
765 jrr[jss::result][jss::error_message] ==
766 "Field 'build_path' not allowed in this context.");
771 Env env{*
this, features};
773 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
775 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
776 auto const MPT = mptAlice[
"MPT"];
778 mptAlice.authorize({.account = bob});
779 mptAlice.authorize({.account = carol});
792 Env env{*
this, features};
794 MPTTester mptAlice(env, alice, {.holders = {bob}});
796 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
798 mptAlice.authorize({.account = bob});
807 Env env{*
this, features};
809 MPTTester mptAlice(env, alice, {.holders = {bob}});
811 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
813 mptAlice.authorize({.account = bob});
826 Env env{*
this, features};
828 MPTTester mptAlice(env, alice, {.holders = {bob}});
835 mptAlice.authorize({.account = bob});
843 Env env{*
this, features};
845 MPTTester mptAlice(env, alice, {.holders = {bob}});
853 mptAlice.authorize({.account = bob});
856 mptAlice.authorize({.account = alice, .holder = bob});
859 mptAlice.pay(alice, bob, 100);
872 Env env(*
this, features);
877 MPTTester mptAlice(env, alice, {.holders = {bob, cindy}});
880 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
883 mptAlice.authorize({.account = bob});
886 mptAlice.authorize({.account = cindy});
889 mptAlice.pay(alice, bob, 100);
896 mptAlice.pay(bob, alice, 10);
901 Env env{*
this, features};
903 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
920 Env env{*
this, features};
922 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
926 mptAlice.authorize({.account = bob});
927 mptAlice.authorize({.account = carol});
929 mptAlice.pay(alice, bob, 100);
940 Env env{*
this, features};
942 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
947 mptAlice.authorize({.account = bob});
948 mptAlice.authorize({.account = carol});
950 mptAlice.pay(alice, bob, 100);
951 mptAlice.pay(alice, carol, 100);
954 mptAlice.set({.account = alice, .flags =
tfMPTLock});
959 mptAlice.pay(alice, bob, 3);
961 mptAlice.pay(bob, alice, 4);
964 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
966 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
971 mptAlice.pay(alice, bob, 7);
973 mptAlice.pay(bob, alice, 8);
978 Env env{*
this, features};
980 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
984 {.transferFee = 10'000,
990 mptAlice.authorize({.account = bob});
991 mptAlice.authorize({.account = carol});
994 mptAlice.pay(alice, bob, 2'000);
997 mptAlice.pay(bob, alice, 1'000);
998 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 1'000));
1008 auto const MPT = mptAlice[
"MPT"];
1010 env(
pay(bob, carol,
MPT(100)),
1019 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 780));
1020 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 200));
1023 env(
pay(bob, carol,
MPT(100)),
1028 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 690));
1029 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 282));
1034 Env env{*
this, features};
1036 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1042 mptAlice.authorize({.account = bob});
1043 mptAlice.authorize({.account = carol});
1044 mptAlice.pay(alice, bob, 1'000);
1046 auto const MPT = mptAlice[
"MPT"];
1048 env(
pay(bob, carol,
MPT(100)),
1051 env(
pay(bob, alice,
MPT(100)),
1057 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 100));
1059 env(
pay(bob, carol,
MPT(100)),
1062 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 199));
1067 Env env{*
this, features};
1069 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1075 mptAlice.authorize({.account = bob});
1076 mptAlice.authorize({.account = carol});
1077 mptAlice.pay(alice, bob, 1'000);
1079 auto const MPT = mptAlice[
"MPT"];
1082 env(
pay(bob, alice,
MPT(100)),
1088 env(
pay(bob, alice,
MPT(100)),
1096 Env env{*
this, features};
1098 MPTTester mptAlice(env, alice, {.holders = {bob}});
1106 mptAlice.authorize({.account = bob});
1109 mptAlice.pay(alice, bob, 100);
1118 Env env{*
this, features};
1120 MPTTester mptAlice(env, alice, {.holders = {bob}});
1122 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1124 mptAlice.authorize({.account = bob});
1136 Env env{*
this, features};
1137 env.fund(
XRP(1'000), alice, bob);
1140 jv[jss::secret] = alice.
name();
1141 jv[jss::tx_json] =
pay(alice, bob, mpt);
1142 jv[jss::tx_json][jss::Amount][jss::value] =
1144 auto const jrr = env.rpc(
"json",
"submit",
to_string(jv));
1145 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1151 Env env{*
this, features};
1153 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1161 auto const MPT = mptAlice[
"MPT"];
1163 mptAlice.authorize({.account = bob});
1164 mptAlice.authorize({.account = carol});
1167 mptAlice.pay(alice, bob, 10'000);
1170 env(
pay(bob, carol,
MPT(10'000)),
1174 auto const meta = env.meta()->getJson(
1178 meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1179 [sfOutstandingAmount.fieldName] ==
"9990");
1182 meta[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1183 [sfMPTAmount.fieldName] ==
"9990");
1186 meta[2u][sfModifiedNode.fieldName][sfPreviousFields.fieldName]
1187 [sfMPTAmount.fieldName] ==
"10000");
1189 !meta[2u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1190 .isMember(sfMPTAmount.fieldName));
1194 env(
pay(bob, carol,
MPT(10'000)),
1201 Env env{*
this, features};
1203 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1210 auto const MPT = mptAlice[
"MPT"];
1212 mptAlice.authorize({.account = bob});
1213 mptAlice.authorize({.account = carol});
1226 BEAST_EXPECT(mptAlice.checkMPTokenOutstandingAmount(0));
1231 Env env{*
this, features};
1233 MPTTester mptAlice(env, alice, {.holders = {bob}});
1235 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1237 mptAlice.authorize({.account = bob});
1240 mptAlice.destroy({.ownerCount = 0});
1249 Env env{*
this, features};
1251 env.fund(
XRP(1'000), alice, bob);
1260 Env env{*
this, features};
1262 MPTTester mptAlice(env, alice, {.holders = {bob}});
1264 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1267 mptAlice.destroy({.ownerCount = 0});
1277 Env env{*
this, features};
1282 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1287 mptAlice.authorize({.account = bob});
1288 mptAlice.authorize({.account = carol});
1290 mptAlice.pay(alice, bob, 100);
1293 mptAlice.pay(bob, carol, 100);
1298 Env env{*
this, features};
1300 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1305 mptAlice.authorize({.account = bob});
1306 mptAlice.authorize({.account = carol});
1309 mptAlice.pay(alice, bob, 100);
1312 mptAlice.pay(bob, alice, 100);
1315 mptAlice.pay(alice, bob, 100);
1316 mptAlice.pay(bob, carol, 50);
1325 using namespace test::jtx;
1329 Account const dpIssuer(
"dpIssuer");
1331 char const credType[] =
"abcde";
1336 env.
fund(
XRP(50000), diana, dpIssuer);
1339 MPTTester mptAlice(env, alice, {.holders = {bob}});
1345 env(
pay(diana, bob,
XRP(500)));
1349 mptAlice.authorize({.account = bob});
1351 mptAlice.authorize({.account = alice, .holder = bob});
1366 mptAlice.pay(alice, bob, 100);
1376 std::string const credIdx = jv[jss::result][jss::index].asString();
1379 mptAlice.pay(alice, bob, 100,
tesSUCCESS, {{credIdx}});
1403 mptAlice.pay(alice, bob, 100,
tesSUCCESS, {{credIdx}});
1407 testcase(
"DepositPreauth disabled featureCredentials");
1412 "D007AE4B6E1274B4AF872588267B810C2F82716726351D1C7D38D3E5499FC6"
1415 env.
fund(
XRP(50000), diana, dpIssuer);
1418 MPTTester mptAlice(env, alice, {.holders = {bob}});
1424 env(
pay(diana, bob,
XRP(500)));
1428 mptAlice.authorize({.account = bob});
1430 mptAlice.authorize({.account = alice, .holder = bob});
1442 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1450 mptAlice.pay(alice, bob, 100);
1454 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1466 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1474 testcase(
"MPT Issue Invalid in Transaction");
1475 using namespace test::jtx;
1484 for (
auto const& e : format.getSOTemplate())
1490 e.sField().getName() != jss::Fee &&
1491 format.getName() != jss::SetFee)
1494 format.getName() + e.sField().fieldName);
1501 auto const USD = alice[
"USD"];
1504 STAmount mpt{issue, UINT64_C(100)};
1505 auto const jvb =
bridge(alice, USD, alice, USD);
1506 for (
auto const& feature : {features, features - featureMPTokensV1})
1508 Env env{*
this, feature};
1509 env.fund(
XRP(1'000), alice);
1510 env.fund(
XRP(1'000), carol);
1513 txWithAmounts.
erase(
1514 jv[jss::TransactionType].asString() + mptField);
1517 auto jtx = env.jt(jv);
1522 jrr[jss::result][jss::error] ==
"invalidTransaction");
1526 jv1[jss::secret] = alice.
name();
1527 jv1[jss::tx_json] = jv;
1528 jrr = env.rpc(
"json",
"submit",
to_string(jv1));
1529 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1531 jrr = env.rpc(
"json",
"sign",
to_string(jv1));
1532 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1534 auto toSFieldRef = [](
SField const& field) {
1537 auto setMPTFields = [&](
SField const& field,
1539 bool withAmount =
true) {
1541 jv[jss::Asset2] =
to_json(USD.issue());
1543 jv[field.fieldName] =
1545 if (field == sfAsset)
1547 else if (field == sfAsset2)
1557 auto ammCreate = [&](
SField const& field) {
1559 jv[jss::TransactionType] = jss::AMMCreate;
1560 jv[jss::Account] = alice.
human();
1561 jv[jss::Amount] = (field.fieldName == sfAmount.fieldName)
1564 jv[jss::Amount2] = (field.fieldName == sfAmount2.fieldName)
1567 jv[jss::TradingFee] = 0;
1568 test(jv, field.fieldName);
1570 ammCreate(sfAmount);
1571 ammCreate(sfAmount2);
1573 auto ammDeposit = [&](
SField const& field) {
1575 jv[jss::TransactionType] = jss::AMMDeposit;
1576 jv[jss::Account] = alice.
human();
1578 setMPTFields(field, jv);
1579 test(jv, field.fieldName);
1581 for (
SField const& field :
1582 {toSFieldRef(sfAmount),
1583 toSFieldRef(sfAmount2),
1584 toSFieldRef(sfEPrice),
1585 toSFieldRef(sfLPTokenOut),
1586 toSFieldRef(sfAsset),
1587 toSFieldRef(sfAsset2)})
1590 auto ammWithdraw = [&](
SField const& field) {
1592 jv[jss::TransactionType] = jss::AMMWithdraw;
1593 jv[jss::Account] = alice.
human();
1595 setMPTFields(field, jv);
1596 test(jv, field.fieldName);
1598 ammWithdraw(sfAmount);
1599 for (
SField const& field :
1600 {toSFieldRef(sfAmount2),
1601 toSFieldRef(sfEPrice),
1602 toSFieldRef(sfLPTokenIn),
1603 toSFieldRef(sfAsset),
1604 toSFieldRef(sfAsset2)})
1607 auto ammBid = [&](
SField const& field) {
1609 jv[jss::TransactionType] = jss::AMMBid;
1610 jv[jss::Account] = alice.
human();
1611 setMPTFields(field, jv);
1612 test(jv, field.fieldName);
1614 for (
SField const& field :
1615 {toSFieldRef(sfBidMin),
1616 toSFieldRef(sfBidMax),
1617 toSFieldRef(sfAsset),
1618 toSFieldRef(sfAsset2)})
1621 auto ammClawback = [&](
SField const& field) {
1623 jv[jss::TransactionType] = jss::AMMClawback;
1624 jv[jss::Account] = alice.
human();
1625 jv[jss::Holder] = carol.
human();
1626 setMPTFields(field, jv);
1627 test(jv, field.fieldName);
1629 for (
SField const& field :
1630 {toSFieldRef(sfAmount),
1631 toSFieldRef(sfAsset),
1632 toSFieldRef(sfAsset2)})
1635 auto ammDelete = [&](
SField const& field) {
1637 jv[jss::TransactionType] = jss::AMMDelete;
1638 jv[jss::Account] = alice.
human();
1639 setMPTFields(field, jv,
false);
1640 test(jv, field.fieldName);
1643 ammDelete(sfAsset2);
1645 auto ammVote = [&](
SField const& field) {
1647 jv[jss::TransactionType] = jss::AMMVote;
1648 jv[jss::Account] = alice.
human();
1649 jv[jss::TradingFee] = 100;
1650 setMPTFields(field, jv,
false);
1651 test(jv, field.fieldName);
1656 auto checkCash = [&](
SField const& field) {
1658 jv[jss::TransactionType] = jss::CheckCash;
1659 jv[jss::Account] = alice.
human();
1662 test(jv, field.fieldName);
1664 checkCash(sfAmount);
1665 checkCash(sfDeliverMin);
1669 jv[jss::TransactionType] = jss::CheckCreate;
1670 jv[jss::Account] = alice.
human();
1671 jv[jss::Destination] = carol.
human();
1673 test(jv, jss::SendMax.c_str());
1678 jv[jss::TransactionType] = jss::EscrowCreate;
1679 jv[jss::Account] = alice.
human();
1680 jv[jss::Destination] = carol.
human();
1682 test(jv, jss::Amount.c_str());
1687 test(jv, jss::TakerPays.c_str());
1688 jv =
offer(alice, mpt, USD(100));
1689 test(jv, jss::TakerGets.c_str());
1694 jv[jss::TransactionType] = jss::PaymentChannelCreate;
1695 jv[jss::Account] = alice.
human();
1696 jv[jss::Destination] = carol.
human();
1697 jv[jss::SettleDelay] = 1;
1700 test(jv, jss::Amount.c_str());
1705 jv[jss::TransactionType] = jss::PaymentChannelFund;
1706 jv[jss::Account] = alice.
human();
1709 test(jv, jss::Amount.c_str());
1714 jv[jss::TransactionType] = jss::PaymentChannelClaim;
1715 jv[jss::Account] = alice.
human();
1718 test(jv, jss::Amount.c_str());
1723 jv[jss::TransactionType] = jss::NFTokenCreateOffer;
1724 jv[jss::Account] = alice.
human();
1727 test(jv, jss::Amount.c_str());
1732 jv[jss::TransactionType] = jss::NFTokenAcceptOffer;
1733 jv[jss::Account] = alice.
human();
1734 jv[sfNFTokenBrokerFee.fieldName] =
1736 test(jv, sfNFTokenBrokerFee.fieldName);
1741 jv[jss::TransactionType] = jss::NFTokenMint;
1742 jv[jss::Account] = alice.
human();
1743 jv[sfNFTokenTaxon.fieldName] = 1;
1745 test(jv, jss::Amount.c_str());
1748 auto trustSet = [&](
SField const& field) {
1750 jv[jss::TransactionType] = jss::TrustSet;
1751 jv[jss::Account] = alice.
human();
1754 test(jv, field.fieldName);
1756 trustSet(sfLimitAmount);
1761 test(jv, jss::Amount.c_str());
1766 test(jv, jss::Amount.c_str());
1772 test(jv, sfSignatureReward.fieldName);
1786 test(jv, jss::Amount.c_str());
1801 for (
auto const& field :
1802 {sfAmount.fieldName, sfSignatureReward.fieldName})
1811 alice, jvb, alice, mpt,
XRP(10));
1812 for (
auto const& field :
1813 {sfAmount.fieldName, sfSignatureReward.fieldName})
1825 jv[jss::TransactionType] = tt;
1826 jv[jss::Account] = alice.
human();
1827 jv[sfXChainBridge.fieldName] = jvb;
1828 jv[sfSignatureReward.fieldName] =
1830 jv[sfMinAccountCreateAmount.fieldName] =
1834 auto reward =
STAmount{sfSignatureReward, mpt};
1835 auto minAmount =
STAmount{sfMinAccountCreateAmount, USD(10)};
1836 for (
SField const& field :
1838 std::ref(sfMinAccountCreateAmount)})
1841 jss::XChainCreateBridge,
1846 jss::XChainModifyBridge,
1850 reward =
STAmount{sfSignatureReward, USD(10)};
1851 minAmount =
STAmount{sfMinAccountCreateAmount, mpt};
1854 BEAST_EXPECT(txWithAmounts.
empty());
1861 testcase(
"Test synthetic fields from tx response");
1863 using namespace test::jtx;
1868 cfg->FEES.reference_fee = 10;
1869 Env env{*
this, std::move(cfg), features};
1878 "E11F0E0CA14219922B7881F060B9CEE67CFBC87E4049A441ED2AE348FF8FAC"
1881 Json::Value const meta = env.rpc(
"tx", txHash)[jss::result][jss::meta];
1882 auto const id = meta[jss::mpt_issuance_id].
asString();
1884 BEAST_EXPECT(meta.
isMember(jss::mpt_issuance_id));
1887 id ==
"00000004AE123A8556F3CF91154711376AFB0F894F832B3D",
id);
1893 testcase(
"MPT clawback validations");
1894 using namespace test::jtx;
1898 Env env(*
this, features - featureMPTokensV1);
1902 env.
fund(
XRP(1000), alice, bob);
1905 auto const USD = alice[
"USD"];
1921 Env env(*
this, features);
1925 env.
fund(
XRP(1000), alice, bob);
1928 auto const USD = alice[
"USD"];
1955 Env env(*
this, features);
1959 MPTTester mptAlice(env, alice, {.holders = {bob}});
1967 mptAlice.create({.ownerCount = 1, .holderCount = 0});
1969 mptAlice.authorize({.account = bob});
1971 mptAlice.pay(alice, bob, 100);
1980 Env env(*
this, features);
1986 MPTTester mptAlice(env, alice, {.holders = {bob}});
2003 mptAlice.authorize({.account = bob});
2009 mptAlice.pay(alice, bob, 100);
2020 Env env(*
this, features);
2024 env.
fund(
XRP(1000), alice, bob);
2033 jv1[jss::secret] = alice.name();
2034 jv1[jss::tx_json] = jv;
2035 auto const jrr = env.
rpc(
"json",
"submit",
to_string(jv1));
2036 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
2044 using namespace test::jtx;
2047 Env env(*
this, features);
2051 MPTTester mptAlice(env, alice, {.holders = {bob}});
2058 mptAlice.authorize({.account = bob});
2061 mptAlice.pay(alice, bob, 100);
2063 mptAlice.claw(alice, bob, 1);
2065 mptAlice.claw(alice, bob, 1000);
2073 Env env(*
this, features);
2077 MPTTester mptAlice(env, alice, {.holders = {bob}});
2086 mptAlice.authorize({.account = bob});
2089 mptAlice.pay(alice, bob, 100);
2091 mptAlice.set({.account = alice, .flags =
tfMPTLock});
2093 mptAlice.claw(alice, bob, 100);
2098 Env env(*
this, features);
2102 MPTTester mptAlice(env, alice, {.holders = {bob}});
2111 mptAlice.authorize({.account = bob});
2114 mptAlice.pay(alice, bob, 100);
2116 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
2118 mptAlice.claw(alice, bob, 100);
2123 Env env(*
this, features);
2127 MPTTester mptAlice(env, alice, {.holders = {bob}});
2136 mptAlice.authorize({.account = bob});
2139 mptAlice.authorize({.account = alice, .holder = bob});
2142 mptAlice.pay(alice, bob, 100);
2148 mptAlice.claw(alice, bob, 100);
2155 using namespace test::jtx;
2169 Asset const assetMpt1Gw1{mpt1};
2170 Asset const assetMpt1Gw1a{mpt1a};
2171 Asset const assetMpt1Gw2{mpt2};
2172 Asset const assetMpt2Gw2{mpt3};
2176 BEAST_EXPECT(
equalTokens(assetCur1Gw1, assetCur1Gw1a));
2177 BEAST_EXPECT(
equalTokens(assetCur2Gw1, assetCur2Gw2));
2180 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw1));
2181 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw2));
2185 BEAST_EXPECT(
equalTokens(assetMpt1Gw1, assetMpt1Gw1a));
2187 BEAST_EXPECT(!
equalTokens(assetMpt1Gw1, assetMpt1Gw2));
2188 BEAST_EXPECT(!
equalTokens(assetMpt1Gw2, assetMpt2Gw2));
2191 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetMpt1Gw1));
2192 BEAST_EXPECT(!
equalTokens(assetMpt2Gw2, assetCur2Gw2));
2198 using namespace test::jtx;
2205 STAmount const amt3{asset3, 10'000};
2208 testcase(
"Test STAmount MPT arithmetics");
2209 using namespace std::string_literals;
2211 BEAST_EXPECT(res == amt3);
2213 res =
mulRound(amt1, amt2, asset3,
true);
2214 BEAST_EXPECT(res == amt3);
2217 BEAST_EXPECT(res == amt3);
2220 STAmount mptOverflow{asset2, UINT64_C(3037000500)};
2223 res =
multiply(mptOverflow, mptOverflow, asset3);
2224 fail(
"should throw runtime exception 1");
2228 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2231 mptOverflow =
STAmount{asset2, UINT64_C(2147483648)};
2232 uint64_t
const mantissa = (2ull << 32) + 2;
2236 fail(
"should throw runtime exception 2");
2240 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2245 testcase(
"Test MPTAmount arithmetics");
2248 BEAST_EXPECT((mptAmt1 += mptAmt2) ==
MPTAmount{200});
2249 BEAST_EXPECT(mptAmt1 == 200);
2250 BEAST_EXPECT((mptAmt1 -= mptAmt2) == mptAmt1);
2251 BEAST_EXPECT(mptAmt1 == mptAmt2);
2252 BEAST_EXPECT(mptAmt1 == 100);
2257 testcase(
"Test MPTIssue from/to Json");
2266 testcase(
"Test Asset from/to Json");
2272 "{\"mpt_issuance_id\":"
2273 "\"00000001A407AF5856CCF3C42619DAA925813FC955C72983\"}");
2282 using namespace test::jtx;
2323BEAST_DEFINE_TESTSUITE_PRIO(MPToken, tx,
ripple, 2);
Lightweight wrapper to tag static string.
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *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.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
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.