45        using namespace test::jtx;
 
   46        Account issuer{
"issuer"};
 
   47        Account owner{
"owner"};
 
   48        Account depositor{
"depositor"};
 
   49        Account charlie{
"charlie"};  
 
   52        auto const testSequence = [&, 
this](
 
   57            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
   58            tx[sfData] = 
"AFEED00E";
 
   59            tx[sfAssetsMaximum] = asset(100).number();
 
   62            BEAST_EXPECT(env.le(keylet));
 
   65            auto const [share, vaultAccount] =
 
   70                auto const vault = env.le(keylet);
 
   71                BEAST_EXPECT(vault != 
nullptr);
 
   72                if (asset.raw().holds<
Issue>() && !asset.raw().
native())
 
   73                    BEAST_EXPECT(vault->at(sfScale) == 6);
 
   75                    BEAST_EXPECT(vault->at(sfScale) == 0);
 
   78                BEAST_EXPECT(shares != 
nullptr);
 
   79                if (asset.raw().holds<
Issue>() && !asset.raw().
native())
 
   80                    BEAST_EXPECT(shares->at(sfAssetScale) == 6);
 
   82                    BEAST_EXPECT(shares->at(sfAssetScale) == 0);
 
   85                    Account(
"vault", vault->at(sfAccount))};
 
   87            auto const shares = share.raw().get<
MPTIssue>();
 
   88            env.memoize(vaultAccount);
 
   91            Account alice{
"alice"};
 
   93            env.fund(XRP(1000), alice, erin);
 
   98                testcase(prefix + 
" fail to deposit more than assets held");
 
   99                auto tx = vault.deposit(
 
  100                    {.depositor = depositor,
 
  102                     .amount = asset(10000)});
 
  108                testcase(prefix + 
" deposit non-zero amount");
 
  109                auto tx = vault.deposit(
 
  110                    {.depositor = depositor,
 
  112                     .amount = asset(50)});
 
  116                    env.balance(depositor, shares) == share(50 * scale));
 
  120                testcase(prefix + 
" deposit non-zero amount again");
 
  121                auto tx = vault.deposit(
 
  122                    {.depositor = depositor,
 
  124                     .amount = asset(50)});
 
  128                    env.balance(depositor, shares) == share(100 * scale));
 
  132                testcase(prefix + 
" fail to delete non-empty vault");
 
  133                auto tx = vault.del({.owner = owner, .id = keylet.
key});
 
  139                testcase(prefix + 
" fail to update because wrong owner");
 
  140                auto tx = vault.set({.owner = issuer, .id = keylet.
key});
 
  141                tx[sfAssetsMaximum] = asset(50).number();
 
  148                    prefix + 
" fail to set maximum lower than current amount");
 
  149                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  150                tx[sfAssetsMaximum] = asset(50).number();
 
  156                testcase(prefix + 
" set maximum higher than current amount");
 
  157                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  158                tx[sfAssetsMaximum] = asset(150).number();
 
  164                testcase(prefix + 
" set maximum is idempotent, set it again");
 
  165                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  166                tx[sfAssetsMaximum] = asset(150).number();
 
  173                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  180                testcase(prefix + 
" fail to set domain on public vault");
 
  181                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  188                testcase(prefix + 
" fail to deposit more than maximum");
 
  189                auto tx = vault.deposit(
 
  190                    {.depositor = depositor,
 
  192                     .amount = asset(100)});
 
  198                testcase(prefix + 
" reset maximum to zero i.e. not enforced");
 
  199                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  200                tx[sfAssetsMaximum] = asset(0).number();
 
  206                testcase(prefix + 
" fail to withdraw more than assets held");
 
  207                auto tx = vault.withdraw(
 
  208                    {.depositor = depositor,
 
  210                     .amount = asset(1000)});
 
  216                testcase(prefix + 
" deposit some more");
 
  217                auto tx = vault.deposit(
 
  218                    {.depositor = depositor,
 
  220                     .amount = asset(100)});
 
  224                    env.balance(depositor, shares) == share(200 * scale));
 
  228                testcase(prefix + 
" clawback some");
 
  231                auto tx = vault.clawback(
 
  235                     .amount = asset(10)});
 
  238                if (!asset.raw().native())
 
  241                        env.balance(depositor, shares) == share(190 * scale));
 
  249                auto tx = vault.clawback(
 
  250                    {.issuer = issuer, .id = keylet.
key, .holder = depositor});
 
  253                if (!asset.raw().native())
 
  255                    BEAST_EXPECT(env.balance(depositor, shares) == share(0));
 
  258                        auto tx = vault.clawback(
 
  262                             .amount = asset(10)});
 
  268                        auto tx = vault.withdraw(
 
  269                            {.depositor = depositor,
 
  271                             .amount = asset(10)});
 
  278            if (!asset.raw().native())
 
  280                testcase(prefix + 
" deposit again");
 
  281                auto tx = vault.deposit(
 
  282                    {.depositor = depositor,
 
  284                     .amount = asset(200)});
 
  288                    env.balance(depositor, shares) == share(200 * scale));
 
  292                testcase(prefix + 
" deposit/withdrawal same or less than fee");
 
  293                auto const amount = env.current()->fees().base;
 
  295                auto tx = vault.deposit(
 
  296                    {.depositor = depositor,
 
  303                    {.depositor = depositor,
 
  310                    {.depositor = depositor,
 
  318                    {.depositor = depositor,
 
  321                tx[sfDestination] = charlie.human();
 
  326                    {.depositor = depositor,
 
  328                     .amount = amount - 1});
 
  333                    {.depositor = depositor,
 
  335                     .amount = amount - 1});
 
  342                    prefix + 
" fail to withdraw to 3rd party lsfDepositAuth");
 
  343                auto tx = vault.withdraw(
 
  344                    {.depositor = depositor,
 
  346                     .amount = asset(100)});
 
  347                tx[sfDestination] = alice.human();
 
  353                testcase(prefix + 
" fail to withdraw to zero destination");
 
  354                auto tx = vault.withdraw(
 
  355                    {.depositor = depositor,
 
  357                     .amount = asset(1000)});
 
  358                tx[sfDestination] = 
"0";
 
  363            if (!asset.raw().native())
 
  366                    prefix + 
" fail to withdraw to 3rd party no authorization");
 
  367                auto tx = vault.withdraw(
 
  368                    {.depositor = depositor,
 
  370                     .amount = asset(100)});
 
  371                tx[sfDestination] = erin.human();
 
  380                    " fail to withdraw to 3rd party lsfRequireDestTag");
 
  381                auto tx = vault.withdraw(
 
  382                    {.depositor = depositor,
 
  384                     .amount = asset(100)});
 
  385                tx[sfDestination] = dave.human();
 
  391                testcase(prefix + 
" withdraw to 3rd party lsfRequireDestTag");
 
  392                auto tx = vault.withdraw(
 
  393                    {.depositor = depositor,
 
  395                     .amount = asset(50)});
 
  396                tx[sfDestination] = dave.human();
 
  397                tx[sfDestinationTag] = 
"0";
 
  403                testcase(prefix + 
" deposit again");
 
  404                auto tx = vault.deposit(
 
  405                    {.depositor = dave, .id = keylet.
key, .amount = asset(50)});
 
  411                testcase(prefix + 
" fail to withdraw lsfRequireDestTag");
 
  412                auto tx = vault.withdraw(
 
  413                    {.depositor = dave, .id = keylet.
key, .amount = asset(50)});
 
  419                testcase(prefix + 
" withdraw with tag");
 
  420                auto tx = vault.withdraw(
 
  421                    {.depositor = dave, .id = keylet.
key, .amount = asset(50)});
 
  422                tx[sfDestinationTag] = 
