1148 using namespace test::jtx;
1152 {{
"permissioned domain with no rules."}},
1156 slePd->setAccountID(sfOwner,
A1);
1157 slePd->setFieldU32(sfSequence, 10);
1159 ac.view().insert(slePd);
1166 testcase <<
"PermissionedDomain 2";
1170 {{
"permissioned domain bad credentials size " +
std::to_string(tooBig)}},
1174 slePd->setAccountID(sfOwner,
A1);
1175 slePd->setFieldU32(sfSequence, 10);
1177 STArray credentials(sfAcceptedCredentials, tooBig);
1181 cred.setAccountID(sfIssuer,
A2);
1183 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1186 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1187 ac.view().insert(slePd);
1194 testcase <<
"PermissionedDomain 3";
1196 {{
"permissioned domain credentials aren't sorted"}},
1200 slePd->setAccountID(sfOwner,
A1);
1201 slePd->setFieldU32(sfSequence, 10);
1203 STArray credentials(sfAcceptedCredentials, 2);
1207 cred.setAccountID(sfIssuer,
A2);
1209 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1212 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1213 ac.view().insert(slePd);
1220 testcase <<
"PermissionedDomain 4";
1222 {{
"permissioned domain credentials aren't unique"}},
1226 slePd->setAccountID(sfOwner,
A1);
1227 slePd->setFieldU32(sfSequence, 10);
1229 STArray credentials(sfAcceptedCredentials, 2);
1233 cred.setAccountID(sfIssuer,
A2);
1234 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1237 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1238 ac.view().insert(slePd);
1245 testcase <<
"PermissionedDomain Set 1";
1247 {{
"permissioned domain with no rules."}},
1257 STArray credentials(sfAcceptedCredentials, 2);
1258 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1259 ac.view().update(slePd);
1268 testcase <<
"PermissionedDomain Set 2";
1270 {{
"permissioned domain bad credentials size " +
std::to_string(tooBig)}},
1280 STArray credentials(sfAcceptedCredentials, tooBig);
1285 cred.setAccountID(sfIssuer,
A2);
1287 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1291 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1292 ac.view().update(slePd);
1301 testcase <<
"PermissionedDomain Set 3";
1303 {{
"permissioned domain credentials aren't sorted"}},
1313 STArray credentials(sfAcceptedCredentials, 2);
1317 cred.setAccountID(sfIssuer,
A2);
1319 cred.setFieldVL(sfCredentialType,
Slice(credType.c_str(), credType.size()));
1323 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1324 ac.view().update(slePd);
1333 testcase <<
"PermissionedDomain Set 4";
1335 {{
"permissioned domain credentials aren't unique"}},
1345 STArray credentials(sfAcceptedCredentials, 2);
1349 cred.setAccountID(sfIssuer,
A2);
1350 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1353 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1354 ac.view().update(slePd);
1961 using namespace test::jtx;
1963 struct AccountAmount
1980 auto sleVault = ac.
peek(keylet);
1984 auto const mptIssuanceID = (*sleVault)[sfShareMPTID];
1990 if (args.lossUnrealized)
1991 (*sleVault)[sfLossUnrealized] = *args.lossUnrealized;
1992 if (args.assetsMaximum)
1993 (*sleVault)[sfAssetsMaximum] = *args.assetsMaximum;
1996 if (args.assetsTotal)
1997 (*sleVault)[sfAssetsTotal] = *(*sleVault)[sfAssetsTotal] + *args.assetsTotal;
1998 if (args.assetsAvailable)
1999 (*sleVault)[sfAssetsAvailable] = *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable;
2002 if (args.sharesTotal)
2004 (*sleShares)[sfOutstandingAmount] = *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal;
2008 auto const assets = *(*sleVault)[sfAsset];
2009 auto const pseudoId = *(*sleVault)[sfAccount];
2010 if (args.vaultAssets)
2012 if (assets.native())
2015 if (!slePseudoAccount)
2017 (*slePseudoAccount)[sfBalance] = *(*slePseudoAccount)[sfBalance] + *args.vaultAssets;
2018 ac.
update(slePseudoAccount);
2022 auto const mptId = assets.get<
MPTIssue>().getMptID();
2026 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets;
2033 if (args.accountAssets)
2035 auto const& pair = *args.accountAssets;
2036 if (assets.native())
2041 (*sleAccount)[sfBalance] = *(*sleAccount)[sfBalance] + pair.amount;
2046 auto const mptID = assets.get<
MPTIssue>().getMptID();
2050 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + pair.amount;
2057 if (args.accountShares)
2059 auto const& pair = *args.accountShares;
2063 (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + pair.amount;
2069 constexpr auto args = [](
AccountID id,
int adjustment,
auto fn) -> Adjustments {
2070 Adjustments sample = {
2071 .assetsTotal = adjustment,
2072 .assetsAvailable = adjustment,
2073 .lossUnrealized = 0,
2074 .sharesTotal = adjustment,
2075 .vaultAssets = adjustment,
2077 AccountAmount{id, -adjustment},
2079 AccountAmount{id, adjustment}};
2087 env.fund(
XRP(1000), A3, A4);
2089 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2091 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2092 env(vault.deposit({.depositor = A2, .id = keylet.key, .amount = XRP(10)}));
2093 env(vault.deposit({.depositor = A3, .id = keylet.key, .amount = XRP(10)}));
2097 testcase <<
"Vault general checks";
2099 {
"vault deletion succeeded without deleting a vault"},
2102 auto sleVault = ac.view().
peek(keylet);
2105 ac.view().
update(sleVault);
2113 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2119 {
"vault updated by a wrong transaction type"},
2122 auto sleVault = ac.view().
peek(keylet);
2125 ac.view().
erase(sleVault);
2133 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2139 {
"vault updated by a wrong transaction type"},
2142 auto sleVault = ac.view().
peek(keylet);
2145 ac.view().
update(sleVault);
2153 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2159 {
"vault updated by a wrong transaction type"},
2161 auto const sequence = ac.view().
seq();
2164 auto const vaultPage =
2166 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2167 ac.view().
insert(sleVault);
2175 {
"vault deleted by a wrong transaction type"},
2178 auto sleVault = ac.view().
peek(keylet);
2181 ac.view().
erase(sleVault);
2189 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2195 {
"vault operation updated more than single vault"},
2199 auto sleVault = ac.view().
peek(keylet);
2202 ac.view().
erase(sleVault);
2206 auto sleVault = ac.view().
peek(keylet);
2209 ac.view().
erase(sleVault);
2219 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2223 auto [tx, _] = vault.create({.owner =
A2, .asset =
xrpIssue()});
2230 {
"vault operation updated more than single vault"},
2232 auto const sequence = ac.view().
seq();
2233 auto const insertVault = [&](
Account const A) {
2236 auto const vaultPage =
2238 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2239 ac.view().
insert(sleVault);
2250 {
"deleted vault must also delete shares"},
2253 auto sleVault = ac.view().
peek(keylet);
2256 ac.view().
erase(sleVault);
2264 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2270 {
"deleted vault must have no shares outstanding",
2271 "deleted vault must have no assets outstanding",
2272 "deleted vault must have no assets available"},
2275 auto sleVault = ac.view().
peek(keylet);
2281 ac.view().
erase(sleVault);
2282 ac.view().
erase(sleShares);
2290 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2292 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2297 {
"vault operation succeeded without modifying a vault"},
2300 auto sleVault = ac.view().
peek(keylet);
2308 sleShares->setFieldH256(sfDomainID,
uint256(13));
2309 ac.view().
update(sleShares);
2319 {
"vault operation succeeded without modifying a vault"},
2326 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2332 {
"vault operation succeeded without modifying a vault"},
2339 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2345 {
"vault operation succeeded without modifying a vault"},
2352 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2358 {
"vault operation succeeded without modifying a vault"},
2365 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2371 {
"vault operation succeeded without modifying a vault"},
2378 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2384 {
"updated vault must have shares"},
2387 auto sleVault = ac.view().
peek(keylet);
2390 (*sleVault)[sfAssetsMaximum] = 200;
2391 ac.view().
update(sleVault);
2396 ac.view().
erase(sleShares);
2404 auto [tx, _] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2410 {
"vault operation succeeded without updating shares",
2411 "assets available must not be greater than assets outstanding"},
2414 auto sleVault = ac.view().
peek(keylet);
2417 (*sleVault)[sfAssetsTotal] = 9;
2418 ac.view().
update(sleVault);
2426 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2428 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)}));
2433 {
"set must not change assets outstanding",
2434 "set must not change assets available",
2435 "set must not change shares outstanding",
2436 "set must not change vault balance",
2437 "assets available must be positive",
2438 "assets available must not be greater than assets outstanding",
2439 "assets outstanding must be positive"},
2442 auto sleVault = ac.view().
peek(keylet);
2446 if (!slePseudoAccount)
2448 (*slePseudoAccount)[sfBalance] = *(*slePseudoAccount)[sfBalance] - 10;
2449 ac.view().
update(slePseudoAccount);
2455 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2458 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {
2459 sample.assetsAvailable = (DROPS_PER_XRP * -100).value();
2460 sample.assetsTotal = (DROPS_PER_XRP * -200).value();
2461 sample.sharesTotal = -1;
2471 {
"violation of vault immutable data"},
2474 auto sleVault = ac.view().
peek(keylet);
2478 ac.view().
update(sleVault);
2487 {
"violation of vault immutable data"},
2490 auto sleVault = ac.view().
peek(keylet);
2493 sleVault->setAccountID(sfAccount,
A2.id());
2494 ac.view().
update(sleVault);
2503 {
"violation of vault immutable data"},
2506 auto sleVault = ac.view().
peek(keylet);
2509 (*sleVault)[sfShareMPTID] =
MPTID(42);
2510 ac.view().
update(sleVault);
2519 {
"vault transaction must not change loss unrealized",
"set must not change assets outstanding"},
2522 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {
2523 sample.lossUnrealized = 13;
2524 sample.assetsTotal = 20;
2534 {
"loss unrealized must not exceed the difference "
2535 "between assets outstanding and available",
2536 "vault transaction must not change loss unrealized"},
2540 ac.view(), keylet, args(
A2.id(), 100, [&](Adjustments& sample) { sample.lossUnrealized = 13; }));
2549 {
"set assets outstanding must not exceed assets maximum"},
2553 ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) { sample.assetsMaximum = 1; }));
2562 {
"assets maximum must be positive"},
2566 ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) { sample.assetsMaximum = -1; }));
2575 {
"set must not change shares outstanding",
2576 "updated zero sized vault must have no assets outstanding",
2577 "updated zero sized vault must have no assets available"},
2580 auto sleVault = ac.view().
peek(keylet);
2583 ac.view().
update(sleVault);
2587 (*sleShares)[sfOutstandingAmount] = 0;
2588 ac.view().
update(sleShares);
2598 {
"updated shares must not exceed maximum"},
2601 auto sleVault = ac.view().
peek(keylet);
2607 (*sleShares)[sfMaximumAmount] = 10;
2608 ac.view().
update(sleShares);
2610 return adjust(ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2619 {
"updated shares must not exceed maximum"},
2622 adjust(ac.view(), keylet, args(
A2.id(), 10, [](Adjustments&) {}));
2624 auto sleVault = ac.view().
peek(keylet);
2631 ac.view().
update(sleShares);
2643 "created vault must be empty",
2644 "updated zero sized vault must have no assets outstanding",
2645 "create operation must not have updated a vault",
2649 auto sleVault = ac.view().
peek(keylet);
2652 (*sleVault)[sfAssetsTotal] = 9;
2653 ac.view().
update(sleVault);
2661 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2668 "created vault must be empty",
2669 "updated zero sized vault must have no assets available",
2670 "assets available must not be greater than assets outstanding",
2671 "create operation must not have updated a vault",
2675 auto sleVault = ac.view().
peek(keylet);
2678 (*sleVault)[sfAssetsAvailable] = 9;
2679 ac.view().
update(sleVault);
2687 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2694 "created vault must be empty",
2695 "loss unrealized must not exceed the difference between assets "
2696 "outstanding and available",
2697 "vault transaction must not change loss unrealized",
2698 "create operation must not have updated a vault",
2702 auto sleVault = ac.view().
peek(keylet);
2705 (*sleVault)[sfLossUnrealized] = 1;
2706 ac.view().
update(sleVault);
2714 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2721 "created vault must be empty",
2722 "create operation must not have updated a vault",
2726 auto sleVault = ac.view().
peek(keylet);
2732 ac.view().
update(sleVault);
2733 (*sleShares)[sfOutstandingAmount] = 9;
2734 ac.view().
update(sleShares);
2742 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2749 "assets maximum must be positive",
2750 "create operation must not have updated a vault",
2754 auto sleVault = ac.view().
peek(keylet);
2757 (*sleVault)[sfAssetsMaximum] =
Number(-1);
2758 ac.view().
update(sleVault);
2766 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2772 {
"create operation must not have updated a vault",
2773 "shares issuer and vault pseudo-account must be the same",
2774 "shares issuer must be a pseudo-account",
2775 "shares issuer pseudo-account must point back to the vault"},
2778 auto sleVault = ac.view().
peek(keylet);
2784 ac.view().
update(sleVault);
2785 (*sleShares)[sfIssuer] =
A1.id();
2786 ac.view().
update(sleShares);
2794 auto [tx, keylet] = vault.create({.owner =
A1, .asset =
xrpIssue()});
2800 {
"vault created by a wrong transaction type",
"account root created illegally"},
2805 auto const sequence = ac.view().
seq();
2808 auto const vaultPage =
2810 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2815 sleAccount->setAccountID(sfAccount, pseudoId);
2816 sleAccount->setFieldAmount(sfBalance,
STAmount{});
2821 sleAccount->setFieldU32(sfSequence, seqno);
2823 sleAccount->setFieldH256(sfVaultID, vaultKeylet.key);
2824 ac.view().
insert(sleAccount);
2826 auto const sharesMptId =
makeMptID(sequence, pseudoId);
2829 auto const sharesPage =
2831 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2833 sleShares->at(sfFlags) = 0;
2834 sleShares->at(sfIssuer) = pseudoId;
2835 sleShares->at(sfOutstandingAmount) = 0;
2836 sleShares->at(sfSequence) = sequence;
2838 sleVault->at(sfAccount) = pseudoId;
2839 sleVault->at(sfFlags) = 0;
2840 sleVault->at(sfSequence) = sequence;
2841 sleVault->at(sfOwner) =
A1.id();
2842 sleVault->at(sfAssetsTotal) =
Number(0);
2843 sleVault->at(sfAssetsAvailable) =
Number(0);
2844 sleVault->at(sfLossUnrealized) =
Number(0);
2845 sleVault->at(sfShareMPTID) = sharesMptId;
2848 ac.view().
insert(sleVault);
2849 ac.view().
insert(sleShares);
2857 {
"shares issuer and vault pseudo-account must be the same",
2858 "shares issuer pseudo-account must point back to the vault"},
2860 auto const sequence = ac.view().
seq();
2863 auto const vaultPage =
2865 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2870 sleAccount->setAccountID(sfAccount, pseudoId);
2871 sleAccount->setFieldAmount(sfBalance,
STAmount{});
2876 sleAccount->setFieldU32(sfSequence, seqno);
2880 sleAccount->setFieldH256(sfVaultID,
uint256(42));
2881 ac.view().
insert(sleAccount);
2883 auto const sharesMptId =
makeMptID(sequence, pseudoId);
2886 auto const sharesPage =
2888 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2890 sleShares->at(sfFlags) = 0;
2891 sleShares->at(sfIssuer) = pseudoId;
2892 sleShares->at(sfOutstandingAmount) = 0;
2893 sleShares->at(sfSequence) = sequence;
2897 sleVault->at(sfAccount) =
A2.id();
2898 sleVault->at(sfFlags) = 0;
2899 sleVault->at(sfSequence) = sequence;
2900 sleVault->at(sfOwner) =
A1.id();
2901 sleVault->at(sfAssetsTotal) =
Number(0);
2902 sleVault->at(sfAssetsAvailable) =
Number(0);
2903 sleVault->at(sfLossUnrealized) =
Number(0);
2904 sleVault->at(sfShareMPTID) = sharesMptId;
2907 ac.view().
insert(sleVault);
2908 ac.view().
insert(sleShares);
2916 {
"shares issuer and vault pseudo-account must be the same",
"shares issuer must exist"},
2918 auto const sequence = ac.view().
seq();
2921 auto const vaultPage =
2923 sleVault->setFieldU64(sfOwnerNode, *vaultPage);
2925 auto const sharesMptId =
makeMptID(sequence,
A2.id());
2928 auto const sharesPage =
2930 sleShares->setFieldU64(sfOwnerNode, *sharesPage);
2932 sleShares->at(sfFlags) = 0;
2935 sleShares->at(sfOutstandingAmount) = 0;
2936 sleShares->at(sfSequence) = sequence;
2938 sleVault->at(sfAccount) =
A2.id();
2939 sleVault->at(sfFlags) = 0;
2940 sleVault->at(sfSequence) = sequence;
2941 sleVault->at(sfOwner) =
A1.id();
2942 sleVault->at(sfAssetsTotal) =
Number(0);
2943 sleVault->at(sfAssetsAvailable) =
Number(0);
2944 sleVault->at(sfLossUnrealized) =
Number(0);
2945 sleVault->at(sfShareMPTID) = sharesMptId;
2948 ac.view().
insert(sleVault);
2949 ac.view().
insert(sleShares);
2958 {
"deposit must change vault balance"},
2962 ac.view(), keylet, args(
A2.id(), 0, [](Adjustments& sample) { sample.vaultAssets.reset(); }));
2970 {
"deposit assets outstanding must not exceed assets maximum"},
2974 ac.view(), keylet, args(
A2.id(), 200, [&](Adjustments& sample) { sample.assetsMaximum = 1; }));
2987 {
"deposit must increase vault balance",
"deposit must change depositor balance"},
2995 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
2998 return adjust(ac.view(), keylet, args(A3.id(), -10, [&](Adjustments& sample) {
2999 sample.accountAssets->amount = -100;
3007 tx[sfAccount] = A3.id();
3013 {
"deposit must increase vault balance",
3014 "deposit must decrease depositor balance",
3015 "deposit must change vault and depositor balance by equal amount",
3016 "deposit and assets outstanding must add up",
3017 "deposit and assets available must add up"},
3025 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3028 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3029 sample.vaultAssets = -20;
3030 sample.accountAssets->amount = 10;
3040 {
"deposit must change depositor balance"},
3048 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 10;
3051 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3052 sample.accountAssets->amount = 0;
3062 {
"deposit must change depositor shares"},
3066 ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) { sample.accountShares.reset(); }));
3075 {
"deposit must change vault shares"},
3080 ac.view(), keylet, args(
A2.id(), 10, [](Adjustments& sample) { sample.sharesTotal = 0; }));
3089 {
"deposit must increase depositor shares",
3090 "deposit must change depositor and vault shares by equal amount",
3091 "deposit must not change vault balance by more than deposited "
3095 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3096 sample.accountShares->amount = -5;
3097 sample.sharesTotal = -10;
3107 {
"deposit and assets outstanding must add up"},
3110 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3115 ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) { sample.assetsTotal = 11; }));
3122 tx[sfDelegate] = A3.id();
3130 {
"deposit and assets outstanding must add up",
"deposit and assets available must add up"},
3133 return adjust(ac.view(), keylet, args(
A2.id(), 10, [&](Adjustments& sample) {
3134 sample.assetsTotal = 7;
3135 sample.assetsAvailable = 7;
3146 {
"withdrawal must change vault balance"},
3150 ac.view(), keylet, args(
A2.id(), 0, [](Adjustments& sample) { sample.vaultAssets.reset(); }));
3162 {
"withdrawal must change one destination balance"},
3170 (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10;
3173 return adjust(ac.view(), keylet, args(A3.id(), -10, [&](Adjustments& sample) {
3174 sample.accountAssets->amount = -100;
3182 tx[sfAccount] = A3.id();
3190 {
"withdrawal must change vault and destination balance by "
3192 "withdrawal must decrease vault balance",
3193 "withdrawal must increase destination balance",
3194 "withdrawal and assets outstanding must add up",
3195 "withdrawal and assets available must add up"},
3203 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10;
3206 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3207 sample.vaultAssets = 10;
3208 sample.accountAssets->amount = -20;
3218 {
"withdrawal must change one destination balance"},
3222 ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) { *sample.vaultAssets -= 5; })))
3227 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 5;
3238 {
"withdrawal must change depositor shares"},
3242 ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) { sample.accountShares.reset(); }));
3251 {
"withdrawal must change vault shares"},
3255 ac.view(), keylet, args(
A2.id(), -10, [](Adjustments& sample) { sample.sharesTotal = 0; }));
3264 {
"withdrawal must decrease depositor shares",
3265 "withdrawal must change depositor and vault shares by equal "
3269 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3270 sample.accountShares->amount = 5;
3271 sample.sharesTotal = 10;
3281 {
"withdrawal and assets outstanding must add up",
"withdrawal and assets available must add up"},
3284 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3285 sample.assetsTotal = -15;
3286 sample.assetsAvailable = -15;
3296 {
"withdrawal and assets outstanding must add up"},
3299 (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 2000;
3304 ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) { sample.assetsTotal = -7; }));
3311 tx[sfDelegate] = A3.id();
3319 env.fund(
XRP(1000), A3, A4);
3324 jv[sfAccount] = A3.human();
3325 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
3331 auto const mptID =
makeMptID(env.seq(A3) - 1, A3);
3336 jv[sfAccount] =
A1.human();
3337 jv[sfTransactionType] = jss::MPTokenAuthorize;
3338 jv[sfMPTokenIssuanceID] =
to_string(mptID);
3340 jv[sfAccount] =
A2.human();
3342 jv[sfAccount] = A4.human();
3349 env(
pay(A3,
A1, asset(1000)));
3350 env(
pay(A3,
A2, asset(1000)));
3351 env(
pay(A3, A4, asset(1000)));
3356 auto [tx, keylet] = vault.create({.owner =
A1, .asset = asset});
3358 env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = asset(10)}));
3359 env(vault.deposit({.depositor = A2, .id = keylet.key, .amount = asset(10)}));
3360 env(vault.deposit({.depositor = A4, .id = keylet.key, .amount = asset(10)}));
3365 {
"withdrawal must decrease depositor shares",
3366 "withdrawal must change depositor and vault shares by equal "
3370 return adjust(ac.view(), keylet, args(
A2.id(), -10, [&](Adjustments& sample) {
3371 sample.accountShares->amount = 5;
3375 STTx{ttVAULT_WITHDRAW, [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3382 {
"clawback must change vault balance"},
3386 ac.view(), keylet, args(
A2.id(), -1, [&](Adjustments& sample) { sample.vaultAssets.reset(); }));
3389 STTx{ttVAULT_CLAWBACK, [&](
STObject& tx) { tx[sfAccount] = A3.id(); }},
3395 {
"clawback may only be performed by the asset issuer"},
3398 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {}));
3407 {
"clawback may only be performed by the asset issuer"},
3410 return adjust(ac.view(), keylet, args(
A2.id(), 0, [&](Adjustments& sample) {}));
3413 STTx{ttVAULT_CLAWBACK, [&](
STObject& tx) { tx[sfAccount] = A4.id(); }},
3418 {
"clawback must decrease vault balance",
3419 "clawback must decrease holder shares",
3420 "clawback must change vault shares"},
3424 ac.view(), keylet, args(A4.id(), 10, [&](Adjustments& sample) { sample.sharesTotal = 0; }));
3430 tx[sfAccount] = A3.id();
3431 tx[sfHolder] = A4.id();
3437 {
"clawback must change holder shares"},
3441 ac.view(), keylet, args(A4.id(), -10, [&](Adjustments& sample) { sample.accountShares.reset(); }));
3447 tx[sfAccount] = A3.id();
3448 tx[sfHolder] = A4.id();
3454 {
"clawback must change holder and vault shares by equal amount",
3455 "clawback and assets outstanding must add up",
3456 "clawback and assets available must add up"},
3459 return adjust(ac.view(), keylet, args(A4.id(), -10, [&](Adjustments& sample) {
3460 sample.accountShares->amount = -8;
3461 sample.assetsTotal = -7;
3462 sample.assetsAvailable = -7;
3469 tx[sfAccount] = A3.id();
3470 tx[sfHolder] = A4.id();