1205 using namespace test::jtx;
1209 {{
"permissioned domain with no rules."}},
1213 slePd->setAccountID(sfOwner,
A1);
1214 slePd->setFieldU32(sfSequence, 10);
1216 ac.view().insert(slePd);
1223 testcase <<
"PermissionedDomain 2";
1227 {{
"permissioned domain bad credentials size " +
1232 slePd->setAccountID(sfOwner,
A1);
1233 slePd->setFieldU32(sfSequence, 10);
1235 STArray credentials(sfAcceptedCredentials, tooBig);
1239 cred.setAccountID(sfIssuer,
A2);
1244 Slice(credType.c_str(), credType.size()));
1247 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1248 ac.view().insert(slePd);
1255 testcase <<
"PermissionedDomain 3";
1257 {{
"permissioned domain credentials aren't sorted"}},
1261 slePd->setAccountID(sfOwner,
A1);
1262 slePd->setFieldU32(sfSequence, 10);
1264 STArray credentials(sfAcceptedCredentials, 2);
1268 cred.setAccountID(sfIssuer,
A2);
1273 Slice(credType.c_str(), credType.size()));
1276 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1277 ac.view().insert(slePd);
1284 testcase <<
"PermissionedDomain 4";
1286 {{
"permissioned domain credentials aren't unique"}},
1290 slePd->setAccountID(sfOwner,
A1);
1291 slePd->setFieldU32(sfSequence, 10);
1293 STArray credentials(sfAcceptedCredentials, 2);
1297 cred.setAccountID(sfIssuer,
A2);
1298 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1301 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1302 ac.view().insert(slePd);
1309 testcase <<
"PermissionedDomain Set 1";
1311 {{
"permissioned domain with no rules."}},
1321 STArray credentials(sfAcceptedCredentials, 2);
1322 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1323 ac.view().update(slePd);
1332 testcase <<
"PermissionedDomain Set 2";
1334 {{
"permissioned domain bad credentials size " +
1345 STArray credentials(sfAcceptedCredentials, tooBig);
1350 cred.setAccountID(sfIssuer,
A2);
1354 Slice(credType.c_str(), credType.size()));
1358 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1359 ac.view().update(slePd);
1368 testcase <<
"PermissionedDomain Set 3";
1370 {{
"permissioned domain credentials aren't sorted"}},
1380 STArray credentials(sfAcceptedCredentials, 2);
1384 cred.setAccountID(sfIssuer,
A2);
1389 Slice(credType.c_str(), credType.size()));
1393 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1394 ac.view().update(slePd);
1403 testcase <<
"PermissionedDomain Set 4";
1405 {{
"permissioned domain credentials aren't unique"}},
1415 STArray credentials(sfAcceptedCredentials, 2);
1419 cred.setAccountID(sfIssuer,
A2);
1421 sfCredentialType,
Slice(
"cred_type", 9));
1424 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1425 ac.view().update(slePd);
1728 using namespace test::jtx;
1730 struct AccountAmount
1746 auto constexpr adjust = [&](
ApplyView& ac,
1749 auto sleVault = ac.
peek(keylet);
1753 auto const mptIssuanceID = (*sleVault)[sfShareMPTID];
1759 if (args.lossUnrealized)
1760 (*sleVault)[sfLossUnrealized] = *args.lossUnrealized;
1761 if (args.assetsMaximum)
1762 (*sleVault)[sfAssetsMaximum] = *args.assetsMaximum;
1765 if (args.assetsTotal)
1766 (*sleVault)[sfAssetsTotal] =
1767 *(*sleVault)[sfAssetsTotal] + *args.assetsTotal;
1768 if (args.assetsAvailable)
1769 (*sleVault)[sfAssetsAvailable] =
1770 *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable;
1773 if (args.sharesTotal)
1775 (*sleShares)[sfOutstandingAmount] =
1776 *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal;
1780 auto const assets = *(*sleVault)[sfAsset];
1781 auto const pseudoId = *(*sleVault)[sfAccount];
1782 if (args.vaultAssets)
1784 if (assets.native())
1787 if (!slePseudoAccount)
1789 (*slePseudoAccount)[sfBalance] =
1790 *(*slePseudoAccount)[sfBalance] + *args.vaultAssets;
1791 ac.
update(slePseudoAccount);
1795 auto const mptId = assets.get<
MPTIssue>().getMptID();
1799 (*sleMPToken)[sfMPTAmount] =
1800 *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets;
1807 if (args.accountAssets)
1809 auto const& pair = *args.accountAssets;
1810 if (assets.native())
1815 (*sleAccount)[sfBalance] =
1816 *(*sleAccount)[sfBalance] + pair.amount;
1821 auto const mptID = assets.get<
MPTIssue>().getMptID();
1826 (*sleMPToken)[sfMPTAmount] =
1827 *(*sleMPToken)[sfMPTAmount] + pair.amount;
1834 if (args.accountShares)
1836 auto const& pair = *args.accountShares;
1841 (*sleMPToken)[sfMPTAmount] =
1842 *(*sleMPToken)[sfMPTAmount] + pair.amount;
1848 constexpr auto args =
1849 [](
AccountID id,
int adjustment,
auto fn) -> Adjustments {
1850 Adjustments sample = {
1851 .assetsTotal = adjustment,
1852 .assetsAvailable = adjustment,
1853 .lossUnrealized = 0,
1854 .sharesTotal = adjustment,
1855 .vaultAssets = adjustment,
1857 AccountAmount{id, -adjustment},
1859 AccountAmount{id, adjustment}};
1866 auto const precloseXrp =
1868 env.fund(
XRP(1000), A3, A4);
1871 vault.create({.owner =
A1, .asset =
xrpIssue()});
1874 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
1876 {.depositor = A2, .id = keylet.key, .amount = XRP(10)}));
1878 {.depositor = A3, .id = keylet.key, .amount = XRP(10)}));
1882 testcase <<
"Vault general checks";
1884 {
"vault deletion succeeded without deleting a vault"},
1887 auto sleVault = ac.view().
peek(keylet);
1890 ac.view().
update(sleVault);
1898 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1904 {
"vault updated by a wrong transaction type"},
1907 auto sleVault = ac.view().
peek(keylet);
1910 ac.view().
erase(sleVault);
1918 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1924 {
"vault updated by a wrong transaction type"},
1927 auto sleVault = ac.view().
peek(keylet);
1930 ac.view().
update(sleVault);
1938 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1944 {
"vault updated by a wrong transaction type"},
1946 auto const sequence = ac.view().
seq();
1949 auto const vaultPage = ac.view().
dirInsert(
1953 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
1954 ac.view().
insert(sleVault);
1962 {
"vault deleted by a wrong transaction type"},
1965 auto sleVault = ac.view().
peek(keylet);
1968 ac.view().
erase(sleVault);
1976 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1982 {
"vault operation updated more than single vault"},
1986 auto sleVault = ac.view().
peek(keylet);
1989 ac.view().
erase(sleVault);
1993 auto sleVault = ac.view().
peek(keylet);
1996 ac.view().
erase(sleVault);
2007 vault.create({.owner =
A1, .asset =
xrpIssue()});
2012 vault.create({.owner =
A2, .asset =
xrpIssue()});
2019 {
"vault operation updated more than single vault"},
2021 auto const sequence = ac.view().
seq();
2022 auto const insertVault = [&](
Account const A) {
2025 auto const vaultPage = ac.view().
dirInsert(
2029 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2030 ac.view().
insert(sleVault);
2041 {
"deleted vault must also delete shares"},
2044 auto sleVault = ac.view().
peek(keylet);
2047 ac.view().
erase(sleVault);
2055 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2061 {
"deleted vault must have no shares outstanding",
2062 "deleted vault must have no assets outstanding",
2063 "deleted vault must have no assets available"},
2066 auto sleVault = ac.view().
peek(keylet);
2069 auto sleShares = ac.view().
peek(
2073 ac.view().
erase(sleVault);
2074 ac.view().
erase(sleShares);
2083 vault.create({.owner =
A1, .asset =
xrpIssue()});
2086 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2091 {
"vault operation succeeded without modifying a vault"},
2094 auto sleVault = ac.view().
peek(keylet);
2097 auto sleShares = ac.view().
peek(
2103 sleShares->setFieldH256(sfDomainID,
uint256(13));
2104 ac.view().
update(sleShares);
2114 {
"vault operation succeeded without modifying a vault"},
2123 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2129 {
"vault operation succeeded without modifying a vault"},
2138 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2144 {
"vault operation succeeded without modifying a vault"},
2153 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2159 {
"vault operation succeeded without modifying a vault"},
2168 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2174 {
"vault operation succeeded without modifying a vault"},
2183 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2189 {
"updated vault must have shares"},
2192 auto sleVault = ac.view().
peek(keylet);
2195 (*sleVault)[sfAssetsMaximum] = 200;
2196 ac.view().
update(sleVault);
2198 auto sleShares = ac.view().
peek(
2202 ac.view().
erase(sleShares);
2210 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2216 {
"vault operation succeeded without updating shares",
2217 "assets available must not be greater than assets outstanding"},
2220 auto sleVault = ac.view().
peek(keylet);
2223 (*sleVault)[sfAssetsTotal] = 9;
2224 ac.view().
update(sleVault);
2233 vault.create({.owner =
A1, .asset =
xrpIssue()});
2236 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2241 {
"set must not change assets outstanding",
2242 "set must not change assets available",
2243 "set must not change shares outstanding",
2244 "set must not change vault balance",
2245 "assets available must be positive",
2246 "assets available must not be greater than assets outstanding",
2247 "assets outstanding must be positive"},
2250 auto sleVault = ac.view().
peek(keylet);
2253 auto slePseudoAccount =
2255 if (!slePseudoAccount)
2257 (*slePseudoAccount)[sfBalance] =
2258 *(*slePseudoAccount)[sfBalance] - 10;
2259 ac.view().
update(slePseudoAccount);
2265 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2271 args(
A2.id(), 0, [&](Adjustments& sample) {
2272 sample.assetsAvailable = (DROPS_PER_XRP * -100).value();
2273 sample.assetsTotal = (DROPS_PER_XRP * -200).value();
2274 sample.sharesTotal = -1;
2284 {
"violation of vault immutable data"},
2287 auto sleVault = ac.view().
peek(keylet);
2290 sleVault->setFieldIssue(
2292 ac.view().
update(sleVault);
2301 {
"violation of vault immutable data"},
2304 auto sleVault = ac.view().
peek(keylet);
2307 sleVault->setAccountID(sfAccount,
A2.id());
2308 ac.view().
update(sleVault);
2317 {
"violation of vault immutable data"},
2320 auto sleVault = ac.view().
peek(keylet);
2323 (*sleVault)[sfShareMPTID] =
MPTID(42);
2324 ac.view().
update(sleVault);
2333 {
"vault transaction must not change loss unrealized",
2334 "set must not change assets outstanding"},
2340 args(
A2.id(), 0, [&](Adjustments& sample) {
2341 sample.lossUnrealized = 13;
2342 sample.assetsTotal = 20;
2352 {
"loss unrealized must not exceed the difference "
2353 "between assets outstanding and available",
2354 "vault transaction must not change loss unrealized"},
2360 args(
A2.id(), 100, [&](Adjustments& sample) {
2361 sample.lossUnrealized = 13;
2375 {
"set assets outstanding must not exceed assets maximum"},
2381 args(
A2.id(), 0, [&](Adjustments& sample) {
2382 sample.assetsMaximum = 1;
2392 {
"assets maximum must be positive"},
2398 args(
A2.id(), 0, [&](Adjustments& sample) {
2399 sample.assetsMaximum = -1;
2409 {
"set must not change shares outstanding",
2410 "updated zero sized vault must have no assets outstanding",
2411 "updated zero sized vault must have no assets available"},
2414 auto sleVault = ac.view().
peek(keylet);
2417 ac.view().
update(sleVault);
2418 auto sleShares = ac.view().
peek(
2422 (*sleShares)[sfOutstandingAmount] = 0;
2423 ac.view().
update(sleShares);
2433 {
"updated shares must not exceed maximum"},
2436 auto sleVault = ac.view().
peek(keylet);
2439 auto sleShares = ac.view().
peek(
2443 (*sleShares)[sfMaximumAmount] = 10;
2444 ac.view().
update(sleShares);
2447 ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2456 {
"updated shares must not exceed maximum"},
2460 ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2462 auto sleVault = ac.view().
peek(keylet);
2465 auto sleShares = ac.view().
peek(
2470 ac.view().
update(sleShares);
2482 "created vault must be empty",
2483 "updated zero sized vault must have no assets outstanding",
2484 "create operation must not have updated a vault",
2488 auto sleVault = ac.view().
peek(keylet);
2491 (*sleVault)[sfAssetsTotal] = 9;
2492 ac.view().
update(sleVault);
2501 vault.create({.owner =
A1, .asset =
xrpIssue()});
2508 "created vault must be empty",
2509 "updated zero sized vault must have no assets available",
2510 "assets available must not be greater than assets outstanding",
2511 "create operation must not have updated a vault",
2515 auto sleVault = ac.view().
peek(keylet);
2518 (*sleVault)[sfAssetsAvailable] = 9;
2519 ac.view().
update(sleVault);
2528 vault.create({.owner =
A1, .asset =
xrpIssue()});
2535 "created vault must be empty",
2536 "loss unrealized must not exceed the difference between assets "
2537 "outstanding and available",
2538 "vault transaction must not change loss unrealized",
2539 "create operation must not have updated a vault",
2543 auto sleVault = ac.view().
peek(keylet);
2546 (*sleVault)[sfLossUnrealized] = 1;
2547 ac.view().
update(sleVault);
2556 vault.create({.owner =
A1, .asset =
xrpIssue()});
2563 "created vault must be empty",
2564 "create operation must not have updated a vault",
2568 auto sleVault = ac.view().
peek(keylet);
2571 auto sleShares = ac.view().
peek(
2575 ac.view().
update(sleVault);
2576 (*sleShares)[sfOutstandingAmount] = 9;
2577 ac.view().
update(sleShares);
2586 vault.create({.owner =
A1, .asset =
xrpIssue()});
2593 "assets maximum must be positive",
2594 "create operation must not have updated a vault",
2598 auto sleVault = ac.view().
peek(keylet);
2601 (*sleVault)[sfAssetsMaximum] =
Number(-1);
2602 ac.view().
update(sleVault);
2611 vault.create({.owner =
A1, .asset =
xrpIssue()});
2617 {
"create operation must not have updated a vault",
2618 "shares issuer and vault pseudo-account must be the same",
2619 "shares issuer must be a pseudo-account",
2620 "shares issuer pseudo-account must point back to the vault"},
2623 auto sleVault = ac.view().
peek(keylet);
2626 auto sleShares = ac.view().
peek(
2630 ac.view().
update(sleVault);
2631 (*sleShares)[sfIssuer] =
A1.id();
2632 ac.view().
update(sleShares);
2641 vault.create({.owner =
A1, .asset =
xrpIssue()});
2647 {
"vault created by a wrong transaction type",
2648 "account root created illegally"},
2653 auto const sequence = ac.view().
seq();
2656 auto const vaultPage = ac.view().
dirInsert(
2660 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2667 sleAccount->setAccountID(sfAccount, pseudoId);
2668 sleAccount->setFieldAmount(sfBalance,
STAmount{});
2673 sleAccount->setFieldU32(sfSequence, seqno);
2674 sleAccount->setFieldU32(
2677 sleAccount->setFieldH256(sfVaultID, vaultKeylet.key);
2678 ac.view().
insert(sleAccount);
2680 auto const sharesMptId =
makeMptID(sequence, pseudoId);
2683 auto const sharesPage = ac.view().
dirInsert(
2687 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2689 sleShares->at(sfFlags) = 0;
2690 sleShares->at(sfIssuer) = pseudoId;
2691 sleShares->at(sfOutstandingAmount) = 0;
2692 sleShares->at(sfSequence) = sequence;
2694 sleVault->at(sfAccount) = pseudoId;
2695 sleVault->at(sfFlags) = 0;
2696 sleVault->at(sfSequence) = sequence;
2697 sleVault->at(sfOwner) =
A1.id();
2698 sleVault->at(sfAssetsTotal) =
Number(0);
2699 sleVault->at(sfAssetsAvailable) =
Number(0);
2700 sleVault->at(sfLossUnrealized) =
Number(0);
2701 sleVault->at(sfShareMPTID) = sharesMptId;
2702 sleVault->at(sfWithdrawalPolicy) =
2705 ac.view().
insert(sleVault);
2706 ac.view().
insert(sleShares);
2714 {
"shares issuer and vault pseudo-account must be the same",
2715 "shares issuer pseudo-account must point back to the vault"},
2717 auto const sequence = ac.view().
seq();
2720 auto const vaultPage = ac.view().
dirInsert(
2724 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2731 sleAccount->setAccountID(sfAccount, pseudoId);
2732 sleAccount->setFieldAmount(sfBalance,
STAmount{});
2737 sleAccount->setFieldU32(sfSequence, seqno);
2738 sleAccount->setFieldU32(
2743 sleAccount->setFieldH256(sfVaultID,
uint256(42));
2744 ac.view().
insert(sleAccount);
2746 auto const sharesMptId =
makeMptID(sequence, pseudoId);
2749 auto const sharesPage = ac.view().
dirInsert(
2753 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2755 sleShares->at(sfFlags) = 0;
2756 sleShares->at(sfIssuer) = pseudoId;
2757 sleShares->at(sfOutstandingAmount) = 0;
2758 sleShares->at(sfSequence) = sequence;
2762 sleVault->at(sfAccount) =
A2.id();
2763 sleVault->at(sfFlags) = 0;
2764 sleVault->at(sfSequence) = sequence;
2765 sleVault->at(sfOwner) =
A1.id();
2766 sleVault->at(sfAssetsTotal) =
Number(0);
2767 sleVault->at(sfAssetsAvailable) =
Number(0);
2768 sleVault->at(sfLossUnrealized) =
Number(0);
2769 sleVault->at(sfShareMPTID) = sharesMptId;
2770 sleVault->at(sfWithdrawalPolicy) =
2773 ac.view().
insert(sleVault);
2774 ac.view().
insert(sleShares);
2782 {
"shares issuer and vault pseudo-account must be the same",
2783 "shares issuer must exist"},
2785 auto const sequence = ac.view().
seq();
2788 auto const vaultPage = ac.view().
dirInsert(
2792 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2794 auto const sharesMptId =
makeMptID(sequence,
A2.id());
2797 auto const sharesPage = ac.view().
dirInsert(
2801 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2803 sleShares->at(sfFlags) = 0;
2806 sleShares->at(sfOutstandingAmount) = 0;
2807 sleShares->at(sfSequence) = sequence;
2809 sleVault->at(sfAccount) =
A2.id();
2810 sleVault->at(sfFlags) = 0;
2811 sleVault->at(sfSequence) = sequence;
2812 sleVault->at(sfOwner) =
A1.id();
2813 sleVault->at(sfAssetsTotal) =
Number(0);
2814 sleVault->at(sfAssetsAvailable) =
Number(0);
2815 sleVault->at(sfLossUnrealized) =
Number(0);
2816 sleVault->at(sfShareMPTID) = sharesMptId;
2817 sleVault->at(sfWithdrawalPolicy) =
2820 ac.view().
insert(sleVault);
2821 ac.view().
insert(sleShares);
2830 {
"deposit must change vault balance"},
2836 args(
A2.id(), 0, [](Adjustments& sample) {
2837 sample.vaultAssets.reset();
2846 {
"deposit assets outstanding must not exceed assets maximum"},
2852 args(
A2.id(), 200, [&](Adjustments& sample) {
2853 sample.assetsMaximum = 1;
2871 {
"deposit must increase vault balance",
2872 "deposit must change depositor balance"},
2880 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2886 args(A3.id(), -10, [&](Adjustments& sample) {
2887 sample.accountAssets->amount = -100;
2895 tx[sfAccount] = A3.id();
2901 {
"deposit must increase vault balance",
2902 "deposit must decrease depositor balance",
2903 "deposit must change vault and depositor balance by equal amount",
2904 "deposit and assets outstanding must add up",
2905 "deposit and assets available must add up"},
2913 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
2919 args(
A2.id(), 10, [&](Adjustments& sample) {
2920 sample.vaultAssets = -20;
2921 sample.accountAssets->amount = 10;
2933 {
"deposit must change depositor balance"},
2941 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 10;
2947 args(
A2.id(), 10, [&](Adjustments& sample) {
2948 sample.accountAssets->amount = 0;
2960 {
"deposit must change depositor shares"},
2966 args(
A2.id(), 10, [&](Adjustments& sample) {
2967 sample.accountShares.reset();
2979 {
"deposit must change vault shares"},
2986 args(
A2.id(), 10, [](Adjustments& sample) {
2987 sample.sharesTotal = 0;
2999 {
"deposit must increase depositor shares",
3000 "deposit must change depositor and vault shares by equal amount",
3001 "deposit must not change vault balance by more than deposited "
3008 args(
A2.id(), 10, [&](Adjustments& sample) {
3009 sample.accountShares->amount = -5;
3010 sample.sharesTotal = -10;
3022 {
"deposit and assets outstanding must add up"},
3025 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3032 args(
A2.id(), 10, [&](Adjustments& sample) {
3033 sample.assetsTotal = 11;
3041 tx[sfDelegate] = A3.id();
3049 {
"deposit and assets outstanding must add up",
3050 "deposit and assets available must add up"},
3056 args(
A2.id(), 10, [&](Adjustments& sample) {
3057 sample.assetsTotal = 7;
3058 sample.assetsAvailable = 7;
3071 {
"withdrawal must change vault balance"},
3077 args(
A2.id(), 0, [](Adjustments& sample) {
3078 sample.vaultAssets.reset();
3091 {
"withdrawal must change one destination balance"},
3099 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3105 args(A3.id(), -10, [&](Adjustments& sample) {
3106 sample.accountAssets->amount = -100;
3114 tx[sfAccount] = A3.id();
3122 {
"withdrawal must change vault and destination balance by "
3124 "withdrawal must decrease vault balance",
3125 "withdrawal must increase destination balance",
3126 "withdrawal and assets outstanding must add up",
3127 "withdrawal and assets available must add up"},
3135 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3141 args(
A2.id(), -10, [&](Adjustments& sample) {
3142 sample.vaultAssets = 10;
3143 sample.accountAssets->amount = -20;
3153 {
"withdrawal must change one destination balance"},
3159 args(
A2.id(), -10, [&](Adjustments& sample) {
3160 *sample.vaultAssets -= 5;
3166 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 5;
3179 {
"withdrawal must change depositor shares"},
3185 args(
A2.id(), -10, [&](Adjustments& sample) {
3186 sample.accountShares.reset();
3196 {
"withdrawal must change vault shares"},
3202 args(
A2.id(), -10, [](Adjustments& sample) {
3203 sample.sharesTotal = 0;
3213 {
"withdrawal must decrease depositor shares",
3214 "withdrawal must change depositor and vault shares by equal "
3221 args(
A2.id(), -10, [&](Adjustments& sample) {
3222 sample.accountShares->amount = 5;
3223 sample.sharesTotal = 10;
3233 {
"withdrawal and assets outstanding must add up",
3234 "withdrawal and assets available must add up"},
3240 args(
A2.id(), -10, [&](Adjustments& sample) {
3241 sample.assetsTotal = -15;
3242 sample.assetsAvailable = -15;
3252 {
"withdrawal and assets outstanding must add up"},
3255 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3262 args(
A2.id(), -10, [&](Adjustments& sample) {
3263 sample.assetsTotal = -7;
3271 tx[sfDelegate] = A3.id();
3278 auto const precloseMpt =
3280 env.fund(
XRP(1000), A3, A4);
3285 jv[sfAccount] = A3.human();
3286 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3292 auto const mptID =
makeMptID(env.seq(A3) - 1, A3);
3297 jv[sfAccount] =
A1.human();
3298 jv[sfTransactionType] = jss::MPTokenAuthorize;
3299 jv[sfMPTokenIssuanceID] =
to_string(mptID);
3301 jv[sfAccount] =
A2.human();
3303 jv[sfAccount] = A4.human();
3310 env(
pay(A3,
A1, asset(1000)));
3311 env(
pay(A3,
A2, asset(1000)));
3312 env(
pay(A3, A4, asset(1000)));
3317 auto [tx, keylet] = vault.create({.owner =
A1, .asset = asset});
3320 {.depositor = A1, .id = keylet.key, .amount = asset(10)}));
3322 {.depositor = A2, .id = keylet.key, .amount = asset(10)}));
3324 {.depositor = A4, .id = keylet.key, .amount = asset(10)}));
3329 {
"withdrawal must decrease depositor shares",
3330 "withdrawal must change depositor and vault shares by equal "
3337 args(
A2.id(), -10, [&](Adjustments& sample) {
3338 sample.accountShares->amount = 5;
3344 [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3351 {
"clawback must change vault balance"},
3357 args(
A2.id(), -1, [&](Adjustments& sample) {
3358 sample.vaultAssets.reset();
3364 [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3370 {
"clawback may only be performed by the asset issuer"},
3376 args(
A2.id(), 0, [&](Adjustments& sample) {}));
3385 {
"clawback may only be performed by the asset issuer"},
3391 args(
A2.id(), 0, [&](Adjustments& sample) {}));
3396 [&](
STObject& tx) { tx[sfAccount] = A4.id(); }},
3401 {
"clawback must decrease vault balance",
3402 "clawback must decrease holder shares",
3403 "clawback must change vault shares"},
3409 args(A4.id(), 10, [&](Adjustments& sample) {
3410 sample.sharesTotal = 0;
3417 tx[sfAccount] = A3.id();
3418 tx[sfHolder] = A4.id();
3424 {
"clawback must change holder shares"},
3430 args(A4.id(), -10, [&](Adjustments& sample) {
3431 sample.accountShares.reset();
3438 tx[sfAccount] = A3.id();
3439 tx[sfHolder] = A4.id();
3445 {
"clawback must change holder and vault shares by equal amount",
3446 "clawback and assets outstanding must add up",
3447 "clawback and assets available must add up"},
3453 args(A4.id(), -10, [&](Adjustments& sample) {
3454 sample.accountShares->amount = -8;
3455 sample.assetsTotal = -7;
3456 sample.assetsAvailable = -7;
3463 tx[sfAccount] = A3.id();
3464 tx[sfHolder] = A4.id();