55        testcase(
"exercise partial cross new XRP/IOU offer Q change");
 
   59        auto const gw = 
Account{
"gateway"};
 
   60        auto const alice = 
Account{
"alice"};
 
   61        auto const bob = 
Account{
"bob"};
 
   62        auto const USD = gw[
"USD"];
 
   68            env.fund(
XRP(10'000'000), gw, alice, bob);
 
   71            env(
trust(alice, USD(10'000'000)));
 
   72            env(
trust(bob, USD(10'000'000)));
 
   75            env(
pay(gw, bob, USD(10'000'000)));
 
   83            auto exerciseOfferPair =
 
   84                [
this, &env, &alice, &bob](
 
   85                    Amounts 
const& inLedger,
 
   86                    Amounts 
const& newOffer) -> 
unsigned int {
 
   89                env(
offer(alice, inLedger.in, inLedger.out));
 
   93                STAmount const initialRate = Quality(newOffer).rate();
 
   95                STAmount const bobInitialBalance = env.balance(bob);
 
   96                STAmount const bobsFee = env.current()->fees().base;
 
  100                STAmount const bobFinalBalance = env.balance(bob);
 
  104                if (!BEAST_EXPECT(!
offerInLedger(env, alice, aliceOfferSeq)))
 
  110                unsigned int badRate = 1;
 
  116                        sfTakerGets, bobOffer[jss::node][sfTakerGets.jsonName]);
 
  118                        sfTakerPays, bobOffer[jss::node][sfTakerPays.jsonName]);
 
  120                        env.balance(bob) + bobsFee - bobInitialBalance;
 
  121                    BEAST_EXPECT(reducedTakerPays < newOffer.in);
 
  122                    BEAST_EXPECT(reducedTakerGets < newOffer.out);
 
  124                        Quality(Amounts{reducedTakerPays, reducedTakerGets})
 
  127                    badRate = inLedgerRate > initialRate ? 1 : 0;
 
  137                            reducedTakerPays + 
drops(1);
 
  139                            Quality(Amounts{tweakedTakerPays, reducedTakerGets})
 
  141                        BEAST_EXPECT(tweakedRate > initialRate);
 
  144                    std::cout << 
"Placed rate: " << initialRate
 
  145                              << 
"; in-ledger rate: " << inLedgerRate
 
  146                              << 
"; TakerPays: " << reducedTakerPays
 
  147                              << 
"; TakerGets: " << reducedTakerGets
 
  148                              << 
"; bob already got: " << bobGot << 
std::endl;
 
  151                        inLedgerRate > initialRate ? 
"**" : 
"  ";
 
  152                    std::cout << 
"| `" << reducedTakerGets << 
"` | `" 
  153                              << reducedTakerPays << 
"` | `" << initialRate
 
  154                              << 
"` | " << filler << 
"`" << inLedgerRate << 
"`" 
  162                    env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
 
  167            Amounts 
const bobsOffer{
 
  173            unsigned int blockedCount = 0;
 
  175                 mantissaReduce <= 5'000'000'000ull;
 
  176                 mantissaReduce += 20'000'000ull)
 
  179                    bobsOffer.out.
issue(),
 
  180                    bobsOffer.out.mantissa() - mantissaReduce,
 
  181                    bobsOffer.out.exponent()};
 
  183                    bobsOffer.in.
issue(), bobsOffer.in.mantissa() - 1};
 
  184                Amounts alicesOffer{aliceUSD, aliceXRP};
 
  185                blockedCount += exerciseOfferPair(alicesOffer, bobsOffer);
 
  190            BEAST_EXPECT(blockedCount == 0);
 
 
  197        testcase(
"exercise partial cross old XRP/IOU offer Q change");
 
  201        auto const gw = 
Account{
"gateway"};
 
  202        auto const alice = 
Account{
"alice"};
 
  203        auto const bob = 
Account{
"bob"};
 
  204        auto const USD = gw[
"USD"];
 
  209            env.fund(
XRP(10'000'000), gw, alice, bob);
 
  212            env(
trust(alice, USD(10'000'000)));
 
  213            env(
trust(bob, USD(10'000'000)));
 
  216            env(
pay(gw, alice, USD(10'000'000)));
 
  223            auto exerciseOfferPair =
 
  224                [
this, &env, &alice, &bob](
 
  225                    Amounts 
const& inLedger,
 
  226                    Amounts 
const& newOffer) -> 
unsigned int {
 
  229                STAmount const initialRate = Quality(inLedger).rate();
 
  231                env(
offer(alice, inLedger.in, inLedger.out));
 
  236                STAmount const aliceInitialBalance = env.balance(alice);
 
  237                env(
offer(bob, newOffer.in, newOffer.out));
 
  239                STAmount const aliceFinalBalance = env.balance(alice);
 
  247                        env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
 
  252                unsigned int badRate = 1;
 
  259                        aliceOffer[jss::node][sfTakerGets.jsonName]);
 
  262                        aliceOffer[jss::node][sfTakerPays.jsonName]);
 
  264                        env.balance(alice) - aliceInitialBalance;
 
  265                    BEAST_EXPECT(reducedTakerPays < inLedger.in);
 
  266                    BEAST_EXPECT(reducedTakerGets < inLedger.out);
 
  268                        Quality(Amounts{reducedTakerPays, reducedTakerGets})
 
  270                    badRate = inLedgerRate > initialRate ? 1 : 0;
 
  280                            reducedTakerPays + 