"0";
 
  428                testcase(prefix + 
" withdraw to authorized 3rd party");
 
  429                auto tx = vault.withdraw(
 
  430                    {.depositor = depositor,
 
  432                     .amount = asset(50)});
 
  433                tx[sfDestination] = charlie.human();
 
  437                    env.balance(depositor, shares) == share(100 * scale));
 
  441                testcase(prefix + 
" withdraw to issuer");
 
  442                auto tx = vault.withdraw(
 
  443                    {.depositor = depositor,
 
  445                     .amount = asset(50)});
 
  446                tx[sfDestination] = issuer.human();
 
  450                    env.balance(depositor, shares) == share(50 * scale));
 
  453            if (!asset.raw().native())
 
  455                testcase(prefix + 
" issuer deposits");
 
  456                auto tx = vault.deposit(
 
  457                    {.depositor = issuer,
 
  459                     .amount = asset(10)});
 
  462                BEAST_EXPECT(env.balance(issuer, shares) == share(10 * scale));
 
  464                testcase(prefix + 
" issuer withdraws");
 
  466                    {.depositor = issuer,
 
  468                     .amount = share(10 * scale)});
 
  471                BEAST_EXPECT(env.balance(issuer, shares) == share(0 * scale));
 
  475                testcase(prefix + 
" withdraw remaining assets");
 
  476                auto tx = vault.withdraw(
 
  477                    {.depositor = depositor,
 
  479                     .amount = asset(50)});
 
  482                BEAST_EXPECT(env.balance(depositor, shares) == share(0));
 
  484                if (!asset.raw().native())
 
  486                    auto tx = vault.clawback(
 
  490                         .amount = asset(0)});
 
  496                    auto tx = vault.withdraw(
 
  497                        {.depositor = depositor,
 
  499                         .amount = share(10)});
 
  505            if (!asset.raw().native() && asset.raw().holds<
Issue>())
 
  507                testcase(prefix + 
" temporary authorization for 3rd party");
 
  508                env(trust(erin, asset(1000)));
 
  509                env(trust(issuer, asset(0), erin, 
tfSetfAuth));
 
  510                env(pay(issuer, erin, asset(10)));
 
  513                auto tx = vault.deposit(
 
  514                    {.depositor = erin, .id = keylet.
key, .amount = asset(10)});
 
  518                    auto tx = pay(erin, depositor, share(10 * scale));
 
  526                        {.depositor = depositor,
 
  528                         .amount = asset(1)}));
 
  535                testcase(prefix + 
" withdraw to authorized 3rd party");
 
  538                    {.depositor = depositor,
 
  540                     .amount = asset(10)});
 
  541                tx[sfDestination] = erin.human();
 
  546                env(pay(erin, issuer, asset(10)));
 
  549                testcase(prefix + 
" fail to pay to unauthorized 3rd party");
 
  550                env(trust(erin, asset(0)));
 
  554                env(pay(depositor, erin, share(1)), ter{
tecNO_LINE});
 
  559                    {.depositor = depositor,
 
  561                     .amount = asset(1)});
 
  567                testcase(prefix + 
" fail to delete because wrong owner");
 
  568                auto tx = vault.del({.owner = issuer, .id = keylet.
key});
 
  574                testcase(prefix + 
" delete empty vault");
 
  575                auto tx = vault.del({.owner = owner, .id = keylet.
key});
 
  578                BEAST_EXPECT(!env.le(keylet));
 
  582        auto testCases = [&, 
this](
 
  585            Env env{*
this, testable_amendments() | featureSingleAssetVault};
 
  588            env.fund(XRP(1000), issuer, owner, depositor, charlie, dave);
 
  598            testSequence(prefix, env, vault, asset);
 
  605        testCases(
"IOU", [&](Env& env) -> 
Asset {
 
  607            env(trust(owner, asset(1000)));
 
  608            env(trust(depositor, asset(1000)));
 
  609            env(trust(charlie, asset(1000)));
 
  610            env(trust(dave, asset(1000)));
 
  611            env(trust(issuer, asset(0), owner, 
tfSetfAuth));
 
  612            env(trust(issuer, asset(0), depositor, 
tfSetfAuth));
 
  613            env(trust(issuer, asset(0), charlie, 
tfSetfAuth));
 
  614            env(trust(issuer, asset(0), dave, 
tfSetfAuth));
 
  615            env(pay(issuer, depositor, asset(1000)));
 
  620        testCases(
"MPT", [&](Env& env) -> 
Asset {
 
  621            MPTTester mptt{env, issuer, mptInitNoFund};
 
  625            mptt.authorize({.account = depositor});
 
  626            mptt.authorize({.account = charlie});
 
  627            mptt.authorize({.account = dave});
 
  628            env(pay(issuer, depositor, asset(1000)));
 
 
  637        using namespace test::jtx;
 
  642                testable_amendments() | featureSingleAssetVault;
 
  645        auto testCase = [&, 
this](
 
  648                                Account 
const& issuer,
 
  649                                Account 
const& owner,
 
  652                            CaseArgs args = {}) {
 
  653            Env env{*
this, args.features};
 
  654            Account issuer{
"issuer"};
 
  655            Account owner{
"owner"};
 
  657            env.fund(XRP(1000), issuer, owner);
 
  665            env(trust(owner, asset(1000)));
 
  666            env(trust(issuer, asset(0), owner, 
tfSetfAuth));
 
  667            env(pay(issuer, owner, asset(1000)));
 
  670            test(env, issuer, owner, asset, vault);
 
  675                Account 
const& issuer,
 
  676                Account 
const& owner,
 
  679                testcase(
"disabled single asset vault");
 
  682                    vault.create({.owner = owner, .asset = asset});
 
  686                    auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  691                    auto tx = vault.deposit(
 
  694                         .amount = asset(10)});
 
  699                    auto tx = vault.withdraw(
 
  702                         .amount = asset(10)});
 
  707                    auto tx = vault.clawback(
 
  711                         .amount = asset(10)});
 
  716                    auto tx = vault.del({.owner = owner, .id = keylet.
key});
 
  720            {.features = testable_amendments() - featureSingleAssetVault});
 
  722        testCase([&](Env& env,
 
  723                     Account 
const& issuer,
 
  724                     Account 
const& owner,
 
  729            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
  734                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  740                auto tx = vault.deposit(
 
  743                     .amount = asset(10)});
 
  749                auto tx = vault.withdraw(
 
  752                     .amount = asset(10)});
 
  758                auto tx = vault.clawback(
 
  762                     .amount = asset(10)});
 
  768                auto tx = vault.del({.owner = owner, .id = keylet.
key});
 
  774        testCase([&](Env& env,
 
  775                     Account 
const& issuer,
 
  776                     Account 
const& owner,
 
  781            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
  786                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  792                auto tx = vault.deposit(
 
  795                     .amount = asset(10)});
 
  801                auto tx = vault.withdraw(
 
  804                     .amount = asset(10)});
 
  810                auto tx = vault.clawback(
 
  814                     .amount = asset(10)});
 
  820                auto tx = vault.del({.owner = owner, .id = keylet.
key});
 
  829                Account 
const& owner,
 
  832                testcase(
"disabled permissioned domain");
 
  835                    vault.create({.owner = owner, .asset = 
xrpIssue()});
 
  840                    auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  846                    auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
  847                    tx[sfDomainID] = 
