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,
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)
1794 (*sleShares)[sfOutstandingAmount] =
1795 *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal;
1799 auto const assets = *(*sleVault)[sfAsset];
1800 auto const pseudoId = *(*sleVault)[sfAccount];
1801 if (args.vaultAssets)
1803 if (assets.native())
1806 if (!slePseudoAccount)
1808 (*slePseudoAccount)[sfBalance] =
1809 *(*slePseudoAccount)[sfBalance] + *args.vaultAssets;
1810 ac.
update(slePseudoAccount);
1814 auto const mptId = assets.get<
MPTIssue>().getMptID();
1818 (*sleMPToken)[sfMPTAmount] =
1819 *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets;
1826 if (args.accountAssets)
1828 auto const& pair = *args.accountAssets;
1829 if (assets.native())
1834 (*sleAccount)[sfBalance] =
1835 *(*sleAccount)[sfBalance] + pair.amount;
1840 auto const mptID = assets.get<
MPTIssue>().getMptID();
1845 (*sleMPToken)[sfMPTAmount] =
1846 *(*sleMPToken)[sfMPTAmount] + pair.amount;
1853 if (args.accountShares)
1855 auto const& pair = *args.accountShares;
1860 (*sleMPToken)[sfMPTAmount] =
1861 *(*sleMPToken)[sfMPTAmount] + pair.amount;
1867 constexpr auto args =
1868 [](
AccountID id,
int adjustment,
auto fn) -> Adjustments {
1869 Adjustments sample = {
1870 .assetsTotal = adjustment,
1871 .assetsAvailable = adjustment,
1872 .lossUnrealized = 0,
1873 .sharesTotal = adjustment,
1874 .vaultAssets = adjustment,
1876 AccountAmount{id, -adjustment},
1878 AccountAmount{id, adjustment}};
1885 auto const precloseXrp =
1887 env.fund(
XRP(1000), A3, A4);
1890 vault.create({.owner =
A1, .asset =
xrpIssue()});
1893 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
1895 {.depositor = A2, .id = keylet.key, .amount = XRP(10)}));
1897 {.depositor = A3, .id = keylet.key, .amount = XRP(10)}));
1901 testcase <<
"Vault general checks";
1903 {
"vault deletion succeeded without deleting a vault"},
1906 auto sleVault = ac.view().
peek(keylet);
1909 ac.view().
update(sleVault);
1917 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1923 {
"vault updated by a wrong transaction type"},
1926 auto sleVault = ac.view().
peek(keylet);
1929 ac.view().
erase(sleVault);
1937 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1943 {
"vault updated by a wrong transaction type"},
1946 auto sleVault = ac.view().
peek(keylet);
1949 ac.view().
update(sleVault);
1957 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
1963 {
"vault updated by a wrong transaction type"},
1965 auto const sequence = ac.view().
seq();
1968 auto const vaultPage = ac.view().
dirInsert(
1972 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
1973 ac.view().
insert(sleVault);
1981 {
"vault deleted by a wrong transaction type"},
1984 auto sleVault = ac.view().
peek(keylet);
1987 ac.view().
erase(sleVault);
1995 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2001 {
"vault operation updated more than single vault"},
2005 auto sleVault = ac.view().
peek(keylet);
2008 ac.view().
erase(sleVault);
2012 auto sleVault = ac.view().
peek(keylet);
2015 ac.view().
erase(sleVault);
2026 vault.create({.owner =
A1, .asset =
xrpIssue()});
2031 vault.create({.owner =
A2, .asset =
xrpIssue()});
2038 {
"vault operation updated more than single vault"},
2040 auto const sequence = ac.view().
seq();
2041 auto const insertVault = [&](
Account const A) {
2044 auto const vaultPage = ac.view().
dirInsert(
2048 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2049 ac.view().
insert(sleVault);
2060 {
"deleted vault must also delete shares"},
2063 auto sleVault = ac.view().
peek(keylet);
2066 ac.view().
erase(sleVault);
2074 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2080 {
"deleted vault must have no shares outstanding",
2081 "deleted vault must have no assets outstanding",
2082 "deleted vault must have no assets available"},
2085 auto sleVault = ac.view().
peek(keylet);
2088 auto sleShares = ac.view().
peek(
2092 ac.view().
erase(sleVault);
2093 ac.view().
erase(sleShares);
2102 vault.create({.owner =
A1, .asset =
xrpIssue()});
2105 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2110 {
"vault operation succeeded without modifying a vault"},
2113 auto sleVault = ac.view().
peek(keylet);
2116 auto sleShares = ac.view().
peek(
2122 sleShares->setFieldH256(sfDomainID,
uint256(13));
2123 ac.view().
update(sleShares);
2133 {
"vault operation succeeded without modifying a vault"},
2142 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2148 {
"vault operation succeeded without modifying a vault"},
2157 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2163 {
"vault operation succeeded without modifying a vault"},
2172 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2178 {
"vault operation succeeded without modifying a vault"},
2187 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2193 {
"vault operation succeeded without modifying a vault"},
2202 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2208 {
"updated vault must have shares"},
2211 auto sleVault = ac.view().
peek(keylet);
2214 (*sleVault)[sfAssetsMaximum] = 200;
2215 ac.view().
update(sleVault);
2217 auto sleShares = ac.view().
peek(
2221 ac.view().
erase(sleShares);
2229 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2235 {
"vault operation succeeded without updating shares",
2236 "assets available must not be greater than assets outstanding"},
2239 auto sleVault = ac.view().
peek(keylet);
2242 (*sleVault)[sfAssetsTotal] = 9;
2243 ac.view().
update(sleVault);
2252 vault.create({.owner =
A1, .asset =
xrpIssue()});
2255 {.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2260 {
"set must not change assets outstanding",
2261 "set must not change assets available",
2262 "set must not change shares outstanding",
2263 "set must not change vault balance",
2264 "assets available must be positive",
2265 "assets available must not be greater than assets outstanding",
2266 "assets outstanding must be positive"},
2269 auto sleVault = ac.view().
peek(keylet);
2272 auto slePseudoAccount =
2274 if (!slePseudoAccount)
2276 (*slePseudoAccount)[sfBalance] =
2277 *(*slePseudoAccount)[sfBalance] - 10;
2278 ac.view().
update(slePseudoAccount);
2284 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2290 args(
A2.id(), 0, [&](Adjustments& sample) {
2291 sample.assetsAvailable = (DROPS_PER_XRP * -100).value();
2292 sample.assetsTotal = (DROPS_PER_XRP * -200).value();
2293 sample.sharesTotal = -1;
2303 {
"violation of vault immutable data"},
2306 auto sleVault = ac.view().
peek(keylet);
2309 sleVault->setFieldIssue(
2311 ac.view().
update(sleVault);
2320 {
"violation of vault immutable data"},
2323 auto sleVault = ac.view().
peek(keylet);
2326 sleVault->setAccountID(sfAccount,
A2.id());
2327 ac.view().
update(sleVault);
2336 {
"violation of vault immutable data"},
2339 auto sleVault = ac.view().
peek(keylet);
2342 (*sleVault)[sfShareMPTID] =
MPTID(42);
2343 ac.view().
update(sleVault);
2352 {
"vault transaction must not change loss unrealized",
2353 "set must not change assets outstanding"},
2359 args(
A2.id(), 0, [&](Adjustments& sample) {
2360 sample.lossUnrealized = 13;
2361 sample.assetsTotal = 20;
2371 {
"loss unrealized must not exceed the difference "
2372 "between assets outstanding and available",
2373 "vault transaction must not change loss unrealized"},
2379 args(
A2.id(), 100, [&](Adjustments& sample) {
2380 sample.lossUnrealized = 13;
2394 {
"set assets outstanding must not exceed assets maximum"},
2400 args(
A2.id(), 0, [&](Adjustments& sample) {
2401 sample.assetsMaximum = 1;
2411 {
"assets maximum must be positive"},
2417 args(
A2.id(), 0, [&](Adjustments& sample) {
2418 sample.assetsMaximum = -1;
2428 {
"set must not change shares outstanding",
2429 "updated zero sized vault must have no assets outstanding",
2430 "updated zero sized vault must have no assets available"},
2433 auto sleVault = ac.view().
peek(keylet);
2436 ac.view().
update(sleVault);
2437 auto sleShares = ac.view().
peek(
2441 (*sleShares)[sfOutstandingAmount] = 0;
2442 ac.view().
update(sleShares);
2452 {
"updated shares must not exceed maximum"},
2455 auto sleVault = ac.view().
peek(keylet);
2458 auto sleShares = ac.view().
peek(
2462 (*sleShares)[sfMaximumAmount] = 10;
2463 ac.view().
update(sleShares);
2466 ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2475 {
"updated shares must not exceed maximum"},
2479 ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2481 auto sleVault = ac.view().
peek(keylet);
2484 auto sleShares = ac.view().
peek(
2489 ac.view().
update(sleShares);
2501 "created vault must be empty",
2502 "updated zero sized vault must have no assets outstanding",
2503 "create operation must not have updated a vault",
2507 auto sleVault = ac.view().
peek(keylet);
2510 (*sleVault)[sfAssetsTotal] = 9;
2511 ac.view().
update(sleVault);
2520 vault.create({.owner =
A1, .asset =
xrpIssue()});
2527 "created vault must be empty",
2528 "updated zero sized vault must have no assets available",
2529 "assets available must not be greater than assets outstanding",
2530 "create operation must not have updated a vault",
2534 auto sleVault = ac.view().
peek(keylet);
2537 (*sleVault)[sfAssetsAvailable] = 9;
2538 ac.view().
update(sleVault);
2547 vault.create({.owner =
A1, .asset =
xrpIssue()});
2554 "created vault must be empty",
2555 "loss unrealized must not exceed the difference between assets "
2556 "outstanding and available",
2557 "vault transaction must not change loss unrealized",
2558 "create operation must not have updated a vault",
2562 auto sleVault = ac.view().
peek(keylet);
2565 (*sleVault)[sfLossUnrealized] = 1;
2566 ac.view().
update(sleVault);
2575 vault.create({.owner =
A1, .asset =
xrpIssue()});
2582 "created vault must be empty",
2583 "create operation must not have updated a vault",
2587 auto sleVault = ac.view().
peek(keylet);
2590 auto sleShares = ac.view().
peek(
2594 ac.view().
update(sleVault);
2595 (*sleShares)[sfOutstandingAmount] = 9;
2596 ac.view().
update(sleShares);
2605 vault.create({.owner =
A1, .asset =
xrpIssue()});
2612 "assets maximum must be positive",
2613 "create operation must not have updated a vault",
2617 auto sleVault = ac.view().
peek(keylet);
2620 (*sleVault)[sfAssetsMaximum] =
Number(-1);
2621 ac.view().
update(sleVault);
2630 vault.create({.owner =
A1, .asset =
xrpIssue()});
2636 {
"create operation must not have updated a vault",
2637 "shares issuer and vault pseudo-account must be the same",
2638 "shares issuer must be a pseudo-account",
2639 "shares issuer pseudo-account must point back to the vault"},
2642 auto sleVault = ac.view().
peek(keylet);
2645 auto sleShares = ac.view().
peek(
2649 ac.view().
update(sleVault);
2650 (*sleShares)[sfIssuer] =
A1.id();
2651 ac.view().
update(sleShares);
2660 vault.create({.owner =
A1, .asset =
xrpIssue()});
2666 {
"vault created by a wrong transaction type",
2667 "account root created illegally"},
2672 auto const sequence = ac.view().
seq();
2675 auto const vaultPage = ac.view().
dirInsert(
2679 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2686 sleAccount->setAccountID(sfAccount, pseudoId);
2687 sleAccount->setFieldAmount(sfBalance,
STAmount{});
2692 sleAccount->setFieldU32(sfSequence, seqno);
2693 sleAccount->setFieldU32(
2696 sleAccount->setFieldH256(sfVaultID, vaultKeylet.key);
2697 ac.view().
insert(sleAccount);
2699 auto const sharesMptId =
makeMptID(sequence, pseudoId);
2702 auto const sharesPage = ac.view().
dirInsert(
2706 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2708 sleShares->at(sfFlags) = 0;
2709 sleShares->at(sfIssuer) = pseudoId;
2710 sleShares->at(sfOutstandingAmount) = 0;
2711 sleShares->at(sfSequence) = sequence;
2713 sleVault->at(sfAccount) = pseudoId;
2714 sleVault->at(sfFlags) = 0;
2715 sleVault->at(sfSequence) = sequence;
2716 sleVault->at(sfOwner) =
A1.id();
2717 sleVault->at(sfAssetsTotal) =
Number(0);
2718 sleVault->at(sfAssetsAvailable) =
Number(0);
2719 sleVault->at(sfLossUnrealized) =
Number(0);
2720 sleVault->at(sfShareMPTID) = sharesMptId;
2721 sleVault->at(sfWithdrawalPolicy) =
2724 ac.view().
insert(sleVault);
2725 ac.view().
insert(sleShares);
2733 {
"shares issuer and vault pseudo-account must be the same",
2734 "shares issuer pseudo-account must point back to the vault"},
2736 auto const sequence = ac.view().
seq();
2739 auto const vaultPage = ac.view().
dirInsert(
2743 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2750 sleAccount->setAccountID(sfAccount, pseudoId);
2751 sleAccount->setFieldAmount(sfBalance,
STAmount{});
2756 sleAccount->setFieldU32(sfSequence, seqno);
2757 sleAccount->setFieldU32(
2762 sleAccount->setFieldH256(sfVaultID,
uint256(42));
2763 ac.view().
insert(sleAccount);
2765 auto const sharesMptId =
makeMptID(sequence, pseudoId);
2768 auto const sharesPage = ac.view().
dirInsert(
2772 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2774 sleShares->at(sfFlags) = 0;
2775 sleShares->at(sfIssuer) = pseudoId;
2776 sleShares->at(sfOutstandingAmount) = 0;
2777 sleShares->at(sfSequence) = sequence;
2781 sleVault->at(sfAccount) =
A2.id();
2782 sleVault->at(sfFlags) = 0;
2783 sleVault->at(sfSequence) = sequence;
2784 sleVault->at(sfOwner) =
A1.id();
2785 sleVault->at(sfAssetsTotal) =
Number(0);
2786 sleVault->at(sfAssetsAvailable) =
Number(0);
2787 sleVault->at(sfLossUnrealized) =
Number(0);
2788 sleVault->at(sfShareMPTID) = sharesMptId;
2789 sleVault->at(sfWithdrawalPolicy) =
2792 ac.view().
insert(sleVault);
2793 ac.view().
insert(sleShares);
2801 {
"shares issuer and vault pseudo-account must be the same",
2802 "shares issuer must exist"},
2804 auto const sequence = ac.view().
seq();
2807 auto const vaultPage = ac.view().
dirInsert(
2811 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2813 auto const sharesMptId =
makeMptID(sequence,
A2.id());
2816 auto const sharesPage = ac.view().
dirInsert(
2820 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2822 sleShares->at(sfFlags) = 0;
2825 sleShares->at(sfOutstandingAmount) = 0;
2826 sleShares->at(sfSequence) = sequence;
2828 sleVault->at(sfAccount) =
A2.id();
2829 sleVault->at(sfFlags) = 0;
2830 sleVault->at(sfSequence) = sequence;
2831 sleVault->at(sfOwner) =
A1.id();
2832 sleVault->at(sfAssetsTotal) =
Number(0);
2833 sleVault->at(sfAssetsAvailable) =
Number(0);
2834 sleVault->at(sfLossUnrealized) =
Number(0);
2835 sleVault->at(sfShareMPTID) = sharesMptId;
2836 sleVault->at(sfWithdrawalPolicy) =
2839 ac.view().
insert(sleVault);
2840 ac.view().
insert(sleShares);
2849 {
"deposit must change vault balance"},
2855 args(
A2.id(), 0, [](Adjustments& sample) {
2856 sample.vaultAssets.reset();
2865 {
"deposit assets outstanding must not exceed assets maximum"},
2871 args(
A2.id(), 200, [&](Adjustments& sample) {
2872 sample.assetsMaximum = 1;
2890 {
"deposit must increase vault balance",
2891 "deposit must change depositor balance"},
2899 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2905 args(A3.id(), -10, [&](Adjustments& sample) {
2906 sample.accountAssets->amount = -100;
2914 tx[sfAccount] = A3.id();
2920 {
"deposit must increase vault balance",
2921 "deposit must decrease depositor balance",
2922 "deposit must change vault and depositor balance by equal amount",
2923 "deposit and assets outstanding must add up",
2924 "deposit and assets available must add up"},
2932 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
2938 args(
A2.id(), 10, [&](Adjustments& sample) {
2939 sample.vaultAssets = -20;
2940 sample.accountAssets->amount = 10;
2952 {
"deposit must change depositor balance"},
2960 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 10;
2966 args(
A2.id(), 10, [&](Adjustments& sample) {
2967 sample.accountAssets->amount = 0;
2979 {
"deposit must change depositor shares"},
2985 args(
A2.id(), 10, [&](Adjustments& sample) {
2986 sample.accountShares.reset();
2998 {
"deposit must change vault shares"},
3005 args(
A2.id(), 10, [](Adjustments& sample) {
3006 sample.sharesTotal = 0;
3018 {
"deposit must increase depositor shares",
3019 "deposit must change depositor and vault shares by equal amount",
3020 "deposit must not change vault balance by more than deposited "
3027 args(
A2.id(), 10, [&](Adjustments& sample) {
3028 sample.accountShares->amount = -5;
3029 sample.sharesTotal = -10;
3041 {
"deposit and assets outstanding must add up"},
3044 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3051 args(
A2.id(), 10, [&](Adjustments& sample) {
3052 sample.assetsTotal = 11;
3060 tx[sfDelegate] = A3.id();
3068 {
"deposit and assets outstanding must add up",
3069 "deposit and assets available must add up"},
3075 args(
A2.id(), 10, [&](Adjustments& sample) {
3076 sample.assetsTotal = 7;
3077 sample.assetsAvailable = 7;
3090 {
"withdrawal must change vault balance"},
3096 args(
A2.id(), 0, [](Adjustments& sample) {
3097 sample.vaultAssets.reset();
3110 {
"withdrawal must change one destination balance"},
3118 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3124 args(A3.id(), -10, [&](Adjustments& sample) {
3125 sample.accountAssets->amount = -100;
3133 tx[sfAccount] = A3.id();
3141 {
"withdrawal must change vault and destination balance by "
3143 "withdrawal must decrease vault balance",
3144 "withdrawal must increase destination balance",
3145 "withdrawal and assets outstanding must add up",
3146 "withdrawal and assets available must add up"},
3154 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3160 args(
A2.id(), -10, [&](Adjustments& sample) {
3161 sample.vaultAssets = 10;
3162 sample.accountAssets->amount = -20;
3172 {
"withdrawal must change one destination balance"},
3178 args(
A2.id(), -10, [&](Adjustments& sample) {
3179 *sample.vaultAssets -= 5;
3185 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 5;
3198 {
"withdrawal must change depositor shares"},
3204 args(
A2.id(), -10, [&](Adjustments& sample) {
3205 sample.accountShares.reset();
3215 {
"withdrawal must change vault shares"},
3221 args(
A2.id(), -10, [](Adjustments& sample) {
3222 sample.sharesTotal = 0;
3232 {
"withdrawal must decrease depositor shares",
3233 "withdrawal must change depositor and vault shares by equal "
3240 args(
A2.id(), -10, [&](Adjustments& sample) {
3241 sample.accountShares->amount = 5;
3242 sample.sharesTotal = 10;
3252 {
"withdrawal and assets outstanding must add up",
3253 "withdrawal and assets available must add up"},
3259 args(
A2.id(), -10, [&](Adjustments& sample) {
3260 sample.assetsTotal = -15;
3261 sample.assetsAvailable = -15;
3271 {
"withdrawal and assets outstanding must add up"},
3274 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3281 args(
A2.id(), -10, [&](Adjustments& sample) {
3282 sample.assetsTotal = -7;
3290 tx[sfDelegate] = A3.id();
3297 auto const precloseMpt =
3299 env.fund(
XRP(1000), A3, A4);
3304 jv[sfAccount] = A3.human();
3305 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3311 auto const mptID =
makeMptID(env.seq(A3) - 1, A3);
3316 jv[sfAccount] =
A1.human();
3317 jv[sfTransactionType] = jss::MPTokenAuthorize;
3318 jv[sfMPTokenIssuanceID] =
to_string(mptID);
3320 jv[sfAccount] =
A2.human();
3322 jv[sfAccount] = A4.human();
3329 env(
pay(A3,
A1, asset(1000)));
3330 env(
pay(A3,
A2, asset(1000)));
3331 env(
pay(A3, A4, asset(1000)));
3336 auto [tx, keylet] = vault.create({.owner =
A1, .asset = asset});
3339 {.depositor = A1, .id = keylet.key, .amount = asset(10)}));
3341 {.depositor = A2, .id = keylet.key, .amount = asset(10)}));
3343 {.depositor = A4, .id = keylet.key, .amount = asset(10)}));
3348 {
"withdrawal must decrease depositor shares",
3349 "withdrawal must change depositor and vault shares by equal "
3356 args(
A2.id(), -10, [&](Adjustments& sample) {
3357 sample.accountShares->amount = 5;
3363 [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3370 {
"clawback must change vault balance"},
3376 args(
A2.id(), -1, [&](Adjustments& sample) {
3377 sample.vaultAssets.reset();
3383 [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3389 {
"clawback may only be performed by the asset issuer"},
3395 args(
A2.id(), 0, [&](Adjustments& sample) {}));
3404 {
"clawback may only be performed by the asset issuer"},
3410 args(
A2.id(), 0, [&](Adjustments& sample) {}));
3415 [&](
STObject& tx) { tx[sfAccount] = A4.id(); }},
3420 {
"clawback must decrease vault balance",
3421 "clawback must decrease holder shares",
3422 "clawback must change vault shares"},
3428 args(A4.id(), 10, [&](Adjustments& sample) {
3429 sample.sharesTotal = 0;
3436 tx[sfAccount] = A3.id();
3437 tx[sfHolder] = A4.id();
3443 {
"clawback must change holder shares"},
3449 args(A4.id(), -10, [&](Adjustments& sample) {
3450 sample.accountShares.reset();
3457 tx[sfAccount] = A3.id();
3458 tx[sfHolder] = A4.id();
3464 {
"clawback must change holder and vault shares by equal amount",
3465 "clawback and assets outstanding must add up",
3466 "clawback and assets available must add up"},
3472 args(A4.id(), -10, [&](Adjustments& sample) {
3473 sample.accountShares->amount = -8;
3474 sample.assetsTotal = -7;
3475 sample.assetsAvailable = -7;
3482 tx[sfAccount] = A3.id();
3483 tx[sfHolder] = A4.id();