drops(1);
 
  282                            Quality(Amounts{tweakedTakerPays, reducedTakerGets})
 
  284                        BEAST_EXPECT(tweakedRate > initialRate);
 
  287                    std::cout << 
"Placed rate: " << initialRate
 
  288                              << 
"; in-ledger rate: " << inLedgerRate
 
  289                              << 
"; TakerPays: " << reducedTakerPays
 
  290                              << 
"; TakerGets: " << reducedTakerGets
 
  291                              << 
"; alice already got: " << aliceGot
 
  295                    std::cout << 
"| `" << reducedTakerGets << 
"` | `" 
  296                              << reducedTakerPays << 
"` | `" << initialRate
 
  297                              << 
"` | " << filler << 
"`" << inLedgerRate << 
"`" 
  298                              << filler << 
" | `" << aliceGot << 
"` |" 
  306                    env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
 
  311            Amounts 
const aliceOffer{
 
  317            unsigned int blockedCount = 0;
 
  319                 mantissaReduce <= 4'000'000'000ull;
 
  320                 mantissaReduce += 20'000'000ull)
 
  323                    aliceOffer.out.
issue(),
 
  324                    aliceOffer.out.mantissa() - mantissaReduce,
 
  325                    aliceOffer.out.exponent()};
 
  327                    aliceOffer.in.
issue(), aliceOffer.in.mantissa() - 1};
 
  328                Amounts bobsOffer{bobUSD, bobXRP};
 
  330                blockedCount += exerciseOfferPair(aliceOffer, bobsOffer);
 
  335            BEAST_EXPECT(blockedCount == 0);
 
 
  342        testcase(
"exercise underfunded XRP/IOU offer Q change");
 
  347        auto const alice = 
Account{
"alice"};
 
  348        auto const bob = 
Account{
"bob"};
 
  350        auto const USD = gw[
"USD"];
 
  355            env.fund(
XRP(10000), alice, bob, gw);
 
  357            env.trust(USD(1000), alice, bob);
 
  359            int blockedOrderBookCount = 0;
 
  360            for (
STAmount initialBobUSD = USD(0.45); initialBobUSD <= USD(1);
 
  361                 initialBobUSD += USD(0.025))
 
  364                env(
pay(gw, bob, initialBobUSD));
 
  383                    bool const bobsOfferGone =
 
  385                    STAmount const aliceBalanceUSD = env.balance(alice, USD);
 
  388                    if (aliceBalanceUSD.
signum() > 0)
 
  390                        BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
 
  391                        BEAST_EXPECT(env.balance(bob, USD) == USD(0));
 
  392                        BEAST_EXPECT(bobsOfferGone);
 
  396                    if (!bobsOfferGone && aliceBalanceUSD.
signum() == 0)
 
  398                        ++blockedOrderBookCount;
 
  404                        env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
 
  407                    if (
STAmount const aliceBalance = env.balance(alice, USD);
 
  408                        aliceBalance.signum() > 0)
 
  409                        env(
pay(alice, gw, aliceBalance));
 
  411                    if (
STAmount const bobBalance = env.balance(bob, USD);
 
  413                        env(
pay(bob, gw, bobBalance));
 
  421            BEAST_EXPECT(blockedOrderBookCount == 0);
 
 
  428        testcase(
"exercise underfunded IOU/IOU offer Q change");
 
  433        using namespace std::chrono_literals;
 
  434        auto const alice = 
Account{
"alice"};
 
  435        auto const bob = 
Account{
"bob"};
 
  438        auto const USD = gw[
"USD"];
 
  439        auto const EUR = gw[
"EUR"];
 
  441        STAmount const tinyUSD(USD.issue(),  1,  -81);
 
  446            env.fund(
XRP(10000), alice, bob, gw);
 
  448            env.trust(USD(1000), alice, bob);
 
  449            env.trust(EUR(1000), alice, bob);
 
  452                EUR.issue(),  2957,  -76);
 
  454                USD.issue(),  7109,  -76);
 
  457                USD.issue(),  50,  -81);
 
  459            int blockedOrderBookCount = 0;
 
  460            for (
STAmount initialBobUSD = tinyUSD; initialBobUSD <= endLoop;
 
  461                 initialBobUSD += tinyUSD)
 
  464                env(
pay(gw, bob, initialBobUSD));
 
  465                env(
pay(gw, alice, EUR(100)));
 
  470                env(
offer(bob, eurOffer, usdOffer));
 
  472                env.require(
offers(bob, 1));
 
  476                env(
offer(alice, usdOffer, eurOffer));
 
  481                    bool const bobsOfferGone =
 
  483                    STAmount aliceBalanceUSD = env.balance(alice, USD);
 
  486                        << 
