1197 using namespace test::jtx;
1199 bool const fixPDEnabled = features[fixPermissionedDomainInvariant];
1206 Env(*
this, features),
1207 {{
"permissioned domain with no rules."}},
1213 fixPDEnabled ? failTers : badTers);
1215 testcase <<
"PermissionedDomain 2";
1219 Env(*
this, features),
1220 {{
"permissioned domain bad credentials size " +
std::to_string(tooBig)}},
1226 fixPDEnabled ? failTers : badTers);
1228 testcase <<
"PermissionedDomain 3";
1230 Env(*
this, features),
1231 {{
"permissioned domain credentials aren't sorted"}},
1235 STArray credentials(sfAcceptedCredentials, 2);
1239 cred.setAccountID(sfIssuer,
A2);
1241 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1244 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1245 ac.view().update(slePd);
1250 fixPDEnabled ? failTers : badTers);
1252 testcase <<
"PermissionedDomain 4";
1254 Env(*
this, features),
1255 {{
"permissioned domain credentials aren't unique"}},
1259 STArray credentials(sfAcceptedCredentials, 2);
1263 cred.setAccountID(sfIssuer,
A2);
1264 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1267 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1268 ac.view().update(slePd);
1273 fixPDEnabled ? failTers : badTers);
1275 testcase <<
"PermissionedDomain Set 1";
1277 Env(*
this, features),
1278 {{
"permissioned domain with no rules."}},
1285 STArray credentials(sfAcceptedCredentials, 2);
1286 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1287 ac.view().update(slePd);
1294 fixPDEnabled ? failTers : badTers);
1296 testcase <<
"PermissionedDomain Set 2";
1298 Env(*
this, features),
1299 {{
"permissioned domain bad credentials size " +
std::to_string(tooBig)}},
1306 STArray credentials(sfAcceptedCredentials, tooBig);
1311 cred.setAccountID(sfIssuer,
A2);
1313 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1317 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1318 ac.view().update(slePd);
1325 fixPDEnabled ? failTers : badTers);
1327 testcase <<
"PermissionedDomain Set 3";
1329 Env(*
this, features),
1330 {{
"permissioned domain credentials aren't sorted"}},
1337 STArray credentials(sfAcceptedCredentials, 2);
1341 cred.setAccountID(sfIssuer,
A2);
1343 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1347 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1348 ac.view().update(slePd);
1355 fixPDEnabled ? failTers : badTers);
1357 testcase <<
"PermissionedDomain Set 4";
1359 Env(*
this, features),
1360 {{
"permissioned domain credentials aren't unique"}},
1367 STArray credentials(sfAcceptedCredentials, 2);
1371 cred.setAccountID(sfIssuer,
A2);
1372 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1375 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1376 ac.view().update(slePd);
1383 fixPDEnabled ? failTers : badTers);
1395 testcase <<
"PermissionedDomain set 2 domains ";
1397 Env(*
this, features),
1398 fixPDEnabled ? badMoreThan1 : emptyV,
1406 fixPDEnabled ? failTers : goodTers);
1410 testcase <<
"PermissionedDomain del 2 domains";
1412 Env env1(*
this, features);
1427 fixPDEnabled ? badMoreThan1 : emptyV,
1429 auto sle1 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd1});
1430 auto sle2 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd2});
1431 ac.view().
erase(sle1);
1432 ac.view().erase(sle2);
1437 fixPDEnabled ? failTers : goodTers);
1441 testcase <<
"PermissionedDomain set 0 domains ";
1443 Env(*
this, features),
1444 fixPDEnabled ? badNoDomains : emptyV,
1448 fixPDEnabled ? badTers : goodTers);
1452 testcase <<
"PermissionedDomain del 0 domains";
1454 Env env1(*
this, features);
1466 Env(*
this, features),
1469 fixPDEnabled ? badNoDomains : emptyV,
1473 fixPDEnabled ? badTers : goodTers);
1477 testcase <<
"PermissionedDomain set, delete domain";
1479 Env env1(*
this, features);
1493 fixPDEnabled ? badDeleted : emptyV,
1495 auto sle1 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd1});
1496 ac.view().
erase(sle1);
1501 fixPDEnabled ? failTers : goodTers);
1505 testcase <<
"PermissionedDomain del, create domain ";
1507 Env(*
this, features),
1508 fixPDEnabled ? badNotDeleted : emptyV,
1515 fixPDEnabled ? failTers : goodTers);
1519 testcase <<
"PermissionedDomain invalid tx";
1522 fixPDEnabled ? badTx : emptyV,
2195 using namespace test::jtx;
2197 struct AccountAmount
2214 auto sleVault = ac.
peek(keylet);
2218 auto const mptIssuanceID = (*sleVault)[sfShareMPTID];
2224 if (args.lossUnrealized)
2225 (*sleVault)[sfLossUnrealized] = *args.lossUnrealized;
2226 if (args.assetsMaximum)
2227 (*sleVault)[sfAssetsMaximum] = *args.assetsMaximum;
2230 if (args.assetsTotal)
2231 (*sleVault)[sfAssetsTotal] = *(*sleVault)[sfAssetsTotal] + *args.assetsTotal;
2232 if (args.assetsAvailable)
2233 (*sleVault)[sfAssetsAvailable] = *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable;
2236 if (args.sharesTotal)
2238 (*sleShares)[sfOutstandingAmount] = *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal;
2242 auto const assets = *(*sleVault)[sfAsset];
2243 auto const pseudoId = *(*sleVault)[sfAccount];
2244 if (args.vaultAssets)
2246 if (assets.native())
2249 if (!slePseudoAccount)
2251 (*slePseudoAccount)[sfBalance] = *(*slePseudoAccount)[sfBalance] + *args.vaultAssets;
2252 ac.
update(slePseudoAccount);
2256 auto const mptId = assets.get<
MPTIssue>().getMptID();
2260 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets;
2267 if (args.accountAssets)
2269 auto const& pair = *args.accountAssets;
2270 if (assets.native())
2275 (*sleAccount)[sfBalance] = *(*sleAccount)[sfBalance] + pair.amount;
2280 auto const mptID = assets.get<
MPTIssue>().getMptID();
2284 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + pair.amount;
2291 if (args.accountShares)
2293 auto const& pair = *args.accountShares;
2297 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + pair.amount;
2303 constexpr auto args = [](
AccountID id,
int adjustment,
auto fn) -> Adjustments {
2304 Adjustments sample = {
2305 .assetsTotal = adjustment,
2306 .assetsAvailable = adjustment,
2307 .lossUnrealized = 0,
2308 .sharesTotal = adjustment,
2309 .vaultAssets = adjustment,
2311 AccountAmount{id, -adjustment},
2313 AccountAmount{id, adjustment}};
2321 env.fund(
XRP(1000), A3, A4);
2323 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2325 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2326 env(vault.deposit({.depositor = A2, .id = keylet.key, .amount = XRP(10)}));
2327 env(vault.deposit({.depositor = A3, .id = keylet.key, .amount = XRP(10)}));
2331 testcase <<
"Vault general checks";
2333 {
"vault deletion succeeded without deleting a vault"},
2336 auto sleVault = ac.view().
peek(keylet);
2339 ac.view().
update(sleVault);
2347 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2353 {
"vault updated by a wrong transaction type"},
2356 auto sleVault = ac.view().
peek(keylet);
2359 ac.view().
erase(sleVault);
2367 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2373 {
"vault updated by a wrong transaction type"},
2376 auto sleVault = ac.view().
peek(keylet);
2379 ac.view().
update(sleVault);
2387 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2393 {
"vault updated by a wrong transaction type"},
2395 auto const sequence = ac.view().
seq();
2398 auto const vaultPage =
2400 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2401 ac.view().
insert(sleVault);
2409 {
"vault deleted by a wrong transaction type"},
2412 auto sleVault = ac.view().
peek(keylet);
2415 ac.view().
erase(sleVault);
2423 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2429 {
"vault operation updated more than single vault"},
2433 auto sleVault = ac.view().
peek(keylet);
2436 ac.view().
erase(sleVault);
2440 auto sleVault = ac.view().
peek(keylet);
2443 ac.view().
erase(sleVault);
2453 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2457 auto [tx, _] = vault.create({.owner =
A2, .asset =
xrpIssue()});
2464 {
"vault operation updated more than single vault"},
2466 auto const sequence = ac.view().
seq();
2467 auto const insertVault = [&](
Account const A) {
2470 auto const vaultPage =
2472 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2473 ac.view().
insert(sleVault);
2484 {
"deleted vault must also delete shares"},
2487 auto sleVault = ac.view().
peek(keylet);
2490 ac.view().
erase(sleVault);
2498 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2504 {
"deleted vault must have no shares outstanding",
2505 "deleted vault must have no assets outstanding",
2506 "deleted vault must have no assets available"},
2509 auto sleVault = ac.view().
peek(keylet);
2515 ac.view().
erase(sleVault);
2516 ac.view().
erase(sleShares);
2524 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2526 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2531 {
"vault operation succeeded without modifying a vault"},
2534 auto sleVault = ac.view().
peek(keylet);
2542 sleShares->setFieldH256(sfDomainID,
uint256(13));
2543 ac.view().
update(sleShares);
2553 {
"vault operation succeeded without modifying a vault"},
2560 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2566 {
"vault operation succeeded without modifying a vault"},
2573 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2579 {
"vault operation succeeded without modifying a vault"},
2586 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2592 {
"vault operation succeeded without modifying a vault"},
2599 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2605 {
"vault operation succeeded without modifying a vault"},
2612 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2618 {
"updated vault must have shares"},
2621 auto sleVault = ac.view().
peek(keylet);
2624 (*sleVault)[sfAssetsMaximum] = 200;
2625 ac.view().
update(sleVault);
2630 ac.view().
erase(sleShares);
2638 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2644 {
"vault operation succeeded without updating shares",
2645 "assets available must not be greater than assets outstanding"},
2648 auto sleVault = ac.view().
peek(keylet);
2651 (*sleVault)[sfAssetsTotal] = 9;
2652 ac.view().
update(sleVault);
2660 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2662 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2667 {
"set must not change assets outstanding",
2668 "set must not change assets available",
2669 "set must not change shares outstanding",
2670 "set must not change vault balance",
2671 "assets available must be positive",
2672 "assets available must not be greater than assets outstanding",
2673 "assets outstanding must be positive"},
2676 auto sleVault = ac.view().
peek(keylet);
2680 if (!slePseudoAccount)
2682 (*slePseudoAccount)[sfBalance] = *(*slePseudoAccount)[sfBalance] - 10;
2683 ac.view().
update(slePseudoAccount);
2689 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2692 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {
2693 sample.assetsAvailable = (DROPS_PER_XRP * -100).value();
2694 sample.assetsTotal = (DROPS_PER_XRP * -200).value();
2695 sample.sharesTotal = -1;
2705 {
"violation of vault immutable data"},
2708 auto sleVault = ac.view().
peek(keylet);
2712 ac.view().
update(sleVault);
2721 {
"violation of vault immutable data"},
2724 auto sleVault = ac.view().
peek(keylet);
2727 sleVault->setAccountID(sfAccount,
A2.id());
2728 ac.view().
update(sleVault);
2737 {
"violation of vault immutable data"},
2740 auto sleVault = ac.view().
peek(keylet);
2743 (*sleVault)[sfShareMPTID] =
MPTID(42);
2744 ac.view().
update(sleVault);
2753 {
"vault transaction must not change loss unrealized",
"set must not change assets outstanding"},
2756 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {
2757 sample.lossUnrealized = 13;
2758 sample.assetsTotal = 20;
2768 {
"loss unrealized must not exceed the difference "
2769 "between assets outstanding and available",
2770 "vault transaction must not change loss unrealized"},
2774 ac.view(), keylet, args(
A2.id(), 100, [&](Adjustments& sample) { sample.lossUnrealized = 13; }));
2783 {
"set assets outstanding must not exceed assets maximum"},
2787 ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) { sample.assetsMaximum = 1; }));
2796 {
"assets maximum must be positive"},
2800 ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) { sample.assetsMaximum = -1; }));
2809 {
"set must not change shares outstanding",
2810 "updated zero sized vault must have no assets outstanding",
2811 "updated zero sized vault must have no assets available"},
2814 auto sleVault = ac.view().
peek(keylet);
2817 ac.view().
update(sleVault);
2821 (*sleShares)[sfOutstandingAmount] = 0;
2822 ac.view().
update(sleShares);
2832 {
"updated shares must not exceed maximum"},
2835 auto sleVault = ac.view().
peek(keylet);
2841 (*sleShares)[sfMaximumAmount] = 10;
2842 ac.view().
update(sleShares);
2844 return adjust(ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2853 {
"updated shares must not exceed maximum"},
2856 adjust(ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2858 auto sleVault = ac.view().
peek(keylet);
2865 ac.view().
update(sleShares);
2877 "created vault must be empty",
2878 "updated zero sized vault must have no assets outstanding",
2879 "create operation must not have updated a vault",
2883 auto sleVault = ac.view().
peek(keylet);
2886 (*sleVault)[sfAssetsTotal] = 9;
2887 ac.view().
update(sleVault);
2895 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2902 "created vault must be empty",
2903 "updated zero sized vault must have no assets available",
2904 "assets available must not be greater than assets outstanding",
2905 "create operation must not have updated a vault",
2909 auto sleVault = ac.view().
peek(keylet);
2912 (*sleVault)[sfAssetsAvailable] = 9;
2913 ac.view().
update(sleVault);
2921 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2928 "created vault must be empty",
2929 "loss unrealized must not exceed the difference between assets "
2930 "outstanding and available",
2931 "vault transaction must not change loss unrealized",
2932 "create operation must not have updated a vault",
2936 auto sleVault = ac.view().
peek(keylet);
2939 (*sleVault)[sfLossUnrealized] = 1;
2940 ac.view().
update(sleVault);
2948 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2955 "created vault must be empty",
2956 "create operation must not have updated a vault",
2960 auto sleVault = ac.view().
peek(keylet);
2966 ac.view().
update(sleVault);
2967 (*sleShares)[sfOutstandingAmount] = 9;
2968 ac.view().
update(sleShares);
2976 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2983 "assets maximum must be positive",
2984 "create operation must not have updated a vault",
2988 auto sleVault = ac.view().
peek(keylet);
2991 (*sleVault)[sfAssetsMaximum] =
Number(-1);
2992 ac.view().
update(sleVault);
3000 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
3006 {
"create operation must not have updated a vault",
3007 "shares issuer and vault pseudo-account must be the same",
3008 "shares issuer must be a pseudo-account",
3009 "shares issuer pseudo-account must point back to the vault"},
3012 auto sleVault = ac.view().
peek(keylet);
3018 ac.view().
update(sleVault);
3019 (*sleShares)[sfIssuer] =
A1.id();
3020 ac.view().
update(sleShares);
3028 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
3034 {
"vault created by a wrong transaction type",
"account root created illegally"},
3039 auto const sequence = ac.view().
seq();
3042 auto const vaultPage =
3044 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3049 sleAccount->setAccountID(sfAccount, pseudoId);
3050 sleAccount->setFieldAmount(sfBalance,
STAmount{});
3055 sleAccount->setFieldU32(sfSequence, seqno);
3057 sleAccount->setFieldH256(sfVaultID, vaultKeylet.key);
3058 ac.view().
insert(sleAccount);
3060 auto const sharesMptId =
makeMptID(sequence, pseudoId);
3063 auto const sharesPage =
3065 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3067 sleShares->at(sfFlags) = 0;
3068 sleShares->at(sfIssuer) = pseudoId;
3069 sleShares->at(sfOutstandingAmount) = 0;
3070 sleShares->at(sfSequence) = sequence;
3072 sleVault->at(sfAccount) = pseudoId;
3073 sleVault->at(sfFlags) = 0;
3074 sleVault->at(sfSequence) = sequence;
3075 sleVault->at(sfOwner) =
A1.id();
3076 sleVault->at(sfAssetsTotal) =
Number(0);
3077 sleVault->at(sfAssetsAvailable) =
Number(0);
3078 sleVault->at(sfLossUnrealized) =
Number(0);
3079 sleVault->at(sfShareMPTID) = sharesMptId;
3082 ac.view().
insert(sleVault);
3083 ac.view().
insert(sleShares);
3091 {
"shares issuer and vault pseudo-account must be the same",
3092 "shares issuer pseudo-account must point back to the vault"},
3094 auto const sequence = ac.view().
seq();
3097 auto const vaultPage =
3099 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3104 sleAccount->setAccountID(sfAccount, pseudoId);
3105 sleAccount->setFieldAmount(sfBalance,
STAmount{});
3110 sleAccount->setFieldU32(sfSequence, seqno);
3114 sleAccount->setFieldH256(sfVaultID,
uint256(42));
3115 ac.view().
insert(sleAccount);
3117 auto const sharesMptId =
makeMptID(sequence, pseudoId);
3120 auto const sharesPage =
3122 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3124 sleShares->at(sfFlags) = 0;
3125 sleShares->at(sfIssuer) = pseudoId;
3126 sleShares->at(sfOutstandingAmount) = 0;
3127 sleShares->at(sfSequence) = sequence;
3131 sleVault->at(sfAccount) =
A2.id();
3132 sleVault->at(sfFlags) = 0;
3133 sleVault->at(sfSequence) = sequence;
3134 sleVault->at(sfOwner) =
A1.id();
3135 sleVault->at(sfAssetsTotal) =
Number(0);
3136 sleVault->at(sfAssetsAvailable) =
Number(0);
3137 sleVault->at(sfLossUnrealized) =
Number(0);
3138 sleVault->at(sfShareMPTID) = sharesMptId;
3141 ac.view().
insert(sleVault);
3142 ac.view().
insert(sleShares);
3150 {
"shares issuer and vault pseudo-account must be the same",
"shares issuer must exist"},
3152 auto const sequence = ac.view().
seq();
3155 auto const vaultPage =
3157 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3159 auto const sharesMptId =
makeMptID(sequence,
A2.id());
3162 auto const sharesPage =
3164 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3166 sleShares->at(sfFlags) = 0;
3169 sleShares->at(sfOutstandingAmount) = 0;
3170 sleShares->at(sfSequence) = sequence;
3172 sleVault->at(sfAccount) =
A2.id();
3173 sleVault->at(sfFlags) = 0;
3174 sleVault->at(sfSequence) = sequence;
3175 sleVault->at(sfOwner) =
A1.id();
3176 sleVault->at(sfAssetsTotal) =
Number(0);
3177 sleVault->at(sfAssetsAvailable) =
Number(0);
3178 sleVault->at(sfLossUnrealized) =
Number(0);
3179 sleVault->at(sfShareMPTID) = sharesMptId;
3182 ac.view().
insert(sleVault);
3183 ac.view().
insert(sleShares);
3192 {
"deposit must change vault balance"},
3196 ac.view(), keylet, args(
A2.id(), 0, [](Adjustments& sample) { sample.vaultAssets.reset(); }));
3204 {
"deposit assets outstanding must not exceed assets maximum"},
3208 ac.view(), keylet, args(
A2.id(), 200, [&](Adjustments& sample) { sample.assetsMaximum = 1; }));
3221 {
"deposit must increase vault balance",
"deposit must change depositor balance"},
3229 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3232 return adjust(ac.view(), keylet, args(A3.id(), -10, [&](Adjustments& sample) {
3233 sample.accountAssets->amount = -100;
3241 tx[sfAccount] = A3.id();
3247 {
"deposit must increase vault balance",
3248 "deposit must decrease depositor balance",
3249 "deposit must change vault and depositor balance by equal amount",
3250 "deposit and assets outstanding must add up",
3251 "deposit and assets available must add up"},
3259 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3262 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3263 sample.vaultAssets = -20;
3264 sample.accountAssets->amount = 10;
3274 {
"deposit must change depositor balance"},
3282 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 10;
3285 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3286 sample.accountAssets->amount = 0;
3296 {
"deposit must change depositor shares"},
3300 ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) { sample.accountShares.reset(); }));
3309 {
"deposit must change vault shares"},
3314 ac.view(), keylet, args(
A2.id(), 10, [](Adjustments& sample) { sample.sharesTotal = 0; }));
3323 {
"deposit must increase depositor shares",
3324 "deposit must change depositor and vault shares by equal amount",
3325 "deposit must not change vault balance by more than deposited "
3329 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3330 sample.accountShares->amount = -5;
3331 sample.sharesTotal = -10;
3341 {
"deposit and assets outstanding must add up"},
3344 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3349 ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) { sample.assetsTotal = 11; }));
3356 tx[sfDelegate] = A3.id();
3364 {
"deposit and assets outstanding must add up",
"deposit and assets available must add up"},
3367 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3368 sample.assetsTotal = 7;
3369 sample.assetsAvailable = 7;
3380 {
"withdrawal must change vault balance"},
3384 ac.view(), keylet, args(
A2.id(), 0, [](Adjustments& sample) { sample.vaultAssets.reset(); }));
3396 {
"withdrawal must change one destination balance"},
3404 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3407 return adjust(ac.view(), keylet, args(A3.id(), -10, [&](Adjustments& sample) {
3408 sample.accountAssets->amount = -100;
3416 tx[sfAccount] = A3.id();
3424 {
"withdrawal must change vault and destination balance by "
3426 "withdrawal must decrease vault balance",
3427 "withdrawal must increase destination balance",
3428 "withdrawal and assets outstanding must add up",
3429 "withdrawal and assets available must add up"},
3437 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3440 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3441 sample.vaultAssets = 10;
3442 sample.accountAssets->amount = -20;
3452 {
"withdrawal must change one destination balance"},
3456 ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) { *sample.vaultAssets -= 5; })))
3461 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 5;
3472 {
"withdrawal must change depositor shares"},
3476 ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) { sample.accountShares.reset(); }));
3485 {
"withdrawal must change vault shares"},
3489 ac.view(), keylet, args(
A2.id(), -10, [](Adjustments& sample) { sample.sharesTotal = 0; }));
3498 {
"withdrawal must decrease depositor shares",
3499 "withdrawal must change depositor and vault shares by equal "
3503 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3504 sample.accountShares->amount = 5;
3505 sample.sharesTotal = 10;
3515 {
"withdrawal and assets outstanding must add up",
"withdrawal and assets available must add up"},
3518 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3519 sample.assetsTotal = -15;
3520 sample.assetsAvailable = -15;
3530 {
"withdrawal and assets outstanding must add up"},
3533 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3538 ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) { sample.assetsTotal = -7; }));
3545 tx[sfDelegate] = A3.id();
3553 env.fund(
XRP(1000), A3, A4);
3558 jv[sfAccount] = A3.human();
3559 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3565 auto const mptID =
makeMptID(env.seq(A3) - 1, A3);
3570 jv[sfAccount] =
A1.human();
3571 jv[sfTransactionType] = jss::MPTokenAuthorize;
3572 jv[sfMPTokenIssuanceID] =
to_string(mptID);
3574 jv[sfAccount] =
A2.human();
3576 jv[sfAccount] = A4.human();
3583 env(
pay(A3,
A1, asset(1000)));
3584 env(
pay(A3,
A2, asset(1000)));
3585 env(
pay(A3, A4, asset(1000)));
3590 auto [tx, keylet] = vault.create({.owner =
A1, .asset = asset});
3592 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = asset(10)}));
3593 env(vault.deposit({.depositor = A2, .id = keylet.key, .amount = asset(10)}));
3594 env(vault.deposit({.depositor = A4, .id = keylet.key, .amount = asset(10)}));
3599 {
"withdrawal must decrease depositor shares",
3600 "withdrawal must change depositor and vault shares by equal "
3604 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3605 sample.accountShares->amount = 5;
3609 STTx{ttVAULT_WITHDRAW, [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3616 {
"clawback must change vault balance"},
3620 ac.view(), keylet, args(
A2.id(), -1, [&](Adjustments& sample) { sample.vaultAssets.reset(); }));
3623 STTx{ttVAULT_CLAWBACK, [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3629 {
"clawback may only be performed by the asset issuer"},
3632 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {}));
3641 {
"clawback may only be performed by the asset issuer"},
3644 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {}));
3647 STTx{ttVAULT_CLAWBACK, [&](
STObject& tx) { tx[sfAccount] = A4.id(); }},
3652 {
"clawback must decrease vault balance",
3653 "clawback must decrease holder shares",
3654 "clawback must change vault shares"},
3658 ac.view(), keylet, args(A4.id(), 10, [&](Adjustments& sample) { sample.sharesTotal = 0; }));
3664 tx[sfAccount] = A3.id();
3665 tx[sfHolder] = A4.id();
3671 {
"clawback must change holder shares"},
3675 ac.view(), keylet, args(A4.id(), -10, [&](Adjustments& sample) { sample.accountShares.reset(); }));
3681 tx[sfAccount] = A3.id();
3682 tx[sfHolder] = A4.id();
3688 {
"clawback must change holder and vault shares by equal amount",
3689 "clawback and assets outstanding must add up",
3690 "clawback and assets available must add up"},
3693 return adjust(ac.view(), keylet, args(A4.id(), -10, [&](Adjustments& sample) {
3694 sample.accountShares->amount = -8;
3695 sample.assetsTotal = -7;
3696 sample.assetsAvailable = -7;
3703 tx[sfAccount] = A3.id();
3704 tx[sfHolder] = A4.id();