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 jv[jss::TransactionType] = jss::EscrowCreate;
1701 jv[jss::Account] = alice.
human();
1702 jv[jss::Destination] = carol.
human();
1704 test(jv, jss::Amount.c_str());
1709 test(jv, jss::TakerPays.c_str());
1710 jv =
offer(alice, mpt, USD(100));
1711 test(jv, jss::TakerGets.c_str());
1716 jv[jss::TransactionType] = jss::PaymentChannelCreate;
1717 jv[jss::Account] = alice.
human();
1718 jv[jss::Destination] = carol.
human();
1719 jv[jss::SettleDelay] = 1;
1722 test(jv, jss::Amount.c_str());
1727 jv[jss::TransactionType] = jss::PaymentChannelFund;
1728 jv[jss::Account] = alice.
human();
1731 test(jv, jss::Amount.c_str());
1736 jv[jss::TransactionType] = jss::PaymentChannelClaim;
1737 jv[jss::Account] = alice.
human();
1740 test(jv, jss::Amount.c_str());
1745 jv[jss::TransactionType] = jss::NFTokenCreateOffer;
1746 jv[jss::Account] = alice.
human();
1749 test(jv, jss::Amount.c_str());
1754 jv[jss::TransactionType] = jss::NFTokenAcceptOffer;
1755 jv[jss::Account] = alice.
human();
1756 jv[sfNFTokenBrokerFee.fieldName] =
1758 test(jv, sfNFTokenBrokerFee.fieldName);
1763 jv[jss::TransactionType] = jss::NFTokenMint;
1764 jv[jss::Account] = alice.
human();
1765 jv[sfNFTokenTaxon.fieldName] = 1;
1767 test(jv, jss::Amount.c_str());
1770 auto trustSet = [&](
SField const& field) {
1772 jv[jss::TransactionType] = jss::TrustSet;
1773 jv[jss::Account] = alice.
human();
1776 test(jv, field.fieldName);
1778 trustSet(sfLimitAmount);
1783 test(jv, jss::Amount.c_str());
1788 test(jv, jss::Amount.c_str());
1794 test(jv, sfSignatureReward.fieldName);
1808 test(jv, jss::Amount.c_str());
1823 for (
auto const& field :
1824 {sfAmount.fieldName, sfSignatureReward.fieldName})
1833 alice, jvb, alice, mpt,
XRP(10));
1834 for (
auto const& field :
1835 {sfAmount.fieldName, sfSignatureReward.fieldName})
1847 jv[jss::TransactionType] = tt;
1848 jv[jss::Account] = alice.
human();
1849 jv[sfXChainBridge.fieldName] = jvb;
1850 jv[sfSignatureReward.fieldName] =
1852 jv[sfMinAccountCreateAmount.fieldName] =
1856 auto reward =
STAmount{sfSignatureReward, mpt};
1857 auto minAmount =
STAmount{sfMinAccountCreateAmount, USD(10)};
1858 for (
SField const& field :
1860 std::ref(sfMinAccountCreateAmount)})
1863 jss::XChainCreateBridge,
1868 jss::XChainModifyBridge,
1872 reward =
STAmount{sfSignatureReward, USD(10)};
1873 minAmount =
STAmount{sfMinAccountCreateAmount, mpt};
1876 BEAST_EXPECT(txWithAmounts.
empty());
1883 testcase(
"Test synthetic fields from tx response");
1885 using namespace test::jtx;
1890 cfg->FEES.reference_fee = 10;
1891 Env env{*
this, std::move(cfg), features};
1900 "E11F0E0CA14219922B7881F060B9CEE67CFBC87E4049A441ED2AE348FF8FAC"
1903 Json::Value const meta = env.rpc(
"tx", txHash)[jss::result][jss::meta];
1904 auto const id = meta[jss::mpt_issuance_id].
asString();
1906 BEAST_EXPECT(meta.
isMember(jss::mpt_issuance_id));
1909 id ==
"00000004AE123A8556F3CF91154711376AFB0F894F832B3D",
id);
1915 testcase(
"MPT clawback validations");
1916 using namespace test::jtx;
1920 Env env(*
this, features - featureMPTokensV1);
1924 env.
fund(
XRP(1000), alice, bob);
1927 auto const USD = alice[
"USD"];
1943 Env env(*
this, features);
1947 env.
fund(
XRP(1000), alice, bob);
1950 auto const USD = alice[
"USD"];
1977 Env env(*
this, features);
1981 MPTTester mptAlice(env, alice, {.holders = {bob}});
1989 mptAlice.create({.ownerCount = 1, .holderCount = 0});
1991 mptAlice.authorize({.account = bob});
1993 mptAlice.pay(alice, bob, 100);
2002 Env env(*
this, features);
2008 MPTTester mptAlice(env, alice, {.holders = {bob}});
2025 mptAlice.authorize({.account = bob});
2031 mptAlice.pay(alice, bob, 100);
2042 Env env(*
this, features);
2046 env.
fund(
XRP(1000), alice, bob);
2055 jv1[jss::secret] = alice.name();
2056 jv1[jss::tx_json] = jv;
2057 auto const jrr = env.
rpc(
"json",
"submit",
to_string(jv1));
2058 BEAST_EXPECT(jrr[jss::result][jss::error] ==
"invalidParams");
2066 using namespace test::jtx;
2069 Env env(*
this, features);
2073 MPTTester mptAlice(env, alice, {.holders = {bob}});
2080 mptAlice.authorize({.account = bob});
2083 mptAlice.pay(alice, bob, 100);
2085 mptAlice.claw(alice, bob, 1);
2087 mptAlice.claw(alice, bob, 1000);
2095 Env env(*
this, features);
2099 MPTTester mptAlice(env, alice, {.holders = {bob}});
2108 mptAlice.authorize({.account = bob});
2111 mptAlice.pay(alice, bob, 100);
2113 mptAlice.set({.account = alice, .flags =
tfMPTLock});
2115 mptAlice.claw(alice, bob, 100);
2120 Env env(*
this, features);
2124 MPTTester mptAlice(env, alice, {.holders = {bob}});
2133 mptAlice.authorize({.account = bob});
2136 mptAlice.pay(alice, bob, 100);
2138 mptAlice.set({.account = alice, .holder = bob, .flags =
tfMPTLock});
2140 mptAlice.claw(alice, bob, 100);
2145 Env env(*
this, features);
2149 MPTTester mptAlice(env, alice, {.holders = {bob}});
2158 mptAlice.authorize({.account = bob});
2161 mptAlice.authorize({.account = alice, .holder = bob});
2164 mptAlice.pay(alice, bob, 100);
2170 mptAlice.claw(alice, bob, 100);
2177 using namespace test::jtx;
2191 Asset const assetMpt1Gw1{mpt1};
2192 Asset const assetMpt1Gw1a{mpt1a};
2193 Asset const assetMpt1Gw2{mpt2};
2194 Asset const assetMpt2Gw2{mpt3};
2198 BEAST_EXPECT(
equalTokens(assetCur1Gw1, assetCur1Gw1a));
2199 BEAST_EXPECT(
equalTokens(assetCur2Gw1, assetCur2Gw2));
2202 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw1));
2203 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetCur2Gw2));
2207 BEAST_EXPECT(
equalTokens(assetMpt1Gw1, assetMpt1Gw1a));
2209 BEAST_EXPECT(!
equalTokens(assetMpt1Gw1, assetMpt1Gw2));
2210 BEAST_EXPECT(!
equalTokens(assetMpt1Gw2, assetMpt2Gw2));
2213 BEAST_EXPECT(!
equalTokens(assetCur1Gw1, assetMpt1Gw1));
2214 BEAST_EXPECT(!
equalTokens(assetMpt2Gw2, assetCur2Gw2));
2220 using namespace test::jtx;
2227 STAmount const amt3{asset3, 10'000};
2230 testcase(
"Test STAmount MPT arithmetics");
2231 using namespace std::string_literals;
2233 BEAST_EXPECT(res == amt3);
2235 res =
mulRound(amt1, amt2, asset3,
true);
2236 BEAST_EXPECT(res == amt3);
2239 BEAST_EXPECT(res == amt3);
2242 STAmount mptOverflow{asset2, UINT64_C(3037000500)};
2245 res =
multiply(mptOverflow, mptOverflow, asset3);
2246 fail(
"should throw runtime exception 1");
2250 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2253 mptOverflow =
STAmount{asset2, UINT64_C(2147483648)};
2254 uint64_t
const mantissa = (2ull << 32) + 2;
2258 fail(
"should throw runtime exception 2");
2262 BEAST_EXPECTS(e.
what() ==
"MPT value overflow"s, e.
what());
2267 testcase(
"Test MPTAmount arithmetics");
2270 BEAST_EXPECT((mptAmt1 += mptAmt2) ==
MPTAmount{200});
2271 BEAST_EXPECT(mptAmt1 == 200);
2272 BEAST_EXPECT((mptAmt1 -= mptAmt2) == mptAmt1);
2273 BEAST_EXPECT(mptAmt1 == mptAmt2);
2274 BEAST_EXPECT(mptAmt1 == 100);
2279 testcase(
"Test MPTIssue from/to Json");
2288 testcase(
"Test Asset from/to Json");
2294 "{\"mpt_issuance_id\":"
2295 "\"00000001A407AF5856CCF3C42619DAA925813FC955C72983\"}");
2304 using namespace test::jtx;
2352BEAST_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.