"bobs initial: " << initialBobUSD
 
  487                        << 
"; alice final: " << aliceBalanceUSD
 
  488                        << 
"; bobs offer: " << bobsOfferJson.toStyledString()
 
  492                    if (aliceBalanceUSD.
signum() > 0)
 
  494                        BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
 
  495                        BEAST_EXPECT(env.balance(bob, USD) == USD(0));
 
  496                        BEAST_EXPECT(bobsOfferGone);
 
  500                    if (!bobsOfferGone && aliceBalanceUSD.
signum() == 0)
 
  502                        ++blockedOrderBookCount;
 
  509                    env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
 
  512                auto zeroBalance = [&env, &gw](
 
  519                zeroBalance(alice, EUR);
 
  520                zeroBalance(alice, USD);
 
  521                zeroBalance(bob, EUR);
 
  522                zeroBalance(bob, USD);
 
  528            BEAST_EXPECT(blockedOrderBookCount == 0);
 
 
  549        testcase(
"exercise tfSell partial cross old XRP/IOU offer Q change");
 
  557        auto const USD = gw[
"USD"];
 
  565            Env env{*
this, features};
 
  566            env.fund(
XRP(10'000'000), gw, alice, bob, carol);
 
  569            env(
trust(alice, USD(10'000'000)));
 
  570            env(
trust(bob, USD(10'000'000)));
 
  571            env(
trust(carol, USD(10'000'000)));
 
  574            env(
pay(gw, alice, USD(10'000'000)));
 
  575            env(
pay(gw, bob, USD(10'000'000)));
 
  576            env(
pay(gw, carol, USD(10'000'000)));
 
  583            auto exerciseOfferTrio =
 
  584                [
this, &env, &alice, &bob, &carol, &USD](
 
  585                    Amounts 
const& carolOffer) -> 
unsigned int {
 
  588                static Amounts 
const aliceInitialOffer(USD(2), 
drops(3382562));
 
  589                env(
offer(alice, aliceInitialOffer.in, aliceInitialOffer.out));
 
  593                                env, alice, aliceOfferSeq)[jss::node]))
 
  598                env(
offer(bob, USD(0.97086565812384), 
drops(1642020)));
 
  604                env(
offer(carol, carolOffer.in, carolOffer.out),
 
  618                        {{alice, aliceOfferSeq},
 
  620                         {carol, carolOfferSeq}});
 
  625                unsigned int badRate = 1;
 
  630                    Amounts aliceReducedOffer =
 
  633                    BEAST_EXPECT(aliceReducedOffer.in < aliceInitialOffer.in);
 
  634                    BEAST_EXPECT(aliceReducedOffer.out < aliceInitialOffer.out);
 
  636                        Quality(aliceReducedOffer).rate();
 
  637                    badRate = inLedgerRate > initialRate ? 1 : 0;
 
  647                            aliceReducedOffer.in.issue(),
 
  648                            aliceReducedOffer.in.mantissa() + 1,
 
  649                            aliceReducedOffer.in.exponent(),
 
  650                            aliceReducedOffer.in.negative());
 
  653                                Amounts{aliceReducedOffer.in, tweakedTakerGets})
 
  655                        BEAST_EXPECT(tweakedRate > initialRate);
 
  658                    std::cout << 
"Placed rate: " << initialRate
 
  659                              << 
"; in-ledger rate: " << inLedgerRate
 
  660                              << 
"; TakerPays: " << aliceReducedOffer.in
 
  661                              << 
"; TakerGets: " << aliceReducedOffer.out
 
  665                    std::cout << 
"| " << aliceReducedOffer.in << 
"` | `" 
  666                              << aliceReducedOffer.out << 
"` | `" << initialRate
 
  667                              << 
"` | " << filler << 
"`" << inLedgerRate << 
"`" 
  676                    {{alice, aliceOfferSeq},
 
  678                     {carol, carolOfferSeq}});
 
  682            constexpr int loopCount = 100;
 
  683            unsigned int blockedCount = 0;
 
  687                for (
unsigned int i = 0; i < loopCount; ++i)
 
  689                    blockedCount += exerciseOfferTrio(
 
  690                        Amounts(
drops(1642020), USD(1) + increaseGets));
 
  691                    increaseGets += step;
 
  700            if (features[fixReducedOffersV2])
 
  702                BEAST_EXPECT(blockedCount == 0);
 
  706                BEAST_EXPECT(blockedCount > 80);