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);