"0";
 
  851            {.features = (testable_amendments() | featureSingleAssetVault) -
 
  852                 featurePermissionedDomains});
 
  854        testCase([&](Env& env,
 
  855                     Account 
const& issuer,
 
  856                     Account 
const& owner,
 
  862                vault.create({.owner = owner, .asset = 
xrpIssue()});
 
  865                auto tx = vault.set({
 
  873                auto tx = vault.deposit(
 
  876                     .amount = asset(10)});
 
  881                auto tx = vault.withdraw(
 
  884                     .amount = asset(10)});
 
  889                auto tx = vault.clawback(
 
  893                     .amount = asset(10)});
 
  898                auto tx = vault.del({
 
  906        testCase([&](Env& env,
 
  907                     Account 
const& issuer,
 
  908                     Account 
const& owner,
 
  913            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
  916                auto tx = vault.clawback(
 
  920                     .amount = asset(10)});
 
  925        testCase([&](Env& env,
 
  927                     Account 
const& owner,
 
  930            testcase(
"withdraw to bad destination");
 
  932            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
  935                auto tx = vault.withdraw(
 
  938                     .amount = asset(10)});
 
  939                tx[jss::Destination] = 
"0";
 
  944        testCase([&](Env& env,
 
  946                     Account 
const& owner,
 
  953                    vault.create({.owner = owner, .asset = asset});
 
  960                    vault.create({.owner = owner, .asset = asset});
 
  968                    vault.create({.owner = owner, .asset = asset});
 
  972                auto const sleVault = env.le(keylet);
 
  973                BEAST_EXPECT(sleVault);
 
  974                BEAST_EXPECT((*sleVault)[sfScale] == 18);
 
  979                    vault.create({.owner = owner, .asset = asset});
 
  983                auto const sleVault = env.le(keylet);
 
  984                BEAST_EXPECT(sleVault);
 
  985                BEAST_EXPECT((*sleVault)[sfScale] == 0);
 
  990                    vault.create({.owner = owner, .asset = asset});
 
  993                auto const sleVault = env.le(keylet);
 
  994                BEAST_EXPECT(sleVault);
 
  995                BEAST_EXPECT((*sleVault)[sfScale] == 6);
 
  999        testCase([&](Env& env,
 
 1001                     Account 
const& owner,
 
 1004            testcase(
"create or set invalid data");
 
 1006            auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1022                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 1028                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 1035        testCase([&](Env& env,
 
 1037                     Account 
const& owner,
 
 1042            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1045                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 1050        testCase([&](Env& env,
 
 1052                     Account 
const& owner,
 
 1055            testcase(
"create with invalid metadata");
 
 1057            auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1061                tx[sfMPTokenMetadata] = 
"";
 
 1074        testCase([&](Env& env,
 
 1076                     Account 
const& owner,
 
 1081            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1084                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 1090        testCase([&](Env& env,
 
 1092                     Account 
const& owner,
 
 1095            testcase(
"invalid deposit amount");
 
 1097            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1100                auto tx = vault.deposit(
 
 1101                    {.depositor = owner,
 
 1108                auto tx = vault.deposit(
 
 1109                    {.depositor = owner, .id = keylet.
key, .amount = asset(0)});
 
 1114        testCase([&](Env& env,
 
 1116                     Account 
const& owner,
 
 1119            testcase(
"invalid set immutable flag");
 
 1121            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1124                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 1130        testCase([&](Env& env,
 
 1132                     Account 
const& owner,
 
 1135            testcase(
"invalid withdraw amount");
 
 1137            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1140                auto tx = vault.withdraw(
 
 1141                    {.depositor = owner,
 
 1148                auto tx = vault.withdraw(
 
 1149                    {.depositor = owner, .id = keylet.
key, .amount = asset(0)});
 
 1154        testCase([&](Env& env,
 
 1155                     Account 
const& issuer,
 
 1156                     Account 
const& owner,
 
 1161            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1164                auto tx = vault.clawback(
 
 1168                     .amount = asset(50)});
 
 1173                auto tx = vault.clawback(
 
 1182        testCase([&](Env& env,
 
 1184                     Account 
const& owner,
 
 1189            auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1193                tx[sfWithdrawalPolicy] = 0;
 
 1212                tx[sfDomainID] = 
"0";
 
 
 1701        using namespace test::jtx;
 
 1705            bool enableClawback = 
true;
 
 1707            int initialXRP = 1000;
 
 1710        auto testCase = [
this](
 
 1713                                Account 
const& issuer,
 
 1714                                Account 
const& owner,
 
 1715                                Account 
const& depositor,
 
 1718                                MPTTester& mptt)> test,
 
 1719                            CaseArgs args = {}) {
 
 1720            Env env{*
this, testable_amendments() | featureSingleAssetVault};
 
 1721            Account issuer{
"issuer"};
 
 1722            Account owner{
"owner"};
 
 1723            Account depositor{
"depositor"};
 
 1724            env.fund(XRP(args.initialXRP), issuer, owner, depositor);
 
 1728            MPTTester mptt{env, issuer, mptInitNoFund};
 
 1735            mptt.authorize({.account = owner});
 
 1736            mptt.authorize({.account = depositor});
 
 1737            if (args.requireAuth)
 
 1739                mptt.authorize({.account = issuer, .holder = owner});
 
 1740                mptt.authorize({.account = issuer, .holder = depositor});
 
 1743            env(pay(issuer, depositor, asset(1000)));
 
 1746            test(env, issuer, owner, depositor, asset, vault, mptt);
 
 1751                     Account 
const& issuer,
 
 1752                     Account 
const& owner,
 
 1753                     Account 
const& depositor,
 
 1757            testcase(
"MPT nothing to clawback from");
 
 1758            auto tx = vault.clawback(
 
 1761                 .holder = depositor,
 
 1762                 .amount = asset(10)});
 
 1768                     Account 
const& issuer,
 
 1769                     Account 
const& owner,
 
 1770                     Account 
const& depositor,
 
 1774            testcase(
"MPT global lock blocks create");
 
 1775            mptt.set({.account = issuer, .flags = 
tfMPTLock});
 
 1776            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1782                     Account 
const& issuer,
 
 1783                     Account 
const& owner,
 
 1784                     Account 
const& depositor,
 
 1788            testcase(
"MPT global lock blocks deposit");
 
 1789            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1793            mptt.set({.account = issuer, .flags = 
tfMPTLock});
 
 1797                {.depositor = depositor,
 
 1799                 .amount = asset(100)});
 
 1804            tx = vault.del({.owner = owner, .id = keylet.
key});
 
 1810                     Account 
const& issuer,
 
 1811                     Account 
const& owner,
 
 1812                     Account 
const& depositor,
 
 1816            testcase(
"MPT global lock blocks withdrawal");
 
 1817            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1821                {.depositor = depositor,
 
 1823                 .amount = asset(100)});
 
 1829            auto v = env.le(keylet);
 
 1831            MPTID share = (*v)[sfShareMPTID];
 
 1833            BEAST_EXPECT(issuance);
 
 1834            Number outstandingShares = issuance->at(sfOutstandingAmount);
 
 1835            BEAST_EXPECT(outstandingShares == 100);
 
 1837            mptt.set({.account = issuer, .flags = 
tfMPTLock});
 
 1840            tx = vault.withdraw(
 
 1841                {.depositor = depositor,
 
 1843                 .amount = asset(100)});
 
 1846            tx[sfDestination] = issuer.human();
 
 1850            tx = vault.clawback(
 
 1853                 .holder = depositor,
 
 1854                 .amount = asset(0)});
 
 1860            BEAST_EXPECT(mptSle == 
nullptr);
 
 1863            tx = vault.del({.owner = owner, .id = keylet.
key});
 
 1869                     Account 
const& issuer,
 
 1870                     Account 
const& owner,
 
 1871                     Account 
const& depositor,
 
 1875            testcase(
"MPT only issuer can clawback");
 
 1877            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 1882                {.depositor = depositor,
 
 1884                 .amount = asset(100)});
 
 1889                auto tx = vault.clawback(
 
 1890                    {.issuer = owner, .id = keylet.
key, .holder = depositor});
 
 1898                Account 
const& issuer,
 
 1899                Account 
const& owner,
 
 1900                Account 
const& depositor,
 
 1904                testcase(
"MPT depositor without MPToken, auth required");
 
 1907                    vault.create({.owner = owner, .asset = asset});
 
 1912                    {.depositor = depositor,
 
 1914                     .amount = asset(1000)});
 
 1924                    auto const mptoken =
 
 1926                    auto const sleMPT1 = env.le(mptoken);
 
 1927                    BEAST_EXPECT(sleMPT1 == 
nullptr);
 
 1929                    tx = vault.withdraw(
 
 1930                        {.depositor = depositor,
 
 1932                         .amount = asset(100)});
 
 1936                    auto const sleMPT2 = env.le(mptoken);
 
 1937                    BEAST_EXPECT(sleMPT2 == 
nullptr);
 
 1942                    Account charlie{
"charlie"};
 
 1943                    env.fund(XRP(1000), charlie);
 
 1946                    tx = vault.withdraw(
 
 1947                        {.depositor = depositor,
 
 1949                         .amount = asset(100)});
 
 1950                    tx[sfDestination] = charlie.human();
 
 1954            {.requireAuth = 
true});
 
 1959                Account 
const& issuer,
 
 1960                Account 
const& owner,
 
 1961                Account 
const& depositor,
 
 1965                testcase(
"MPT depositor without MPToken, no auth required");
 
 1968                    vault.create({.owner = owner, .asset = asset});
 
 1971                auto v = env.le(keylet);
 
 1975                    {.depositor = depositor,
 
 1977                     .amount = asset(1000)});  
 
 1987                    auto const mptoken =
 
 1989                    auto const sleMPT1 = env.le(mptoken);
 
 1990                    BEAST_EXPECT(sleMPT1 == 
nullptr);
 
 1992                    tx = vault.withdraw(
 
 1993                        {.depositor = depositor,
 
 1995                         .amount = asset(100)});
 
 1999                    auto const sleMPT2 = env.le(mptoken);
 
 2000                    BEAST_EXPECT(sleMPT2 != 
nullptr);
 
 2001                    BEAST_EXPECT(sleMPT2->at(sfMPTAmount) == 100);
 
 2010                    auto const mptoken =
 
 2012                    auto const sleMPT1 = env.le(mptoken);
 
 2013                    BEAST_EXPECT(sleMPT1 == 
nullptr);
 
 2015                    tx = vault.withdraw(
 
 2016                        {.depositor = depositor,
 
 2018                         .amount = asset(100)});
 
 2019                    tx[sfDestination] = owner.human();
 
 2023                    auto const sleMPT2 = env.le(mptoken);
 
 2024                    BEAST_EXPECT(sleMPT2 == 
nullptr);
 
 2027            {.requireAuth = 
false});
 
 2030            Env env{*
this, testable_amendments()};
 
 2032                env.current()->fees().accountReserve(0).drops() /
 
 2034                env.current()->fees().increment.drops() /
 
 2041                Account 
const& issuer,
 
 2042                Account 
const& owner,
 
 2043                Account 
const& depositor,
 
 2047                testcase(
"MPT failed reserve to re-create MPToken");
 
 2050                    vault.create({.owner = owner, .asset = asset});
 
 2053                auto v = env.le(keylet);
 
 2056                env(pay(depositor, owner, asset(1000)));
 
 2060                    {.depositor = owner,
 
 2062                     .amount = asset(1000)});  
 
 2072                    auto const mptoken =
 
 2074                    auto const sleMPT = env.le(mptoken);
 
 2075                    BEAST_EXPECT(sleMPT == 
nullptr);
 
 2078                    tx = vault.withdraw(
 
 2079                        {.depositor = owner,
 
 2081                         .amount = asset(100)});
 
 2085                    env(pay(depositor, owner, XRP(incReserve)));
 
 2093            {.requireAuth = 
false,
 
 2094             .initialXRP = acctReserve + incReserve * 4 - 1});
 
 2098                     Account 
const& issuer,
 
 2099                     Account 
const& owner,
 
 2100                     Account 
const& depositor,
 
 2106            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2111                {.depositor = depositor,
 
 2113                 .amount = asset(1000)});
 
 2118                auto tx = vault.clawback(
 
 2121                     .holder = depositor,
 
 2122                     .amount = asset(0)});
 
 2126            mptt.destroy({.issuer = issuer, .id = mptt.issuanceID()});
 
 2131                    vault.create({.owner = depositor, .asset = asset});
 
 2136                auto tx = vault.deposit(
 
 2137                    {.depositor = depositor,
 
 2139                     .amount = asset(10)});
 
 2144                auto tx = vault.withdraw(
 
 2145                    {.depositor = depositor,
 
 2147                     .amount = asset(10)});
 
 2152                auto tx = vault.clawback(
 
 2155                     .holder = depositor,
 
 2156                     .amount = asset(0)});
 
 2160            env(vault.del({.owner = owner, .id = keylet.key}));
 
 2165                     Account 
const& issuer,
 
 2166                     Account 
const& owner,
 
 2167                     Account 
const& depositor,
 
 2171            testcase(
"MPT vault owner can receive shares unless unauthorized");
 
 2173            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2178                {.depositor = depositor,
 
 2180                 .amount = asset(1000)});
 
 2185                auto const vault = env.le(keylet);
 
 2186                return vault->at(sfShareMPTID);
 
 2192                env(pay(depositor, owner, shares(1)));
 
 2195                tx = vault.withdraw(
 
 2196                    {.depositor = owner,
 
 2198                     .amount = shares(1)});
 
 2203                env(pay(depositor, owner, shares(1)));
 
 2206                tx = vault.clawback(
 
 2210                     .amount = asset(0)});
 
 2215                env(pay(depositor, owner, shares(1)));
 
 2219                env(pay(owner, depositor, shares(1)));
 
 2225                    jv[sfAccount] = owner.human();
 
 2226                    jv[sfMPTokenIssuanceID] = 
to_string(issuanceId);
 
 2228                    jv[sfTransactionType] = jss::MPTokenAuthorize;
 
 2234                tx = pay(depositor, owner, shares(1));
 
 2239                tx = vault.clawback(
 
 2242                     .holder = depositor,
 
 2243                     .amount = asset(0)});
 
 2248                env(vault.del({.owner = owner, .id = keylet.key}));
 
 2256                Account 
const& issuer,
 
 2257                Account 
const& owner,
 
 2258                Account 
const& depositor,
 
 2265                    vault.create({.owner = owner, .asset = asset});
 
 2270                    {.depositor = depositor,
 
 2272                     .amount = asset(1000)});
 
 2277                    auto tx = vault.clawback(
 
 2280                         .holder = depositor,
 
 2281                         .amount = asset(0)});
 
 2285            {.enableClawback = 
false});
 
 2289                     Account 
const& issuer,
 
 2290                     Account 
const& owner,
 
 2291                     Account 
const& depositor,
 
 2296            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2300                {.depositor = depositor,
 
 2302                 .amount = asset(1000)});
 
 2308                 .holder = depositor,
 
 2313                auto tx = vault.withdraw(
 
 2314                    {.depositor = depositor,
 
 2316                     .amount = asset(100)});
 
 2320                tx[sfDestination] = issuer.human();
 
 2324                tx[sfDestination] = owner.human();
 
 2331                auto tx = vault.deposit(
 
 2332                    {.depositor = depositor,
 
 2334                     .amount = asset(100)});
 
 2339            tx = vault.clawback(
 
 2342                 .holder = depositor,
 
 2343                 .amount = asset(800)});
 
 2347            env(vault.del({.owner = owner, .id = keylet.key}));
 
 2352                     Account 
const& issuer,
 
 2353                     Account 
const& owner,
 
 2354                     Account 
const& depositor,
 
 2358            testcase(
"MPT lock of vault pseudo-account");
 
 2359            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2363            auto const vaultAccount =
 
 2364                [&env, keylet = keylet, 
this]() -> 
AccountID {
 
 2365                auto const vault = env.le(keylet);
 
 2366                BEAST_EXPECT(vault != 
nullptr);
 
 2367                return vault->at(sfAccount);
 
 2371                {.depositor = depositor,
 
 2373                 .amount = asset(100)});
 
 2379                jv[jss::Account] = issuer.human();
 
 2380                jv[sfMPTokenIssuanceID] =
 
 2382                jv[jss::Holder] = 
toBase58(vaultAccount);
 
 2383                jv[jss::TransactionType] = jss::MPTokenIssuanceSet;
 
 2391                {.depositor = depositor,
 
 2393                 .amount = asset(100)});
 
 2396            tx = vault.withdraw(
 
 2397                {.depositor = depositor,
 
 2399                 .amount = asset(100)});
 
 2403            tx = vault.clawback(
 
 2406                 .holder = depositor,
 
 2407                 .amount = asset(100)});
 
 2411            tx = vault.del({.owner = owner, .id = keylet.
key});
 
 2418            Env env{*
this, testable_amendments() | featureSingleAssetVault};
 
 2419            Account owner{
"owner"};
 
 2420            Account issuer{
"issuer"};
 
 2421            env.fund(XRP(1000000), owner, issuer);
 
 2425            MPTTester mptt{env, issuer, mptInitNoFund};
 
 2429            mptt.authorize({.account = owner});
 
 2430            mptt.authorize({.account = issuer, .holder = owner});
 
 2432            env(pay(issuer, owner, asset(100)));
 
 2433            auto [tx1, k1] = vault.create({.owner = owner, .asset = asset});
 
 2437            auto const shares = [&env, keylet = k1, 
this]() -> 
Asset {
 
 2438                auto const vault = env.le(keylet);
 
 2439                BEAST_EXPECT(vault != 
nullptr);
 
 2440                return MPTIssue(vault->at(sfShareMPTID));
 
 2443            auto [tx2, k2] = vault.create({.owner = owner, .asset = shares});
 
 
 2452        using namespace test::jtx;
 
 2456            int initialXRP = 1000;
 
 2464                    Account 
const& owner,
 
 2465                    Account 
const& issuer,
 
 2466                    Account 
const& charlie,
 
 2471                CaseArgs args = {}) {
 
 2472                Env env{*
this, testable_amendments() | featureSingleAssetVault};
 
 2473                Account 
const owner{
"owner"};
 
 2474                Account 
const issuer{
"issuer"};
 
 2475                Account 
const charlie{
"charlie"};
 
 2477                env.fund(XRP(args.initialXRP), issuer, owner, charlie);
 
 2482                env.trust(asset(1000), owner);
 
 2483                env.trust(asset(1000), charlie);
 
 2484                env(pay(issuer, owner, asset(200)));
 
 2485                env(rate(issuer, args.transferRate));
 
 2488                auto const vaultAccount =
 
 2490                    return Account(
"vault", env.le(keylet)->at(sfAccount));
 
 2493                    return env.le(keylet)->at(sfShareMPTID);
 
 2509                     Account 
const& owner,
 
 2510                     Account 
const& issuer,
 
 2516            testcase(
"IOU cannot use different asset");
 
 2519            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2525                auto tx = [&, account = vaultAccount(keylet)]() {
 
 2527                    jv[jss::Account] = issuer.human();
 
 2529                        auto& ja = jv[jss::LimitAmount] =
 
 2531                        ja[jss::issuer] = 
toBase58(account);
 
 2533                    jv[jss::TransactionType] = jss::TrustSet;
 
 2542                auto tx = vault.deposit(
 
 2543                    {.depositor = issuer, .id = keylet.
key, .amount = foo(20)});
 
 2549                auto tx = vault.withdraw(
 
 2550                    {.depositor = issuer, .id = keylet.
key, .amount = foo(20)});
 
 2555            env(vault.del({.owner = owner, .id = keylet.key}));
 
 2561                     Account 
const& owner,
 
 2562                     Account 
const& issuer,
 
 2563                     Account 
const& charlie,
 
 2568            testcase(
"IOU frozen trust line to vault account");
 
 2570            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2575                {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
 
 2578            Asset const share = 
Asset(issuanceId(keylet));
 
 2581            auto trustSet = [&, account = vaultAccount(keylet)]() {
 
 2583                jv[jss::Account] = issuer.human();
 
 2585                    auto& ja = jv[jss::LimitAmount] =
 
 2587                    ja[jss::issuer] = 
toBase58(account);
 
 2589                jv[jss::TransactionType] = jss::TrustSet;
 
 2601                auto tx = vault.deposit(
 
 2602                    {.depositor = owner,
 
 2604                     .amount = asset(80)});
 
 2609                auto tx = vault.withdraw(
 
 2610                    {.depositor = owner,
 
 2612                     .amount = asset(100)});
 
 2616                tx[sfDestination] = charlie.human();
 
 2623                auto tx = vault.clawback(
 
 2627                     .amount = asset(50)});
 
 2638                {.depositor = owner,
 
 2640                 .amount = share(50'000'000)}));
 
 2642            env(vault.del({.owner = owner, .id = keylet.key}));
 
 2649                Account 
const& owner,
 
 2650                Account 
const& issuer,
 
 2651                Account 
const& charlie,
 
 2656                testcase(
"IOU transfer fees not applied");
 
 2659                    vault.create({.owner = owner, .asset = asset});
 
 2664                    {.depositor = owner,
 
 2666                     .amount = asset(100)}));
 
 2670                Asset const share = 
Asset(issuanceId(keylet));
 
 2673                BEAST_EXPECT(env.balance(owner, issue) == asset(100));
 
 2675                    env.balance(vaultAccount(keylet), issue) == asset(100));
 
 2678                    auto tx = vault.clawback(
 
 2682                         .amount = asset(50)});
 
 2688                BEAST_EXPECT(env.balance(owner, issue) == asset(100));
 
 2690                    env.balance(vaultAccount(keylet), issue) == asset(50));
 
 2693                    {.depositor = owner,
 
 2695                     .amount = share(20'000'000)}));
 
 2698                BEAST_EXPECT(env.balance(owner, issue) == asset(120));
 
 2700                    env.balance(vaultAccount(keylet), issue) == asset(30));
 
 2703                    auto tx = vault.withdraw(
 
 2704                        {.depositor = owner,
 
 2706                         .amount = share(30'000'000)});
 
 2707                    tx[sfDestination] = charlie.human();
 
 2712                BEAST_EXPECT(env.balance(owner, issue) == asset(120));
 
 2713                BEAST_EXPECT(env.balance(charlie, issue) == asset(30));
 
 2715                    env.balance(vaultAccount(keylet), issue) == asset(0));
 
 2717                env(vault.del({.owner = owner, .id = keylet.key}));
 
 2720            CaseArgs{.transferRate = 1.25});
 
 2724                     Account 
