1273 using namespace test::jtx;
1277 {{
"permissioned domain with no rules."}},
1281 slePd->setAccountID(sfOwner,
A1);
1282 slePd->setFieldU32(sfSequence, 10);
1284 ac.view().insert(slePd);
1291 testcase <<
"PermissionedDomain 2";
1295 {{
"permissioned domain bad credentials size " +
1300 slePd->setAccountID(sfOwner,
A1);
1301 slePd->setFieldU32(sfSequence, 10);
1303 STArray credentials(sfAcceptedCredentials, tooBig);
1307 cred.setAccountID(sfIssuer,
A2);
1312 Slice(credType.c_str(), credType.size()));
1315 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1316 ac.view().insert(slePd);
1323 testcase <<
"PermissionedDomain 3";
1325 {{
"permissioned domain credentials aren't sorted"}},
1329 slePd->setAccountID(sfOwner,
A1);
1330 slePd->setFieldU32(sfSequence, 10);
1332 STArray credentials(sfAcceptedCredentials, 2);
1336 cred.setAccountID(sfIssuer,
A2);
1341 Slice(credType.c_str(), credType.size()));
1344 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1345 ac.view().insert(slePd);
1352 testcase <<
"PermissionedDomain 4";
1354 {{
"permissioned domain credentials aren't unique"}},
1358 slePd->setAccountID(sfOwner,
A1);
1359 slePd->setFieldU32(sfSequence, 10);
1361 STArray credentials(sfAcceptedCredentials, 2);
1365 cred.setAccountID(sfIssuer,
A2);
1366 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1369 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1370 ac.view().insert(slePd);
1377 testcase <<
"PermissionedDomain Set 1";
1379 {{
"permissioned domain with no rules."}},
1389 STArray credentials(sfAcceptedCredentials, 2);
1390 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1391 ac.view().update(slePd);
1400 testcase <<
"PermissionedDomain Set 2";
1402 {{
"permissioned domain bad credentials size " +
1413 STArray credentials(sfAcceptedCredentials, tooBig);
1418 cred.setAccountID(sfIssuer,
A2);
1422 Slice(credType.c_str(), credType.size()));
1426 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1427 ac.view().update(slePd);
1436 testcase <<
"PermissionedDomain Set 3";
1438 {{
"permissioned domain credentials aren't sorted"}},
1448 STArray credentials(sfAcceptedCredentials, 2);
1452 cred.setAccountID(sfIssuer,
A2);
1457 Slice(credType.c_str(), credType.size()));
1461 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1462 ac.view().update(slePd);
1471 testcase <<
"PermissionedDomain Set 4";
1473 {{
"permissioned domain credentials aren't unique"}},
1483 STArray credentials(sfAcceptedCredentials, 2);
1487 cred.setAccountID(sfIssuer,
A2);
1489 sfCredentialType,
Slice(
"cred_type", 9));
1492 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1493 ac.view().update(slePd);
2149 using namespace test::jtx;
2151 struct AccountAmount
2167 auto constexpr adjust = [&](
ApplyView& ac,
2170 auto sleVault = ac.
peek(keylet);
2174 auto const mptIssuanceID = (*sleVault)[sfShareMPTID];
2180 if (args.lossUnrealized)
2181 (*sleVault)[sfLossUnrealized] = *args.lossUnrealized;
2182 if (args.assetsMaximum)
2183 (*sleVault)[sfAssetsMaximum] = *args.assetsMaximum;
2186 if (args.assetsTotal)
2187 (*sleVault)[sfAssetsTotal] =
2188 *(*sleVault)[sfAssetsTotal] + *args.assetsTotal;
2189 if (args.assetsAvailable)
2190 (*sleVault)[sfAssetsAvailable] =
2191 *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable;
2194 if (args.sharesTotal)
2196 (*sleShares)[sfOutstandingAmount] =
2197 *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal;
2201 auto const assets = *(*sleVault)[sfAsset];
2202 auto const pseudoId = *(*sleVault)[sfAccount];
2203 if (args.vaultAssets)
2205 if (assets.native())
2208 if (!slePseudoAccount)
2210 (*slePseudoAccount)[sfBalance] =
2211 *(*slePseudoAccount)[sfBalance] + *args.vaultAssets;
2212 ac.
update(slePseudoAccount);
2216 auto const mptId = assets.get<
MPTIssue>().getMptID();
2220 (*sleMPToken)[sfMPTAmount] =
2221 *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets;
2228 if (args.accountAssets)
2230 auto const& pair = *args.accountAssets;
2231 if (assets.native())
2236 (*sleAccount)[sfBalance] =
2237 *(*sleAccount)[sfBalance] + pair.amount;
2242 auto const mptID = assets.get<
MPTIssue>().getMptID();
2247 (*sleMPToken)[sfMPTAmount] =
2248 *(*sleMPToken)[sfMPTAmount] + pair.amount;
2255 if (args.accountShares)
2257 auto const& pair = *args.accountShares;
2262 (*sleMPToken)[sfMPTAmount] =
2263 *(*sleMPToken)[sfMPTAmount] + pair.amount;
2269 constexpr auto args =
2270 [](
AccountID id,
int adjustment,
auto fn) -> Adjustments {
2271 Adjustments sample = {
2272 .assetsTotal = adjustment,
2273 .assetsAvailable = adjustment,
2274 .lossUnrealized = 0,
2275 .sharesTotal = adjustment,
2276 .vaultAssets = adjustment,
2278 AccountAmount{id, -adjustment},
2280 AccountAmount{id, adjustment}};
2287 auto const precloseXrp =
2289 env.fund(
XRP(1000), A3, A4);
2292 vault.create({.owner =
A1, .asset =
xrpIssue()});
2295 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2297 {.depositor = A2, .id = keylet.key, .amount = XRP(10)}));
2299 {.depositor = A3, .id = keylet.key, .amount = XRP(10)}));
2303 testcase <<
"Vault general checks";
2305 {
"vault deletion succeeded without deleting a vault"},
2308 auto sleVault = ac.view().
peek(keylet);
2311 ac.view().
update(sleVault);
2319 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2325 {
"vault updated by a wrong transaction type"},
2328 auto sleVault = ac.view().
peek(keylet);
2331 ac.view().
erase(sleVault);
2339 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2345 {
"vault updated by a wrong transaction type"},
2348 auto sleVault = ac.view().
peek(keylet);
2351 ac.view().
update(sleVault);
2359 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2365 {
"vault updated by a wrong transaction type"},
2367 auto const sequence = ac.view().
seq();
2370 auto const vaultPage = ac.view().
dirInsert(
2374 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2375 ac.view().
insert(sleVault);
2383 {
"vault deleted by a wrong transaction type"},
2386 auto sleVault = ac.view().
peek(keylet);
2389 ac.view().
erase(sleVault);
2397 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2403 {
"vault operation updated more than single vault"},
2407 auto sleVault = ac.view().
peek(keylet);
2410 ac.view().
erase(sleVault);
2414 auto sleVault = ac.view().
peek(keylet);
2417 ac.view().
erase(sleVault);
2428 vault.create({.owner =
A1, .asset =
xrpIssue()});
2433 vault.create({.owner =
A2, .asset =
xrpIssue()});
2440 {
"vault operation updated more than single vault"},
2442 auto const sequence = ac.view().
seq();
2443 auto const insertVault = [&](
Account const A) {
2446 auto const vaultPage = ac.view().
dirInsert(
2450 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2451 ac.view().
insert(sleVault);
2462 {
"deleted vault must also delete shares"},
2465 auto sleVault = ac.view().
peek(keylet);
2468 ac.view().
erase(sleVault);
2476 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2482 {
"deleted vault must have no shares outstanding",
2483 "deleted vault must have no assets outstanding",
2484 "deleted vault must have no assets available"},
2487 auto sleVault = ac.view().
peek(keylet);
2490 auto sleShares = ac.view().
peek(
2494 ac.view().
erase(sleVault);
2495 ac.view().
erase(sleShares);
2504 vault.create({.owner =
A1, .asset =
xrpIssue()});
2507 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2512 {
"vault operation succeeded without modifying a vault"},
2515 auto sleVault = ac.view().
peek(keylet);
2518 auto sleShares = ac.view().
peek(
2524 sleShares->setFieldH256(sfDomainID,
uint256(13));
2525 ac.view().
update(sleShares);
2535 {
"vault operation succeeded without modifying a vault"},
2544 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2550 {
"vault operation succeeded without modifying a vault"},
2559 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2565 {
"vault operation succeeded without modifying a vault"},
2574 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2580 {
"vault operation succeeded without modifying a vault"},
2589 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2595 {
"vault operation succeeded without modifying a vault"},
2604 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2610 {
"updated vault must have shares"},
2613 auto sleVault = ac.view().
peek(keylet);
2616 (*sleVault)[sfAssetsMaximum] = 200;
2617 ac.view().
update(sleVault);
2619 auto sleShares = ac.view().
peek(
2623 ac.view().
erase(sleShares);
2631 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2637 {
"vault operation succeeded without updating shares",
2638 "assets available must not be greater than assets outstanding"},
2641 auto sleVault = ac.view().
peek(keylet);
2644 (*sleVault)[sfAssetsTotal] = 9;
2645 ac.view().
update(sleVault);
2654 vault.create({.owner =
A1, .asset =
xrpIssue()});
2657 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2662 {
"set must not change assets outstanding",
2663 "set must not change assets available",
2664 "set must not change shares outstanding",
2665 "set must not change vault balance",
2666 "assets available must be positive",
2667 "assets available must not be greater than assets outstanding",
2668 "assets outstanding must be positive"},
2671 auto sleVault = ac.view().
peek(keylet);
2674 auto slePseudoAccount =
2676 if (!slePseudoAccount)
2678 (*slePseudoAccount)[sfBalance] =
2679 *(*slePseudoAccount)[sfBalance] - 10;
2680 ac.view().
update(slePseudoAccount);
2686 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2692 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);
2711 sleVault->setFieldIssue(
2713 ac.view().
update(sleVault);
2722 {
"violation of vault immutable data"},
2725 auto sleVault = ac.view().
peek(keylet);
2728 sleVault->setAccountID(sfAccount,
A2.id());
2729 ac.view().
update(sleVault);
2738 {
"violation of vault immutable data"},
2741 auto sleVault = ac.view().
peek(keylet);
2744 (*sleVault)[sfShareMPTID] =
MPTID(42);
2745 ac.view().
update(sleVault);
2754 {
"vault transaction must not change loss unrealized",
2755 "set must not change assets outstanding"},
2761 args(
A2.id(), 0, [&](Adjustments& sample) {
2762 sample.lossUnrealized = 13;
2763 sample.assetsTotal = 20;
2773 {
"loss unrealized must not exceed the difference "
2774 "between assets outstanding and available",
2775 "vault transaction must not change loss unrealized"},
2781 args(
A2.id(), 100, [&](Adjustments& sample) {
2782 sample.lossUnrealized = 13;
2796 {
"set assets outstanding must not exceed assets maximum"},
2802 args(
A2.id(), 0, [&](Adjustments& sample) {
2803 sample.assetsMaximum = 1;
2813 {
"assets maximum must be positive"},
2819 args(
A2.id(), 0, [&](Adjustments& sample) {
2820 sample.assetsMaximum = -1;
2830 {
"set must not change shares outstanding",
2831 "updated zero sized vault must have no assets outstanding",
2832 "updated zero sized vault must have no assets available"},
2835 auto sleVault = ac.view().
peek(keylet);
2838 ac.view().
update(sleVault);
2839 auto sleShares = ac.view().
peek(
2843 (*sleShares)[sfOutstandingAmount] = 0;
2844 ac.view().
update(sleShares);
2854 {
"updated shares must not exceed maximum"},
2857 auto sleVault = ac.view().
peek(keylet);
2860 auto sleShares = ac.view().
peek(
2864 (*sleShares)[sfMaximumAmount] = 10;
2865 ac.view().
update(sleShares);
2868 ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2877 {
"updated shares must not exceed maximum"},
2881 ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2883 auto sleVault = ac.view().
peek(keylet);
2886 auto sleShares = ac.view().
peek(
2891 ac.view().
update(sleShares);
2903 "created vault must be empty",
2904 "updated zero sized vault must have no assets outstanding",
2905 "create operation must not have updated a vault",
2909 auto sleVault = ac.view().
peek(keylet);
2912 (*sleVault)[sfAssetsTotal] = 9;
2913 ac.view().
update(sleVault);
2922 vault.create({.owner =
A1, .asset =
xrpIssue()});
2929 "created vault must be empty",
2930 "updated zero sized vault must have no assets available",
2931 "assets available must not be greater than assets outstanding",
2932 "create operation must not have updated a vault",
2936 auto sleVault = ac.view().
peek(keylet);
2939 (*sleVault)[sfAssetsAvailable] = 9;
2940 ac.view().
update(sleVault);
2949 vault.create({.owner =
A1, .asset =
xrpIssue()});
2956 "created vault must be empty",
2957 "loss unrealized must not exceed the difference between assets "
2958 "outstanding and available",
2959 "vault transaction must not change loss unrealized",
2960 "create operation must not have updated a vault",
2964 auto sleVault = ac.view().
peek(keylet);
2967 (*sleVault)[sfLossUnrealized] = 1;
2968 ac.view().
update(sleVault);
2977 vault.create({.owner =
A1, .asset =
xrpIssue()});
2984 "created vault must be empty",
2985 "create operation must not have updated a vault",
2989 auto sleVault = ac.view().
peek(keylet);
2992 auto sleShares = ac.view().
peek(
2996 ac.view().
update(sleVault);
2997 (*sleShares)[sfOutstandingAmount] = 9;
2998 ac.view().
update(sleShares);
3007 vault.create({.owner =
A1, .asset =
xrpIssue()});
3014 "assets maximum must be positive",
3015 "create operation must not have updated a vault",
3019 auto sleVault = ac.view().
peek(keylet);
3022 (*sleVault)[sfAssetsMaximum] =
Number(-1);
3023 ac.view().
update(sleVault);
3032 vault.create({.owner =
A1, .asset =
xrpIssue()});
3038 {
"create operation must not have updated a vault",
3039 "shares issuer and vault pseudo-account must be the same",
3040 "shares issuer must be a pseudo-account",
3041 "shares issuer pseudo-account must point back to the vault"},
3044 auto sleVault = ac.view().
peek(keylet);
3047 auto sleShares = ac.view().
peek(
3051 ac.view().
update(sleVault);
3052 (*sleShares)[sfIssuer] =
A1.id();
3053 ac.view().
update(sleShares);
3062 vault.create({.owner =
A1, .asset =
xrpIssue()});
3068 {
"vault created by a wrong transaction type",
3069 "account root created illegally"},
3074 auto const sequence = ac.view().
seq();
3077 auto const vaultPage = ac.view().
dirInsert(
3081 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3088 sleAccount->setAccountID(sfAccount, pseudoId);
3089 sleAccount->setFieldAmount(sfBalance,
STAmount{});
3094 sleAccount->setFieldU32(sfSequence, seqno);
3095 sleAccount->setFieldU32(
3098 sleAccount->setFieldH256(sfVaultID, vaultKeylet.key);
3099 ac.view().
insert(sleAccount);
3101 auto const sharesMptId =
makeMptID(sequence, pseudoId);
3104 auto const sharesPage = ac.view().
dirInsert(
3108 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3110 sleShares->at(sfFlags) = 0;
3111 sleShares->at(sfIssuer) = pseudoId;
3112 sleShares->at(sfOutstandingAmount) = 0;
3113 sleShares->at(sfSequence) = sequence;
3115 sleVault->at(sfAccount) = pseudoId;
3116 sleVault->at(sfFlags) = 0;
3117 sleVault->at(sfSequence) = sequence;
3118 sleVault->at(sfOwner) =
A1.id();
3119 sleVault->at(sfAssetsTotal) =
Number(0);
3120 sleVault->at(sfAssetsAvailable) =
Number(0);
3121 sleVault->at(sfLossUnrealized) =
Number(0);
3122 sleVault->at(sfShareMPTID) = sharesMptId;
3123 sleVault->at(sfWithdrawalPolicy) =
3126 ac.view().
insert(sleVault);
3127 ac.view().
insert(sleShares);
3135 {
"shares issuer and vault pseudo-account must be the same",
3136 "shares issuer pseudo-account must point back to the vault"},
3138 auto const sequence = ac.view().
seq();
3141 auto const vaultPage = ac.view().
dirInsert(
3145 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3152 sleAccount->setAccountID(sfAccount, pseudoId);
3153 sleAccount->setFieldAmount(sfBalance,
STAmount{});
3158 sleAccount->setFieldU32(sfSequence, seqno);
3159 sleAccount->setFieldU32(
3164 sleAccount->setFieldH256(sfVaultID,
uint256(42));
3165 ac.view().
insert(sleAccount);
3167 auto const sharesMptId =
makeMptID(sequence, pseudoId);
3170 auto const sharesPage = ac.view().
dirInsert(
3174 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3176 sleShares->at(sfFlags) = 0;
3177 sleShares->at(sfIssuer) = pseudoId;
3178 sleShares->at(sfOutstandingAmount) = 0;
3179 sleShares->at(sfSequence) = sequence;
3183 sleVault->at(sfAccount) =
A2.id();
3184 sleVault->at(sfFlags) = 0;
3185 sleVault->at(sfSequence) = sequence;
3186 sleVault->at(sfOwner) =
A1.id();
3187 sleVault->at(sfAssetsTotal) =
Number(0);
3188 sleVault->at(sfAssetsAvailable) =
Number(0);
3189 sleVault->at(sfLossUnrealized) =
Number(0);
3190 sleVault->at(sfShareMPTID) = sharesMptId;
3191 sleVault->at(sfWithdrawalPolicy) =
3194 ac.view().
insert(sleVault);
3195 ac.view().
insert(sleShares);
3203 {
"shares issuer and vault pseudo-account must be the same",
3204 "shares issuer must exist"},
3206 auto const sequence = ac.view().
seq();
3209 auto const vaultPage = ac.view().
dirInsert(
3213 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
3215 auto const sharesMptId =
makeMptID(sequence,
A2.id());
3218 auto const sharesPage = ac.view().
dirInsert(
3222 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
3224 sleShares->at(sfFlags) = 0;
3227 sleShares->at(sfOutstandingAmount) = 0;
3228 sleShares->at(sfSequence) = sequence;
3230 sleVault->at(sfAccount) =
A2.id();
3231 sleVault->at(sfFlags) = 0;
3232 sleVault->at(sfSequence) = sequence;
3233 sleVault->at(sfOwner) =
A1.id();
3234 sleVault->at(sfAssetsTotal) =
Number(0);
3235 sleVault->at(sfAssetsAvailable) =
Number(0);
3236 sleVault->at(sfLossUnrealized) =
Number(0);
3237 sleVault->at(sfShareMPTID) = sharesMptId;
3238 sleVault->at(sfWithdrawalPolicy) =
3241 ac.view().
insert(sleVault);
3242 ac.view().
insert(sleShares);
3251 {
"deposit must change vault balance"},
3257 args(
A2.id(), 0, [](Adjustments& sample) {
3258 sample.vaultAssets.reset();
3267 {
"deposit assets outstanding must not exceed assets maximum"},
3273 args(
A2.id(), 200, [&](Adjustments& sample) {
3274 sample.assetsMaximum = 1;
3292 {
"deposit must increase vault balance",
3293 "deposit must change depositor balance"},
3301 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3307 args(A3.id(), -10, [&](Adjustments& sample) {
3308 sample.accountAssets->amount = -100;
3316 tx[sfAccount] = A3.id();
3322 {
"deposit must increase vault balance",
3323 "deposit must decrease depositor balance",
3324 "deposit must change vault and depositor balance by equal amount",
3325 "deposit and assets outstanding must add up",
3326 "deposit and assets available must add up"},
3334 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3340 args(
A2.id(), 10, [&](Adjustments& sample) {
3341 sample.vaultAssets = -20;
3342 sample.accountAssets->amount = 10;
3354 {
"deposit must change depositor balance"},
3362 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 10;
3368 args(
A2.id(), 10, [&](Adjustments& sample) {
3369 sample.accountAssets->amount = 0;
3381 {
"deposit must change depositor shares"},
3387 args(
A2.id(), 10, [&](Adjustments& sample) {
3388 sample.accountShares.reset();
3400 {
"deposit must change vault shares"},
3407 args(
A2.id(), 10, [](Adjustments& sample) {
3408 sample.sharesTotal = 0;
3420 {
"deposit must increase depositor shares",
3421 "deposit must change depositor and vault shares by equal amount",
3422 "deposit must not change vault balance by more than deposited "
3429 args(
A2.id(), 10, [&](Adjustments& sample) {
3430 sample.accountShares->amount = -5;
3431 sample.sharesTotal = -10;
3443 {
"deposit and assets outstanding must add up"},
3446 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3453 args(
A2.id(), 10, [&](Adjustments& sample) {
3454 sample.assetsTotal = 11;
3462 tx[sfDelegate] = A3.id();
3470 {
"deposit and assets outstanding must add up",
3471 "deposit and assets available must add up"},
3477 args(
A2.id(), 10, [&](Adjustments& sample) {
3478 sample.assetsTotal = 7;
3479 sample.assetsAvailable = 7;
3492 {
"withdrawal must change vault balance"},
3498 args(
A2.id(), 0, [](Adjustments& sample) {
3499 sample.vaultAssets.reset();
3512 {
"withdrawal must change one destination balance"},
3520 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3526 args(A3.id(), -10, [&](Adjustments& sample) {
3527 sample.accountAssets->amount = -100;
3535 tx[sfAccount] = A3.id();
3543 {
"withdrawal must change vault and destination balance by "
3545 "withdrawal must decrease vault balance",
3546 "withdrawal must increase destination balance",
3547 "withdrawal and assets outstanding must add up",
3548 "withdrawal and assets available must add up"},
3556 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3562 args(
A2.id(), -10, [&](Adjustments& sample) {
3563 sample.vaultAssets = 10;
3564 sample.accountAssets->amount = -20;
3574 {
"withdrawal must change one destination balance"},
3580 args(
A2.id(), -10, [&](Adjustments& sample) {
3581 *sample.vaultAssets -= 5;
3587 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 5;
3600 {
"withdrawal must change depositor shares"},
3606 args(
A2.id(), -10, [&](Adjustments& sample) {
3607 sample.accountShares.reset();
3617 {
"withdrawal must change vault shares"},
3623 args(
A2.id(), -10, [](Adjustments& sample) {
3624 sample.sharesTotal = 0;
3634 {
"withdrawal must decrease depositor shares",
3635 "withdrawal must change depositor and vault shares by equal "
3642 args(
A2.id(), -10, [&](Adjustments& sample) {
3643 sample.accountShares->amount = 5;
3644 sample.sharesTotal = 10;
3654 {
"withdrawal and assets outstanding must add up",
3655 "withdrawal and assets available must add up"},
3661 args(
A2.id(), -10, [&](Adjustments& sample) {
3662 sample.assetsTotal = -15;
3663 sample.assetsAvailable = -15;
3673 {
"withdrawal and assets outstanding must add up"},
3676 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3683 args(
A2.id(), -10, [&](Adjustments& sample) {
3684 sample.assetsTotal = -7;
3692 tx[sfDelegate] = A3.id();
3699 auto const precloseMpt =
3701 env.fund(
XRP(1000), A3, A4);
3706 jv[sfAccount] = A3.human();
3707 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3713 auto const mptID =
makeMptID(env.seq(A3) - 1, A3);
3718 jv[sfAccount] =
A1.human();
3719 jv[sfTransactionType] = jss::MPTokenAuthorize;
3720 jv[sfMPTokenIssuanceID] =
to_string(mptID);
3722 jv[sfAccount] =
A2.human();
3724 jv[sfAccount] = A4.human();
3731 env(
pay(A3,
A1, asset(1000)));
3732 env(
pay(A3,
A2, asset(1000)));
3733 env(
pay(A3, A4, asset(1000)));
3738 auto [tx, keylet] = vault.create({.owner =
A1, .asset = asset});
3741 {.depositor = A1, .id = keylet.key, .amount = asset(10)}));
3743 {.depositor = A2, .id = keylet.key, .amount = asset(10)}));
3745 {.depositor = A4, .id = keylet.key, .amount = asset(10)}));
3750 {
"withdrawal must decrease depositor shares",
3751 "withdrawal must change depositor and vault shares by equal "
3758 args(
A2.id(), -10, [&](Adjustments& sample) {
3759 sample.accountShares->amount = 5;
3765 [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3772 {
"clawback must change vault balance"},
3778 args(
A2.id(), -1, [&](Adjustments& sample) {
3779 sample.vaultAssets.reset();
3785 [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3791 {
"clawback may only be performed by the asset issuer"},
3797 args(
A2.id(), 0, [&](Adjustments& sample) {}));
3806 {
"clawback may only be performed by the asset issuer"},
3812 args(
A2.id(), 0, [&](Adjustments& sample) {}));
3817 [&](
STObject& tx) { tx[sfAccount] = A4.id(); }},
3822 {
"clawback must decrease vault balance",
3823 "clawback must decrease holder shares",
3824 "clawback must change vault shares"},
3830 args(A4.id(), 10, [&](Adjustments& sample) {
3831 sample.sharesTotal = 0;
3838 tx[sfAccount] = A3.id();
3839 tx[sfHolder] = A4.id();
3845 {
"clawback must change holder shares"},
3851 args(A4.id(), -10, [&](Adjustments& sample) {
3852 sample.accountShares.reset();
3859 tx[sfAccount] = A3.id();
3860 tx[sfHolder] = A4.id();
3866 {
"clawback must change holder and vault shares by equal amount",
3867 "clawback and assets outstanding must add up",
3868 "clawback and assets available must add up"},
3874 args(A4.id(), -10, [&](Adjustments& sample) {
3875 sample.accountShares->amount = -8;
3876 sample.assetsTotal = -7;
3877 sample.assetsAvailable = -7;
3884 tx[sfAccount] = A3.id();
3885 tx[sfHolder] = A4.id();