1252 using namespace test::jtx;
1254 bool const fixPDEnabled = features[fixPermissionedDomainInvariant];
1261 Env(*
this, features),
1262 {{
"permissioned domain with no rules."}},
1268 fixPDEnabled ? failTers : badTers);
1270 testcase <<
"PermissionedDomain 2";
1274 Env(*
this, features),
1275 {{
"permissioned domain bad credentials size " +
std::to_string(tooBig)}},
1281 fixPDEnabled ? failTers : badTers);
1283 testcase <<
"PermissionedDomain 3";
1285 Env(*
this, features),
1286 {{
"permissioned domain credentials aren't sorted"}},
1290 STArray credentials(sfAcceptedCredentials, 2);
1294 cred.setAccountID(sfIssuer,
A2);
1296 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1299 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1300 ac.view().update(slePd);
1305 fixPDEnabled ? failTers : badTers);
1307 testcase <<
"PermissionedDomain 4";
1309 Env(*
this, features),
1310 {{
"permissioned domain credentials aren't unique"}},
1314 STArray credentials(sfAcceptedCredentials, 2);
1318 cred.setAccountID(sfIssuer,
A2);
1319 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1322 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1323 ac.view().update(slePd);
1328 fixPDEnabled ? failTers : badTers);
1330 testcase <<
"PermissionedDomain Set 1";
1332 Env(*
this, features),
1333 {{
"permissioned domain with no rules."}},
1340 STArray const credentials(sfAcceptedCredentials, 2);
1341 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1342 ac.view().update(slePd);
1349 fixPDEnabled ? failTers : badTers);
1351 testcase <<
"PermissionedDomain Set 2";
1353 Env(*
this, features),
1354 {{
"permissioned domain bad credentials size " +
std::to_string(tooBig)}},
1361 STArray credentials(sfAcceptedCredentials, tooBig);
1366 cred.setAccountID(sfIssuer,
A2);
1368 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1372 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1373 ac.view().update(slePd);
1380 fixPDEnabled ? failTers : badTers);
1382 testcase <<
"PermissionedDomain Set 3";
1384 Env(*
this, features),
1385 {{
"permissioned domain credentials aren't sorted"}},
1392 STArray credentials(sfAcceptedCredentials, 2);
1396 cred.setAccountID(sfIssuer,
A2);
1398 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1402 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1403 ac.view().update(slePd);
1410 fixPDEnabled ? failTers : badTers);
1412 testcase <<
"PermissionedDomain Set 4";
1414 Env(*
this, features),
1415 {{
"permissioned domain credentials aren't unique"}},
1422 STArray credentials(sfAcceptedCredentials, 2);
1426 cred.setAccountID(sfIssuer,
A2);
1427 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1430 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1431 ac.view().update(slePd);
1438 fixPDEnabled ? failTers : badTers);
1443 {
"transaction affected more than 1 permissioned domain entry."}};
1447 {
"domain object modified, but not deleted by "}};
1450 {
"domain object(s) affected by an unauthorized transaction."}};
1453 testcase <<
"PermissionedDomain set 2 domains ";
1455 Env(*
this, features),
1456 fixPDEnabled ? badMoreThan1 : emptyV,
1464 fixPDEnabled ? failTers : goodTers);
1468 testcase <<
"PermissionedDomain del 2 domains";
1470 Env env1(*
this, features);
1485 fixPDEnabled ? badMoreThan1 : emptyV,
1487 auto sle1 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd1});
1488 auto sle2 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd2});
1489 ac.view().
erase(sle1);
1490 ac.view().erase(sle2);
1495 fixPDEnabled ? failTers : goodTers);
1499 testcase <<
"PermissionedDomain set 0 domains ";
1501 Env(*
this, features),
1502 fixPDEnabled ? badNoDomains : emptyV,
1506 fixPDEnabled ? badTers : goodTers);
1510 testcase <<
"PermissionedDomain del 0 domains";
1512 Env env1(*
this, features);
1524 Env(*
this, features),
1527 fixPDEnabled ? badNoDomains : emptyV,
1531 fixPDEnabled ? badTers : goodTers);
1535 testcase <<
"PermissionedDomain set, delete domain";
1537 Env env1(*
this, features);
1551 fixPDEnabled ? badDeleted : emptyV,
1553 auto sle1 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd1});
1554 ac.view().
erase(sle1);
1559 fixPDEnabled ? failTers : goodTers);
1563 testcase <<
"PermissionedDomain del, create domain ";
1565 Env(*
this, features),
1566 fixPDEnabled ? badNotDeleted : emptyV,
1573 fixPDEnabled ? failTers : goodTers);
1577 testcase <<
"PermissionedDomain invalid tx";
1580 fixPDEnabled ? badTx : emptyV,
2308 using namespace test::jtx;
2310 struct AccountAmount
2329 auto sleVault = ac.
peek(keylet);
2333 auto const mptIssuanceID = (*sleVault)[sfShareMPTID];
2339 if (args.lossUnrealized)
2340 (*sleVault)[sfLossUnrealized] = *args.lossUnrealized;
2341 if (args.assetsMaximum)
2342 (*sleVault)[sfAssetsMaximum] = *args.assetsMaximum;
2345 if (args.assetsTotal)
2346 (*sleVault)[sfAssetsTotal] = *(*sleVault)[sfAssetsTotal] + *args.assetsTotal;
2347 if (args.assetsAvailable)
2349 (*sleVault)[sfAssetsAvailable] =
2350 *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable;
2354 if (args.sharesTotal)
2356 (*sleShares)[sfOutstandingAmount] =
2357 *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal;
2361 auto const assets = *(*sleVault)[sfAsset];
2362 auto const pseudoId = *(*sleVault)[sfAccount];
2363 if (args.vaultAssets)
2365 if (assets.native())
2368 if (!slePseudoAccount)
2370 (*slePseudoAccount)[sfBalance] =
2371 *(*slePseudoAccount)[sfBalance] + *args.vaultAssets;
2372 ac.
update(slePseudoAccount);
2376 auto const mptId = assets.get<
MPTIssue>().getMptID();
2380 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets;
2389 if (args.accountAssets)
2391 auto const& pair = *args.accountAssets;
2392 if (assets.native())
2397 (*sleAccount)[sfBalance] = *(*sleAccount)[sfBalance] + pair.amount;
2402 auto const mptID = assets.get<
MPTIssue>().getMptID();
2406 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + pair.amount;
2415 if (args.accountShares)
2417 auto const& pair = *args.accountShares;
2421 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + pair.amount;
2427 constexpr auto args = [](
AccountID id,
int adjustment,
auto fn) -> Adjustments {
2428 Adjustments sample = {
2429 .assetsTotal = adjustment,
2430 .assetsAvailable = adjustment,
2431 .lossUnrealized = 0,
2432 .sharesTotal = adjustment,
2433 .vaultAssets = adjustment,
2435 AccountAmount{id, -adjustment},
2437 AccountAmount{id, adjustment}};
2445 env.fund(
XRP(1000), A3, A4);
2446 Vault const vault{env};
2447 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2449 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2450 env(vault.deposit({.depositor = A2, .id = keylet.key, .amount = XRP(10)}));
2451 env(vault.deposit({.depositor = A3, .id = keylet.key, .amount = XRP(10)}));
2455 testcase <<
"Vault general checks";
2457 {
"vault deletion succeeded without deleting a vault"},
2460 auto sleVault = ac.view().
peek(keylet);
2463 ac.view().
update(sleVault);
2470 Vault const vault{env};
2471 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2477 {
"vault updated by a wrong transaction type"},
2480 auto sleVault = ac.view().
peek(keylet);
2483 ac.view().
erase(sleVault);
2490 Vault const vault{env};
2491 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2497 {
"vault updated by a wrong transaction type"},
2500 auto sleVault = ac.view().
peek(keylet);
2503 ac.view().
update(sleVault);
2510 Vault const vault{env};
2511 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2517 {
"vault updated by a wrong transaction type"},
2519 auto const sequence = ac.view().
seq();
2522 auto const vaultPage = ac.view().
dirInsert(
2524 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2525 ac.view().
insert(sleVault);
2533 {
"vault deleted by a wrong transaction type"},
2536 auto sleVault = ac.view().
peek(keylet);
2539 ac.view().
erase(sleVault);
2546 Vault const vault{env};
2547 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2553 {
"vault operation updated more than single vault"},
2557 auto sleVault = ac.view().
peek(keylet);
2560 ac.view().
erase(sleVault);
2564 auto sleVault = ac.view().
peek(keylet);
2567 ac.view().
erase(sleVault);
2575 Vault const vault{env};
2577 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2581 auto [tx, _] = vault.create({.owner =
A2, .asset =
xrpIssue()});
2588 {
"vault operation updated more than single vault"},
2590 auto const sequence = ac.view().
seq();
2591 auto const insertVault = [&](
Account const A) {
2594 auto const vaultPage = ac.view().
dirInsert(
2596 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2597 ac.view().
insert(sleVault);
2608 {
"deleted vault must also delete shares"},
2611 auto sleVault = ac.view().
peek(keylet);
2614 ac.view().
erase(sleVault);
2621 Vault const vault{env};
2622 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2628 {
"deleted vault must have no shares outstanding",
2629 "deleted vault must have no assets outstanding",
2630 "deleted vault must have no assets available"},
2633 auto sleVault = ac.view().
peek(keylet);
2639 ac.view().
erase(sleVault);
2640 ac.view().
erase(sleShares);
2647 Vault const vault{env};
2648 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2650 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2655 {
"vault operation succeeded without modifying a vault"},
2658 auto sleVault = ac.view().
peek(keylet);
2666 sleShares->setFieldH256(sfDomainID,
uint256(13));
2667 ac.view().
update(sleShares);
2677 {
"vault operation succeeded without modifying a vault"},
2683 Vault const vault{env};
2684 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2690 {
"vault operation succeeded without modifying a vault"},
2696 Vault const vault{env};
2697 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2703 {
"vault operation succeeded without modifying a vault"},
2709 Vault const vault{env};
2710 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2716 {
"vault operation succeeded without modifying a vault"},
2722 Vault const vault{env};
2723 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2729 {
"vault operation succeeded without modifying a vault"},
2735 Vault const vault{env};
2736 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2742 {
"updated vault must have shares"},
2745 auto sleVault = ac.view().
peek(keylet);
2748 (*sleVault)[sfAssetsMaximum] = 200;
2749 ac.view().
update(sleVault);
2754 ac.view().
erase(sleShares);
2761 Vault const vault{env};
2762 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2768 {
"vault operation succeeded without updating shares",
2769 "assets available must not be greater than assets outstanding"},
2772 auto sleVault = ac.view().
peek(keylet);
2775 (*sleVault)[sfAssetsTotal] = 9;
2776 ac.view().
update(sleVault);
2783 Vault const vault{env};
2784 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2786 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2791 {
"set must not change assets outstanding",
2792 "set must not change assets available",
2793 "set must not change shares outstanding",
2794 "set must not change vault balance",
2795 "assets available must be positive",
2796 "assets available must not be greater than assets outstanding",
2797 "assets outstanding must be positive"},
2800 auto sleVault = ac.view().
peek(keylet);
2804 if (!slePseudoAccount)
2806 (*slePseudoAccount)[sfBalance] = *(*slePseudoAccount)[sfBalance] - 10;
2807 ac.view().
update(slePseudoAccount);
2813 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2816 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {
2817 sample.assetsAvailable = (DROPS_PER_XRP * -100).value();
2818 sample.assetsTotal = (DROPS_PER_XRP * -200).value();
2819 sample.sharesTotal = -1;
2829 {
"violation of vault immutable data"},
2832 auto sleVault = ac.view().
peek(keylet);
2836 ac.view().
update(sleVault);
2845 {
"violation of vault immutable data"},
2848 auto sleVault = ac.view().
peek(keylet);
2851 sleVault->setAccountID(sfAccount,
A2.id());
2852 ac.view().
update(sleVault);
2861 {
"violation of vault immutable data"},
2864 auto sleVault = ac.view().
peek(keylet);
2867 (*sleVault)[sfShareMPTID] =
MPTID(42);
2868 ac.view().
update(sleVault);
2877 {
"vault transaction must not change loss unrealized",
2878 "set must not change assets outstanding"},
2881 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {
2882 sample.lossUnrealized = 13;
2883 sample.assetsTotal = 20;
2893 {
"loss unrealized must not exceed the difference "
2894 "between assets outstanding and available",
2895 "vault transaction must not change loss unrealized"},
2898 return adjust(ac.view(), keylet, args(
A2.id(), 100, [&](Adjustments& sample) {
2899 sample.lossUnrealized = 13;
2910 {
"set assets outstanding must not exceed assets maximum"},
2913 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {
2914 sample.assetsMaximum = 1;
2924 {
"assets maximum must be positive"},
2927 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {
2928 sample.assetsMaximum = -1;
2938 {
"set must not change shares outstanding",
2939 "updated zero sized vault must have no assets outstanding",
2940 "updated zero sized vault must have no assets available"},
2943 auto sleVault = ac.view().
peek(keylet);
2946 ac.view().
update(sleVault);
2950 (*sleShares)[sfOutstandingAmount] = 0;
2951 ac.view().
update(sleShares);
2961 {
"updated shares must not exceed maximum"},
2964 auto sleVault = ac.view().
peek(keylet);
2970 (*sleShares)[sfMaximumAmount] = 10;
2971 ac.view().
update(sleShares);
2973 return adjust(ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2982 {
"updated shares must not exceed maximum"},
2985 adjust(ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2987 auto sleVault = ac.view().
peek(keylet);
2994 ac.view().
update(sleShares);
3006 "created vault must be empty",
3007 "updated zero sized vault must have no assets outstanding",
3008 "create operation must not have updated a vault",
3012 auto sleVault = ac.view().
peek(keylet);
3015 (*sleVault)[sfAssetsTotal] = 9;
3016 ac.view().
update(sleVault);
3023 Vault const vault{env};
3024 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
3031 "created vault must be empty",
3032 "updated zero sized vault must have no assets available",
3033 "assets available must not be greater than assets outstanding",
3034 "create operation must not have updated a vault",
3038 auto sleVault = ac.view().
peek(keylet);
3041 (*sleVault)[sfAssetsAvailable] = 9;
3042 ac.view().
update(sleVault);
3049 Vault const vault{env};
3050 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
3057 "created vault must be empty",
3058 "loss unrealized must not exceed the difference between assets "
3059 "outstanding and available",
3060 "vault transaction must not change loss unrealized",
3061 "create operation must not have updated a vault",
3065 auto sleVault = ac.view().
peek(keylet);
3068 (*sleVault)[sfLossUnrealized] = 1;
3069 ac.view().
update(sleVault);
3076 Vault const vault{env};
3077 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
3084 "created vault must be empty",
3085 "create operation must not have updated a vault",
3089 auto sleVault = ac.view().
peek(keylet);
3095 ac.view().
update(sleVault);
3096 (*sleShares)[sfOutstandingAmount] = 9;
3097 ac.view().
update(sleShares);
3104 Vault const vault{env};
3105 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
3112 "assets maximum must be positive",
3113 "create operation must not have updated a vault",
3117 auto sleVault = ac.view().
peek(keylet);
3120 (*sleVault)[sfAssetsMaximum] =
Number(-1);
3121 ac.view().
update(sleVault);
3128 Vault const vault{env};
3129 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
3135 {
"create operation must not have updated a vault",
3136 "shares issuer and vault pseudo-account must be the same",
3137 "shares issuer must be a pseudo-account",
3138 "shares issuer pseudo-account must point back to the vault"},
3141 auto sleVault = ac.view().
peek(keylet);
3147 ac.view().
update(sleVault);
3148 (*sleShares)[sfIssuer] =
A1.id();
3149 ac.view().
update(sleShares);
3156 Vault const vault{env};
3157 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
3163 {
"vault created by a wrong transaction type",
"account root created illegally"},
3168 auto const sequence = ac.view().
seq();
3171 auto const vaultPage = ac.view().
dirInsert(
3173 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3178 sleAccount->setAccountID(sfAccount, pseudoId);
3179 sleAccount->setFieldAmount(sfBalance,
STAmount{});
3184 sleAccount->setFieldU32(sfSequence, seqno);
3185 sleAccount->setFieldU32(
3186 sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
3187 sleAccount->setFieldH256(sfVaultID, vaultKeylet.key);
3188 ac.view().
insert(sleAccount);
3190 auto const sharesMptId =
makeMptID(sequence, pseudoId);
3193 auto const sharesPage = ac.view().
dirInsert(
3195 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3197 sleShares->at(sfFlags) = 0;
3198 sleShares->at(sfIssuer) = pseudoId;
3199 sleShares->at(sfOutstandingAmount) = 0;
3200 sleShares->at(sfSequence) = sequence;
3202 sleVault->at(sfAccount) = pseudoId;
3203 sleVault->at(sfFlags) = 0;
3204 sleVault->at(sfSequence) = sequence;
3205 sleVault->at(sfOwner) =
A1.id();
3206 sleVault->at(sfAssetsTotal) =
Number(0);
3207 sleVault->at(sfAssetsAvailable) =
Number(0);
3208 sleVault->at(sfLossUnrealized) =
Number(0);
3209 sleVault->at(sfShareMPTID) = sharesMptId;
3212 ac.view().
insert(sleVault);
3213 ac.view().
insert(sleShares);
3221 {
"shares issuer and vault pseudo-account must be the same",
3222 "shares issuer pseudo-account must point back to the vault"},
3224 auto const sequence = ac.view().
seq();
3227 auto const vaultPage = ac.view().
dirInsert(
3229 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3234 sleAccount->setAccountID(sfAccount, pseudoId);
3235 sleAccount->setFieldAmount(sfBalance,
STAmount{});
3240 sleAccount->setFieldU32(sfSequence, seqno);
3241 sleAccount->setFieldU32(
3242 sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
3245 sleAccount->setFieldH256(sfVaultID,
uint256(42));
3246 ac.view().
insert(sleAccount);
3248 auto const sharesMptId =
makeMptID(sequence, pseudoId);
3251 auto const sharesPage = ac.view().
dirInsert(
3253 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3255 sleShares->at(sfFlags) = 0;
3256 sleShares->at(sfIssuer) = pseudoId;
3257 sleShares->at(sfOutstandingAmount) = 0;
3258 sleShares->at(sfSequence) = sequence;
3262 sleVault->at(sfAccount) =
A2.id();
3263 sleVault->at(sfFlags) = 0;
3264 sleVault->at(sfSequence) = sequence;
3265 sleVault->at(sfOwner) =
A1.id();
3266 sleVault->at(sfAssetsTotal) =
Number(0);
3267 sleVault->at(sfAssetsAvailable) =
Number(0);
3268 sleVault->at(sfLossUnrealized) =
Number(0);
3269 sleVault->at(sfShareMPTID) = sharesMptId;
3272 ac.view().
insert(sleVault);
3273 ac.view().
insert(sleShares);
3281 {
"shares issuer and vault pseudo-account must be the same",
"shares issuer must exist"},
3283 auto const sequence = ac.view().
seq();
3286 auto const vaultPage = ac.view().
dirInsert(
3288 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3290 auto const sharesMptId =
makeMptID(sequence,
A2.id());
3293 auto const sharesPage = ac.view().
dirInsert(
3295 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3297 sleShares->at(sfFlags) = 0;
3300 sleShares->at(sfOutstandingAmount) = 0;
3301 sleShares->at(sfSequence) = sequence;
3303 sleVault->at(sfAccount) =
A2.id();
3304 sleVault->at(sfFlags) = 0;
3305 sleVault->at(sfSequence) = sequence;
3306 sleVault->at(sfOwner) =
A1.id();
3307 sleVault->at(sfAssetsTotal) =
Number(0);
3308 sleVault->at(sfAssetsAvailable) =
Number(0);
3309 sleVault->at(sfLossUnrealized) =
Number(0);
3310 sleVault->at(sfShareMPTID) = sharesMptId;
3313 ac.view().
insert(sleVault);
3314 ac.view().
insert(sleShares);
3323 {
"deposit must change vault balance"},
3326 return adjust(ac.view(), keylet, args(
A2.id(), 0, [](Adjustments& sample) {
3327 sample.vaultAssets.reset();
3336 {
"deposit assets outstanding must not exceed assets maximum"},
3339 return adjust(ac.view(), keylet, args(
A2.id(), 200, [&](Adjustments& sample) {
3340 sample.assetsMaximum = 1;
3355 {
"deposit must increase vault balance",
"deposit must change depositor balance"},
3363 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3366 return adjust(ac.view(), keylet, args(A3.id(), -10, [&](Adjustments& sample) {
3367 sample.accountAssets->amount = -100;
3375 tx[sfAccount] = A3.id();
3381 {
"deposit must increase vault balance",
3382 "deposit must decrease depositor balance",
3383 "deposit must change vault and depositor balance by equal amount",
3384 "deposit and assets outstanding must add up",
3385 "deposit and assets available must add up"},
3393 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3396 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3397 sample.vaultAssets = -20;
3398 sample.accountAssets->amount = 10;
3408 {
"deposit must change depositor balance"},
3416 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 10;
3419 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3420 sample.accountAssets->amount = 0;
3430 {
"deposit must change depositor shares"},
3433 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3434 sample.accountShares.reset();
3444 {
"deposit must change vault shares"},
3448 return adjust(ac.view(), keylet, args(
A2.id(), 10, [](Adjustments& sample) {
3449 sample.sharesTotal = 0;
3459 {
"deposit must increase depositor shares",
3460 "deposit must change depositor and vault shares by equal amount",
3461 "deposit must not change vault balance by more than deposited "
3465 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3466 sample.accountShares->amount = -5;
3467 sample.sharesTotal = -10;
3477 {
"deposit and assets outstanding must add up"},
3480 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3484 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3485 sample.assetsTotal = 11;
3493 tx[sfDelegate] = A3.id();
3501 {
"deposit and assets outstanding must add up",
3502 "deposit and assets available must add up"},
3505 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3506 sample.assetsTotal = 7;
3507 sample.assetsAvailable = 7;
3518 {
"withdrawal must change vault balance"},
3521 return adjust(ac.view(), keylet, args(
A2.id(), 0, [](Adjustments& sample) {
3522 sample.vaultAssets.reset();
3535 {
"withdrawal must change one destination balance"},
3543 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3546 return adjust(ac.view(), keylet, args(A3.id(), -10, [&](Adjustments& sample) {
3547 sample.accountAssets->amount = -100;
3555 tx[sfAccount] = A3.id();
3564 "withdrawal must change vault and destination balance by equal amount",
3565 "withdrawal must decrease vault balance",
3566 "withdrawal must increase destination balance",
3567 "withdrawal and assets outstanding must add up",
3568 "withdrawal and assets available must add up",
3577 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3580 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3581 sample.vaultAssets = 10;
3582 sample.accountAssets->amount = -20;
3592 {
"withdrawal must change one destination balance"},
3595 if (!adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3596 *sample.vaultAssets -= 5;
3602 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 5;
3613 {
"withdrawal must change depositor shares"},
3616 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3617 sample.accountShares.reset();
3627 {
"withdrawal must change vault shares"},
3630 return adjust(ac.view(), keylet, args(
A2.id(), -10, [](Adjustments& sample) {
3631 sample.sharesTotal = 0;
3641 {
"withdrawal must decrease depositor shares",
3642 "withdrawal must change depositor and vault shares by equal "
3646 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3647 sample.accountShares->amount = 5;
3648 sample.sharesTotal = 10;
3658 {
"withdrawal and assets outstanding must add up",
3659 "withdrawal and assets available must add up"},
3662 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3663 sample.assetsTotal = -15;
3664 sample.assetsAvailable = -15;
3674 {
"withdrawal and assets outstanding must add up"},
3677 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3681 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3682 sample.assetsTotal = -7;
3690 tx[sfDelegate] = A3.id();
3698 env.fund(
XRP(1000), A3, A4);
3703 jv[sfAccount] = A3.human();
3704 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3705 jv[sfFlags] = tfMPTCanTransfer;
3710 auto const mptID =
makeMptID(env.seq(A3) - 1, A3);
3715 jv[sfAccount] =
A1.human();
3716 jv[sfTransactionType] = jss::MPTokenAuthorize;
3717 jv[sfMPTokenIssuanceID] =
to_string(mptID);
3719 jv[sfAccount] =
A2.human();
3721 jv[sfAccount] = A4.human();
3728 env(
pay(A3,
A1, asset(1000)));
3729 env(
pay(A3,
A2, asset(1000)));
3730 env(
pay(A3, A4, asset(1000)));
3734 Vault const vault{env};
3735 auto [tx, keylet] = vault.create({.owner =
A1, .asset = asset});
3737 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = asset(10)}));
3738 env(vault.deposit({.depositor = A2, .id = keylet.key, .amount = asset(10)}));
3739 env(vault.deposit({.depositor = A4, .id = keylet.key, .amount = asset(10)}));
3744 {
"withdrawal must decrease depositor shares",
3745 "withdrawal must change depositor and vault shares by equal "
3749 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3750 sample.accountShares->amount = 5;
3754 STTx{ttVAULT_WITHDRAW, [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3761 {
"clawback must change vault balance"},
3764 return adjust(ac.view(), keylet, args(
A2.id(), -1, [&](Adjustments& sample) {
3765 sample.vaultAssets.reset();
3769 STTx{ttVAULT_CLAWBACK, [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3775 {
"clawback may only be performed by the asset issuer"},
3778 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {}));
3787 {
"clawback may only be performed by the asset issuer"},
3790 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {}));
3793 STTx{ttVAULT_CLAWBACK, [&](
STObject& tx) { tx[sfAccount] = A4.id(); }},
3798 {
"clawback must decrease vault balance",
3799 "clawback must decrease holder shares",
3800 "clawback must change vault shares"},
3803 return adjust(ac.view(), keylet, args(A4.id(), 10, [&](Adjustments& sample) {
3804 sample.sharesTotal = 0;
3811 tx[sfAccount] = A3.id();
3812 tx[sfHolder] = A4.id();
3818 {
"clawback must change holder shares"},
3821 return adjust(ac.view(), keylet, args(A4.id(), -10, [&](Adjustments& sample) {
3822 sample.accountShares.reset();
3829 tx[sfAccount] = A3.id();
3830 tx[sfHolder] = A4.id();
3836 {
"clawback must change holder and vault shares by equal amount",
3837 "clawback and assets outstanding must add up",
3838 "clawback and assets available must add up"},
3841 return adjust(ac.view(), keylet, args(A4.id(), -10, [&](Adjustments& sample) {
3842 sample.accountShares->amount = -8;
3843 sample.assetsTotal = -7;
3844 sample.assetsAvailable = -7;
3851 tx[sfAccount] = A3.id();
3852 tx[sfHolder] = A4.id();