const& owner,
 
 2725                     Account 
const& issuer,
 
 2726                     Account 
const& charlie,
 
 2731            testcase(
"IOU frozen trust line to depositor");
 
 2733            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2738                {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
 
 2743                auto tx = vault.withdraw(
 
 2744                    {.depositor = owner,
 
 2746                     .amount = asset(10)});
 
 2747                tx[sfDestination] = charlie.human();
 
 2750            env(withdrawToCharlie);
 
 2757            auto const withdraw = vault.withdraw(
 
 2758                {.depositor = owner, .id = keylet.
key, .amount = asset(10)});
 
 2767                auto tx = vault.deposit(
 
 2768                    {.depositor = owner,
 
 2770                     .amount = asset(10)});
 
 2776                auto tx = vault.clawback(
 
 2780                     .amount = asset(0)});
 
 2785            env(vault.del({.owner = owner, .id = keylet.key}));
 
 2791                     Account 
const& owner,
 
 2792                     Account 
const& issuer,
 
 2793                     Account 
const& charlie,
 
 2798            testcase(
"IOU no trust line to 3rd party");
 
 2800            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2805                {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
 
 2808            Account 
const erin{
"erin"};
 
 2809            env.fund(XRP(1000), erin);
 
 2814                auto tx = vault.withdraw(
 
 2815                    {.depositor = owner,
 
 2817                     .amount = asset(10)});
 
 2818                tx[sfDestination] = erin.human();
 
 2826                     Account 
const& owner,
 
 2827                     Account 
const& issuer,
 
 2828                     Account 
const& charlie,
 
 2833            testcase(
"IOU no trust line to depositor");
 
 2835            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2840            env.trust(asset(0), owner);
 
 2844                {.depositor = owner, .id = keylet.key, .amount = asset(200)}));
 
 2849            BEAST_EXPECT(trustline == 
nullptr);
 
 2853                auto tx = vault.withdraw(
 
 2854                    {.depositor = owner,
 
 2856                     .amount = asset(10)});
 
 2863            Env env{*
this, testable_amendments()};
 
 2865                env.current()->fees().accountReserve(0).drops() /
 
 2867                env.current()->fees().increment.drops() /
 
 2874                Account 
const& owner,
 
 2875                Account 
const& issuer,
 
 2876                Account 
const& charlie,
 
 2881                testcase(
"IOU no trust line to depositor no reserve");
 
 2883                    vault.create({.owner = owner, .asset = asset});
 
 2889                env.trust(asset(0), owner);
 
 2893                    {.depositor = owner,
 
 2895                     .amount = asset(200)}));
 
 2900                BEAST_EXPECT(trustline == 
nullptr);
 
 2903                tx = vault.withdraw(
 
 2904                    {.depositor = owner,
 
 2906                     .amount = asset(10)});
 
 2910                env(pay(charlie, owner, XRP(incReserve)));
 
 2917            CaseArgs{.initialXRP = acctReserve + incReserve * 4 - 1});
 
 2922                Account 
const& owner,
 
 2923                Account 
const& issuer,
 
 2924                Account 
const& charlie,
 
 2929                testcase(
"IOU no reserve for share MPToken");
 
 2931                    vault.create({.owner = owner, .asset = asset});
 
 2935                env(pay(owner, charlie, asset(100)));
 
 2939                env(ticket::create(charlie, 2));
 
 2944                    {.depositor = charlie,
 
 2946                     .amount = asset(100)});
 
 2950                env(pay(issuer, charlie, XRP(incReserve)));
 
 2957            CaseArgs{.initialXRP = acctReserve + incReserve * 4 - 1});
 
 2961                     Account 
const& owner,
 
 2962                     Account 
const& issuer,
 
 2963                     Account 
const& charlie,
 
 2968            testcase(
"IOU frozen trust line to 3rd party");
 
 2970            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 2975                {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
 
 2980                auto tx = vault.withdraw(
 
 2981                    {.depositor = owner,
 
 2983                     .amount = asset(10)});
 
 2984                tx[sfDestination] = charlie.human();
 
 2987            env(withdrawToCharlie);
 
 2990            env(trust(issuer, asset(0), charlie, 
tfSetFreeze));
 
 2994            auto const withdraw = vault.withdraw(
 
 2995                {.depositor = owner, .id = keylet.
key, .amount = asset(10)});
 
 3007                 .amount = asset(0)}));
 
 3010            env(vault.del({.owner = owner, .id = keylet.key}));
 
 3016                     Account 
const& owner,
 
 3017                     Account 
const& issuer,
 
 3018                     Account 
