21#include <test/jtx/credentials.h>
22#include <test/jtx/permissioned_domains.h>
23#include <test/jtx/trust.h>
24#include <test/jtx/xchain_bridge.h>
26#include <xrpl/basics/base_uint.h>
27#include <xrpl/beast/utility/Zero.h>
28#include <xrpl/protocol/Feature.h>
29#include <xrpl/protocol/TER.h>
30#include <xrpl/protocol/TxFlags.h>
31#include <xrpl/protocol/jss.h>
42 using namespace test::jtx;
49 Env env{*
this, features - featureMPTokensV1};
57 Env env{*
this, features};
70 if (!features[featureSingleAssetVault])
81 else if (!features[featurePermissionedDomains])
108 .domainID = beast::zero,
147 {.maxAmt = 0xFFFF'FFFF'FFFF'FFF0,
166 using namespace test::jtx;
172 Env env{*
this, features};
187 Json::Value const result = env.rpc(
"tx", txHash)[jss::result];
189 result[sfMaximumAmount.getJsonName()] ==
"9223372036854775807");
192 if (features[featureSingleAssetVault])
195 Account const credIssuer1{
"credIssuer1"};
199 {.issuer = credIssuer1, .credType = credType}};
202 Env env{*
this, features};
203 env.fund(
XRP(1000), credIssuer1);
206 auto const domainId1 = [&]() {
220 .domainID = domainId1,
227 Json::Value const result = env.rpc(
"tx", txHash)[jss::result];
229 result[sfMaximumAmount.getJsonName()] ==
230 "9223372036854775807");
240 using namespace test::jtx;
245 Env env{*
this, features - featureMPTokensV1};
247 auto const id =
makeMptID(env.seq(alice), alice);
250 env.enableFeature(featureMPTokensV1);
258 Env env{*
this, features};
259 MPTTester mptAlice(env, alice, {.holders = {bob}});
266 mptAlice.create({.ownerCount = 1});
275 mptAlice.authorize({.account = bob, .holderCount = 1});
278 mptAlice.pay(alice, bob, 100);
290 using namespace test::jtx;
295 Env env{*
this, features};
298 mptAlice.
create({.ownerCount = 1});
300 mptAlice.
destroy({.ownerCount = 0});
306 testcase(
"Validate authorize transaction");
308 using namespace test::jtx;
314 Env env{*
this, features - featureMPTokensV1};
315 MPTTester mptAlice(env, alice, {.holders = {bob}});
325 Env env{*
this, features};
326 MPTTester mptAlice(env, alice, {.holders = {bob}});
328 mptAlice.
create({.ownerCount = 1});
338 mptAlice.authorize({.holder = alice, .err =
temMALFORMED});
344 Env env{*
this, features};
345 MPTTester mptAlice(env, alice, {.holders = {bob}});
346 auto const id =
makeMptID(env.seq(alice), alice);
358 Env env{*
this, features};
359 MPTTester mptAlice(env, alice, {.holders = {bob}});
361 mptAlice.
create({.ownerCount = 1});
371 mptAlice.authorize({.holder = bob, .err =
tecNO_AUTH});
374 mptAlice.authorize({.account = bob, .holderCount = 1});
377 mptAlice.authorize({.account = bob, .err =
tecDUPLICATE});
383 mptAlice.pay(alice, bob, 100);
393 mptAlice.pay(bob, alice, 100);
410 Env env{*
this, features};
411 MPTTester mptAlice(env, alice, {.holders = {bob}});
423 mptAlice.authorize({.holder = cindy, .err =
tecNO_DST});
426 mptAlice.authorize({.account = bob, .holderCount = 1});
435 mptAlice.authorize({.holder = bob});
440 mptAlice.authorize({.holder = bob});
449 Env env{*
this, features};
450 auto const acctReserve = env.current()->fees().accountReserve(0);
451 auto const incReserve = env.current()->fees().increment;
459 .xrpHolders = acctReserve + (incReserve - 1)});
462 MPTTester mptAlice2(env, alice, {.fund =
false});
465 MPTTester mptAlice3(env, alice, {.fund =
false});
466 mptAlice3.
create({.ownerCount = 3});
469 mptAlice1.authorize({.account = bob, .holderCount = 1});
472 mptAlice2.authorize({.account = bob, .holderCount = 2});
478 env.master, bob,
drops(incReserve + incReserve + incReserve)));
481 mptAlice3.authorize({.account = bob, .holderCount = 3});
490 using namespace test::jtx;
495 Env env{*
this, features};
498 MPTTester mptAlice(env, alice, {.holders = {bob}});
500 mptAlice.
create({.ownerCount = 1});
503 mptAlice.authorize({.account = bob, .holderCount = 1});
506 {.account = bob, .holderCount = 1, .err =
tecDUPLICATE});
515 Env env{*
this, features};
518 MPTTester mptAlice(env, alice, {.holders = {bob}});
523 mptAlice.authorize({.account = bob, .holderCount = 1});
526 mptAlice.authorize({.account = alice, .holder = bob});
542 Env env{*
this, features};
543 MPTTester mptAlice(env, alice, {.holders = {bob}});
545 mptAlice.
create({.ownerCount = 1});
548 mptAlice.authorize({.account = bob, .holderCount = 1});
551 mptAlice.destroy({.ownerCount = 0});
563 testcase(
"Validate set transaction");
565 using namespace test::jtx;
571 Env env{*
this, features - featureMPTokensV1};
572 MPTTester mptAlice(env, alice, {.holders = {bob}});
579 env.enableFeature(featureMPTokensV1);
581 mptAlice.create({.ownerCount = 1, .holderCount = 0});
583 mptAlice.authorize({.account = bob, .holderCount = 1});
592 if (!features[featureSingleAssetVault])
626 if (!features[featurePermissionedDomains])
663 Env env{*
this, features};
665 MPTTester mptAlice(env, alice, {.holders = {bob}});
667 mptAlice.
create({.ownerCount = 1});
701 Env env{*
this, features};
703 MPTTester mptAlice(env, alice, {.holders = {bob}});
712 mptAlice.create({.ownerCount = 1, .flags =
tfMPTCanLock});
729 if (features[featureSingleAssetVault] &&
730 features[featurePermissionedDomains])
733 Account const credIssuer1{
"credIssuer1"};
737 {.issuer = credIssuer1, .credType = credType}};
740 Env env{*
this, features};
754 Env env{*
this, features};
771 .domainID = beast::zero,
780 testcase(
"Enabled set transaction");
782 using namespace test::jtx;
788 Env env{*
this, features};
790 MPTTester mptAlice(env, alice, {.holders = {bob}});
794 {.ownerCount = 1, .holderCount = 0, .flags =
tfMPTCanLock});
796 mptAlice.authorize({.account = bob, .holderCount = 1});
799 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
803 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
806 mptAlice.set({.account = alice, .flags =
tfMPTLock});
810 mptAlice.set({.account = alice, .flags =
tfMPTLock});
811 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
815 {.account = alice, .holder = bob, .flags =
tfMPTUnlock});
818 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
819 if (!features[featureSingleAssetVault])
840 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
844 {.account = alice, .holder = bob, .flags =
tfMPTUnlock});
850 {.account = alice, .holder = bob, .flags =
tfMPTUnlock});
851 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
854 if (features[featureSingleAssetVault])
860 Env env{*
this, features};
862 auto const domainId1 = [&]() {
863 Account const credIssuer1{
"credIssuer1"};
864 env.fund(
XRP(1000), credIssuer1);
867 {.issuer = credIssuer1, .credType = credType}};
876 auto const domainId2 = [&]() {
877 Account const credIssuer2{
"credIssuer2"};
878 env.fund(
XRP(1000), credIssuer2);
881 {.issuer = credIssuer2, .credType = credType}};
890 MPTTester mptAlice(env, alice, {.holders = {bob}});
895 BEAST_EXPECT(mptAlice.checkDomainID(std::nullopt));
898 mptAlice.set({.domainID = beast::zero});
899 BEAST_EXPECT(mptAlice.checkDomainID(std::nullopt));
902 mptAlice.set({.domainID = domainId1});
903 BEAST_EXPECT(mptAlice.checkDomainID(domainId1));
906 mptAlice.set({.domainID = domainId2});
907 BEAST_EXPECT(mptAlice.checkDomainID(domainId2));
910 mptAlice.set({.domainID = beast::zero});
911 BEAST_EXPECT(mptAlice.checkDomainID(std::nullopt));
920 using namespace test::jtx;
929 Env env{*
this, features - featureMPTokensV1};
933 env.fund(
XRP(1'000), alice);
934 env.fund(
XRP(1'000), bob);
942 Env env{*
this, features - featureMPTokensV1};
945 auto const USD = alice[
"USD"];
947 env.fund(
XRP(1'000), alice);
948 env.fund(
XRP(1'000), carol);
952 jv[jss::secret] = alice.
name();
953 jv[jss::tx_json] =
pay(alice, carol, mpt);
954 jv[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
955 auto const jrr = env.rpc(
"json",
"submit",
to_string(jv));
956 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"temDISABLED");
961 Env env{*
this, features};
963 MPTTester mptAlice(env, alice, {.holders = {bob}});
965 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
966 auto const MPT = mptAlice[
"MPT"];
968 mptAlice.authorize({.account = bob});
971 env(
pay(alice, bob,
MPT(10)),
978 Env env{*
this, features};
982 MPTTester mptAlice(env, alice, {.holders = {carol}});
984 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
986 mptAlice.authorize({.account = carol});
990 auto const MPT = mptAlice[
"MPT"];
991 env(
pay(alice, carol,
MPT(100)),
994 env(
pay(alice, carol,
MPT(100)),
998 auto const USD = alice[
"USD"];
999 env(
pay(alice, carol, USD(100)),
1002 env(
pay(alice, carol,
XRP(100)),
1005 env(
pay(alice, carol, USD(100)),
1008 env(
pay(alice, carol,
XRP(100)),
1013 "MPT",
makeMptID(env.seq(alice) + 10, alice));
1014 env(
pay(alice, carol, MPT1(100)),
1023 Env env{*
this, features};
1027 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1029 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1030 auto const MPT = mptAlice[
"MPT"];
1032 mptAlice.authorize({.account = carol});
1035 payment[jss::secret] = alice.
name();
1036 payment[jss::tx_json] =
pay(alice, carol,
MPT(100));
1038 payment[jss::build_path] =
true;
1039 auto jrr = env.rpc(
"json",
"submit",
to_string(payment));
1040 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1042 jrr[jss::result][jss::error_message] ==
1043 "Field 'build_path' not allowed in this context.");
1048 Env env{*
this, features};
1050 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1052 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1053 auto const MPT = mptAlice[
"MPT"];
1055 mptAlice.authorize({.account = bob});
1056 mptAlice.authorize({.account = carol});
1069 Env env{*
this, features};
1071 MPTTester mptAlice(env, alice, {.holders = {bob}});
1073 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1075 mptAlice.authorize({.account = bob});
1084 Env env{*
this, features};
1086 MPTTester mptAlice(env, alice, {.holders = {bob}});
1088 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1090 mptAlice.authorize({.account = bob});
1103 Env env{*
this, features};
1105 MPTTester mptAlice(env, alice, {.holders = {bob}});
1112 mptAlice.authorize({.account = bob});
1120 Env env{*
this, features};
1122 MPTTester mptAlice(env, alice, {.holders = {bob}});
1130 mptAlice.authorize({.account = bob});
1133 mptAlice.authorize({.account = alice, .holder = bob});
1136 mptAlice.pay(alice, bob, 100);
1147 if (features[featureSingleAssetVault] &&
1148 features[featurePermissionedDomains])
1152 Env env{*
this, features};
1154 Account const credIssuer1{
"credIssuer1"};
1155 env.fund(
XRP(1000), credIssuer1, bob);
1157 auto const domainId1 = [&]() {
1159 {.issuer = credIssuer1, .credType = credType}};
1179 .domainID = domainId1,
1182 mptAlice.authorize({.account = bob});
1186 mptAlice.pay(alice, bob, 100);
1187 mptAlice.set({.domainID = beast::zero});
1194 Env env{*
this, features};
1196 Account const credIssuer1{
"credIssuer1"};
1197 env.fund(
XRP(1000), credIssuer1, bob);
1199 auto const domainId1 = [&]() {
1201 {.issuer = credIssuer1, .credType = credType}};
1221 .domainID = domainId1,
1225 mptAlice.authorize({.account = bob});
1228 mptAlice.authorize({.account = alice, .holder = bob});
1231 mptAlice.pay(alice, bob, 100);
1240 mptAlice.pay(bob, alice, 10);
1242 mptAlice.set({.domainID = beast::zero});
1250 Env env{*
this, features};
1253 Account const credIssuer1{
"credIssuer1"};
1256 Account const credIssuer2{
"credIssuer2"};
1257 env.fund(
XRP(1000), credIssuer1, credIssuer2, bob, carol);
1259 auto const domainId1 = [&]() {
1261 {.issuer = credIssuer1, .credType = credType}};
1270 auto const domainId2 = [&]() {
1272 {.issuer = credIssuer1, .credType = credType},
1273 {.issuer = credIssuer2, .credType = credType}};
1301 .domainID = domainId1,
1305 mptAlice.authorize({.account = bob});
1306 mptAlice.authorize({.account = carol});
1310 mptAlice.pay(alice, bob, 50);
1321 mptAlice.set({.domainID = domainId2});
1323 mptAlice.pay(alice, carol, 10);
1328 mptAlice.pay(bob, carol, 10);
1333 credIssuer1, bob, credIssuer1, credType));
1343 Env env(*
this, features);
1348 MPTTester mptAlice(env, alice, {.holders = {bob, cindy}});
1351 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1354 mptAlice.authorize({.account = bob});
1357 mptAlice.authorize({.account = cindy});
1360 mptAlice.pay(alice, bob, 100);
1367 mptAlice.pay(bob, alice, 10);
1372 Env env{*
this, features};
1374 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1391 Env env{*
this, features};
1393 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1397 mptAlice.authorize({.account = bob});
1398 mptAlice.authorize({.account = carol});
1400 mptAlice.pay(alice, bob, 100);
1411 Env env{*
this, features};
1413 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1418 mptAlice.authorize({.account = bob});
1419 mptAlice.authorize({.account = carol});
1421 mptAlice.pay(alice, bob, 100);
1422 mptAlice.pay(alice, carol, 100);
1425 mptAlice.set({.account = alice, .flags =
tfMPTLock});
1430 mptAlice.pay(alice, bob, 3);
1432 mptAlice.pay(bob, alice, 4);
1435 mptAlice.set({.account = alice, .flags =
tfMPTUnlock});
1437 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
1442 mptAlice.pay(alice, bob, 7);
1444 mptAlice.pay(bob, alice, 8);
1449 Env env{*
this, features};
1451 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1455 {.transferFee = 10'000,
1461 mptAlice.authorize({.account = bob});
1462 mptAlice.authorize({.account = carol});
1465 mptAlice.pay(alice, bob, 2'000);
1468 mptAlice.pay(bob, alice, 1'000);
1469 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 1'000));
1479 auto const MPT = mptAlice[
"MPT"];
1481 env(
pay(bob, carol,
MPT(100)),
1490 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 780));
1491 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 200));
1494 env(
pay(bob, carol,
MPT(100)),
1499 BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 690));
1500 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 282));
1505 Env env{*
this, features};
1507 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1513 mptAlice.authorize({.account = bob});
1514 mptAlice.authorize({.account = carol});
1515 mptAlice.pay(alice, bob, 1'000);
1517 auto const MPT = mptAlice[
"MPT"];
1519 env(
pay(bob, carol,
MPT(100)),
1522 env(
pay(bob, alice,
MPT(100)),
1528 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 100));
1530 env(
pay(bob, carol,
MPT(100)),
1533 BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 199));
1538 Env env{*
this, features};
1540 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1546 mptAlice.authorize({.account = bob});
1547 mptAlice.authorize({.account = carol});
1548 mptAlice.pay(alice, bob, 1'000);
1550 auto const MPT = mptAlice[
"MPT"];
1553 env(
pay(bob, alice,
MPT(100)),
1559 env(
pay(bob, alice,
MPT(100)),
1567 Env env{*
this, features};
1569 MPTTester mptAlice(env, alice, {.holders = {bob}});
1577 mptAlice.authorize({.account = bob});
1580 mptAlice.pay(alice, bob, 100);
1589 Env env{*
this, features};
1591 MPTTester mptAlice(env, alice, {.holders = {bob}});
1593 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1595 mptAlice.authorize({.account = bob});
1607 Env env{*
this, features};
1608 env.fund(
XRP(1'000), alice, bob);
1611 jv[jss::secret] = alice.
name();
1612 jv[jss::tx_json] =
pay(alice, bob, mpt);
1613 jv[jss::tx_json][jss::Amount][jss::value] =
1615 auto const jrr = env.rpc(
"json",
"submit",
to_string(jv));
1616 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
1622 Env env{*
this, features};
1624 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1632 auto const MPT = mptAlice[
"MPT"];
1634 mptAlice.authorize({.account = bob});
1635 mptAlice.authorize({.account = carol});
1638 mptAlice.pay(alice, bob, 10'000);
1641 env(
pay(bob, carol,
MPT(10'000)),
1645 auto const meta = env.meta()->getJson(
1649 meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1650 [sfOutstandingAmount.fieldName] ==
"9990");
1653 meta[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1654 [sfMPTAmount.fieldName] ==
"9990");
1657 meta[2u][sfModifiedNode.fieldName][sfPreviousFields.fieldName]
1658 [sfMPTAmount.fieldName] ==
"10000");
1660 !meta[2u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
1661 .isMember(sfMPTAmount.fieldName));
1665 env(
pay(bob, carol,
MPT(10'000)),
1672 Env env{*
this, features};
1674 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1681 auto const MPT = mptAlice[
"MPT"];
1683 mptAlice.authorize({.account = bob});
1684 mptAlice.authorize({.account = carol});
1697 BEAST_EXPECT(mptAlice.checkMPTokenOutstandingAmount(0));
1702 Env env{*
this, features};
1704 MPTTester mptAlice(env, alice, {.holders = {bob}});
1706 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1708 mptAlice.authorize({.account = bob});
1711 mptAlice.destroy({.ownerCount = 0});
1720 Env env{*
this, features};
1722 env.fund(
XRP(1'000), alice, bob);
1731 Env env{*
this, features};
1733 MPTTester mptAlice(env, alice, {.holders = {bob}});
1735 mptAlice.
create({.ownerCount = 1, .holderCount = 0});
1738 mptAlice.destroy({.ownerCount = 0});
1748 Env env{*
this, features};
1753 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1758 mptAlice.authorize({.account = bob});
1759 mptAlice.authorize({.account = carol});
1761 mptAlice.pay(alice, bob, 100);
1764 mptAlice.pay(bob, carol, 100);
1769 Env env{*
this, features};
1771 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1776 mptAlice.authorize({.account = bob});
1777 mptAlice.authorize({.account = carol});
1780 mptAlice.pay(alice, bob, 100);
1783 mptAlice.pay(bob, alice, 100);
1786 mptAlice.pay(alice, bob, 100);
1787 mptAlice.pay(bob, carol, 50);
1794 using namespace test::jtx;
1798 Account const dpIssuer(
"dpIssuer");
1800 char const credType[] =
"abcde";
1802 if (features[featureCredentials])
1806 Env env(*
this, features);
1808 env.
fund(
XRP(50000), diana, dpIssuer);
1811 MPTTester mptAlice(env, alice, {.holders = {bob}});
1817 env(
pay(diana, bob,
XRP(500)));
1821 mptAlice.authorize({.account = bob});
1823 mptAlice.authorize({.account = alice, .holder = bob});
1838 mptAlice.pay(alice, bob, 100);
1848 std::string const credIdx = jv[jss::result][jss::index].asString();
1851 mptAlice.pay(alice, bob, 100,
tesSUCCESS, {{credIdx}});
1875 mptAlice.pay(alice, bob, 100,
tesSUCCESS, {{credIdx}});
1879 testcase(
"DepositPreauth disabled featureCredentials");
1884 "D007AE4B6E1274B4AF872588267B810C2F82716726351D1C7D38D3E5499FC6"
1887 env.
fund(
XRP(50000), diana, dpIssuer);
1890 MPTTester mptAlice(env, alice, {.holders = {bob}});
1896 env(
pay(diana, bob,
XRP(500)));
1900 mptAlice.authorize({.account = bob});
1902 mptAlice.authorize({.account = alice, .holder = bob});
1914 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1922 mptAlice.pay(alice, bob, 100);
1926 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1938 mptAlice.pay(alice, bob, 100,
temDISABLED, {{credIdx}});
1946 testcase(
"MPT Issue Invalid in Transaction");
1947 using namespace test::jtx;
1956 for (
auto const& e : format.getSOTemplate())
1962 e.sField().getName() != jss::Fee &&
1963 format.getName() != jss::SetFee)
1966 format.getName() + e.sField().fieldName);
1973 auto const USD = alice[
"USD"];
1976 STAmount mpt{issue, UINT64_C(100)};
1977 auto const jvb =
bridge(alice, USD, alice, USD);
1978 for (
auto const& feature : {features, features - featureMPTokensV1})
1980 Env env{*
this, feature};
1981 env.fund(
XRP(1'000), alice);
1982 env.fund(
XRP(1'000), carol);
1985 txWithAmounts.
erase(
1986 jv[jss::TransactionType].asString() + mptField);
1989 auto jtx = env.jt(jv);
1994 jrr[jss::result][jss::error] ==
"invalidTransaction");
1998 jv1[jss::secret] = alice.
name();
1999 jv1[jss::tx_json] = jv;
2000 jrr = env.rpc(
"json",
"submit",
to_string(jv1));
2001 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
2003 jrr = env.rpc(
"json",
"sign",
to_string(jv1));
2004 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
2006 auto toSFieldRef = [](
SField const& field) {
2009 auto setMPTFields = [&](
SField const& field,
2011 bool withAmount =
true) {
2013 jv[jss::Asset2] =
to_json(USD.issue());
2015 jv[field.fieldName] =
2017 if (field == sfAsset)
2019 else if (field == sfAsset2)
2029 auto ammCreate = [&](
SField const& field) {
2031 jv[jss::TransactionType] = jss::AMMCreate;
2032 jv[jss::Account] = alice.
human();
2033 jv[jss::Amount] = (field.fieldName == sfAmount.fieldName)
2036 jv[jss::Amount2] = (field.fieldName == sfAmount2.fieldName)
2039 jv[jss::TradingFee] = 0;
2040 test(jv, field.fieldName);
2042 ammCreate(sfAmount);
2043 ammCreate(sfAmount2);
2045 auto ammDeposit = [&](
SField const& field) {
2047 jv[jss::TransactionType] = jss::AMMDeposit;
2048 jv[jss::Account] = alice.
human();
2050 setMPTFields(field, jv);
2051 test(jv, field.fieldName);
2053 for (
SField const& field :
2054 {toSFieldRef(sfAmount),
2055 toSFieldRef(sfAmount2),
2056 toSFieldRef(sfEPrice),
2057 toSFieldRef(sfLPTokenOut),
2058 toSFieldRef(sfAsset),
2059 toSFieldRef(sfAsset2)})
2062 auto ammWithdraw = [&](
SField const& field) {
2064 jv[jss::TransactionType] = jss::AMMWithdraw;
2065 jv[jss::Account] = alice.
human();
2067 setMPTFields(field, jv);
2068 test(jv, field.fieldName);
2070 ammWithdraw(sfAmount);
2071 for (
SField const& field :
2072 {toSFieldRef(sfAmount2),
2073 toSFieldRef(sfEPrice),
2074 toSFieldRef(sfLPTokenIn),
2075 toSFieldRef(sfAsset),
2076 toSFieldRef(sfAsset2)})
2079 auto ammBid = [&](
SField const& field) {
2081 jv[jss::TransactionType] = jss::AMMBid;
2082 jv[jss::Account] = alice.
human();
2083 setMPTFields(field, jv);
2084 test(jv, field.fieldName);
2086 for (
SField const& field :
2087 {toSFieldRef(sfBidMin),
2088 toSFieldRef(sfBidMax),
2089 toSFieldRef(sfAsset),
2090 toSFieldRef(sfAsset2)})
2093 auto ammClawback = [&](
SField const& field) {
2095 jv[jss::TransactionType] = jss::AMMClawback;
2096 jv[jss::Account] = alice.
human();
2097 jv[jss::Holder] = carol.
human();
2098 setMPTFields(field, jv);
2099 test(jv, field.fieldName);
2101 for (
SField const& field :
2102 {toSFieldRef(sfAmount),
2103 toSFieldRef(sfAsset),
2104 toSFieldRef(sfAsset2)})
2107 auto ammDelete = [&](
SField const& field) {
2109 jv[jss::TransactionType] = jss::AMMDelete;
2110 jv[jss::Account] = alice.
human();
2111 setMPTFields(field, jv,
false);
2112 test(jv, field.fieldName);
2115 ammDelete(sfAsset2);
2117 auto ammVote = [&](
SField const& field) {
2119 jv[jss::TransactionType] = jss::AMMVote;
2120 jv[jss::Account] = alice.
human();
2121 jv[jss::TradingFee] = 100;
2122 setMPTFields(field, jv,
false);
2123 test(jv, field.fieldName);
2128 auto checkCash = [&](
SField const& field) {
2130 jv[jss::TransactionType] = jss::CheckCash;
2131 jv[jss::Account] = alice.
human();
2134 test(jv, field.fieldName);
2136 checkCash(sfAmount);
2137 checkCash(sfDeliverMin);
2141 jv[jss::TransactionType] = jss::CheckCreate;
2142 jv[jss::Account] = alice.
human();
2143 jv[jss::Destination] = carol.
human();
2145 test(jv, jss::SendMax.c_str());
2150 test(jv, jss::TakerPays.c_str());
2151 jv =
offer(alice, mpt, USD(100));
2152 test(jv, jss::TakerGets.c_str());
2157 jv[jss::TransactionType] = jss::PaymentChannelCreate;
2158 jv[jss::Account] = alice.
human();
2159 jv[jss::Destination] = carol.
human();
2160 jv[jss::SettleDelay] = 1;
2163 test(jv, jss::Amount.c_str());
2168 jv[jss::TransactionType] = jss::PaymentChannelFund;
2169 jv[jss::Account] = alice.
human();
2172 test(jv, jss::Amount.c_str());
2177 jv[jss::TransactionType] = jss::PaymentChannelClaim;
2178 jv[jss::Account] = alice.
human();
2181 test(jv, jss::Amount.c_str());
2186 jv[jss::TransactionType] = jss::NFTokenCreateOffer;
2187 jv[jss::Account] = alice.
human();
2190 test(jv, jss::Amount.c_str());
2195 jv[jss::TransactionType] = jss::NFTokenAcceptOffer;
2196 jv[jss::Account] = alice.
human();
2197 jv[sfNFTokenBrokerFee.fieldName] =
2199 test(jv, sfNFTokenBrokerFee.fieldName);
2204 jv[jss::TransactionType] = jss::NFTokenMint;
2205 jv[jss::Account] = alice.
human();
2206 jv[sfNFTokenTaxon.fieldName] = 1;
2208 test(jv, jss::Amount.c_str());
2211 auto trustSet = [&](
SField const& field) {
2213 jv[jss::TransactionType] = jss::TrustSet;
2214 jv[jss::Account] = alice.
human();
2217 test(jv, field.fieldName);
2219 trustSet(sfLimitAmount);
2224 test(jv, jss::Amount.c_str());
2229 test(jv, jss::Amount.c_str());
2235 test(jv, sfSignatureReward.fieldName);
2249 test(jv, jss::Amount.c_str());
2264 for (
auto const& field :
2265 {sfAmount.fieldName, sfSignatureReward.fieldName})
2274 alice, jvb, alice, mpt,
XRP(10));
2275 for (
auto const& field :
2276 {sfAmount.fieldName, sfSignatureReward.fieldName})
2288 jv[jss::TransactionType] = tt;
2289 jv[jss::Account] = alice.
human();
2290 jv[sfXChainBridge.fieldName] = jvb;
2291 jv[sfSignatureReward.fieldName] =
2293 jv[sfMinAccountCreateAmount.fieldName] =
2297 auto reward =
STAmount{sfSignatureReward, mpt};
2298 auto minAmount =
STAmount{sfMinAccountCreateAmount, USD(10)};
2299 for (
SField const& field :
2301 std::ref(sfMinAccountCreateAmount)})
2304 jss::XChainCreateBridge,
2309 jss::XChainModifyBridge,
2313 reward =
STAmount{sfSignatureReward, USD(10)};
2314 minAmount =
STAmount{sfMinAccountCreateAmount, mpt};
2317 BEAST_EXPECT(txWithAmounts.
empty());
2324 testcase(
"Test synthetic fields from tx response");
2326 using namespace test::jtx;
2331 cfg->FEES.reference_fee = 10;
2332 Env env{*
this, std::move(cfg), features};
2341 "E11F0E0CA14219922B7881F060B9CEE67CFBC87E4049A441ED2AE348FF8FAC"
2344 Json::Value const meta = env.rpc(
"tx", txHash)[jss::result][jss::meta];
2345 auto const id = meta[jss::mpt_issuance_id].
asString();
2347 BEAST_EXPECT(meta.
isMember(jss::mpt_issuance_id));
2350 id ==
"00000004AE123A8556F3CF91154711376AFB0F894F832B3D",
id);
2356 testcase(
"MPT clawback validations");
2357 using namespace test::jtx;
2361 Env env(*
this, features - featureMPTokensV1);
2365 env.
fund(
XRP(1000), alice, bob);
2368 auto const USD = alice[
"USD"];
2384 Env env(*
this, features);
2388 env.
fund(
XRP(1000), alice, bob);
2391 auto const USD = alice[
"USD"];
2418 Env env(*
this, features);
2422 MPTTester mptAlice(env, alice, {.holders = {bob}});
2430 mptAlice.create({.ownerCount = 1, .holderCount = 0});
2432 mptAlice.authorize({.account = bob});
2434 mptAlice.pay(alice, bob, 100);
2443 Env env(*
this, features);
2449 MPTTester mptAlice(env, alice, {.holders = {bob}});
2466 mptAlice.authorize({.account = bob});
2472 mptAlice.pay(alice, bob, 100);
2483 Env env(*
this, features);
2487 env.
fund(
XRP(1000), alice, bob);
2496 jv1[jss::secret] = alice.name();
2497 jv1[jss::tx_json] = jv;
2498 auto const jrr = env.
rpc(
"json",
"submit",
to_string(jv1));
2499 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
2507 using namespace test::jtx;
2510 Env env(*
this, features);
2514 MPTTester mptAlice(env, alice, {.holders = {bob}});
2521 mptAlice.authorize({.account = bob});
2524 mptAlice.pay(alice, bob, 100);
2526 mptAlice.claw(alice, bob, 1);
2528 mptAlice.claw(alice, bob, 1000);
2536 Env env(*
this, features);
2540 MPTTester mptAlice(env, alice, {.holders = {bob}});
2549 mptAlice.authorize({.account = bob});
2552 mptAlice.pay(alice, bob, 100);
2554 mptAlice.set({.account = alice, .flags =
tfMPTLock});
2556 mptAlice.claw(alice, bob, 100);
2561 Env env(*
this, features);
2565 MPTTester mptAlice(env, alice, {.holders = {bob}});
2574 mptAlice.authorize({.account = bob});
2577 mptAlice.pay(alice, bob, 100);
2579 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
2581 mptAlice.claw(alice, bob, 100);
2586 Env env(*
this, features);
2590 MPTTester mptAlice(env, alice, {.holders = {bob}});
2599 mptAlice.authorize({.account = bob});
2602 mptAlice.authorize({.account = alice, .holder = bob});
2605 mptAlice.pay(alice, bob, 100);
2611 mptAlice.claw(alice, bob, 100);
2618 using namespace test::jtx;
2632 Asset const assetMpt1Gw1{mpt1};
2633 Asset const assetMpt1Gw1a{mpt1a};
2634 Asset const assetMpt1Gw2{mpt2};
2635 Asset const assetMpt2Gw2{mpt3};
2639 BEAST_EXPECT(
equalTokens(assetCur1Gw1, assetCur1Gw1a));
2640 BEAST_EXPECT(
equalTokens(assetCur2Gw1, assetCur2Gw2));
2643 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw1));
2644 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw2));
2648 BEAST_EXPECT(
equalTokens(assetMpt1Gw1, assetMpt1Gw1a));
2650 BEAST_EXPECT(!
equalTokens(assetMpt1Gw1, assetMpt1Gw2));
2651 BEAST_EXPECT(!
equalTokens(assetMpt1Gw2, assetMpt2Gw2));
2654 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetMpt1Gw1));
2655 BEAST_EXPECT(!
equalTokens(assetMpt2Gw2, assetCur2Gw2));
2661 using namespace test::jtx;
2668 STAmount const amt3{asset3, 10'000};
2671 testcase(
"Test STAmount MPT arithmetics");
2672 using namespace std::string_literals;
2674 BEAST_EXPECT(res == amt3);
2676 res =
mulRound(amt1, amt2, asset3,
true);
2677 BEAST_EXPECT(res == amt3);
2680 BEAST_EXPECT(res == amt3);
2683 STAmount mptOverflow{asset2, UINT64_C(3037000500)};
2686 res =
multiply(mptOverflow, mptOverflow, asset3);
2687 fail(
"should throw runtime exception 1");
2691 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2694 mptOverflow =
STAmount{asset2, UINT64_C(2147483648)};
2695 uint64_t
const mantissa = (2ull << 32) + 2;
2699 fail(
"should throw runtime exception 2");
2703 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2708 testcase(
"Test MPTAmount arithmetics");
2711 BEAST_EXPECT((mptAmt1 += mptAmt2) ==
MPTAmount{200});
2712 BEAST_EXPECT(mptAmt1 == 200);
2713 BEAST_EXPECT((mptAmt1 -= mptAmt2) == mptAmt1);
2714 BEAST_EXPECT(mptAmt1 == mptAmt2);
2715 BEAST_EXPECT(mptAmt1 == 100);
2720 testcase(
"Test MPTIssue from/to Json");
2729 testcase(
"Test Asset from/to Json");
2735 "{\"mpt_issuance_id\":"
2736 "\"00000001A407AF5856CCF3C42619DAA925813FC955C72983\"}");
2745 using namespace test::jtx;
2751 (
all | featureSingleAssetVault) - featurePermissionedDomains);
2771 (
all | featureSingleAssetVault) - featurePermissionedDomains);
2800BEAST_DEFINE_TESTSUITE_PRIO(MPToken, app,
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 testCreateEnabled(FeatureBitset features)
void testDestroyEnabled(FeatureBitset features)
void testPayment(FeatureBitset features)
void testHelperFunctions()
void testMPTInvalidInTx(FeatureBitset features)
void testAuthorizeEnabled(FeatureBitset features)
void testDepositPreauth(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 deleteCred(jtx::Account const &acc, 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 setTx(AccountID const &account, Credentials const &credentials, std::optional< uint256 > domain)
uint256 getNewDomain(std::shared_ptr< STObject const > const &meta)
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.