20#include <test/jtx/AMM.h>
21#include <test/jtx/AMMTest.h>
22#include <test/jtx/Account.h>
23#include <test/jtx/Env.h>
24#include <test/jtx/amount.h>
25#include <test/jtx/credentials.h>
26#include <test/jtx/fee.h>
27#include <test/jtx/flags.h>
28#include <test/jtx/mpt.h>
29#include <test/jtx/permissioned_domains.h>
30#include <test/jtx/utility.h>
31#include <test/jtx/vault.h>
33#include <xrpld/ledger/View.h>
35#include <xrpl/basics/base_uint.h>
36#include <xrpl/beast/unit_test/suite.h>
37#include <xrpl/json/json_forwards.h>
38#include <xrpl/json/json_value.h>
39#include <xrpl/protocol/AccountID.h>
40#include <xrpl/protocol/Asset.h>
41#include <xrpl/protocol/Feature.h>
42#include <xrpl/protocol/Indexes.h>
43#include <xrpl/protocol/Issue.h>
44#include <xrpl/protocol/MPTIssue.h>
45#include <xrpl/protocol/Protocol.h>
46#include <xrpl/protocol/SField.h>
47#include <xrpl/protocol/STAmount.h>
48#include <xrpl/protocol/STNumber.h>
49#include <xrpl/protocol/TER.h>
50#include <xrpl/protocol/TxFlags.h>
51#include <xrpl/protocol/XRPAmount.h>
52#include <xrpl/protocol/jss.h>
69 using namespace test::jtx;
71 auto const testSequence = [
this](
74 Account
const& issuer,
76 Account
const& depositor,
77 Account
const& charlie,
80 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
81 tx[sfData] =
"AFEED00E";
82 tx[sfAssetsMaximum] = asset(100).number();
85 BEAST_EXPECT(env.le(keylet));
87 auto const share = [&env, keylet = keylet,
this]() ->
PrettyAsset {
88 auto const vault = env.le(keylet);
89 BEAST_EXPECT(vault !=
nullptr);
90 return MPTIssue(vault->at(sfShareMPTID));
94 Account alice{
"alice"};
97 env.fund(XRP(1000), alice, dave, erin);
103 testcase(prefix +
" fail to deposit more than assets held");
104 auto tx = vault.deposit(
105 {.depositor = depositor,
107 .amount = asset(10000)});
112 testcase(prefix +
" deposit non-zero amount");
113 auto tx = vault.deposit(
114 {.depositor = depositor,
116 .amount = asset(50)});
121 testcase(prefix +
" deposit non-zero amount again");
122 auto tx = vault.deposit(
123 {.depositor = depositor,
125 .amount = asset(50)});
130 testcase(prefix +
" fail to delete non-empty vault");
131 auto tx = vault.del({.owner = owner, .id = keylet.
key});
136 testcase(prefix +
" fail to update because wrong owner");
137 auto tx = vault.set({.owner = issuer, .id = keylet.
key});
138 tx[sfAssetsMaximum] = asset(50).number();
144 prefix +
" fail to set maximum lower than current amount");
145 auto tx = vault.set({.owner = owner, .id = keylet.
key});
146 tx[sfAssetsMaximum] = asset(50).number();
151 testcase(prefix +
" set maximum higher than current amount");
152 auto tx = vault.set({.owner = owner, .id = keylet.
key});
153 tx[sfAssetsMaximum] = asset(150).number();
159 auto tx = vault.set({.owner = owner, .id = keylet.
key});
165 testcase(prefix +
" fail to set domain on public vault");
166 auto tx = vault.set({.owner = owner, .id = keylet.
key});
172 testcase(prefix +
" fail to deposit more than maximum");
173 auto tx = vault.deposit(
174 {.depositor = depositor,
176 .amount = asset(100)});
181 testcase(prefix +
" reset maximum to zero i.e. not enforced");
182 auto tx = vault.set({.owner = owner, .id = keylet.
key});
183 tx[sfAssetsMaximum] = asset(0).number();
188 testcase(prefix +
" fail to withdraw more than assets held");
189 auto tx = vault.withdraw(
190 {.depositor = depositor,
192 .amount = asset(1000)});
197 testcase(prefix +
" deposit some more");
198 auto tx = vault.deposit(
199 {.depositor = depositor,
201 .amount = asset(100)});
206 testcase(prefix +
" clawback some");
209 auto tx = vault.clawback(
213 .amount = asset(10)});
221 auto tx = vault.clawback(
222 {.issuer = issuer, .id = keylet.
key, .holder = depositor});
226 if (!asset.raw().native())
228 testcase(prefix +
" deposit again");
229 auto tx = vault.deposit(
230 {.depositor = depositor,
232 .amount = asset(200)});
238 prefix +
" fail to withdraw to 3rd party lsfDepositAuth");
239 auto tx = vault.withdraw(
240 {.depositor = depositor,
242 .amount = asset(100)});
243 tx[sfDestination] = alice.human();
247 if (!asset.raw().native())
250 prefix +
" fail to withdraw to 3rd party no authorization");
251 auto tx = vault.withdraw(
252 {.depositor = depositor,
254 .amount = asset(100)});
255 tx[sfDestination] = erin.human();
260 if (!asset.raw().native() && asset.raw().holds<
Issue>())
262 testcase(prefix +
" temporary authorization for 3rd party");
263 env(trust(erin, asset(1000)));
264 env(trust(issuer, asset(0), erin,
tfSetfAuth));
265 env(pay(issuer, erin, asset(10)));
268 auto tx = vault.deposit(
269 {.depositor = erin, .id = keylet.
key, .amount = asset(10)});
271 env(pay(erin, depositor, share(10)));
273 testcase(prefix +
" withdraw to authorized 3rd party");
276 {.depositor = depositor,
278 .amount = asset(10)});
279 tx[sfDestination] = erin.human();
282 env(pay(erin, issuer, asset(10)));
284 testcase(prefix +
" fail to pay to unauthorized 3rd party");
285 env(trust(erin, asset(0)));
287 env(pay(depositor, erin, share(1)), ter{
tecNO_LINE});
293 " fail to withdraw to 3rd party lsfRequireDestTag");
294 auto tx = vault.withdraw(
295 {.depositor = depositor,
297 .amount = asset(100)});
298 tx[sfDestination] = dave.human();
303 testcase(prefix +
" withdraw to authorized 3rd party");
304 auto tx = vault.withdraw(
305 {.depositor = depositor,
307 .amount = asset(100)});
308 tx[sfDestination] = charlie.human();
313 testcase(prefix +
" withdraw to issuer");
314 auto tx = vault.withdraw(
315 {.depositor = depositor,
317 .amount = asset(50)});
318 tx[sfDestination] = issuer.human();
323 testcase(prefix +
" withdraw remaining assets");
324 auto tx = vault.withdraw(
325 {.depositor = depositor,
327 .amount = asset(50)});
332 testcase(prefix +
" fail to delete because wrong owner");
333 auto tx = vault.del({.owner = issuer, .id = keylet.
key});
338 testcase(prefix +
" delete empty vault");
339 auto tx = vault.del({.owner = owner, .id = keylet.
key});
341 BEAST_EXPECT(!env.le(keylet));
345 auto testCases = [
this, &testSequence](
349 Account
const& issuer,
350 Account
const& owner,
351 Account
const& depositor,
352 Account
const& charlie)> setup) {
353 Env env{*
this, supported_amendments() | featureSingleAssetVault};
354 Account issuer{
"issuer"};
355 Account owner{
"owner"};
356 Account depositor{
"depositor"};
357 Account charlie{
"charlie"};
359 env.fund(XRP(1000), issuer, owner, depositor, charlie);
367 PrettyAsset asset = setup(env, issuer, owner, depositor, charlie);
369 prefix, env, issuer, owner, depositor, charlie, vault, asset);
375 Account
const& issuer,
376 Account
const& owner,
377 Account
const& depositor,
385 Account
const& issuer,
386 Account
const& owner,
387 Account
const& depositor,
388 Account
const& charlie) ->
Asset {
390 env(trust(owner, asset(1000)));
391 env(trust(depositor, asset(1000)));
392 env(trust(charlie, asset(1000)));
393 env(trust(issuer, asset(0), owner,
tfSetfAuth));
394 env(trust(issuer, asset(0), depositor,
tfSetfAuth));
395 env(trust(issuer, asset(0), charlie,
tfSetfAuth));
396 env(pay(issuer, depositor, asset(1000)));
404 Account
const& issuer,
405 Account
const& owner,
406 Account
const& depositor,
407 Account
const& charlie) ->
Asset {
408 MPTTester mptt{env, issuer, mptInitNoFund};
413 mptt.authorize({.account = depositor});
414 mptt.authorize({.account = charlie});
415 env(pay(issuer, depositor, asset(1000)));
424 using namespace test::jtx;
429 supported_amendments() | featureSingleAssetVault;
432 auto testCase = [&,
this](
435 Account
const& issuer,
436 Account
const& owner,
439 CaseArgs args = {}) {
440 Env env{*
this, args.features};
441 Account issuer{
"issuer"};
442 Account owner{
"owner"};
444 env.fund(XRP(1000), issuer, owner);
452 env(trust(owner, asset(1000)));
453 env(trust(issuer, asset(0), owner,
tfSetfAuth));
454 env(pay(issuer, owner, asset(1000)));
457 test(env, issuer, owner, asset, vault);
462 Account
const& issuer,
463 Account
const& owner,
466 testcase(
"disabled single asset vault");
469 vault.create({.owner = owner, .asset = asset});
473 auto tx = vault.set({.owner = owner, .id = keylet.
key});
478 auto tx = vault.deposit(
481 .amount = asset(10)});
486 auto tx = vault.withdraw(
489 .amount = asset(10)});
494 auto tx = vault.clawback(
498 .amount = asset(10)});
503 auto tx = vault.del({.owner = owner, .id = keylet.
key});
507 {.features = supported_amendments() - featureSingleAssetVault});
509 testCase([&](Env& env,
510 Account
const& issuer,
511 Account
const& owner,
516 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
521 auto tx = vault.set({.owner = owner, .id = keylet.
key});
527 auto tx = vault.deposit(
530 .amount = asset(10)});
536 auto tx = vault.withdraw(
539 .amount = asset(10)});
545 auto tx = vault.clawback(
549 .amount = asset(10)});
555 auto tx = vault.del({.owner = owner, .id = keylet.
key});
561 testCase([&](Env& env,
562 Account
const& issuer,
563 Account
const& owner,
568 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
573 auto tx = vault.set({.owner = owner, .id = keylet.
key});
579 auto tx = vault.deposit(
582 .amount = asset(10)});
588 auto tx = vault.withdraw(
591 .amount = asset(10)});
597 auto tx = vault.clawback(
601 .amount = asset(10)});
607 auto tx = vault.del({.owner = owner, .id = keylet.
key});
616 Account
const& owner,
619 testcase(
"disabled permissioned domain");
622 vault.create({.owner = owner, .asset =
xrpIssue()});
627 auto tx = vault.set({.owner = owner, .id = keylet.
key});
633 auto tx = vault.set({.owner = owner, .id = keylet.
key});
634 tx[sfDomainID] =
"0";
638 {.features = (supported_amendments() | featureSingleAssetVault) -
639 featurePermissionedDomains});
641 testCase([&](Env& env,
642 Account
const& issuer,
643 Account
const& owner,
649 vault.create({.owner = owner, .asset =
xrpIssue()});
652 auto tx = vault.set({
660 auto tx = vault.deposit(
663 .amount = asset(10)});
668 auto tx = vault.withdraw(
671 .amount = asset(10)});
676 auto tx = vault.clawback(
680 .amount = asset(10)});
685 auto tx = vault.del({
693 testCase([&](Env& env,
694 Account
const& issuer,
695 Account
const& owner,
700 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
703 auto tx = vault.clawback(
707 .amount = asset(10)});
712 testCase([&](Env& env,
714 Account
const& owner,
717 testcase(
"withdraw to bad destination");
719 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
722 auto tx = vault.withdraw(
725 .amount = asset(10)});
726 tx[jss::Destination] =
"0";
731 testCase([&](Env& env,
733 Account
const& owner,
736 testcase(
"create or set invalid data");
738 auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset});
754 auto tx = vault.set({.owner = owner, .id = keylet.
key});
760 auto tx = vault.set({.owner = owner, .id = keylet.
key});
767 testCase([&](Env& env,
769 Account
const& owner,
774 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
777 auto tx = vault.set({.owner = owner, .id = keylet.
key});
782 testCase([&](Env& env,
784 Account
const& owner,
787 testcase(
"create with invalid metadata");
789 auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset});
793 tx[sfMPTokenMetadata] =
"";
806 testCase([&](Env& env,
808 Account
const& owner,
813 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
816 auto tx = vault.set({.owner = owner, .id = keylet.
key});
822 testCase([&](Env& env,
824 Account
const& owner,
829 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
832 auto tx = vault.deposit(
840 auto tx = vault.deposit(
841 {.depositor = owner, .id = keylet.
key, .amount = asset(0)});
846 testCase([&](Env& env,
848 Account
const& owner,
851 testcase(
"invalid set immutable flag");
853 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
856 auto tx = vault.set({.owner = owner, .id = keylet.
key});
862 testCase([&](Env& env,
864 Account
const& owner,
867 testcase(
"invalid withdraw amount");
869 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
872 auto tx = vault.withdraw(
880 auto tx = vault.withdraw(
881 {.depositor = owner, .id = keylet.
key, .amount = asset(0)});
886 testCase([&](Env& env,
887 Account
const& issuer,
888 Account
const& owner,
893 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
896 auto tx = vault.clawback(
900 .amount = asset(50)});
905 auto tx = vault.clawback(
914 testCase([&](Env& env,
916 Account
const& owner,
921 auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset});
925 tx[sfWithdrawalPolicy] = 0;
944 tx[sfDomainID] =
"0";
954 using namespace test::jtx;
958 Account
const& issuer,
959 Account
const& owner,
960 Account
const& depositor,
962 Vault& vault)> test) {
963 Env env{*
this, supported_amendments() | featureSingleAssetVault};
964 Account issuer{
"issuer"};
965 Account owner{
"owner"};
966 Account depositor{
"depositor"};
967 env.fund(XRP(1000), issuer, owner, depositor);
972 test(env, issuer, owner, depositor, asset, vault);
977 Account
const& issuer,
978 Account
const& owner,
979 Account
const& depositor,
984 tx[sfAssetsMaximum] = asset(0).number();
990 Account
const& issuer,
991 Account
const& owner,
992 Account
const& depositor,
996 auto tx = vault.deposit(
997 {.depositor = depositor,
999 .amount = asset(10)});
1005 Account
const& issuer,
1006 Account
const& owner,
1007 Account
const& depositor,
1010 testcase(
"nothing to withdraw from");
1011 auto tx = vault.withdraw(
1012 {.depositor = depositor,
1014 .amount = asset(10)});
1020 Account
const& issuer,
1021 Account
const& owner,
1022 Account
const& depositor,
1032 Account
const& issuer,
1033 Account
const& owner,
1034 Account
const& depositor,
1037 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1044 Account
const& issuer,
1045 Account
const& owner,
1046 Account
const& depositor,
1049 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1050 tx[sfWithdrawalPolicy] = 1;
1051 testcase(
"explicitly select withdrawal policy");
1057 Account
const& issuer,
1058 Account
const& owner,
1059 Account
const& depositor,
1062 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1069 Account
const& issuer,
1070 Account
const& owner,
1071 Account
const& depositor,
1074 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1078 env(pay(owner, issuer, XRP(775)));
1085 Account
const& issuer,
1086 Account
const& owner,
1087 Account
const& depositor,
1090 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1101 using namespace test::jtx;
1104 testcase(
"IOU fail create frozen");
1106 *
this, supported_amendments() | featureSingleAssetVault};
1107 Account issuer{
"issuer"};
1108 Account owner{
"owner"};
1109 env.fund(XRP(1000), issuer, owner);
1115 Asset asset = issuer[
"IOU"];
1117 vault.create({.owner = owner, .asset = asset});
1124 testcase(
"IOU fail create no ripling");
1126 *
this, supported_amendments() | featureSingleAssetVault};
1127 Account issuer{
"issuer"};
1128 Account owner{
"owner"};
1129 env.fund(XRP(1000), issuer, owner);
1135 Asset asset = issuer[
"IOU"];
1137 vault.create({.owner = owner, .asset = asset});
1145 *
this, supported_amendments() | featureSingleAssetVault};
1146 Account issuer{
"issuer"};
1147 Account owner{
"owner"};
1148 env.fund(XRP(1000), owner);
1152 Asset asset = issuer[
"IOU"];
1155 vault.create({.owner = owner, .asset = asset});
1163 testcase(
"IOU fail create vault for AMM LPToken");
1164 Env env{*
this, supported_amendments() | featureSingleAssetVault};
1165 Account
const gw(
"gateway");
1166 Account
const alice(
"alice");
1167 Account
const carol(
"carol");
1168 IOU
const USD = gw[
"USD"];
1170 auto const [asset1, asset2] =
1175 auto const defXRP = XRP(30000);
1178 return a + XRP(1000);
1185 auto const toFund1 = tofund(asset1);
1186 auto const toFund2 = tofund(asset2);
1187 BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2);
1189 if (!asset1.native() && !asset2.native())
1190 fund(env, gw, {alice, carol}, {toFund1, toFund2}, Fund::All);
1191 else if (asset1.native())
1192 fund(env, gw, {alice, carol}, toFund1, {toFund2}, Fund::All);
1193 else if (asset2.native())
1194 fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All);
1197 env, alice, asset1, asset2, CreateArg{.log =
false, .tfee = 0});
1199 Account
const owner{
"owner"};
1200 env.fund(XRP(1000000), owner);
1204 vault.create({.owner = owner, .asset = ammAlice.lptIssue()});
1213 using namespace test::jtx;
1215 Env env{*
this, supported_amendments() | featureSingleAssetVault};
1216 Account issuer{
"issuer"};
1217 Account owner{
"owner"};
1218 Account depositor{
"depositor"};
1219 env.fund(XRP(1000), issuer, owner, depositor);
1223 MPTTester mptt{env, issuer, mptInitNoFund};
1227 Asset asset = mptt.issuanceID();
1228 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1235 using namespace test::jtx;
1237 Env env{*
this, supported_amendments() | featureSingleAssetVault};
1238 Account issuer{
"issuer"};
1239 Account owner{
"owner"};
1240 Account depositor{
"depositor"};
1241 env.fund(XRP(1000), issuer, owner, depositor);
1246 env.trust(asset(1000), owner);
1247 env(pay(issuer, owner, asset(100)));
1248 env.trust(asset(1000), depositor);
1249 env(pay(issuer, depositor, asset(100)));
1252 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1258 testcase(
"nontransferable deposits");
1259 auto tx1 = vault.deposit(
1260 {.depositor = depositor,
1262 .amount = asset(40)});
1265 auto tx2 = vault.deposit(
1266 {.depositor = owner, .id = keylet.
key, .amount = asset(60)});
1271 auto const vaultAccount =
1273 auto jvVault = env.rpc(
"vault_info",
strHex(key));
1276 jvVault[jss::result][jss::vault][sfAssetsTotal] ==
"100");
1278 jvVault[jss::result][jss::vault][jss::shares]
1279 [sfOutstandingAmount] ==
"100");
1282 return parseBase58<AccountID>(
1283 jvVault[jss::result][jss::vault][jss::Account]
1288 auto const MptID =
makeMptID(1, vaultAccount);
1289 Asset shares = MptID;
1292 testcase(
"nontransferable shares cannot be moved");
1293 env(pay(owner, depositor, shares(10)), ter{
tecNO_AUTH});
1294 env(pay(depositor, owner, shares(10)), ter{
tecNO_AUTH});
1298 testcase(
"nontransferable shares can be used to withdraw");
1299 auto tx1 = vault.withdraw(
1300 {.depositor = depositor,
1302 .amount = asset(20)});
1305 auto tx2 = vault.withdraw(
1306 {.depositor = owner, .id = keylet.
key, .amount = asset(30)});
1312 testcase(
"nontransferable shares balance check");
1313 auto jvVault = env.rpc(
"vault_info",
strHex(keylet.
key));
1315 jvVault[jss::result][jss::vault][sfAssetsTotal] ==
"50");
1317 jvVault[jss::result][jss::vault][jss::shares]
1318 [sfOutstandingAmount] ==
"50");
1322 testcase(
"nontransferable shares withdraw rest");
1323 auto tx1 = vault.withdraw(
1324 {.depositor = depositor,
1326 .amount = asset(20)});
1329 auto tx2 = vault.withdraw(
1330 {.depositor = owner, .id = keylet.
key, .amount = asset(30)});
1336 testcase(
"nontransferable shares delete empty vault");
1337 auto tx = vault.del({.owner = owner, .id = keylet.
key});
1339 BEAST_EXPECT(!env.le(keylet));
1346 using namespace test::jtx;
1350 bool enableClawback =
true;
1353 auto testCase = [
this](
1356 Account
const& issuer,
1357 Account
const& owner,
1358 Account
const& depositor,
1361 MPTTester& mptt)> test,
1362 CaseArgs args = {}) {
1363 Env env{*
this, supported_amendments() | featureSingleAssetVault};
1364 Account issuer{
"issuer"};
1365 Account owner{
"owner"};
1366 Account depositor{
"depositor"};
1367 env.fund(XRP(1000), issuer, owner, depositor);
1371 MPTTester mptt{env, issuer, mptInitNoFund};
1378 mptt.authorize({.account = owner});
1379 mptt.authorize({.account = issuer, .holder = owner});
1380 mptt.authorize({.account = depositor});
1381 mptt.authorize({.account = issuer, .holder = depositor});
1382 env(pay(issuer, depositor, asset(1000)));
1385 test(env, issuer, owner, depositor, asset, vault, mptt);
1390 Account
const& issuer,
1391 Account
const& owner,
1392 Account
const& depositor,
1396 testcase(
"MPT nothing to clawback from");
1397 auto tx = vault.clawback(
1400 .holder = depositor,
1401 .amount = asset(10)});
1407 Account
const& issuer,
1408 Account
const& owner,
1409 Account
const& depositor,
1413 testcase(
"MPT global lock blocks create");
1414 mptt.set({.account = issuer, .flags =
tfMPTLock});
1415 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1421 Account
const& issuer,
1422 Account
const& owner,
1423 Account
const& depositor,
1427 testcase(
"MPT global lock blocks deposit");
1428 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1432 mptt.set({.account = issuer, .flags =
tfMPTLock});
1436 {.depositor = depositor,
1438 .amount = asset(100)});
1443 tx = vault.del({.owner = owner, .id = keylet.
key});
1449 Account
const& issuer,
1450 Account
const& owner,
1451 Account
const& depositor,
1455 testcase(
"MPT global lock blocks withdrawal");
1456 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1460 {.depositor = depositor,
1462 .amount = asset(100)});
1468 auto v = env.le(keylet);
1470 MPTID share = (*v)[sfShareMPTID];
1472 BEAST_EXPECT(issuance);
1473 Number outstandingShares = issuance->at(sfOutstandingAmount);
1474 BEAST_EXPECT(outstandingShares == 100);
1476 mptt.set({.account = issuer, .flags =
tfMPTLock});
1479 tx = vault.withdraw(
1480 {.depositor = depositor,
1482 .amount = asset(100)});
1485 tx[sfDestination] = issuer.human();
1489 tx = vault.clawback(
1492 .holder = depositor,
1493 .amount = asset(0)});
1498 tx = vault.del({.owner = owner, .id = keylet.
key});
1504 Account
const& issuer,
1505 Account
const& owner,
1506 Account
const& depositor,
1510 testcase(
"MPT only issuer can clawback");
1512 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1517 {.depositor = depositor,
1519 .amount = asset(100)});
1524 auto tx = vault.clawback(
1525 {.issuer = owner, .id = keylet.
key, .holder = depositor});
1532 Account
const& issuer,
1533 Account
const& owner,
1534 Account
const& depositor,
1540 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1545 {.depositor = depositor,
1547 .amount = asset(1000)});
1552 auto tx = vault.clawback(
1555 .holder = depositor,
1556 .amount = asset(0)});
1560 mptt.destroy({.issuer = issuer, .id = mptt.issuanceID()});
1565 vault.create({.owner = depositor, .asset = asset});
1570 auto tx = vault.deposit(
1571 {.depositor = depositor,
1573 .amount = asset(10)});
1578 auto tx = vault.withdraw(
1579 {.depositor = depositor,
1581 .amount = asset(10)});
1586 auto tx = vault.clawback(
1589 .holder = depositor,
1590 .amount = asset(0)});
1594 env(vault.del({.owner = owner, .id = keylet.key}));
1600 Account
const& issuer,
1601 Account
const& owner,
1602 Account
const& depositor,
1609 vault.create({.owner = owner, .asset = asset});
1614 {.depositor = depositor,
1616 .amount = asset(1000)});
1621 auto tx = vault.clawback(
1624 .holder = depositor,
1625 .amount = asset(0)});
1629 {.enableClawback =
false});
1633 Account
const& issuer,
1634 Account
const& owner,
1635 Account
const& depositor,
1640 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1644 {.depositor = depositor,
1646 .amount = asset(1000)});
1652 .holder = depositor,
1657 auto tx = vault.withdraw(
1658 {.depositor = depositor,
1660 .amount = asset(100)});
1664 tx[sfDestination] = issuer.human();
1666 tx[sfDestination] = owner.human();
1673 auto tx = vault.deposit(
1674 {.depositor = depositor,
1676 .amount = asset(100)});
1681 tx = vault.clawback(
1684 .holder = depositor,
1685 .amount = asset(800)});
1688 env(vault.del({.owner = owner, .id = keylet.key}));
1693 Account
const& issuer,
1694 Account
const& owner,
1695 Account
const& depositor,
1699 testcase(
"MPT lock of vault pseudo-account");
1700 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1704 auto const vaultAccount =
1705 [&env, keylet = keylet,
this]() ->
AccountID {
1706 auto const vault = env.le(keylet);
1707 BEAST_EXPECT(vault !=
nullptr);
1708 return vault->at(sfAccount);
1712 {.depositor = depositor,
1714 .amount = asset(100)});
1720 jv[jss::Account] = issuer.human();
1721 jv[sfMPTokenIssuanceID] =
1723 jv[jss::Holder] =
toBase58(vaultAccount);
1724 jv[jss::TransactionType] = jss::MPTokenIssuanceSet;
1732 {.depositor = depositor,
1734 .amount = asset(100)});
1737 tx = vault.withdraw(
1738 {.depositor = depositor,
1740 .amount = asset(100)});
1744 tx = vault.clawback(
1747 .holder = depositor,
1748 .amount = asset(100)});
1752 tx = vault.del({.owner = owner, .id = keylet.
key});
1759 Env env{*
this, supported_amendments() | featureSingleAssetVault};
1760 Account owner{
"owner"};
1761 Account issuer{
"issuer"};
1762 env.fund(XRP(1000000), owner, issuer);
1766 MPTTester mptt{env, issuer, mptInitNoFund};
1770 mptt.authorize({.account = owner});
1771 mptt.authorize({.account = issuer, .holder = owner});
1773 env(pay(issuer, owner, asset(100)));
1774 auto [tx1, k1] = vault.create({.owner = owner, .asset = asset});
1778 auto const shares = [&env, keylet = k1,
this]() ->
Asset {
1779 auto const vault = env.le(keylet);
1780 BEAST_EXPECT(vault !=
nullptr);
1781 return MPTIssue(vault->at(sfShareMPTID));
1784 auto [tx2, k2] = vault.create({.owner = owner, .asset = shares});
1793 using namespace test::jtx;
1799 Account
const& owner,
1800 Account
const& issuer,
1801 Account
const& charlie,
1809 *
this, supported_amendments() | featureSingleAssetVault};
1810 Account
const owner{
"owner"};
1811 Account
const issuer{
"issuer"};
1812 Account
const charlie{
"charlie"};
1814 env.fund(XRP(1000), issuer, owner, charlie);
1819 env.trust(asset(1000), owner);
1820 env(pay(issuer, owner, asset(200)));
1821 env(rate(issuer, 1.25));
1824 auto const [tx, keylet] =
1825 vault.create({.owner = owner, .asset = asset});
1829 auto const vaultAccount =
1831 return env.le(keylet)->at(sfAccount);
1834 return env.le(keylet)->at(sfShareMPTID);
1836 auto const vaultBalance =
1837 [&env, &vaultAccount, issue = asset.
raw().
get<
Issue>()](
1839 auto const account = vaultAccount(keylet);
1844 env.lookup(issue.account).name()};
1845 auto amount = sle->getFieldAmount(sfBalance);
1847 if (account > issue.account)
1849 return {amount, env.lookup(issue.account).name()};
1866 Account
const& owner,
1867 Account
const& issuer,
1873 testcase(
"IOU cannot use different asset");
1876 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1882 auto tx = [&, account = vaultAccount(keylet)]() {
1884 jv[jss::Account] = issuer.human();
1886 auto& ja = jv[jss::LimitAmount] =
1888 ja[jss::issuer] =
toBase58(account);
1890 jv[jss::TransactionType] = jss::TrustSet;
1899 auto tx = vault.deposit(
1900 {.depositor = issuer, .id = keylet.
key, .amount = foo(20)});
1906 auto tx = vault.withdraw(
1907 {.depositor = issuer, .id = keylet.
key, .amount = foo(20)});
1912 env(vault.del({.owner = owner, .id = keylet.key}));
1918 Account
const& owner,
1919 Account
const& issuer,
1920 Account
const& charlie,
1926 testcase(
"IOU frozen trust line to vault account");
1928 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
1933 {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
1936 Asset const share =
Asset(issuanceId(keylet));
1939 auto trustSet = [&, account = vaultAccount(keylet)]() {
1941 jv[jss::Account] = issuer.human();
1943 auto& ja = jv[jss::LimitAmount] =
1945 ja[jss::issuer] =
toBase58(account);
1947 jv[jss::TransactionType] = jss::TrustSet;
1959 auto tx = vault.deposit(
1960 {.depositor = owner,
1962 .amount = asset(80)});
1967 auto tx = vault.withdraw(
1968 {.depositor = owner,
1970 .amount = asset(100)});
1974 tx[sfDestination] = charlie.human();
1981 auto tx = vault.clawback(
1985 .amount = asset(50)});
1996 {.depositor = owner, .id = keylet.key, .amount = share(50)}));
1998 env(vault.del({.owner = owner, .id = keylet.key}));
2004 Account
const& owner,
2005 Account
const& issuer,
2006 Account
const& charlie,
2011 auto vaultBalance) {
2012 testcase(
"IOU transfer fees not applied");
2014 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
2019 {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
2023 Asset const share =
Asset(issuanceId(keylet));
2026 BEAST_EXPECT(env.balance(owner, issue) == asset(100));
2027 BEAST_EXPECT(vaultBalance(keylet) == asset(100));
2030 auto tx = vault.clawback(
2034 .amount = asset(50)});
2040 BEAST_EXPECT(env.balance(owner, issue) == asset(100));
2041 BEAST_EXPECT(vaultBalance(keylet) == asset(50));
2044 {.depositor = owner, .id = keylet.key, .amount = share(20)}));
2047 BEAST_EXPECT(env.balance(owner, issue) == asset(120));
2048 BEAST_EXPECT(vaultBalance(keylet) == asset(30));
2051 auto tx = vault.withdraw(
2052 {.depositor = owner,
2054 .amount = share(30)});
2055 tx[sfDestination] = charlie.human();
2060 BEAST_EXPECT(env.balance(owner, issue) == asset(120));
2061 BEAST_EXPECT(env.balance(charlie, issue) == asset(30));
2062 BEAST_EXPECT(vaultBalance(keylet) == asset(0));
2064 env(vault.del({.owner = owner, .id = keylet.key}));
2070 Account
const& owner,
2071 Account
const& issuer,
2072 Account
const& charlie,
2077 testcase(
"IOU frozen trust line to depositor");
2079 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
2084 {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
2089 auto tx = vault.withdraw(
2090 {.depositor = owner,
2092 .amount = asset(10)});
2093 tx[sfDestination] = charlie.human();
2096 env(withdrawToCharlie);
2103 auto const withdraw = vault.withdraw(
2104 {.depositor = owner, .id = keylet.
key, .amount = asset(10)});
2113 auto tx = vault.deposit(
2114 {.depositor = owner,
2116 .amount = asset(10)});
2122 auto tx = vault.clawback(
2126 .amount = asset(0)});
2131 env(vault.del({.owner = owner, .id = keylet.key}));
2137 Account
const& owner,
2138 Account
const& issuer,
2139 Account
const& charlie,
2144 testcase(
"IOU frozen trust line to 3rd party");
2146 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
2151 {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
2156 auto tx = vault.withdraw(
2157 {.depositor = owner,
2159 .amount = asset(10)});
2160 tx[sfDestination] = charlie.human();
2163 env(withdrawToCharlie);
2166 env(trust(issuer, asset(0), charlie,
tfSetFreeze));
2170 auto const withdraw = vault.withdraw(
2171 {.depositor = owner, .id = keylet.
key, .amount = asset(10)});
2183 .amount = asset(0)}));
2186 env(vault.del({.owner = owner, .id = keylet.key}));
2192 Account
const& owner,
2193 Account
const& issuer,
2194 Account
const& charlie,
2201 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
2206 {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
2214 auto tx = vault.withdraw(
2215 {.depositor = owner,
2217 .amount = asset(10)});
2221 tx[sfDestination] = charlie.human();
2227 {.depositor = owner,
2229 .amount = asset(10)});
2239 .amount = asset(0)}));
2242 env(vault.del({.owner = owner, .id = keylet.key}));
2250 using namespace test::jtx;
2254 Env env{*
this, supported_amendments() | featureSingleAssetVault};
2255 Account issuer{
"issuer"};
2256 Account owner{
"owner"};
2257 Account depositor{
"depositor"};
2258 Account charlie{
"charlie"};
2259 Account pdOwner{
"pdOwner"};
2260 Account credIssuer1{
"credIssuer1"};
2261 Account credIssuer2{
"credIssuer2"};
2279 env.trust(asset(1000), owner);
2280 env(pay(issuer, owner, asset(500)));
2281 env.trust(asset(1000), depositor);
2282 env(pay(issuer, depositor, asset(500)));
2283 env.trust(asset(1000), charlie);
2284 env(pay(issuer, charlie, asset(5)));
2287 auto [tx, keylet] = vault.create(
2291 BEAST_EXPECT(env.le(keylet));
2294 testcase(
"private vault owner can deposit");
2295 auto tx = vault.deposit(
2296 {.depositor = owner, .id = keylet.
key, .amount = asset(50)});
2301 testcase(
"private vault depositor not authorized yet");
2302 auto tx = vault.deposit(
2303 {.depositor = depositor,
2305 .amount = asset(50)});
2310 testcase(
"private vault cannot set non-existing domain");
2311 auto tx = vault.set({.owner = owner, .id = keylet.
key});
2317 testcase(
"private vault set domainId");
2320 pdomain::Credentials
const credentials1{
2321 {.issuer = credIssuer1, .credType = credType}};
2323 env(pdomain::setTx(pdOwner, credentials1));
2324 auto const domainId1 = [&]() {
2326 return pdomain::getNewDomain(env.meta());
2329 auto tx = vault.set({.owner = owner, .id = keylet.
key});
2340 pdomain::Credentials
const credentials{
2341 {.issuer = credIssuer1, .credType = credType},
2342 {.issuer = credIssuer2, .credType = credType}};
2344 env(pdomain::setTx(pdOwner, credentials));
2345 auto const domainId = [&]() {
2347 return pdomain::getNewDomain(env.meta());
2350 auto tx = vault.set({.owner = owner, .id = keylet.
key});
2358 testcase(
"private vault depositor still not authorized");
2359 auto tx = vault.deposit(
2360 {.depositor = depositor,
2362 .amount = asset(50)});
2367 auto const credKeylet =
2368 credentials::keylet(depositor, credIssuer1, credType);
2370 testcase(
"private vault depositor now authorized");
2371 env(credentials::create(depositor, credIssuer1, credType));
2372 env(credentials::accept(depositor, credIssuer1, credType));
2373 env(credentials::create(charlie, credIssuer1, credType));
2376 auto credSle = env.le(credKeylet);
2377 BEAST_EXPECT(credSle !=
nullptr);
2379 auto tx = vault.deposit(
2380 {.depositor = depositor,
2382 .amount = asset(50)});
2387 {.depositor = charlie, .id = keylet.
key, .amount = asset(50)});
2393 testcase(
"private vault depositor lost authorization");
2394 env(credentials::deleteCred(
2395 credIssuer1, depositor, credIssuer1, credType));
2396 env(credentials::deleteCred(
2397 credIssuer1, charlie, credIssuer1, credType));
2399 auto credSle = env.le(credKeylet);
2400 BEAST_EXPECT(credSle ==
nullptr);
2402 auto tx = vault.deposit(
2403 {.depositor = depositor,
2405 .amount = asset(50)});
2410 auto const shares = [&env, keylet = keylet,
this]() ->
Asset {
2411 auto const vault = env.le(keylet);
2412 BEAST_EXPECT(vault !=
nullptr);
2413 return MPTIssue(vault->at(sfShareMPTID));
2417 testcase(
"private vault expired authorization");
2418 uint32_t
const closeTime = env.current()
2420 .parentCloseTime.time_since_epoch()
2424 credentials::create(depositor, credIssuer2, credType);
2425 tx0[sfExpiration] = closeTime + 20;
2427 tx0 = credentials::create(charlie, credIssuer2, credType);
2428 tx0[sfExpiration] = closeTime + 20;
2432 env(credentials::accept(depositor, credIssuer2, credType));
2433 env(credentials::accept(charlie, credIssuer2, credType));
2438 auto tx1 = vault.deposit(
2439 {.depositor = depositor,
2441 .amount = asset(50)});
2447 BEAST_EXPECT(env.le(tokenKeylet) !=
nullptr);
2456 auto const credsKeylet =
2457 credentials::keylet(depositor, credIssuer2, credType);
2458 BEAST_EXPECT(env.le(credsKeylet) !=
nullptr);
2460 auto tx2 = vault.deposit(
2461 {.depositor = depositor,
2463 .amount = asset(1)});
2467 BEAST_EXPECT(env.le(credsKeylet) ==
nullptr);
2471 auto const credsKeylet =
2472 credentials::keylet(charlie, credIssuer2, credType);
2473 BEAST_EXPECT(env.le(credsKeylet) !=
nullptr);
2476 BEAST_EXPECT(env.le(tokenKeylet) ==
nullptr);
2478 auto tx3 = vault.deposit(
2479 {.depositor = charlie,
2481 .amount = asset(2)});
2485 BEAST_EXPECT(env.le(credsKeylet) ==
nullptr);
2486 BEAST_EXPECT(env.le(tokenKeylet) ==
nullptr);
2491 testcase(
"private vault reset domainId");
2492 auto tx = vault.set({.owner = owner, .id = keylet.
key});
2493 tx[sfDomainID] =
"0";
2498 {.depositor = depositor,
2500 .amount = asset(50)});
2504 tx = vault.withdraw(
2505 {.depositor = depositor,
2507 .amount = asset(50)});
2510 tx = vault.clawback(
2513 .holder = depositor,
2514 .amount = asset(0)});
2517 tx = vault.clawback(
2521 .amount = asset(0)});
2535 using namespace test::jtx;
2539 Env env{*
this, supported_amendments() | featureSingleAssetVault};
2540 Account owner{
"owner"};
2541 Account depositor{
"depositor"};
2542 Account alice{
"charlie"};
2545 env.fund(XRP(100000), owner, depositor, alice);
2549 auto [tx, keylet] = vault.create(
2554 auto const [vaultAccount, issuanceId] =
2556 auto const vault = env.le(keylet);
2557 BEAST_EXPECT(vault !=
nullptr);
2558 return {vault->at(sfAccount), vault->at(sfShareMPTID)};
2565 testcase(
"private XRP vault owner can deposit");
2566 auto tx = vault.deposit(
2567 {.depositor = owner, .id = keylet.
key, .amount = asset(50)});
2572 testcase(
"private XRP vault cannot pay shares to depositor yet");
2573 env(pay(owner, depositor, shares(1)), ter{
tecNO_AUTH});
2577 testcase(
"private XRP vault depositor not authorized yet");
2578 auto tx = vault.deposit(
2579 {.depositor = depositor,
2581 .amount = asset(50)});
2586 testcase(
"private XRP vault set DomainID");
2587 pdomain::Credentials
const credentials{
2588 {.issuer = owner, .credType = credType}};
2590 env(pdomain::setTx(owner, credentials));
2591 auto const domainId = [&]() {
2593 return pdomain::getNewDomain(env.meta());
2596 auto tx = vault.set({.owner = owner, .id = keylet.
key});
2602 auto const credKeylet = credentials::keylet(depositor, owner, credType);
2604 testcase(
"private XRP vault depositor now authorized");
2605 env(credentials::create(depositor, owner, credType));
2606 env(credentials::accept(depositor, owner, credType));
2609 BEAST_EXPECT(env.le(credKeylet));
2610 auto tx = vault.deposit(
2611 {.depositor = depositor,
2613 .amount = asset(50)});
2619 testcase(
"private XRP vault can pay shares to depositor");
2620 env(pay(owner, depositor, shares(1)));
2624 testcase(
"private XRP vault cannot pay shares to 3rd party");
2626 jv[sfAccount] = alice.human();
2627 jv[sfTransactionType] = jss::MPTokenAuthorize;
2628 jv[sfMPTokenIssuanceID] =
to_string(issuanceId);
2632 env(pay(owner, alice, shares(1)), ter{
tecNO_AUTH});
2639 using namespace test::jtx;
2641 testcase(
"failed pseudo-account allocation");
2642 Env env{*
this, supported_amendments() | featureSingleAssetVault};
2643 Account
const owner{
"owner"};
2645 env.fund(XRP(1000), owner);
2647 auto const keylet =
keylet::vault(owner.id(), env.seq(owner));
2648 for (
int i = 0; i < 256; ++i)
2653 env(pay(env.master.id(), accountId, XRP(1000)),
2659 auto [tx, keylet1] =
2660 vault.create({.owner = owner, .asset =
xrpIssue()});
2661 BEAST_EXPECT(keylet.
key == keylet1.key);
2668 using namespace test::jtx;
2671 Env env{*
this, supported_amendments() | featureSingleAssetVault};
2672 Account
const owner{
"owner"};
2673 Account
const issuer{
"issuer"};
2675 env.fund(XRP(1000), issuer, owner);
2679 env.trust(asset(1000), owner);
2680 env(pay(issuer, owner, asset(200)));
2683 auto const sequence = env.seq(owner);
2684 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
2690 auto tx1 = vault.deposit(
2691 {.depositor = owner, .id = keylet.
key, .amount = asset(50)});
2694 auto tx2 = vault.set({.owner = owner, .id = keylet.
key});
2695 tx2[sfAssetsMaximum] = asset(1000).number();
2700 auto const sleVault = [&env, keylet = keylet,
this]() {
2701 auto const vault = env.le(keylet);
2702 BEAST_EXPECT(vault !=
nullptr);
2706 auto const check = [&, keylet = keylet, sle = sleVault,
this](
2709 BEAST_EXPECT(vault.isObject());
2711 constexpr auto checkString =
2713 return node.isMember(field.fieldName) &&
2714 node[field.fieldName].isString() &&
2715 node[field.fieldName] == v;
2717 constexpr auto checkObject =
2719 return node.isMember(field.fieldName) &&
2720 node[field.fieldName].isObject() &&
2721 node[field.fieldName] == v;
2723 constexpr auto checkInt =
2724 [](
auto& node,
SField const& field,
int v) ->
bool {
2725 return node.isMember(field.fieldName) &&
2726 ((node[field.fieldName].isInt() &&
2727 node[field.fieldName] ==
Json::Int(v)) ||
2728 (node[field.fieldName].isUInt() &&
2732 BEAST_EXPECT(vault[
"LedgerEntryType"].asString() ==
"Vault");
2733 BEAST_EXPECT(vault[jss::index].asString() ==
strHex(keylet.
key));
2734 BEAST_EXPECT(checkInt(vault, sfFlags, 0));
2738 checkString(vault, sfAccount,
toBase58(sle->at(sfAccount))));
2740 checkObject(vault, sfAsset,
to_json(sle->at(sfAsset))));
2741 BEAST_EXPECT(checkString(vault, sfAssetsAvailable,
"50"));
2742 BEAST_EXPECT(checkString(vault, sfAssetsMaximum,
"1000"));
2743 BEAST_EXPECT(checkString(vault, sfAssetsTotal,
"50"));
2744 BEAST_EXPECT(checkString(vault, sfLossUnrealized,
"0"));
2746 auto const strShareID =
strHex(sle->at(sfShareMPTID));
2747 BEAST_EXPECT(checkString(vault, sfShareMPTID, strShareID));
2748 BEAST_EXPECT(checkString(vault, sfOwner,
toBase58(owner.id())));
2749 BEAST_EXPECT(checkInt(vault, sfSequence, sequence));
2750 BEAST_EXPECT(checkInt(
2753 if (issuance.isObject())
2756 issuance[
"LedgerEntryType"].asString() ==
2759 issuance[jss::mpt_issuance_id].asString() == strShareID);
2760 BEAST_EXPECT(checkInt(issuance, sfSequence, 1));
2761 BEAST_EXPECT(checkInt(
2765 BEAST_EXPECT(checkString(issuance, sfOutstandingAmount,
"50"));
2770 testcase(
"RPC ledger_entry selected by key");
2772 jvParams[jss::ledger_index] = jss::validated;
2773 jvParams[jss::vault] =
strHex(keylet.
key);
2774 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2776 BEAST_EXPECT(!jvVault[jss::result].isMember(jss::error));
2777 BEAST_EXPECT(jvVault[jss::result].isMember(jss::node));
2778 check(jvVault[jss::result][jss::node]);
2782 testcase(
"RPC ledger_entry selected by owner and seq");
2784 jvParams[jss::ledger_index] = jss::validated;
2785 jvParams[jss::vault][jss::owner] = owner.human();
2786 jvParams[jss::vault][jss::seq] = sequence;
2787 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2789 BEAST_EXPECT(!jvVault[jss::result].isMember(jss::error));
2790 BEAST_EXPECT(jvVault[jss::result].isMember(jss::node));
2791 check(jvVault[jss::result][jss::node]);
2795 testcase(
"RPC ledger_entry cannot find vault by key");
2797 jvParams[jss::ledger_index] = jss::validated;
2799 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2801 jvVault[jss::result][jss::error].asString() ==
"entryNotFound");
2805 testcase(
"RPC ledger_entry cannot find vault by owner and seq");
2807 jvParams[jss::ledger_index] = jss::validated;
2808 jvParams[jss::vault][jss::owner] = issuer.human();
2809 jvParams[jss::vault][jss::seq] = 1'000'000;
2810 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2812 jvVault[jss::result][jss::error].asString() ==
"entryNotFound");
2816 testcase(
"RPC ledger_entry malformed key");
2818 jvParams[jss::ledger_index] = jss::validated;
2819 jvParams[jss::vault] = 42;
2820 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2822 jvVault[jss::result][jss::error].asString() ==
2823 "malformedRequest");
2827 testcase(
"RPC ledger_entry malformed owner");
2829 jvParams[jss::ledger_index] = jss::validated;
2830 jvParams[jss::vault][jss::owner] = 42;
2831 jvParams[jss::vault][jss::seq] = sequence;
2832 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2834 jvVault[jss::result][jss::error].asString() ==
2839 testcase(
"RPC ledger_entry malformed seq");
2841 jvParams[jss::ledger_index] = jss::validated;
2842 jvParams[jss::vault][jss::owner] = issuer.human();
2843 jvParams[jss::vault][jss::seq] =
"foo";
2844 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2846 jvVault[jss::result][jss::error].asString() ==
2847 "malformedRequest");
2851 testcase(
"RPC ledger_entry zero seq");
2853 jvParams[jss::ledger_index] = jss::validated;
2854 jvParams[jss::vault][jss::owner] = issuer.human();
2855 jvParams[jss::vault][jss::seq] = 0;
2856 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2858 jvVault[jss::result][jss::error].asString() ==
2859 "malformedRequest");
2863 testcase(
"RPC ledger_entry negative seq");
2865 jvParams[jss::ledger_index] = jss::validated;
2866 jvParams[jss::vault][jss::owner] = issuer.human();
2867 jvParams[jss::vault][jss::seq] = -1;
2868 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2870 jvVault[jss::result][jss::error].asString() ==
2871 "malformedRequest");
2875 testcase(
"RPC ledger_entry oversized seq");
2877 jvParams[jss::ledger_index] = jss::validated;
2878 jvParams[jss::vault][jss::owner] = issuer.human();
2879 jvParams[jss::vault][jss::seq] = 1e20;
2880 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2882 jvVault[jss::result][jss::error].asString() ==
2883 "malformedRequest");
2887 testcase(
"RPC ledger_entry bool seq");
2889 jvParams[jss::ledger_index] = jss::validated;
2890 jvParams[jss::vault][jss::owner] = issuer.human();
2891 jvParams[jss::vault][jss::seq] =
true;
2892 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
2894 jvVault[jss::result][jss::error].asString() ==
2895 "malformedRequest");
2902 jvParams[jss::account] = owner.human();
2903 jvParams[jss::type] = jss::vault;
2905 "json",
"account_objects",
to_string(jvParams))[jss::result];
2907 BEAST_EXPECT(jv[jss::account_objects].size() == 1);
2908 check(jv[jss::account_objects][0u]);
2915 jvParams[jss::ledger_index] = jss::validated;
2916 jvParams[jss::binary] =
false;
2917 jvParams[jss::type] = jss::vault;
2919 env.rpc(
"json",
"ledger_data",
to_string(jvParams));
2920 BEAST_EXPECT(jv[jss::result][jss::state].size() == 1);
2921 check(jv[jss::result][jss::state][0u]);
2925 testcase(
"RPC vault_info command line");
2927 env.rpc(
"vault_info",
strHex(keylet.
key),
"validated");
2929 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
2930 BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
2932 jv[jss::result][jss::vault],
2933 jv[jss::result][jss::vault][jss::shares]);
2939 jvParams[jss::ledger_index] = jss::validated;
2940 jvParams[jss::vault_id] =
strHex(keylet.
key);
2941 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
2943 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
2944 BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
2946 jv[jss::result][jss::vault],
2947 jv[jss::result][jss::vault][jss::shares]);
2951 testcase(
"RPC vault_info invalid vault_id");
2953 jvParams[jss::ledger_index] = jss::validated;
2954 jvParams[jss::vault_id] =
"foobar";
2955 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
2957 jv[jss::result][jss::error].asString() ==
"malformedRequest");
2961 testcase(
"RPC vault_info json invalid index");
2963 jvParams[jss::ledger_index] = jss::validated;
2964 jvParams[jss::vault_id] = 0;
2965 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
2967 jv[jss::result][jss::error].asString() ==
"malformedRequest");
2971 testcase(
"RPC vault_info json by owner and sequence");
2973 jvParams[jss::ledger_index] = jss::validated;
2974 jvParams[jss::owner] = owner.human();
2975 jvParams[jss::seq] = sequence;
2976 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
2978 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
2979 BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
2981 jv[jss::result][jss::vault],
2982 jv[jss::result][jss::vault][jss::shares]);
2986 testcase(
"RPC vault_info json malformed sequence");
2988 jvParams[jss::ledger_index] = jss::validated;
2989 jvParams[jss::owner] = owner.human();
2990 jvParams[jss::seq] =
"foobar";
2991 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
2993 jv[jss::result][jss::error].asString() ==
"malformedRequest");
2997 testcase(
"RPC vault_info json invalid sequence");
2999 jvParams[jss::ledger_index] = jss::validated;
3000 jvParams[jss::owner] = owner.human();
3001 jvParams[jss::seq] = 0;
3002 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3004 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3008 testcase(
"RPC vault_info json negative sequence");
3010 jvParams[jss::ledger_index] = jss::validated;
3011 jvParams[jss::owner] = owner.human();
3012 jvParams[jss::seq] = -1;
3013 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3015 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3019 testcase(
"RPC vault_info json oversized sequence");
3021 jvParams[jss::ledger_index] = jss::validated;
3022 jvParams[jss::owner] = owner.human();
3023 jvParams[jss::seq] = 1e20;
3024 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3026 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3030 testcase(
"RPC vault_info json bool sequence");
3032 jvParams[jss::ledger_index] = jss::validated;
3033 jvParams[jss::owner] = owner.human();
3034 jvParams[jss::seq] =
true;
3035 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3037 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3041 testcase(
"RPC vault_info json malformed owner");
3043 jvParams[jss::ledger_index] = jss::validated;
3044 jvParams[jss::owner] =
"foobar";
3045 jvParams[jss::seq] = sequence;
3046 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3048 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3052 testcase(
"RPC vault_info json invalid combination only owner");
3054 jvParams[jss::ledger_index] = jss::validated;
3055 jvParams[jss::owner] = owner.human();
3056 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3058 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3062 testcase(
"RPC vault_info json invalid combination only seq");
3064 jvParams[jss::ledger_index] = jss::validated;
3065 jvParams[jss::seq] = sequence;
3066 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3068 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3072 testcase(
"RPC vault_info json invalid combination seq vault_id");
3074 jvParams[jss::ledger_index] = jss::validated;
3075 jvParams[jss::vault_id] =
strHex(keylet.
key);
3076 jvParams[jss::seq] = sequence;
3077 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3079 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3083 testcase(
"RPC vault_info json invalid combination owner vault_id");
3085 jvParams[jss::ledger_index] = jss::validated;
3086 jvParams[jss::vault_id] =
strHex(keylet.
key);
3087 jvParams[jss::owner] = owner.human();
3088 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3090 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3095 "RPC vault_info json invalid combination owner seq "
3098 jvParams[jss::ledger_index] = jss::validated;
3099 jvParams[jss::vault_id] =
strHex(keylet.
key);
3100 jvParams[jss::seq] = sequence;
3101 jvParams[jss::owner] = owner.human();
3102 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3104 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3108 testcase(
"RPC vault_info json no input");
3110 jvParams[jss::ledger_index] = jss::validated;
3111 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
3113 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3117 testcase(
"RPC vault_info command line invalid index");
3118 Json::Value jv = env.rpc(
"vault_info",
"foobar",
"validated");
3119 BEAST_EXPECT(jv[jss::error].asString() ==
"invalidParams");
3123 testcase(
"RPC vault_info command line invalid index");
3124 Json::Value jv = env.rpc(
"vault_info",
"0",
"validated");
3126 jv[jss::result][jss::error].asString() ==
"malformedRequest");
3130 testcase(
"RPC vault_info command line invalid index");
3134 jv[jss::result][jss::error].asString() ==
"entryNotFound");
3138 testcase(
"RPC vault_info command line invalid ledger");
3141 jv[jss::result][jss::error].asString() ==
"lgrNotFound");
3164BEAST_DEFINE_TESTSUITE_PRIO(Vault, tx,
ripple, 1);
testcase_t testcase
Memberspace for declaring test cases.
constexpr TIss const & get() const
A currency issued by an account.
constexpr MPTID const & getMptID() const
void setIssuer(AccountID const &uIssuer)
Issue const & issue() const
void testFailedPseudoAccount()
ripple::test::jtx::PrettyAsset PrettyAsset
void testNonTransferableShares()
void testWithDomainCheck()
static auto constexpr negativeAmount
void run() override
Runs the suite.
void testWithDomainCheckXRP()
ripple::test::jtx::PrettyAmount PrettyAmount
Integers of any length that is a multiple of 32-bits.
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet const & skip() noexcept
The index of the "short" skip list.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
constexpr std::uint32_t asfGlobalFreeze
constexpr std::uint32_t asfDepositAuth
constexpr std::uint32_t const tfMPTCanTransfer
constexpr std::uint32_t asfRequireDest
base_uint< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
constexpr std::uint32_t const tfVaultPrivate
Json::Value to_json(Asset const &asset)
std::string strHex(FwdIt begin, FwdIt end)
constexpr std::uint32_t const tfMPTUnauthorize
constexpr std::uint32_t tfSetfAuth
constexpr std::uint32_t asfDefaultRipple
constexpr std::uint32_t tfClearFreeze
@ tecINSUFFICIENT_RESERVE
constexpr std::uint32_t const tfMPTLock
constexpr std::uint32_t const tfVaultShareNonTransferable
AccountID pseudoAccountAddress(ReadView const &view, uint256 const &pseudoOwnerKey)
constexpr std::uint32_t tfClearDeepFreeze
std::string to_string(base_uint< Bits, Tag > const &a)
std::uint8_t constexpr vaultStrategyFirstComeFirstServe
Vault withdrawal policies.
constexpr std::uint32_t asfAllowTrustLineClawback
constexpr std::uint32_t asfRequireAuth
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
constexpr std::uint32_t const tfMPTRequireAuth
constexpr std::uint32_t tfSetFreeze
constexpr std::uint32_t const tfMPTCanLock
constexpr std::uint32_t const tfMPTCanClawback
A pair of SHAMap key and LedgerEntryType.
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Asset const & raw() const