const& charlie,
 
 3025            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 3030                {.depositor = owner, .id = keylet.key, .amount = asset(100)}));
 
 3038                auto tx = vault.withdraw(
 
 3039                    {.depositor = owner,
 
 3041                     .amount = asset(10)});
 
 3045                tx[sfDestination] = charlie.human();
 
 3051                    {.depositor = owner,
 
 3053                     .amount = asset(10)});
 
 3063                 .amount = asset(0)}));
 
 3066            env(vault.del({.owner = owner, .id = keylet.key}));
 
 
 3074        using namespace test::jtx;
 
 3078        Env env{*
this, testable_amendments() | featureSingleAssetVault};
 
 3079        Account issuer{
"issuer"};
 
 3080        Account owner{
"owner"};
 
 3081        Account depositor{
"depositor"};
 
 3082        Account charlie{
"charlie"};
 
 3083        Account pdOwner{
"pdOwner"};
 
 3084        Account credIssuer1{
"credIssuer1"};
 
 3085        Account credIssuer2{
"credIssuer2"};
 
 3103        env.trust(asset(1000), owner);
 
 3104        env(pay(issuer, owner, asset(500)));
 
 3105        env.trust(asset(1000), depositor);
 
 3106        env(pay(issuer, depositor, asset(500)));
 
 3107        env.trust(asset(1000), charlie);
 
 3108        env(pay(issuer, charlie, asset(5)));
 
 3111        auto [tx, keylet] = vault.create(
 
 3115        BEAST_EXPECT(env.le(keylet));
 
 3118            testcase(
"private vault owner can deposit");
 
 3119            auto tx = vault.deposit(
 
 3120                {.depositor = owner, .id = keylet.
key, .amount = asset(50)});
 
 3125            testcase(
"private vault depositor not authorized yet");
 
 3126            auto tx = vault.deposit(
 
 3127                {.depositor = depositor,
 
 3129                 .amount = asset(50)});
 
 3134            testcase(
"private vault cannot set non-existing domain");
 
 3135            auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 3141            testcase(
"private vault set domainId");
 
 3144                pdomain::Credentials 
const credentials1{
 
 3145                    {.issuer = credIssuer1, .credType = credType}};
 
 3147                env(pdomain::setTx(pdOwner, credentials1));
 
 3148                auto const domainId1 = [&]() {
 
 3150                    return pdomain::getNewDomain(env.meta());
 
 3153                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 3164                pdomain::Credentials 
const credentials{
 
 3165                    {.issuer = credIssuer1, .credType = credType},
 
 3166                    {.issuer = credIssuer2, .credType = credType}};
 
 3168                env(pdomain::setTx(pdOwner, credentials));
 
 3169                auto const domainId = [&]() {
 
 3171                    return pdomain::getNewDomain(env.meta());
 
 3174                auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 3180                tx = vault.set({.owner = owner, .id = keylet.
key});
 
 3188            testcase(
"private vault depositor still not authorized");
 
 3189            auto tx = vault.deposit(
 
 3190                {.depositor = depositor,
 
 3192                 .amount = asset(50)});
 
 3197        auto const credKeylet =
 
 3198            credentials::keylet(depositor, credIssuer1, credType);
 
 3200            testcase(
"private vault depositor now authorized");
 
 3201            env(credentials::create(depositor, credIssuer1, credType));
 
 3202            env(credentials::accept(depositor, credIssuer1, credType));
 
 3203            env(credentials::create(charlie, credIssuer1, credType));
 
 3206            auto credSle = env.le(credKeylet);
 
 3207            BEAST_EXPECT(credSle != 
nullptr);
 
 3209            auto tx = vault.deposit(
 
 3210                {.depositor = depositor,
 
 3212                 .amount = asset(50)});
 
 3217                {.depositor = charlie, .id = keylet.
key, .amount = asset(50)});
 
 3223            testcase(
"private vault depositor lost authorization");
 
 3224            env(credentials::deleteCred(
 
 3225                credIssuer1, depositor, credIssuer1, credType));
 
 3226            env(credentials::deleteCred(
 
 3227                credIssuer1, charlie, credIssuer1, credType));
 
 3229            auto credSle = env.le(credKeylet);
 
 3230            BEAST_EXPECT(credSle == 
nullptr);
 
 3232            auto tx = vault.deposit(
 
 3233                {.depositor = depositor,
 
 3235                 .amount = asset(50)});
 
 3240        auto const shares = [&env, keylet = keylet, 
this]() -> 
Asset {
 
 3241            auto const vault = env.le(keylet);
 
 3242            BEAST_EXPECT(vault != 
nullptr);
 
 3243            return MPTIssue(vault->at(sfShareMPTID));
 
 3247            testcase(
"private vault expired authorization");
 
 3248            uint32_t 
const closeTime = env.current()
 
 3250                                           .parentCloseTime.time_since_epoch()
 
 3254                    credentials::create(depositor, credIssuer2, credType);
 
 3255                tx0[sfExpiration] = closeTime + 20;
 
 3257                tx0 = credentials::create(charlie, credIssuer2, credType);
 
 3258                tx0[sfExpiration] = closeTime + 20;
 
 3262                env(credentials::accept(depositor, credIssuer2, credType));
 
 3263                env(credentials::accept(charlie, credIssuer2, credType));
 
 3268                auto tx1 = vault.deposit(
 
 3269                    {.depositor = depositor,
 
 3271                     .amount = asset(50)});
 
 3277                BEAST_EXPECT(env.le(tokenKeylet) != 
nullptr);
 
 3286                auto const credsKeylet =
 
 3287                    credentials::keylet(depositor, credIssuer2, credType);
 
 3288                BEAST_EXPECT(env.le(credsKeylet) != 
nullptr);
 
 3290                auto tx2 = vault.deposit(
 
 3291                    {.depositor = depositor,
 
 3293                     .amount = asset(1)});
 
 3297                BEAST_EXPECT(env.le(credsKeylet) == 
nullptr);
 
 3301                auto const credsKeylet =
 
 3302                    credentials::keylet(charlie, credIssuer2, credType);
 
 3303                BEAST_EXPECT(env.le(credsKeylet) != 
nullptr);
 
 3306                BEAST_EXPECT(env.le(tokenKeylet) == 
nullptr);
 
 3308                auto tx3 = vault.deposit(
 
 3309                    {.depositor = charlie,
 
 3311                     .amount = asset(2)});
 
 3315                BEAST_EXPECT(env.le(credsKeylet) == 
nullptr);
 
 3316                BEAST_EXPECT(env.le(tokenKeylet) == 
nullptr);
 
 3321            testcase(
"private vault reset domainId");
 
 3322            auto tx = vault.set({.owner = owner, .id = keylet.
key});
 
 3323            tx[sfDomainID] = 
"0";
 
 3328                {.depositor = depositor,
 
 3330                 .amount = asset(50)});
 
 3334            tx = vault.withdraw(
 
 3335                {.depositor = depositor,
 
 3337                 .amount = asset(50)});
 
 3341            tx = vault.clawback(
 
 3344                 .holder = depositor,
 
 3345                 .amount = asset(0)});
 
 3348            tx = vault.clawback(
 
 3352                 .amount = asset(0)});
 
 
 3501        using namespace test::jtx;
 
 3505            Account 
const& owner;
 
 3506            Account 
const& issuer;
 
 3507            Account 
const& depositor;
 
 3508            Account 
