1224 using namespace test::jtx;
1228 {{
"permissioned domain with no rules."}},
1232 slePd->setAccountID(sfOwner,
A1);
1233 slePd->setFieldU32(sfSequence, 10);
1235 ac.view().insert(slePd);
1242 testcase <<
"PermissionedDomain 2";
1246 {{
"permissioned domain bad credentials size " +
1251 slePd->setAccountID(sfOwner,
A1);
1252 slePd->setFieldU32(sfSequence, 10);
1254 STArray credentials(sfAcceptedCredentials, tooBig);
1258 cred.setAccountID(sfIssuer,
A2);
1263 Slice(credType.c_str(), credType.size()));
1266 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1267 ac.view().insert(slePd);
1274 testcase <<
"PermissionedDomain 3";
1276 {{
"permissioned domain credentials aren't sorted"}},
1280 slePd->setAccountID(sfOwner,
A1);
1281 slePd->setFieldU32(sfSequence, 10);
1283 STArray credentials(sfAcceptedCredentials, 2);
1287 cred.setAccountID(sfIssuer,
A2);
1292 Slice(credType.c_str(), credType.size()));
1295 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1296 ac.view().insert(slePd);
1303 testcase <<
"PermissionedDomain 4";
1305 {{
"permissioned domain credentials aren't unique"}},
1309 slePd->setAccountID(sfOwner,
A1);
1310 slePd->setFieldU32(sfSequence, 10);
1312 STArray credentials(sfAcceptedCredentials, 2);
1316 cred.setAccountID(sfIssuer,
A2);
1317 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1320 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1321 ac.view().insert(slePd);
1328 testcase <<
"PermissionedDomain Set 1";
1330 {{
"permissioned domain with no rules."}},
1340 STArray credentials(sfAcceptedCredentials, 2);
1341 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1342 ac.view().update(slePd);
1351 testcase <<
"PermissionedDomain Set 2";
1353 {{
"permissioned domain bad credentials size " +
1364 STArray credentials(sfAcceptedCredentials, tooBig);
1369 cred.setAccountID(sfIssuer,
A2);
1373 Slice(credType.c_str(), credType.size()));
1377 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1378 ac.view().update(slePd);
1387 testcase <<
"PermissionedDomain Set 3";
1389 {{
"permissioned domain credentials aren't sorted"}},
1399 STArray credentials(sfAcceptedCredentials, 2);
1403 cred.setAccountID(sfIssuer,
A2);
1408 Slice(credType.c_str(), credType.size()));
1412 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1413 ac.view().update(slePd);
1422 testcase <<
"PermissionedDomain Set 4";
1424 {{
"permissioned domain credentials aren't unique"}},
1434 STArray credentials(sfAcceptedCredentials, 2);
1438 cred.setAccountID(sfIssuer,
A2);
1440 sfCredentialType,
Slice(
"cred_type", 9));
1443 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1444 ac.view().update(slePd);
1747 using namespace test::jtx;
1749 struct AccountAmount
1765 auto constexpr adjust = [&](
ApplyView& ac,
1767 Adjustements args) {
1768 auto sleVault = ac.
peek(keylet);
1772 auto const mptIssuanceID = (*sleVault)[sfShareMPTID];
1778 if (args.lossUnrealized)
1779 (*sleVault)[sfLossUnrealized] = *args.lossUnrealized;
1780 if (args.assetsMaximum)
1781 (*sleVault)[sfAssetsMaximum] = *args.assetsMaximum;
1784 if (args.assetsTotal)
1785 (*sleVault)[sfAssetsTotal] =
1786 *(*sleVault)[sfAssetsTotal] + *args.assetsTotal;
1787 if (args.assetsAvailable)
1788 (*sleVault)[sfAssetsAvailable] =
1789 *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable;
1792 if (args.sharesTotal)
1793 (*sleShares)[sfOutstandingAmount] =
1794 *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal;
1797 auto const assets = *(*sleVault)[sfAsset];
1798 auto const pseudoId = *(*sleVault)[sfAccount];
1799 if (args.vaultAssets)
1801 if (assets.native())
1804 if (!slePseudoAccount)
1806 (*slePseudoAccount)[sfBalance] =
1807 *(*slePseudoAccount)[sfBalance] + *args.vaultAssets;
1808 ac.
update(slePseudoAccount);
1812 auto const mptId = assets.get<
MPTIssue>().getMptID();
1816 (*sleMPToken)[sfMPTAmount] =
1817 *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets;
1824 if (args.accountAssets)
1826 auto const& pair = *args.accountAssets;
1827 if (assets.native())
1832 (*sleAccount)[sfBalance] =
1833 *(*sleAccount)[sfBalance] + pair.amount;
1838 auto const mptID = assets.get<
MPTIssue>().getMptID();
1843 (*sleMPToken)[sfMPTAmount] =
1844 *(*sleMPToken)[sfMPTAmount] + pair.amount;
1851 if (args.accountShares)
1853 auto const& pair = *args.accountShares;
1858 (*sleMPToken)[sfMPTAmount] =
1859 *(*sleMPToken)[sfMPTAmount] + pair.amount;
1865 constexpr auto args =
1866 [](
AccountID id,
int adjustement,
auto fn) -> Adjustements {
1867 Adjustements sample = {
1868 .assetsTotal = adjustement,
1869 .assetsAvailable = adjustement,
1870 .lossUnrealized = 0,
1871 .sharesTotal = adjustement,
1872 .vaultAssets = adjustement,
1874 AccountAmount{id, -adjustement},
1876 AccountAmount{id, adjustement}};
1883 auto const precloseXrp =
1885 env.fund(
XRP(1000), A3, A4);
1888 vault.create({.owner =
A1, .asset =
xrpIssue()});
1891 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
1893 {.depositor = A2, .id = keylet.key, .amount = XRP(10)}));
1895 {.depositor = A3, .id = keylet.key, .amount = XRP(10)}));
1899 testcase <<
"Vault general checks";
1901 {
"vault deletion succeeded without deleting a vault"},
1904 auto sleVault = ac.view().
peek(keylet);
1907 ac.view().
update(sleVault);
1915 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1921 {
"vault updated by a wrong transaction type"},
1924 auto sleVault = ac.view().
peek(keylet);
1927 ac.view().
erase(sleVault);
1935 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1941 {
"vault updated by a wrong transaction type"},
1944 auto sleVault = ac.view().
peek(keylet);
1947 ac.view().
update(sleVault);
1955 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1961 {
"vault updated by a wrong transaction type"},
1963 auto const sequence = ac.view().
seq();
1966 auto const vaultPage = ac.view().
dirInsert(
1970 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
1971 ac.view().
insert(sleVault);
1979 {
"vault deleted by a wrong transaction type"},
1982 auto sleVault = ac.view().
peek(keylet);
1985 ac.view().
erase(sleVault);
1993 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1999 {
"vault operation updated more than single vault"},
2003 auto sleVault = ac.view().
peek(keylet);
2006 ac.view().
erase(sleVault);
2010 auto sleVault = ac.view().
peek(keylet);
2013 ac.view().
erase(sleVault);
2024 vault.create({.owner =
A1, .asset =
xrpIssue()});
2029 vault.create({.owner =
A2, .asset =
xrpIssue()});
2036 {
"vault operation updated more than single vault"},
2038 auto const sequence = ac.view().
seq();
2039 auto const insertVault = [&](
Account const A) {
2042 auto const vaultPage = ac.view().
dirInsert(
2046 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2047 ac.view().
insert(sleVault);
2058 {
"deleted vault must also delete shares"},
2061 auto sleVault = ac.view().
peek(keylet);
2064 ac.view().
erase(sleVault);
2072 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2078 {
"deleted vault must have no shares outstanding",
2079 "deleted vault must have no assets outstanding",
2080 "deleted vault must have no assets available"},
2083 auto sleVault = ac.view().
peek(keylet);
2086 auto sleShares = ac.view().
peek(
2090 ac.view().
erase(sleVault);
2091 ac.view().
erase(sleShares);
2100 vault.create({.owner =
A1, .asset =
xrpIssue()});
2103 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2108 {
"vault operation succeeded without modifying a vault"},
2111 auto sleVault = ac.view().
peek(keylet);
2114 auto sleShares = ac.view().
peek(
2120 sleShares->setFieldH256(sfDomainID,
uint256(13));
2121 ac.view().
update(sleShares);
2131 {
"vault operation succeeded without modifying a vault"},
2140 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2146 {
"vault operation succeeded without modifying a vault"},
2155 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2161 {
"vault operation succeeded without modifying a vault"},
2170 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2176 {
"vault operation succeeded without modifying a vault"},
2185 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2191 {
"vault operation succeeded without modifying a vault"},
2200 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2206 {
"updated vault must have shares"},
2209 auto sleVault = ac.view().
peek(keylet);
2212 (*sleVault)[sfAssetsMaximum] = 200;
2213 ac.view().
update(sleVault);
2215 auto sleShares = ac.view().
peek(
2219 ac.view().
erase(sleShares);
2227 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2233 {
"vault operation succeeded without updating shares",
2234 "assets available must not be greater than assets outstanding"},
2237 auto sleVault = ac.view().
peek(keylet);
2240 (*sleVault)[sfAssetsTotal] = 9;
2241 ac.view().
update(sleVault);
2250 vault.create({.owner =
A1, .asset =
xrpIssue()});
2253 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2258 {
"set must not change assets outstanding",
2259 "set must not change assets available",
2260 "set must not change shares outstanding",
2261 "set must not change vault balance",
2262 "assets available must be positive",
2263 "assets available must not be greater than assets outstanding",
2264 "assets outstanding must be positive"},
2267 auto sleVault = ac.view().
peek(keylet);
2270 auto slePseudoAccount =
2272 if (!slePseudoAccount)
2274 (*slePseudoAccount)[sfBalance] =
2275 *(*slePseudoAccount)[sfBalance] - 10;
2276 ac.view().
update(slePseudoAccount);
2282 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2288 args(
A2.id(), 0, [&](Adjustements& sample) {
2289 sample.assetsAvailable = (DROPS_PER_XRP * -100).value();
2290 sample.assetsTotal = (DROPS_PER_XRP * -200).value();
2291 sample.sharesTotal = -1;
2301 {
"violation of vault immutable data"},
2304 auto sleVault = ac.view().
peek(keylet);
2307 sleVault->setFieldIssue(
2309 ac.view().
update(sleVault);
2318 {
"violation of vault immutable data"},
2321 auto sleVault = ac.view().
peek(keylet);
2324 sleVault->setAccountID(sfAccount,
A2.id());
2325 ac.view().
update(sleVault);
2334 {
"violation of vault immutable data"},
2337 auto sleVault = ac.view().
peek(keylet);
2340 (*sleVault)[sfShareMPTID] =
MPTID(42);
2341 ac.view().
update(sleVault);
2350 {
"vault transaction must not change loss unrealized",
2351 "set must not change assets outstanding"},
2357 args(
A2.id(), 0, [&](Adjustements& sample) {
2358 sample.lossUnrealized = 13;
2359 sample.assetsTotal = 20;
2369 {
"loss unrealized must not exceed the difference "
2370 "between assets outstanding and available",
2371 "vault transaction must not change loss unrealized"},
2377 args(
A2.id(), 100, [&](Adjustements& sample) {
2378 sample.lossUnrealized = 13;
2392 {
"set assets outstanding must not exceed assets maximum"},
2398 args(
A2.id(), 0, [&](Adjustements& sample) {
2399 sample.assetsMaximum = 1;
2409 {
"assets maximum must be positive"},
2415 args(
A2.id(), 0, [&](Adjustements& sample) {
2416 sample.assetsMaximum = -1;
2426 {
"set must not change shares outstanding",
2427 "updated zero sized vault must have no assets outstanding",
2428 "updated zero sized vault must have no assets available"},
2431 auto sleVault = ac.view().
peek(keylet);
2434 ac.view().
update(sleVault);
2435 auto sleShares = ac.view().
peek(
2439 (*sleShares)[sfOutstandingAmount] = 0;
2440 ac.view().
update(sleShares);
2450 {
"updated shares must not exceed maximum"},
2453 auto sleVault = ac.view().
peek(keylet);
2456 auto sleShares = ac.view().
peek(
2460 (*sleShares)[sfMaximumAmount] = 10;
2461 ac.view().
update(sleShares);
2464 ac.view(), keylet, args(
A2.id(), 10, [](Adjustements&) {}));
2473 {
"updated shares must not exceed maximum"},
2477 ac.view(), keylet, args(
A2.id(), 10, [](Adjustements&) {}));
2479 auto sleVault = ac.view().
peek(keylet);
2482 auto sleShares = ac.view().
peek(
2487 ac.view().
update(sleShares);
2499 "created vault must be empty",
2500 "updated zero sized vault must have no assets outstanding",
2501 "create operation must not have updated a vault",
2505 auto sleVault = ac.view().
peek(keylet);
2508 (*sleVault)[sfAssetsTotal] = 9;
2509 ac.view().
update(sleVault);
2518 vault.create({.owner =
A1, .asset =
xrpIssue()});
2525 "created vault must be empty",
2526 "updated zero sized vault must have no assets available",
2527 "assets available must not be greater than assets outstanding",
2528 "create operation must not have updated a vault",
2532 auto sleVault = ac.view().
peek(keylet);
2535 (*sleVault)[sfAssetsAvailable] = 9;
2536 ac.view().
update(sleVault);
2545 vault.create({.owner =
A1, .asset =
xrpIssue()});
2552 "created vault must be empty",
2553 "loss unrealized must not exceed the difference between assets "
2554 "outstanding and available",
2555 "vault transaction must not change loss unrealized",
2556 "create operation must not have updated a vault",
2560 auto sleVault = ac.view().
peek(keylet);
2563 (*sleVault)[sfLossUnrealized] = 1;
2564 ac.view().
update(sleVault);
2573 vault.create({.owner =
A1, .asset =
xrpIssue()});
2580 "created vault must be empty",
2581 "create operation must not have updated a vault",
2585 auto sleVault = ac.view().
peek(keylet);
2588 auto sleShares = ac.view().
peek(
2592 ac.view().
update(sleVault);
2593 (*sleShares)[sfOutstandingAmount] = 9;
2594 ac.view().
update(sleShares);
2603 vault.create({.owner =
A1, .asset =
xrpIssue()});
2610 "assets maximum must be positive",
2611 "create operation must not have updated a vault",
2615 auto sleVault = ac.view().
peek(keylet);
2618 (*sleVault)[sfAssetsMaximum] =
Number(-1);
2619 ac.view().
update(sleVault);
2628 vault.create({.owner =
A1, .asset =
xrpIssue()});
2634 {
"create operation must not have updated a vault",
2635 "shares issuer and vault pseudo-account must be the same",
2636 "shares issuer must be a pseudo-account",
2637 "shares issuer pseudo-account must point back to the vault"},
2640 auto sleVault = ac.view().
peek(keylet);
2643 auto sleShares = ac.view().
peek(
2647 ac.view().
update(sleVault);
2648 (*sleShares)[sfIssuer] =
A1.id();
2649 ac.view().
update(sleShares);
2658 vault.create({.owner =
A1, .asset =
xrpIssue()});
2664 {
"vault created by a wrong transaction type",
2665 "account root created illegally"},
2670 auto const sequence = ac.view().
seq();
2673 auto const vaultPage = ac.view().
dirInsert(
2677 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2684 sleAccount->setAccountID(sfAccount, pseudoId);
2685 sleAccount->setFieldAmount(sfBalance,
STAmount{});
2690 sleAccount->setFieldU32(sfSequence, seqno);
2691 sleAccount->setFieldU32(
2694 sleAccount->setFieldH256(sfVaultID, vaultKeylet.key);
2695 ac.view().
insert(sleAccount);
2697 auto const sharesMptId =
makeMptID(sequence, pseudoId);
2700 auto const sharesPage = ac.view().
dirInsert(
2704 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2706 sleShares->at(sfFlags) = 0;
2707 sleShares->at(sfIssuer) = pseudoId;
2708 sleShares->at(sfOutstandingAmount) = 0;
2709 sleShares->at(sfSequence) = sequence;
2711 sleVault->at(sfAccount) = pseudoId;
2712 sleVault->at(sfFlags) = 0;
2713 sleVault->at(sfSequence) = sequence;
2714 sleVault->at(sfOwner) =
A1.id();
2715 sleVault->at(sfAssetsTotal) =
Number(0);
2716 sleVault->at(sfAssetsAvailable) =
Number(0);
2717 sleVault->at(sfLossUnrealized) =
Number(0);
2718 sleVault->at(sfShareMPTID) = sharesMptId;
2719 sleVault->at(sfWithdrawalPolicy) =
2722 ac.view().
insert(sleVault);
2723 ac.view().
insert(sleShares);
2731 {
"shares issuer and vault pseudo-account must be the same",
2732 "shares issuer pseudo-account must point back to the vault"},
2734 auto const sequence = ac.view().
seq();
2737 auto const vaultPage = ac.view().
dirInsert(
2741 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2748 sleAccount->setAccountID(sfAccount, pseudoId);
2749 sleAccount->setFieldAmount(sfBalance,
STAmount{});
2754 sleAccount->setFieldU32(sfSequence, seqno);
2755 sleAccount->setFieldU32(
2760 sleAccount->setFieldH256(sfVaultID,
uint256(42));
2761 ac.view().
insert(sleAccount);
2763 auto const sharesMptId =
makeMptID(sequence, pseudoId);
2766 auto const sharesPage = ac.view().
dirInsert(
2770 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2772 sleShares->at(sfFlags) = 0;
2773 sleShares->at(sfIssuer) = pseudoId;
2774 sleShares->at(sfOutstandingAmount) = 0;
2775 sleShares->at(sfSequence) = sequence;
2779 sleVault->at(sfAccount) =
A2.id();
2780 sleVault->at(sfFlags) = 0;
2781 sleVault->at(sfSequence) = sequence;
2782 sleVault->at(sfOwner) =
A1.id();
2783 sleVault->at(sfAssetsTotal) =
Number(0);
2784 sleVault->at(sfAssetsAvailable) =
Number(0);
2785 sleVault->at(sfLossUnrealized) =
Number(0);
2786 sleVault->at(sfShareMPTID) = sharesMptId;
2787 sleVault->at(sfWithdrawalPolicy) =
2790 ac.view().
insert(sleVault);
2791 ac.view().
insert(sleShares);
2799 {
"shares issuer and vault pseudo-account must be the same",
2800 "shares issuer must exist"},
2802 auto const sequence = ac.view().
seq();
2805 auto const vaultPage = ac.view().
dirInsert(
2809 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2811 auto const sharesMptId =
makeMptID(sequence,
A2.id());
2814 auto const sharesPage = ac.view().
dirInsert(
2818 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2820 sleShares->at(sfFlags) = 0;
2823 sleShares->at(sfOutstandingAmount) = 0;
2824 sleShares->at(sfSequence) = sequence;
2826 sleVault->at(sfAccount) =
A2.id();
2827 sleVault->at(sfFlags) = 0;
2828 sleVault->at(sfSequence) = sequence;
2829 sleVault->at(sfOwner) =
A1.id();
2830 sleVault->at(sfAssetsTotal) =
Number(0);
2831 sleVault->at(sfAssetsAvailable) =
Number(0);
2832 sleVault->at(sfLossUnrealized) =
Number(0);
2833 sleVault->at(sfShareMPTID) = sharesMptId;
2834 sleVault->at(sfWithdrawalPolicy) =
2837 ac.view().
insert(sleVault);
2838 ac.view().
insert(sleShares);
2847 {
"deposit must change vault balance"},
2853 args(
A2.id(), 0, [&](Adjustements& sample) {}));
2861 {
"deposit assets outstanding must not exceed assets maximum"},
2867 args(
A2.id(), 200, [&](Adjustements& sample) {
2868 sample.assetsMaximum = 1;
2886 {
"deposit must increase vault balance",
2887 "deposit must change depositor balance"},
2895 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2901 args(A3.id(), -10, [&](Adjustements& sample) {
2902 sample.accountAssets->amount = -100;
2910 tx[sfAccount] = A3.id();
2916 {
"deposit must increase vault balance",
2917 "deposit must decrease depositor balance",
2918 "deposit must change vault and depositor balance by equal amount",
2919 "deposit and assets outstanding must add up",
2920 "deposit and assets available must add up"},
2928 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
2934 args(
A2.id(), 10, [&](Adjustements& sample) {
2935 sample.vaultAssets = -20;
2936 sample.accountAssets->amount = 10;
2948 {
"deposit must change depositor balance"},
2956 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 10;
2962 args(
A2.id(), 10, [&](Adjustements& sample) {
2963 sample.accountAssets->amount = 0;
2975 {
"deposit must change depositor shares"},
2981 args(
A2.id(), 10, [&](Adjustements& sample) {
2982 sample.accountShares->amount = 0;
2994 {
"deposit must change vault shares"},
3000 args(
A2.id(), 10, [&](Adjustements& sample) {
3001 sample.sharesTotal = 0;
3013 {
"deposit must increase depositor shares",
3014 "deposit must change depositor and vault shares by equal amount",
3015 "deposit must not change vault balance by more than deposited "
3022 args(
A2.id(), 10, [&](Adjustements& sample) {
3023 sample.accountShares->amount = -5;
3024 sample.sharesTotal = -10;
3036 {
"deposit and assets outstanding must add up",
3037 "deposit and assets available must add up"},
3043 args(
A2.id(), 10, [&](Adjustements& sample) {
3044 sample.assetsTotal = 7;
3045 sample.assetsAvailable = 7;
3058 {
"withdrawal must change vault balance"},
3064 args(
A2.id(), 0, [&](Adjustements& sample) {}));
3076 {
"withdrawal must change one destination balance"},
3084 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3090 args(A3.id(), -10, [&](Adjustements& sample) {
3091 sample.accountAssets->amount = -100;
3099 tx[sfAccount] = A3.id();
3107 {
"withdrawal must change vault and destination balance by "
3109 "withdrawal must decrease vault balance",
3110 "withdrawal must increase destination balance",
3111 "withdrawal and assets outstanding must add up",
3112 "withdrawal and assets available must add up"},
3120 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3126 args(
A2.id(), -10, [&](Adjustements& sample) {
3127 sample.vaultAssets = 10;
3128 sample.accountAssets->amount = -20;
3138 {
"withdrawal must change one destination balance"},
3144 args(
A2.id(), -10, [&](Adjustements& sample) {
3145 *sample.vaultAssets -= 5;
3151 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 5;
3164 {
"withdrawal must change depositor shares"},
3170 args(
A2.id(), -10, [&](Adjustements& sample) {
3171 sample.accountShares->amount = 0;
3181 {
"withdrawal must change vault shares"},
3187 args(
A2.id(), -10, [&](Adjustements& sample) {
3188 sample.sharesTotal = 0;
3198 {
"withdrawal must decrease depositor shares",
3199 "withdrawal must change depositor and vault shares by equal "
3206 args(
A2.id(), -10, [&](Adjustements& sample) {
3207 sample.accountShares->amount = 5;
3208 sample.sharesTotal = 10;
3218 {
"withdrawal and assets outstanding must add up",
3219 "withdrawal and assets available must add up"},
3225 args(
A2.id(), -10, [&](Adjustements& sample) {
3226 sample.assetsTotal = -15;
3227 sample.assetsAvailable = -15;
3236 auto const precloseMpt =
3238 env.fund(
XRP(1000), A3, A4);
3243 jv[sfAccount] = A3.human();
3244 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3250 auto const mptID =
makeMptID(env.seq(A3) - 1, A3);
3255 jv[sfAccount] =
A1.human();
3256 jv[sfTransactionType] = jss::MPTokenAuthorize;
3257 jv[sfMPTokenIssuanceID] =
to_string(mptID);
3259 jv[sfAccount] =
A2.human();
3261 jv[sfAccount] = A4.human();
3268 env(
pay(A3,
A1, asset(1000)));
3269 env(
pay(A3,
A2, asset(1000)));
3270 env(
pay(A3, A4, asset(1000)));
3275 auto [tx, keylet] = vault.create({.owner =
A1, .asset = asset});
3278 {.depositor = A1, .id = keylet.key, .amount = asset(10)}));
3280 {.depositor = A2, .id = keylet.key, .amount = asset(10)}));
3282 {.depositor = A4, .id = keylet.key, .amount = asset(10)}));
3287 {
"withdrawal must decrease depositor shares",
3288 "withdrawal must change depositor and vault shares by equal "
3295 args(
A2.id(), -10, [&](Adjustements& sample) {
3296 sample.accountShares->amount = 5;
3302 [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3309 {
"clawback must change vault balance"},
3315 args(
A2.id(), -1, [&](Adjustements& sample) {
3316 sample.vaultAssets = 0;
3322 [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3328 {
"clawback may only be performed by the asset issuer"},
3334 args(
A2.id(), 0, [&](Adjustements& sample) {}));
3343 {
"clawback may only be performed by the asset issuer"},
3349 args(
A2.id(), 0, [&](Adjustements& sample) {}));
3354 [&](
STObject& tx) { tx[sfAccount] = A4.id(); }},
3359 {
"clawback must decrease vault balance",
3360 "clawback must decrease holder shares",
3361 "clawback must change vault shares"},
3367 args(A4.id(), 10, [&](Adjustements& sample) {
3368 sample.sharesTotal = 0;
3375 tx[sfAccount] = A3.id();
3376 tx[sfHolder] = A4.id();
3382 {
"clawback must change holder shares"},
3388 args(A4.id(), -10, [&](Adjustements& sample) {
3389 sample.accountShares->amount = 0;
3396 tx[sfAccount] = A3.id();
3397 tx[sfHolder] = A4.id();
3403 {
"clawback must change holder and vault shares by equal amount",
3404 "clawback and assets outstanding must add up",
3405 "clawback and assets available must add up"},
3411 args(A4.id(), -10, [&](Adjustements& sample) {
3412 sample.accountShares->amount = -8;
3413 sample.assetsTotal = -7;
3414 sample.assetsAvailable = -7;
3421 tx[sfAccount] = A3.id();
3422 tx[sfHolder] = A4.id();