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});
416 {.account = bob, .holderCount = 1, .err =
tecDUPLICATE});
425 Env env{*
this, features};
428 MPTTester mptAlice(env, alice, {.holders = {bob}});
433 mptAlice.authorize({.account = bob, .holderCount = 1});
436 mptAlice.authorize({.account = alice, .holder = bob});
452 Env env{*
this, features};
453 MPTTester mptAlice(env, alice, {.holders = {bob}});
455 mptAlice.
create({.ownerCount = 1});
458 mptAlice.authorize({.account = bob, .holderCount = 1});
461 mptAlice.destroy({.ownerCount = 0});
473 testcase(
"Validate set transaction");
475 using namespace test::jtx;
481 Env env{*
this, features - featureMPTokensV1};
482 MPTTester mptAlice(env, alice, {.holders = {bob}});
489 env.enableFeature(featureMPTokensV1);
491 mptAlice.create({.ownerCount = 1, .holderCount = 0});
493 mptAlice.authorize({.account = bob, .holderCount = 1});
520 Env env{*
this, features};
522 MPTTester mptAlice(env, alice, {.holders = {bob}});
524 mptAlice.
create({.ownerCount = 1});
558 Env env{*
this, features};
560 MPTTester mptAlice(env, alice, {.holders = {bob}});
569 mptAlice.create({.ownerCount = 1, .flags =
tfMPTCanLock});
590 testcase(
"Enabled set transaction");
592 using namespace test::jtx;
595 Env env{*
this, features};
599 MPTTester mptAlice(env, alice, {.holders = {bob}});
603 {.ownerCount = 1, .holderCount = 0, .flags =
tfMPTCanLock});
605 mptAlice.authorize({.account = bob, .holderCount = 1});
608 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
612 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
615 mptAlice.set({.account = alice, .flags =
tfMPTLock});
619 mptAlice.set({.account = alice, .flags =
tfMPTLock});
620 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
623 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
626 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
627 if (!features[featureSingleAssetVault])
648 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
651 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
656 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTUnlock});
657 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
665 using namespace test::jtx;
674 Env env{*
this, features - featureMPTokensV1};
678 env.fund(
XRP(1'000), alice);
679 env.fund(
XRP(1'000), bob);
687 Env env{*
this, features - featureMPTokensV1};
690 auto const USD = alice[
"USD"];
692 env.fund(
XRP(1'000), alice);
693 env.fund(
XRP(1'000), carol);
697 jv[jss::secret] = alice.
name();
698 jv[jss::tx_json] =
pay(alice, carol, mpt);
699 jv[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
700 auto const jrr = env.rpc(
"json",
"submit",
to_string(jv));
701 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"temDISABLED");
706 Env env{*
this, features};
708 MPTTester mptAlice(env, alice, {.holders = {bob}});
710 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
711 auto const MPT = mptAlice[
"MPT"];
713 mptAlice.authorize({.account = bob});
716 env(
pay(alice, bob,
MPT(10)),
723 Env env{*
this, features};
727 MPTTester mptAlice(env, alice, {.holders = {carol}});
729 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
731 mptAlice.authorize({.account = carol});
735 auto const MPT = mptAlice[
"MPT"];
736 env(
pay(alice, carol,
MPT(100)),
739 env(
pay(alice, carol,
MPT(100)),
743 auto const USD = alice[
"USD"];
744 env(
pay(alice, carol, USD(100)),
747 env(
pay(alice, carol,
XRP(100)),
750 env(
pay(alice, carol, USD(100)),
753 env(
pay(alice, carol,
XRP(100)),
758 "MPT",
makeMptID(env.seq(alice) + 10, alice));
759 env(
pay(alice, carol, MPT1(100)),
768 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 = carol});
780 payment[jss::secret] = alice.
name();
781 payment[jss::tx_json] =
pay(alice, carol,
MPT(100));
783 payment[jss::build_path] =
true;
784 auto jrr = env.rpc(
"json",
"submit",
to_string(payment));
785 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
787 jrr[jss::result][jss::error_message] ==
788 "Field 'build_path' not allowed in this context.");
793 Env env{*
this, features};
795 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
797 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
798 auto const MPT = mptAlice[
"MPT"];
800 mptAlice.authorize({.account = bob});
801 mptAlice.authorize({.account = carol});
814 Env env{*
this, features};
816 MPTTester mptAlice(env, alice, {.holders = {bob}});
818 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
820 mptAlice.authorize({.account = bob});
829 Env env{*
this, features};
831 MPTTester mptAlice(env, alice, {.holders = {bob}});
833 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
835 mptAlice.authorize({.account = bob});
848 Env env{*
this, features};
850 MPTTester mptAlice(env, alice, {.holders = {bob}});
857 mptAlice.authorize({.account = bob});
865 Env env{*
this, features};
867 MPTTester mptAlice(env, alice, {.holders = {bob}});
875 mptAlice.authorize({.account = bob});
878 mptAlice.authorize({.account = alice, .holder = bob});
881 mptAlice.pay(alice, bob, 100);
894 Env env(*
this, features);
899 MPTTester mptAlice(env, alice, {.holders = {bob, cindy}});
902 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
905 mptAlice.authorize({.account = bob});
908 mptAlice.authorize({.account = cindy});
911 mptAlice.pay(alice, bob, 100);
918 mptAlice.pay(bob, alice, 10);
923 Env env{*
this, features};
925 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
942 Env env{*
this, features};
944 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
948 mptAlice.authorize({.account = bob});
949 mptAlice.authorize({.account = carol});
951 mptAlice.pay(alice, bob, 100);
962 Env env{*
this, features};
964 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
969 mptAlice.authorize({.account = bob});
970 mptAlice.authorize({.account = carol});
972 mptAlice.pay(alice, bob, 100);
973 mptAlice.pay(alice, carol, 100);
976 mptAlice.set({.account = alice, .flags =
tfMPTLock});
981 mptAlice.pay(alice, bob, 3);
983 mptAlice.pay(bob, alice, 4);
986 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
988 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
993 mptAlice.pay(alice, bob, 7);
995 mptAlice.pay(bob, alice, 8);
1000 Env env{*
this, features};
1002 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1006 {.transferFee = 10'000,
1012 mptAlice.authorize({.account = bob});
1013 mptAlice.authorize({.account = carol});
1016 mptAlice.pay(alice, bob, 2'000);
1019 mptAlice.pay(bob, alice, 1'000);
1020 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 1'000));
1030 auto const MPT = mptAlice[
"MPT"];
1032 env(
pay(bob, carol,
MPT(100)),
1041 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 780));
1042 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 200));
1045 env(
pay(bob, carol,
MPT(100)),
1050 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 690));
1051 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 282));
1056 Env env{*
this, features};
1058 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1064 mptAlice.authorize({.account = bob});
1065 mptAlice.authorize({.account = carol});
1066 mptAlice.pay(alice, bob, 1'000);
1068 auto const MPT = mptAlice[
"MPT"];
1070 env(
pay(bob, carol,
MPT(100)),
1073 env(
pay(bob, alice,
MPT(100)),
1079 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 100));
1081 env(
pay(bob, carol,
MPT(100)),
1084 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 199));
1089 Env env{*
this, features};
1091 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1097 mptAlice.authorize({.account = bob});
1098 mptAlice.authorize({.account = carol});
1099 mptAlice.pay(alice, bob, 1'000);
1101 auto const MPT = mptAlice[
"MPT"];
1104 env(
pay(bob, alice,
MPT(100)),
1110 env(
pay(bob, alice,
MPT(100)),
1118 Env env{*
this, features};
1120 MPTTester mptAlice(env, alice, {.holders = {bob}});
1128 mptAlice.authorize({.account = bob});
1131 mptAlice.pay(alice, bob, 100);
1140 Env env{*
this, features};
1142 MPTTester mptAlice(env, alice, {.holders = {bob}});
1144 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1146 mptAlice.authorize({.account = bob});
1158 Env env{*
this, features};
1159 env.fund(
XRP(1'000), alice, bob);
1162 jv[jss::secret] = alice.
name();
1163 jv[jss::tx_json] =
pay(alice, bob, mpt);
1164 jv[jss::tx_json][jss::Amount][jss::value] =
1166 auto const jrr = env.rpc(
"json",
"submit",
to_string(jv));
1167 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1173 Env env{*
this, features};
1175 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1183 auto const MPT = mptAlice[
"MPT"];
1185 mptAlice.authorize({.account = bob});
1186 mptAlice.authorize({.account = carol});
1189 mptAlice.pay(alice, bob, 10'000);
1192 env(
pay(bob, carol,
MPT(10'000)),
1196 auto const meta = env.meta()->getJson(
1200 meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1201 [sfOutstandingAmount.fieldName] ==
"9990");
1204 meta[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1205 [sfMPTAmount.fieldName] ==
"9990");
1208 meta[2u][sfModifiedNode.fieldName][sfPreviousFields.fieldName]
1209 [sfMPTAmount.fieldName] ==
"10000");
1211 !meta[2u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1212 .isMember(sfMPTAmount.fieldName));
1216 env(
pay(bob, carol,
MPT(10'000)),
1223 Env env{*
this, features};
1225 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1232 auto const MPT = mptAlice[
"MPT"];
1234 mptAlice.authorize({.account = bob});
1235 mptAlice.authorize({.account = carol});
1248 BEAST_EXPECT(mptAlice.checkMPTokenOutstandingAmount(0));
1253 Env env{*
this, features};
1255 MPTTester mptAlice(env, alice, {.holders = {bob}});
1257 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1259 mptAlice.authorize({.account = bob});
1262 mptAlice.destroy({.ownerCount = 0});
1271 Env env{*
this, features};
1273 env.fund(
XRP(1'000), alice, bob);
1282 Env env{*
this, features};
1284 MPTTester mptAlice(env, alice, {.holders = {bob}});
1286 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1289 mptAlice.destroy({.ownerCount = 0});
1299 Env env{*
this, features};
1304 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1309 mptAlice.authorize({.account = bob});
1310 mptAlice.authorize({.account = carol});
1312 mptAlice.pay(alice, bob, 100);
1315 mptAlice.pay(bob, carol, 100);
1320 Env env{*
this, features};
1322 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1327 mptAlice.authorize({.account = bob});
1328 mptAlice.authorize({.account = carol});
1331 mptAlice.pay(alice, bob, 100);
1334 mptAlice.pay(bob, alice, 100);
1337 mptAlice.pay(alice, bob, 100);
1338 mptAlice.pay(bob, carol, 50);
1347 using namespace test::jtx;
1351 Account const dpIssuer(
"dpIssuer");
1353 char const credType[] =
"abcde";
1358 env.
fund(
XRP(50000), diana, dpIssuer);
1361 MPTTester mptAlice(env, alice, {.holders = {bob}});
1367 env(
pay(diana, bob,
XRP(500)));
1371 mptAlice.authorize({.account = bob});
1373 mptAlice.authorize({.account = alice, .holder = bob});
1388 mptAlice.pay(alice, bob, 100);
1398 std::string const credIdx = jv[jss::result][jss::index].asString();
1401 mptAlice.pay(alice, bob, 100,
tesSUCCESS, {{credIdx}});
1425 mptAlice.pay(alice, bob, 100,
tesSUCCESS, {{credIdx}});
1429 testcase(
"DepositPreauth disabled featureCredentials");
1434 "D007AE4B6E1274B4AF872588267B810C2F82716726351D1C7D38D3E5499FC6"
1437 env.
fund(
XRP(50000), diana, dpIssuer);
1440 MPTTester mptAlice(env, alice, {.holders = {bob}});
1446 env(
pay(diana, bob,
XRP(500)));
1450 mptAlice.authorize({.account = bob});
1452 mptAlice.authorize({.account = alice, .holder = bob});
1464 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1472 mptAlice.pay(alice, bob, 100);
1476 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1488 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1496 testcase(
"MPT Issue Invalid in Transaction");
1497 using namespace test::jtx;
1506 for (
auto const& e : format.getSOTemplate())
1512 e.sField().getName() != jss::Fee &&
1513 format.getName() != jss::SetFee)
1516 format.getName() + e.sField().fieldName);
1523 auto const USD = alice[
"USD"];
1526 STAmount mpt{issue, UINT64_C(100)};
1527 auto const jvb =
bridge(alice, USD, alice, USD);
1528 for (
auto const& feature : {features, features - featureMPTokensV1})
1530 Env env{*
this, feature};
1531 env.fund(
XRP(1'000), alice);
1532 env.fund(
XRP(1'000), carol);
1535 txWithAmounts.
erase(
1536 jv[jss::TransactionType].asString() + mptField);
1539 auto jtx = env.jt(jv);
1544 jrr[jss::result][jss::error] ==
"invalidTransaction");
1548 jv1[jss::secret] = alice.
name();
1549 jv1[jss::tx_json] = jv;
1550 jrr = env.rpc(
"json",
"submit",
to_string(jv1));
1551 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1553 jrr = env.rpc(
"json",
"sign",
to_string(jv1));
1554 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1556 auto toSFieldRef = [](
SField const& field) {
1559 auto setMPTFields = [&](
SField const& field,
1561 bool withAmount =
true) {
1563 jv[jss::Asset2] =
to_json(USD.issue());
1565 jv[field.fieldName] =
1567 if (field == sfAsset)
1569 else if (field == sfAsset2)
1579 auto ammCreate = [&](
SField const& field) {
1581 jv[jss::TransactionType] = jss::AMMCreate;
1582 jv[jss::Account] = alice.
human();
1583 jv[jss::Amount] = (field.fieldName == sfAmount.fieldName)
1586 jv[jss::Amount2] = (field.fieldName == sfAmount2.fieldName)
1589 jv[jss::TradingFee] = 0;
1590 test(jv, field.fieldName);
1592 ammCreate(sfAmount);
1593 ammCreate(sfAmount2);
1595 auto ammDeposit = [&](
SField const& field) {
1597 jv[jss::TransactionType] = jss::AMMDeposit;
1598 jv[jss::Account] = alice.
human();
1600 setMPTFields(field, jv);
1601 test(jv, field.fieldName);
1603 for (
SField const& field :
1604 {toSFieldRef(sfAmount),
1605 toSFieldRef(sfAmount2),
1606 toSFieldRef(sfEPrice),
1607 toSFieldRef(sfLPTokenOut),
1608 toSFieldRef(sfAsset),
1609 toSFieldRef(sfAsset2)})
1612 auto ammWithdraw = [&](
SField const& field) {
1614 jv[jss::TransactionType] = jss::AMMWithdraw;
1615 jv[jss::Account] = alice.
human();
1617 setMPTFields(field, jv);
1618 test(jv, field.fieldName);
1620 ammWithdraw(sfAmount);
1621 for (
SField const& field :
1622 {toSFieldRef(sfAmount2),
1623 toSFieldRef(sfEPrice),
1624 toSFieldRef(sfLPTokenIn),
1625 toSFieldRef(sfAsset),
1626 toSFieldRef(sfAsset2)})
1629 auto ammBid = [&](
SField const& field) {
1631 jv[jss::TransactionType] = jss::AMMBid;
1632 jv[jss::Account] = alice.
human();
1633 setMPTFields(field, jv);
1634 test(jv, field.fieldName);
1636 for (
SField const& field :
1637 {toSFieldRef(sfBidMin),
1638 toSFieldRef(sfBidMax),
1639 toSFieldRef(sfAsset),
1640 toSFieldRef(sfAsset2)})
1643 auto ammClawback = [&](
SField const& field) {
1645 jv[jss::TransactionType] = jss::AMMClawback;
1646 jv[jss::Account] = alice.
human();
1647 jv[jss::Holder] = carol.
human();
1648 setMPTFields(field, jv);
1649 test(jv, field.fieldName);
1651 for (
SField const& field :
1652 {toSFieldRef(sfAmount),
1653 toSFieldRef(sfAsset),
1654 toSFieldRef(sfAsset2)})
1657 auto ammDelete = [&](
SField const& field) {
1659 jv[jss::TransactionType] = jss::AMMDelete;
1660 jv[jss::Account] = alice.
human();
1661 setMPTFields(field, jv,
false);
1662 test(jv, field.fieldName);
1665 ammDelete(sfAsset2);
1667 auto ammVote = [&](
SField const& field) {
1669 jv[jss::TransactionType] = jss::AMMVote;
1670 jv[jss::Account] = alice.
human();
1671 jv[jss::TradingFee] = 100;
1672 setMPTFields(field, jv,
false);
1673 test(jv, field.fieldName);
1678 auto checkCash = [&](
SField const& field) {
1680 jv[jss::TransactionType] = jss::CheckCash;
1681 jv[jss::Account] = alice.
human();
1684 test(jv, field.fieldName);
1686 checkCash(sfAmount);
1687 checkCash(sfDeliverMin);
1691 jv[jss::TransactionType] = jss::CheckCreate;
1692 jv[jss::Account] = alice.
human();
1693 jv[jss::Destination] = carol.
human();
1695 test(jv, jss::SendMax.c_str());
1700 test(jv, jss::TakerPays.c_str());
1701 jv =
offer(alice, mpt, USD(100));
1702 test(jv, jss::TakerGets.c_str());
1707 jv[jss::TransactionType] = jss::PaymentChannelCreate;
1708 jv[jss::Account] = alice.
human();
1709 jv[jss::Destination] = carol.
human();
1710 jv[jss::SettleDelay] = 1;
1713 test(jv, jss::Amount.c_str());
1718 jv[jss::TransactionType] = jss::PaymentChannelFund;
1719 jv[jss::Account] = alice.
human();
1722 test(jv, jss::Amount.c_str());
1727 jv[jss::TransactionType] = jss::PaymentChannelClaim;
1728 jv[jss::Account] = alice.
human();
1731 test(jv, jss::Amount.c_str());
1736 jv[jss::TransactionType] = jss::NFTokenCreateOffer;
1737 jv[jss::Account] = alice.
human();
1740 test(jv, jss::Amount.c_str());
1745 jv[jss::TransactionType] = jss::NFTokenAcceptOffer;
1746 jv[jss::Account] = alice.
human();
1747 jv[sfNFTokenBrokerFee.fieldName] =
1749 test(jv, sfNFTokenBrokerFee.fieldName);
1754 jv[jss::TransactionType] = jss::NFTokenMint;
1755 jv[jss::Account] = alice.
human();
1756 jv[sfNFTokenTaxon.fieldName] = 1;
1758 test(jv, jss::Amount.c_str());
1761 auto trustSet = [&](
SField const& field) {
1763 jv[jss::TransactionType] = jss::TrustSet;
1764 jv[jss::Account] = alice.
human();
1767 test(jv, field.fieldName);
1769 trustSet(sfLimitAmount);
1774 test(jv, jss::Amount.c_str());
1779 test(jv, jss::Amount.c_str());
1785 test(jv, sfSignatureReward.fieldName);
1799 test(jv, jss::Amount.c_str());
1814 for (
auto const& field :
1815 {sfAmount.fieldName, sfSignatureReward.fieldName})
1824 alice, jvb, alice, mpt,
XRP(10));
1825 for (
auto const& field :
1826 {sfAmount.fieldName, sfSignatureReward.fieldName})
1838 jv[jss::TransactionType] = tt;
1839 jv[jss::Account] = alice.
human();
1840 jv[sfXChainBridge.fieldName] = jvb;
1841 jv[sfSignatureReward.fieldName] =
1843 jv[sfMinAccountCreateAmount.fieldName] =
1847 auto reward =
STAmount{sfSignatureReward, mpt};
1848 auto minAmount =
STAmount{sfMinAccountCreateAmount, USD(10)};
1849 for (
SField const& field :
1851 std::ref(sfMinAccountCreateAmount)})
1854 jss::XChainCreateBridge,
1859 jss::XChainModifyBridge,
1863 reward =
STAmount{sfSignatureReward, USD(10)};
1864 minAmount =
STAmount{sfMinAccountCreateAmount, mpt};
1867 BEAST_EXPECT(txWithAmounts.
empty());
1874 testcase(
"Test synthetic fields from tx response");
1876 using namespace test::jtx;
1881 cfg->FEES.reference_fee = 10;
1882 Env env{*
this, std::move(cfg), features};
1891 "E11F0E0CA14219922B7881F060B9CEE67CFBC87E4049A441ED2AE348FF8FAC"
1894 Json::Value const meta = env.rpc(
"tx", txHash)[jss::result][jss::meta];
1895 auto const id = meta[jss::mpt_issuance_id].
asString();
1897 BEAST_EXPECT(meta.
isMember(jss::mpt_issuance_id));
1900 id ==
"00000004AE123A8556F3CF91154711376AFB0F894F832B3D",
id);
1906 testcase(
"MPT clawback validations");
1907 using namespace test::jtx;
1911 Env env(*
this, features - featureMPTokensV1);
1915 env.
fund(
XRP(1000), alice, bob);
1918 auto const USD = alice[
"USD"];
1934 Env env(*
this, features);
1938 env.
fund(
XRP(1000), alice, bob);
1941 auto const USD = alice[
"USD"];
1968 Env env(*
this, features);
1972 MPTTester mptAlice(env, alice, {.holders = {bob}});
1980 mptAlice.create({.ownerCount = 1, .holderCount = 0});
1982 mptAlice.authorize({.account = bob});
1984 mptAlice.pay(alice, bob, 100);
1993 Env env(*
this, features);
1999 MPTTester mptAlice(env, alice, {.holders = {bob}});
2016 mptAlice.authorize({.account = bob});
2022 mptAlice.pay(alice, bob, 100);
2033 Env env(*
this, features);
2037 env.
fund(
XRP(1000), alice, bob);
2046 jv1[jss::secret] = alice.name();
2047 jv1[jss::tx_json] = jv;
2048 auto const jrr = env.
rpc(
"json",
"submit",
to_string(jv1));
2049 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
2057 using namespace test::jtx;
2060 Env env(*
this, features);
2064 MPTTester mptAlice(env, alice, {.holders = {bob}});
2071 mptAlice.authorize({.account = bob});
2074 mptAlice.pay(alice, bob, 100);
2076 mptAlice.claw(alice, bob, 1);
2078 mptAlice.claw(alice, bob, 1000);
2086 Env env(*
this, features);
2090 MPTTester mptAlice(env, alice, {.holders = {bob}});
2099 mptAlice.authorize({.account = bob});
2102 mptAlice.pay(alice, bob, 100);
2104 mptAlice.set({.account = alice, .flags =
tfMPTLock});
2106 mptAlice.claw(alice, bob, 100);
2111 Env env(*
this, features);
2115 MPTTester mptAlice(env, alice, {.holders = {bob}});
2124 mptAlice.authorize({.account = bob});
2127 mptAlice.pay(alice, bob, 100);
2129 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
2131 mptAlice.claw(alice, bob, 100);
2136 Env env(*
this, features);
2140 MPTTester mptAlice(env, alice, {.holders = {bob}});
2149 mptAlice.authorize({.account = bob});
2152 mptAlice.authorize({.account = alice, .holder = bob});
2155 mptAlice.pay(alice, bob, 100);
2161 mptAlice.claw(alice, bob, 100);
2168 using namespace test::jtx;
2182 Asset const assetMpt1Gw1{mpt1};
2183 Asset const assetMpt1Gw1a{mpt1a};
2184 Asset const assetMpt1Gw2{mpt2};
2185 Asset const assetMpt2Gw2{mpt3};
2189 BEAST_EXPECT(
equalTokens(assetCur1Gw1, assetCur1Gw1a));
2190 BEAST_EXPECT(
equalTokens(assetCur2Gw1, assetCur2Gw2));
2193 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw1));
2194 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw2));
2198 BEAST_EXPECT(
equalTokens(assetMpt1Gw1, assetMpt1Gw1a));
2200 BEAST_EXPECT(!
equalTokens(assetMpt1Gw1, assetMpt1Gw2));
2201 BEAST_EXPECT(!
equalTokens(assetMpt1Gw2, assetMpt2Gw2));
2204 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetMpt1Gw1));
2205 BEAST_EXPECT(!
equalTokens(assetMpt2Gw2, assetCur2Gw2));
2211 using namespace test::jtx;
2218 STAmount const amt3{asset3, 10'000};
2221 testcase(
"Test STAmount MPT arithmetics");
2222 using namespace std::string_literals;
2224 BEAST_EXPECT(res == amt3);
2226 res =
mulRound(amt1, amt2, asset3,
true);
2227 BEAST_EXPECT(res == amt3);
2230 BEAST_EXPECT(res == amt3);
2233 STAmount mptOverflow{asset2, UINT64_C(3037000500)};
2236 res =
multiply(mptOverflow, mptOverflow, asset3);
2237 fail(
"should throw runtime exception 1");
2241 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2244 mptOverflow =
STAmount{asset2, UINT64_C(2147483648)};
2245 uint64_t
const mantissa = (2ull << 32) + 2;
2249 fail(
"should throw runtime exception 2");
2253 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2258 testcase(
"Test MPTAmount arithmetics");
2261 BEAST_EXPECT((mptAmt1 += mptAmt2) ==
MPTAmount{200});
2262 BEAST_EXPECT(mptAmt1 == 200);
2263 BEAST_EXPECT((mptAmt1 -= mptAmt2) == mptAmt1);
2264 BEAST_EXPECT(mptAmt1 == mptAmt2);
2265 BEAST_EXPECT(mptAmt1 == 100);
2270 testcase(
"Test MPTIssue from/to Json");
2279 testcase(
"Test Asset from/to Json");
2285 "{\"mpt_issuance_id\":"
2286 "\"00000001A407AF5856CCF3C42619DAA925813FC955C72983\"}");
2295 using namespace test::jtx;
2343BEAST_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
FeatureBitset testable_amendments()
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.
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.