const& vaultAccount;
 
 3518        auto testCase = [&, 
this](
 
 3521            Env env{*
this, testable_amendments() | featureSingleAssetVault};
 
 3522            Account 
const owner{
"owner"};
 
 3523            Account 
const issuer{
"issuer"};
 
 3524            Account 
const depositor{
"depositor"};
 
 3526            env.fund(XRP(1000), issuer, owner, depositor);
 
 3531            env.trust(asset(1000), owner);
 
 3532            env.trust(asset(1000), depositor);
 
 3533            env(pay(issuer, owner, asset(200)));
 
 3534            env(pay(issuer, depositor, asset(200)));
 
 3537            auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 3538            tx[sfScale] = scale;
 
 3541            auto const [vaultAccount, issuanceId] =
 
 3543                auto const vault = env.le(keylet);
 
 3545                    Account(
"vault", vault->at(sfAccount)),
 
 3546                    vault->at(sfShareMPTID)};
 
 3549            env.memoize(vaultAccount);
 
 3553                return env.app().openLedger().modify(
 
 3557                        if (!BEAST_EXPECT(vault != 
nullptr))
 
 3559                        auto shares = sb.
peek(
 
 3561                        if (!BEAST_EXPECT(shares != 
nullptr))
 
 3563                        if (fn(*vault, *shares))
 
 3578                 .depositor = depositor,
 
 3579                 .vaultAccount = vaultAccount,
 
 3589        testCase(18, [&, 
this](Env& env, Data d) {
 
 3590            testcase(
"Scale deposit overflow on first deposit");
 
 3591            auto tx = d.vault.deposit(
 
 3592                {.depositor = d.depositor,
 
 3594                 .amount = d.asset(10)});
 
 3599        testCase(18, [&, 
this](Env& env, Data d) {
 
 3600            testcase(
"Scale deposit overflow on second deposit");
 
 3603                auto tx = d.vault.deposit(
 
 3604                    {.depositor = d.depositor,
 
 3606                     .amount = d.asset(5)});
 
 3612                auto tx = d.vault.deposit(
 
 3613                    {.depositor = d.depositor,
 
 3615                     .amount = d.asset(10)});
 
 3621        testCase(18, [&, 
this](Env& env, Data d) {
 
 3622            testcase(
"Scale deposit overflow on total shares");
 
 3625                auto tx = d.vault.deposit(
 
 3626                    {.depositor = d.depositor,
 
 3628                     .amount = d.asset(5)});
 
 3634                auto tx = d.vault.deposit(
 
 3635                    {.depositor = d.depositor,
 
 3637                     .amount = d.asset(5)});
 
 3643        testCase(1, [&, 
this](Env& env, Data d) {
 
 3646            auto const start = env.balance(d.depositor, d.assets).number();
 
 3647            auto tx = d.vault.deposit(
 
 3648                {.depositor = d.depositor,
 
 3650                 .amount = d.asset(1)});
 
 3653            BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(10));
 
 3655                env.balance(d.depositor, d.assets) ==
 
 3659        testCase(1, [&, 
this](Env& env, Data d) {
 
 3660            testcase(
"Scale deposit insignificant amount");
 
 3662            auto tx = d.vault.deposit(
 
 3663                {.depositor = d.depositor,
 
 3669        testCase(1, [&, 
this](Env& env, Data d) {
 
 3670            testcase(
"Scale deposit exact, using full precision");
 
 3672            auto const start = env.balance(d.depositor, d.assets).number();
 
 3673            auto tx = d.vault.deposit(
 
 3674                {.depositor = d.depositor,
 
 3679            BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(15));
 
 3681                env.balance(d.depositor, d.assets) ==
 
 3685        testCase(1, [&, 
this](Env& env, Data d) {
 
 3686            testcase(
"Scale deposit exact, truncating from .5");
 
 3688            auto const start = env.balance(d.depositor, d.assets).number();
 
 3692                auto tx = d.vault.deposit(
 
 3693                    {.depositor = d.depositor,
 
 3698                BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(12));
 
 3700                    env.balance(d.depositor, d.assets) ==
 
 3705                auto tx = d.vault.deposit(
 
 3706                    {.depositor = d.depositor,
 
 3711                BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(24));
 
 3713                    env.balance(d.depositor, d.assets) ==
 
 3718                auto tx = d.vault.deposit(
 
 3719                    {.depositor = d.depositor,
 
 3724                BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(36));
 
 3726                    env.balance(d.depositor, d.assets) ==
 
 3731        testCase(1, [&, 
this](Env& env, Data d) {
 
 3732            testcase(
"Scale deposit exact, truncating from .01");
 
 3734            auto const start = env.balance(d.depositor, d.assets).number();
 
 3736            auto tx = d.vault.deposit(
 
 3737                {.depositor = d.depositor,
 
 3742            BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(12));
 
 3744                env.balance(d.depositor, d.assets) ==
 
 3749                auto tx = d.vault.deposit(
 
 3750                    {.depositor = d.depositor,
 
 3755                BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(18));
 
 3757                    env.balance(d.depositor, d.assets) ==
 
 3762        testCase(1, [&, 
this](Env& env, Data d) {
 
 3763            testcase(
"Scale deposit exact, truncating from .99");
 
 3765            auto const start = env.balance(d.depositor, d.assets).number();
 
 3767            auto tx = d.vault.deposit(
 
 3768                {.depositor = d.depositor,
 
 3773            BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(12));
 
 3775                env.balance(d.depositor, d.assets) ==
 
 3780                auto tx = d.vault.deposit(
 
 3781                    {.depositor = d.depositor,
 
 3786                BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(18));
 
 3788                    env.balance(d.depositor, d.assets) ==
 
 3793        testCase(1, [&, 
this](Env& env, Data d) {
 
 3795            auto const start = env.balance(d.depositor, d.assets).number();
 
 3796            auto tx = d.vault.deposit(
 
 3797                {.depositor = d.depositor,
 
 3802            BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(1000));
 
 3804                env.balance(d.depositor, d.assets) ==
 
 3807                env.balance(d.vaultAccount, d.assets) ==
 
 3810                env.balance(d.vaultAccount, d.shares) ==
 
 3819                auto const start = env.balance(d.depositor, d.assets).number();
 
 3820                auto tx = d.vault.withdraw(
 
 3821                    {.depositor = d.depositor,
 
 3827                    env.balance(d.depositor, d.shares) == d.share(900));
 
 3829                    env.balance(d.depositor, d.assets) ==
 
 3832                    env.balance(d.vaultAccount, d.assets) ==
 
 3835                    env.balance(d.vaultAccount, d.shares) ==
 
 3840                testcase(
"Scale redeem with rounding");
 
 3845                auto const start = env.balance(d.depositor, d.assets).number();
 
 3846                d.peek([](
SLE& vault, 
auto&) -> 
bool {
 
 3847                    vault[sfAssetsAvailable] = 
Number(1);
 
 3855                auto tx = d.vault.withdraw(
 
 3856                    {.depositor = d.depositor,
 
 3862                    env.balance(d.depositor, d.shares) == d.share(900 - 25));
 
 3864                    env.balance(d.depositor, d.assets) ==
 
 3867                    env.balance(d.vaultAccount, d.assets) ==
 
 3870                    env.balance(d.vaultAccount, d.shares) ==
 
 3880                auto const start = env.balance(d.depositor, d.assets).number();
 
 3882                tx = d.vault.withdraw(
 
 3883                    {.depositor = d.depositor,
 
 3889                    env.balance(d.depositor, d.shares) == d.share(875 - 21));
 
 3891                    env.balance(d.depositor, d.assets) ==
 
 3894                    env.balance(d.vaultAccount, d.assets) ==
 
 3897                    env.balance(d.vaultAccount, d.shares) ==
 
 3903                auto const rest = env.balance(d.depositor, d.shares).number();
 
 3905                tx = d.vault.withdraw(
 
 3906                    {.depositor = d.depositor,
 
 3908                     .amount = 
STAmount(d.share, rest)});
 
 3911                BEAST_EXPECT(env.balance(d.depositor, d.shares).number() == 0);
 
 3913                    env.balance(d.vaultAccount, d.assets).number() == 0);
 
 3915                    env.balance(d.vaultAccount, d.shares).number() == 0);
 
 3919        testCase(18, [&, 
this](Env& env, Data d) {
 
 3920            testcase(
"Scale withdraw overflow");
 
 3923                auto tx = d.vault.deposit(
 
 3924                    {.depositor = d.depositor,
 
 3926                     .amount = d.asset(5)});
 
 3932                auto tx = d.vault.withdraw(
 
 3933                    {.depositor = d.depositor,
 
 3941        testCase(1, [&, 
this](Env& env, Data d) {
 
 3943            auto const start = env.balance(d.depositor, d.assets).number();
 
 3944            auto tx = d.vault.deposit(
 
 3945                {.depositor = d.depositor,
 
 3950            BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(1000));
 
 3952                env.balance(d.depositor, d.assets) ==
 
 3955                env.balance(d.vaultAccount, d.assets) ==
 
 3958                env.balance(d.vaultAccount, d.shares) ==
 
 3970                auto const start = env.balance(d.depositor, d.assets).number();
 
 3971                auto tx = d.vault.withdraw(
 
 3972                    {.depositor = d.depositor,
 
 3978                    env.balance(d.depositor, d.shares) == d.share(900));
 
 3980                    env.balance(d.depositor, d.assets) ==
 
 3983                    env.balance(d.vaultAccount, d.assets) ==
 
 3986                    env.balance(d.vaultAccount, d.shares) ==
 
 3991                testcase(
"Scale withdraw insignificant amount");
 
 3992                auto tx = d.vault.withdraw(
 
 3993                    {.depositor = d.depositor,
 
 4000                testcase(
"Scale withdraw with rounding assets");
 
 4008                auto const start = env.balance(d.depositor, d.assets).number();
 
 4009                d.peek([](
SLE& vault, 
auto&) -> 
bool {
 
 4010                    vault[sfAssetsAvailable] = 
Number(1);
 
 4018                auto tx = d.vault.withdraw(
 
 4019                    {.depositor = d.depositor,
 
 4025                    env.balance(d.depositor, d.shares) == d.share(900 - 25));
 
 4027                    env.balance(d.depositor, d.assets) ==
 
 4030                    env.balance(d.vaultAccount, d.assets) ==
 
 4033                    env.balance(d.vaultAccount, d.shares) ==
 
 4038                testcase(
"Scale withdraw with rounding shares up");
 
 4046                auto const start = env.balance(d.depositor, d.assets).number();
 
 4047                auto tx = d.vault.withdraw(
 
 4048                    {.depositor = d.depositor,
 
 4054                    env.balance(d.depositor, d.shares) == d.share(875 - 38));
 
 4056                    env.balance(d.depositor, d.assets) ==
 
 4059                    env.balance(d.vaultAccount, d.assets) ==
 
 4062                    env.balance(d.vaultAccount, d.shares) ==
 
 4067                testcase(
"Scale withdraw with rounding shares down");
 
 4075                auto const start = env.balance(d.depositor, d.assets).number();
 
 4076                auto tx = d.vault.withdraw(
 
 4077                    {.depositor = d.depositor,
 
 4083                    env.balance(d.depositor, d.shares) == d.share(837 - 37));
 
 4085                    env.balance(d.depositor, d.assets) ==
 
 4088                    env.balance(d.vaultAccount, d.assets) ==
 
 4091                    env.balance(d.vaultAccount, d.shares) ==
 
 4096                testcase(
"Scale withdraw tiny amount");
 
 4098                auto const start = env.balance(d.depositor, d.assets).number();
 
 4099                auto tx = d.vault.withdraw(
 
 4100                    {.depositor = d.depositor,
 
 4106                    env.balance(d.depositor, d.shares) == d.share(800 - 1));
 
 4108                    env.balance(d.depositor, d.assets) ==
 
 4111                    env.balance(d.vaultAccount, d.assets) ==
 
 4114                    env.balance(d.vaultAccount, d.shares) ==
 
 4121                    env.balance(d.vaultAccount, d.assets).number();
 
 4123                tx = d.vault.withdraw(
 
 4124                    {.depositor = d.depositor,
 
 4126                     .amount = 
STAmount(d.asset, rest)});
 
 4129                BEAST_EXPECT(env.balance(d.depositor, d.shares).number() == 0);
 
 4131                    env.balance(d.vaultAccount, d.assets).number() == 0);
 
 4133                    env.balance(d.vaultAccount, d.shares).number() == 0);
 
 4137        testCase(18, [&, 
this](Env& env, Data d) {
 
 4138            testcase(
"Scale clawback overflow");
 
 4141                auto tx = d.vault.deposit(
 
 4142                    {.depositor = d.depositor,
 
 4144                     .amount = d.asset(5)});
 
 4150                auto tx = d.vault.clawback(
 
 4151                    {.issuer = d.issuer,
 
 4153                     .holder = d.depositor,
 
 4160        testCase(1, [&, 
this](Env& env, Data d) {
 
 4162            auto const start = env.balance(d.depositor, d.assets).number();
 
 4163            auto tx = d.vault.deposit(
 
 4164                {.depositor = d.depositor,
 
 4169            BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(1000));
 
 4171                env.balance(d.depositor, d.assets) ==
 
 4174                env.balance(d.vaultAccount, d.assets) ==
 
 4177                env.balance(d.vaultAccount, d.shares) ==
 
 4188                auto const start = env.balance(d.depositor, d.assets).number();
 
 4189                auto tx = d.vault.clawback(
 
 4190                    {.issuer = d.issuer,
 
 4192                     .holder = d.depositor,
 
 4197                    env.balance(d.depositor, d.shares) == d.share(900));
 
 4199                    env.balance(d.depositor, d.assets) ==
 
 4202                    env.balance(d.vaultAccount, d.assets) ==
 
 4205                    env.balance(d.vaultAccount, d.shares) ==
 
 4210                testcase(
"Scale clawback insignificant amount");
 
 4211                auto tx = d.vault.clawback(
 
 4212                    {.issuer = d.issuer,
 
 4214                     .holder = d.depositor,
 
 4220                testcase(
"Scale clawback with rounding assets");
 
 4228                auto const start = env.balance(d.depositor, d.assets).number();
 
 4229                auto tx = d.vault.clawback(
 
 4230                    {.issuer = d.issuer,
 
 4232                     .holder = d.depositor,
 
 4237                    env.balance(d.depositor, d.shares) == d.share(900 - 25));
 
 4239                    env.balance(d.depositor, d.assets) ==
 
 4242                    env.balance(d.vaultAccount, d.assets) ==
 
 4245                    env.balance(d.vaultAccount, d.shares) ==
 
 4250                testcase(
"Scale clawback with rounding shares up");
 
 4258                auto const start = env.balance(d.depositor, d.assets).number();
 
 4259                auto tx = d.vault.clawback(
 
 4260                    {.issuer = d.issuer,
 
 4262                     .holder = d.depositor,
 
 4267                    env.balance(d.depositor, d.shares) == d.share(875 - 38));
 
 4269                    env.balance(d.depositor, d.assets) ==
 
 4272                    env.balance(d.vaultAccount, d.assets) ==
 
 4275                    env.balance(d.vaultAccount, d.shares) ==
 
 4280                testcase(
"Scale clawback with rounding shares down");
 
 4288                auto const start = env.balance(d.depositor, d.assets).number();
 
 4289                auto tx = d.vault.clawback(
 
 4290                    {.issuer = d.issuer,
 
 4292                     .holder = d.depositor,
 
 4297                    env.balance(d.depositor, d.shares) == d.share(837 - 37));
 
 4299                    env.balance(d.depositor, d.assets) ==
 
 4302                    env.balance(d.vaultAccount, d.assets) ==
 
 4305                    env.balance(d.vaultAccount, d.shares) ==
 
 4310                testcase(
"Scale clawback tiny amount");
 
 4312                auto const start = env.balance(d.depositor, d.assets).number();
 
 4313                auto tx = d.vault.clawback(
 
 4314                    {.issuer = d.issuer,
 
 4316                     .holder = d.depositor,
 
 4321                    env.balance(d.depositor, d.shares) == d.share(800 - 1));
 
 4323                    env.balance(d.depositor, d.assets) ==
 
 4326                    env.balance(d.vaultAccount, d.assets) ==
 
 4329                    env.balance(d.vaultAccount, d.shares) ==
 
 4336                    env.balance(d.vaultAccount, d.assets).number();
 
 4337                d.peek([](
SLE& vault, 
auto&) -> 
bool {
 
 4338                    vault[sfAssetsAvailable] = 
Number(5);
 
 4346                tx = d.vault.clawback(
 
 4347                    {.issuer = d.issuer,
 
 4349                     .holder = d.depositor,
 
 4350                     .amount = 
STAmount(d.asset, rest)});
 
 4353                BEAST_EXPECT(env.balance(d.depositor, d.shares).number() == 0);
 
 4355                    env.balance(d.vaultAccount, d.assets).number() == 0);
 
 4357                    env.balance(d.vaultAccount, d.shares).number() == 0);
 
 
 4365        using namespace test::jtx;
 
 4368        Env env{*
this, testable_amendments() | featureSingleAssetVault};
 
 4369        Account 
const owner{
"owner"};
 
 4370        Account 
const issuer{
"issuer"};
 
 4372        env.fund(XRP(1000), issuer, owner);
 
 4376        env.trust(asset(1000), owner);
 
 4377        env(pay(issuer, owner, asset(200)));
 
 4380        auto const sequence = env.seq(owner);
 
 4381        auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
 
 4387            auto tx1 = vault.deposit(
 
 4388                {.depositor = owner, .id = keylet.
key, .amount = asset(50)});
 
 4391            auto tx2 = vault.set({.owner = owner, .id = keylet.
key});
 
 4392            tx2[sfAssetsMaximum] = asset(1000).number();
 
 4397        auto const sleVault = [&env, keylet = keylet, 
this]() {
 
 4398            auto const vault = env.le(keylet);
 
 4399            BEAST_EXPECT(vault != 
nullptr);
 
 4403        auto const check = [&, keylet = keylet, sle = sleVault, 
this](
 
 4406            BEAST_EXPECT(vault.isObject());
 
 4408            constexpr auto checkString =
 
 4410                return node.isMember(field.fieldName) &&
 
 4411                    node[field.fieldName].isString() &&
 
 4412                    node[field.fieldName] == v;
 
 4414            constexpr auto checkObject =
 
 4416                return node.isMember(field.fieldName) &&
 
 4417                    node[field.fieldName].isObject() &&
 
 4418                    node[field.fieldName] == v;
 
 4420            constexpr auto checkInt =
 
 4421                [](
auto& node, 
SField const& field, 
int v) -> 
bool {
 
 4422                return node.isMember(field.fieldName) &&
 
 4423                    ((node[field.fieldName].isInt() &&
 
 4424                      node[field.fieldName] == 
Json::Int(v)) ||
 
 4425                     (node[field.fieldName].isUInt() &&
 
 4429            BEAST_EXPECT(vault[
"LedgerEntryType"].asString() == 
"Vault");
 
 4430            BEAST_EXPECT(vault[jss::index].asString() == 
strHex(keylet.
key));
 
 4431            BEAST_EXPECT(checkInt(vault, sfFlags, 0));
 
 4435                checkString(vault, sfAccount, 
toBase58(sle->at(sfAccount))));
 
 4437                checkObject(vault, sfAsset, 
to_json(sle->at(sfAsset))));
 
 4438            BEAST_EXPECT(checkString(vault, sfAssetsAvailable, 
"50"));
 
 4439            BEAST_EXPECT(checkString(vault, sfAssetsMaximum, 
"1000"));
 
 4440            BEAST_EXPECT(checkString(vault, sfAssetsTotal, 
"50"));
 
 4441            BEAST_EXPECT(checkString(vault, sfLossUnrealized, 
"0"));
 
 4443            auto const strShareID = 
strHex(sle->at(sfShareMPTID));
 
 4444            BEAST_EXPECT(checkString(vault, sfShareMPTID, strShareID));
 
 4445            BEAST_EXPECT(checkString(vault, sfOwner, 
toBase58(owner.id())));
 
 4446            BEAST_EXPECT(checkInt(vault, sfSequence, sequence));
 
 4447            BEAST_EXPECT(checkInt(
 
 4450            if (issuance.isObject())
 
 4453                    issuance[
"LedgerEntryType"].asString() ==
 
 4456                    issuance[jss::mpt_issuance_id].asString() == strShareID);
 
 4457                BEAST_EXPECT(checkInt(issuance, sfSequence, 1));
 
 4458                BEAST_EXPECT(checkInt(
 
 4463                    checkString(issuance, sfOutstandingAmount, 
"50000000"));
 
 4468            testcase(
"RPC ledger_entry selected by key");
 
 4470            jvParams[jss::ledger_index] = jss::validated;
 
 4471            jvParams[jss::vault] = 
strHex(keylet.
key);
 
 4472            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4474            BEAST_EXPECT(!jvVault[jss::result].isMember(jss::error));
 
 4475            BEAST_EXPECT(jvVault[jss::result].isMember(jss::node));
 
 4476            check(jvVault[jss::result][jss::node]);
 
 4480            testcase(
"RPC ledger_entry selected by owner and seq");
 
 4482            jvParams[jss::ledger_index] = jss::validated;
 
 4483            jvParams[jss::vault][jss::owner] = owner.human();
 
 4484            jvParams[jss::vault][jss::seq] = sequence;
 
 4485            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4487            BEAST_EXPECT(!jvVault[jss::result].isMember(jss::error));
 
 4488            BEAST_EXPECT(jvVault[jss::result].isMember(jss::node));
 
 4489            check(jvVault[jss::result][jss::node]);
 
 4493            testcase(
"RPC ledger_entry cannot find vault by key");
 
 4495            jvParams[jss::ledger_index] = jss::validated;
 
 4497            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4499                jvVault[jss::result][jss::error].asString() == 
"entryNotFound");
 
 4503            testcase(
"RPC ledger_entry cannot find vault by owner and seq");
 
 4505            jvParams[jss::ledger_index] = jss::validated;
 
 4506            jvParams[jss::vault][jss::owner] = issuer.human();
 
 4507            jvParams[jss::vault][jss::seq] = 1'000'000;
 
 4508            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4510                jvVault[jss::result][jss::error].asString() == 
"entryNotFound");
 
 4514            testcase(
"RPC ledger_entry malformed key");
 
 4516            jvParams[jss::ledger_index] = jss::validated;
 
 4517            jvParams[jss::vault] = 42;
 
 4518            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4520                jvVault[jss::result][jss::error].asString() ==
 
 4521                "malformedRequest");
 
 4525            testcase(
"RPC ledger_entry malformed owner");
 
 4527            jvParams[jss::ledger_index] = jss::validated;
 
 4528            jvParams[jss::vault][jss::owner] = 42;
 
 4529            jvParams[jss::vault][jss::seq] = sequence;
 
 4530            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4532                jvVault[jss::result][jss::error].asString() ==
 
 4537            testcase(
"RPC ledger_entry malformed seq");
 
 4539            jvParams[jss::ledger_index] = jss::validated;
 
 4540            jvParams[jss::vault][jss::owner] = issuer.human();
 
 4541            jvParams[jss::vault][jss::seq] = 
"foo";
 
 4542            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4544                jvVault[jss::result][jss::error].asString() ==
 
 4545                "malformedRequest");
 
 4549            testcase(
"RPC ledger_entry negative seq");
 
 4551            jvParams[jss::ledger_index] = jss::validated;
 
 4552            jvParams[jss::vault][jss::owner] = issuer.human();
 
 4553            jvParams[jss::vault][jss::seq] = -1;
 
 4554            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4556                jvVault[jss::result][jss::error].asString() ==
 
 4557                "malformedRequest");
 
 4561            testcase(
"RPC ledger_entry oversized seq");
 
 4563            jvParams[jss::ledger_index] = jss::validated;
 
 4564            jvParams[jss::vault][jss::owner] = issuer.human();
 
 4565            jvParams[jss::vault][jss::seq] = 1e20;
 
 4566            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4568                jvVault[jss::result][jss::error].asString() ==
 
 4569                "malformedRequest");
 
 4573            testcase(
"RPC ledger_entry bool seq");
 
 4575            jvParams[jss::ledger_index] = jss::validated;
 
 4576            jvParams[jss::vault][jss::owner] = issuer.human();
 
 4577            jvParams[jss::vault][jss::seq] = 
true;
 
 4578            auto jvVault = env.rpc(
"json", 
"ledger_entry", 
to_string(jvParams));
 
 4580                jvVault[jss::result][jss::error].asString() ==
 
 4581                "malformedRequest");
 
 4588            jvParams[jss::account] = owner.human();
 
 4589            jvParams[jss::type] = jss::vault;
 
 4591                "json", 
"account_objects", 
to_string(jvParams))[jss::result];
 
 4593            BEAST_EXPECT(jv[jss::account_objects].size() == 1);
 
 4594            check(jv[jss::account_objects][0u]);
 
 4601            jvParams[jss::ledger_index] = jss::validated;
 
 4602            jvParams[jss::binary] = 
false;
 
 4603            jvParams[jss::type] = jss::vault;
 
 4605                env.rpc(
"json", 
"ledger_data", 
to_string(jvParams));
 
 4606            BEAST_EXPECT(jv[jss::result][jss::state].size() == 1);
 
 4607            check(jv[jss::result][jss::state][0u]);
 
 4611            testcase(
"RPC vault_info command line");
 
 4613                env.rpc(
"vault_info", 
strHex(keylet.
key), 
"validated");
 
 4615            BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
 
 4616            BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
 
 4618                jv[jss::result][jss::vault],
 
 4619                jv[jss::result][jss::vault][jss::shares]);
 
 4625            jvParams[jss::ledger_index] = jss::validated;
 
 4626            jvParams[jss::vault_id] = 
strHex(keylet.
key);
 
 4627            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4629            BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
 
 4630            BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
 
 4632                jv[jss::result][jss::vault],
 
 4633                jv[jss::result][jss::vault][jss::shares]);
 
 4637            testcase(
"RPC vault_info invalid vault_id");
 
 4639            jvParams[jss::ledger_index] = jss::validated;
 
 4640            jvParams[jss::vault_id] = 
"foobar";
 
 4641            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4643                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4647            testcase(
"RPC vault_info json invalid index");
 
 4649            jvParams[jss::ledger_index] = jss::validated;
 
 4650            jvParams[jss::vault_id] = 0;
 
 4651            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4653                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4657            testcase(
"RPC vault_info json by owner and sequence");
 
 4659            jvParams[jss::ledger_index] = jss::validated;
 
 4660            jvParams[jss::owner] = owner.human();
 
 4661            jvParams[jss::seq] = sequence;
 
 4662            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4664            BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
 
 4665            BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
 
 4667                jv[jss::result][jss::vault],
 
 4668                jv[jss::result][jss::vault][jss::shares]);
 
 4672            testcase(
"RPC vault_info json malformed sequence");
 
 4674            jvParams[jss::ledger_index] = jss::validated;
 
 4675            jvParams[jss::owner] = owner.human();
 
 4676            jvParams[jss::seq] = 
"foobar";
 
 4677            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4679                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4683            testcase(
"RPC vault_info json invalid sequence");
 
 4685            jvParams[jss::ledger_index] = jss::validated;
 
 4686            jvParams[jss::owner] = owner.human();
 
 4687            jvParams[jss::seq] = 0;
 
 4688            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4690                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4694            testcase(
"RPC vault_info json negative sequence");
 
 4696            jvParams[jss::ledger_index] = jss::validated;
 
 4697            jvParams[jss::owner] = owner.human();
 
 4698            jvParams[jss::seq] = -1;
 
 4699            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4701                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4705            testcase(
"RPC vault_info json oversized sequence");
 
 4707            jvParams[jss::ledger_index] = jss::validated;
 
 4708            jvParams[jss::owner] = owner.human();
 
 4709            jvParams[jss::seq] = 1e20;
 
 4710            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4712                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4716            testcase(
"RPC vault_info json bool sequence");
 
 4718            jvParams[jss::ledger_index] = jss::validated;
 
 4719            jvParams[jss::owner] = owner.human();
 
 4720            jvParams[jss::seq] = 
true;
 
 4721            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4723                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4727            testcase(
"RPC vault_info json malformed owner");
 
 4729            jvParams[jss::ledger_index] = jss::validated;
 
 4730            jvParams[jss::owner] = 
"foobar";
 
 4731            jvParams[jss::seq] = sequence;
 
 4732            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4734                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4738            testcase(
"RPC vault_info json invalid combination only owner");
 
 4740            jvParams[jss::ledger_index] = jss::validated;
 
 4741            jvParams[jss::owner] = owner.human();
 
 4742            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4744                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4748            testcase(
"RPC vault_info json invalid combination only seq");
 
 4750            jvParams[jss::ledger_index] = jss::validated;
 
 4751            jvParams[jss::seq] = sequence;
 
 4752            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4754                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4758            testcase(
"RPC vault_info json invalid combination seq vault_id");
 
 4760            jvParams[jss::ledger_index] = jss::validated;
 
 4761            jvParams[jss::vault_id] = 
strHex(keylet.
key);
 
 4762            jvParams[jss::seq] = sequence;
 
 4763            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4765                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4769            testcase(
"RPC vault_info json invalid combination owner vault_id");
 
 4771            jvParams[jss::ledger_index] = jss::validated;
 
 4772            jvParams[jss::vault_id] = 
strHex(keylet.
key);
 
 4773            jvParams[jss::owner] = owner.human();
 
 4774            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4776                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4781                "RPC vault_info json invalid combination owner seq " 
 4784            jvParams[jss::ledger_index] = jss::validated;
 
 4785            jvParams[jss::vault_id] = 
strHex(keylet.
key);
 
 4786            jvParams[jss::seq] = sequence;
 
 4787            jvParams[jss::owner] = owner.human();
 
 4788            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4790                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4794            testcase(
"RPC vault_info json no input");
 
 4796            jvParams[jss::ledger_index] = jss::validated;
 
 4797            auto jv = env.rpc(
"json", 
"vault_info", 
to_string(jvParams));
 
 4799                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4803            testcase(
"RPC vault_info command line invalid index");
 
 4804            Json::Value jv = env.rpc(
"vault_info", 
"foobar", 
"validated");
 
 4805            BEAST_EXPECT(jv[jss::error].asString() == 
"invalidParams");
 
 4809            testcase(
"RPC vault_info command line invalid index");
 
 4810            Json::Value jv = env.rpc(
"vault_info", 
"0", 
"validated");
 
 4812                jv[jss::result][jss::error].asString() == 
"malformedRequest");
 
 4816            testcase(
"RPC vault_info command line invalid index");
 
 4820                jv[jss::result][jss::error].asString() == 
"entryNotFound");
 
 4824            testcase(
"RPC vault_info command line invalid ledger");
 
 4827                jv[jss::result][jss::error].asString() == 
"lgrNotFound");
 
 
 4834        using namespace test::jtx;
 
 4836        Env env(*
this, testable_amendments());
 
 4837        Account alice{
"alice"};
 
 4839        Account carol{
"carol"};
 
 4846        auto const xrpBalance =
 
 4850            if (BEAST_EXPECT(sle != 
nullptr))
 
 4851                return sle->getFieldAmount(sfBalance).xrp().drops();
 
 4855        auto testCase = [&, 
this](
auto test, CaseArgs args = {}) {
 
 4856            Env env{*
this, testable_amendments() | featureSingleAssetVault};
 
 4861            env.fund(XRP(10000), alice);
 
 4862            env.fund(XRP(20000), bob);
 
 4863            env.fund(XRP(30000), carol);
 
 4877            test(env, vault, args.asset);
 
 4880        testCase([&, 
this](Env& env, Vault& vault, 
PrettyAsset const& asset) {
 
 4881            testcase(
"delegated vault creation");
 
 4882            auto startBalance = xrpBalance(env, carol);
 
 4883            if (!BEAST_EXPECT(startBalance.has_value()))
 
 4886            auto [tx, keylet] = vault.create({.owner = carol, .asset = asset});
 
 4887            env(tx, delegate::as(alice));
 
 4889            BEAST_EXPECT(xrpBalance(env, carol) == *startBalance);
 
 4892        testCase([&, 
this](Env& env, Vault& vault, 
PrettyAsset const& asset) {
 
 4893            testcase(
"delegated deposit and withdrawal");
 
 4894            auto [tx, keylet] = vault.create({.owner = carol, .asset = asset});
 
 4898            auto const amount = 1513;
 
 4899            auto const baseFee = env.current()->fees().base;
 
 4901            auto startBalance = xrpBalance(env, carol);
 
 4902            if (!BEAST_EXPECT(startBalance.has_value()))
 
 4906                {.depositor = carol,
 
 4908                 .amount = asset(amount)});
 
 4909            env(tx, delegate::as(alice));
 
 4911            BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount);
 
 4913            tx = vault.withdraw(
 
 4914                {.depositor = carol,
 
 4916                 .amount = asset(amount - 1)});
 
 4917            env(tx, delegate::as(alice));
 
 4919            BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - 1);
 
 4921            tx = vault.withdraw(
 
 4922                {.depositor = carol, .id = keylet.
key, .amount = asset(1)});
 
 4925            BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - baseFee);
 
 4928        testCase([&, 
this](Env& env, Vault& vault, 
PrettyAsset const& asset) {
 
 4929            testcase(
"delegated withdrawal same as base fee and deletion");
 
 4930            auto [tx, keylet] = vault.create({.owner = carol, .asset = asset});
 
 4934            auto const amount = 25537;
 
 4935            auto const baseFee = env.current()->fees().base;
 
 4937            auto startBalance = xrpBalance(env, carol);
 
 4938            if (!BEAST_EXPECT(startBalance.has_value()))
 
 4942                {.depositor = carol,
 
 4944                 .amount = asset(amount)});
 
 4948                xrpBalance(env, carol) == *startBalance - amount - baseFee);
 
 4950            tx = vault.withdraw(
 
 4951                {.depositor = carol,
 
 4953                 .amount = asset(baseFee)});
 
 4954            env(tx, delegate::as(alice));
 
 4956            BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount);
 
 4958            tx = vault.withdraw(
 
 4959                {.depositor = carol,
 
 4961                 .amount = asset(amount - baseFee)});
 
 4962            env(tx, delegate::as(alice));
 
 4964            BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - baseFee);
 
 4966            tx = vault.del({.owner = carol, .id = keylet.
key});
 
 4967            env(tx, delegate::as(alice));