74 testcase(
"exercise partial cross new XRP/IOU offer Q change");
78 auto const gw =
Account{
"gateway"};
79 auto const alice =
Account{
"alice"};
80 auto const bob =
Account{
"bob"};
81 auto const USD = gw[
"USD"];
87 env.fund(
XRP(10'000'000), gw, alice, bob);
90 env(
trust(alice, USD(10'000'000)));
91 env(
trust(bob, USD(10'000'000)));
94 env(
pay(gw, bob, USD(10'000'000)));
102 auto exerciseOfferPair =
103 [
this, &env, &alice, &bob](
104 Amounts
const& inLedger,
105 Amounts
const& newOffer) ->
unsigned int {
108 env(
offer(alice, inLedger.in, inLedger.out));
112 STAmount const initialRate = Quality(newOffer).rate();
114 STAmount const bobInitialBalance = env.balance(bob);
115 STAmount const bobsFee = env.current()->fees().base;
119 STAmount const bobFinalBalance = env.balance(bob);
123 if (!BEAST_EXPECT(!
offerInLedger(env, alice, aliceOfferSeq)))
129 unsigned int badRate = 1;
135 sfTakerGets, bobOffer[jss::node][sfTakerGets.jsonName]);
137 sfTakerPays, bobOffer[jss::node][sfTakerPays.jsonName]);
139 env.balance(bob) + bobsFee - bobInitialBalance;
140 BEAST_EXPECT(reducedTakerPays < newOffer.in);
141 BEAST_EXPECT(reducedTakerGets < newOffer.out);
143 Quality(Amounts{reducedTakerPays, reducedTakerGets})
146 badRate = inLedgerRate > initialRate ? 1 : 0;
156 reducedTakerPays +
drops(1);
158 Quality(Amounts{tweakedTakerPays, reducedTakerGets})
160 BEAST_EXPECT(tweakedRate > initialRate);
163 std::cout <<
"Placed rate: " << initialRate
164 <<
"; in-ledger rate: " << inLedgerRate
165 <<
"; TakerPays: " << reducedTakerPays
166 <<
"; TakerGets: " << reducedTakerGets
167 <<
"; bob already got: " << bobGot <<
std::endl;
170 inLedgerRate > initialRate ?
"**" :
" ";
171 std::cout <<
"| `" << reducedTakerGets <<
"` | `"
172 << reducedTakerPays <<
"` | `" << initialRate
173 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
181 env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
186 Amounts
const bobsOffer{
192 unsigned int blockedCount = 0;
194 mantissaReduce <= 5'000'000'000ull;
195 mantissaReduce += 20'000'000ull)
198 bobsOffer.out.
issue(),
199 bobsOffer.out.mantissa() - mantissaReduce,
200 bobsOffer.out.exponent()};
202 bobsOffer.in.
issue(), bobsOffer.in.mantissa() - 1};
203 Amounts alicesOffer{aliceUSD, aliceXRP};
204 blockedCount += exerciseOfferPair(alicesOffer, bobsOffer);
209 BEAST_EXPECT(blockedCount == 0);
216 testcase(
"exercise partial cross old XRP/IOU offer Q change");
220 auto const gw =
Account{
"gateway"};
221 auto const alice =
Account{
"alice"};
222 auto const bob =
Account{
"bob"};
223 auto const USD = gw[
"USD"];
228 env.fund(
XRP(10'000'000), gw, alice, bob);
231 env(
trust(alice, USD(10'000'000)));
232 env(
trust(bob, USD(10'000'000)));
235 env(
pay(gw, alice, USD(10'000'000)));
242 auto exerciseOfferPair =
243 [
this, &env, &alice, &bob](
244 Amounts
const& inLedger,
245 Amounts
const& newOffer) ->
unsigned int {
248 STAmount const initialRate = Quality(inLedger).rate();
250 env(
offer(alice, inLedger.in, inLedger.out));
255 STAmount const aliceInitialBalance = env.balance(alice);
256 env(
offer(bob, newOffer.in, newOffer.out));
258 STAmount const aliceFinalBalance = env.balance(alice);
266 env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
271 unsigned int badRate = 1;
278 aliceOffer[jss::node][sfTakerGets.jsonName]);
281 aliceOffer[jss::node][sfTakerPays.jsonName]);
283 env.balance(alice) - aliceInitialBalance;
284 BEAST_EXPECT(reducedTakerPays < inLedger.in);
285 BEAST_EXPECT(reducedTakerGets < inLedger.out);
287 Quality(Amounts{reducedTakerPays, reducedTakerGets})
289 badRate = inLedgerRate > initialRate ? 1 : 0;
299 reducedTakerPays +
drops(1);
301 Quality(Amounts{tweakedTakerPays, reducedTakerGets})
303 BEAST_EXPECT(tweakedRate > initialRate);
306 std::cout <<
"Placed rate: " << initialRate
307 <<
"; in-ledger rate: " << inLedgerRate
308 <<
"; TakerPays: " << reducedTakerPays
309 <<
"; TakerGets: " << reducedTakerGets
310 <<
"; alice already got: " << aliceGot
314 std::cout <<
"| `" << reducedTakerGets <<
"` | `"
315 << reducedTakerPays <<
"` | `" << initialRate
316 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
317 << filler <<
" | `" << aliceGot <<
"` |"
325 env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
330 Amounts
const aliceOffer{
336 unsigned int blockedCount = 0;
338 mantissaReduce <= 4'000'000'000ull;
339 mantissaReduce += 20'000'000ull)
342 aliceOffer.out.
issue(),
343 aliceOffer.out.mantissa() - mantissaReduce,
344 aliceOffer.out.exponent()};
346 aliceOffer.in.
issue(), aliceOffer.in.mantissa() - 1};
347 Amounts bobsOffer{bobUSD, bobXRP};
349 blockedCount += exerciseOfferPair(aliceOffer, bobsOffer);
354 BEAST_EXPECT(blockedCount == 0);
361 testcase(
"exercise underfunded XRP/IOU offer Q change");
366 auto const alice =
Account{
"alice"};
367 auto const bob =
Account{
"bob"};
369 auto const USD = gw[
"USD"];
374 env.fund(
XRP(10000), alice, bob, gw);
376 env.trust(USD(1000), alice, bob);
378 int blockedOrderBookCount = 0;
379 for (
STAmount initialBobUSD = USD(0.45); initialBobUSD <= USD(1);
380 initialBobUSD += USD(0.025))
383 env(
pay(gw, bob, initialBobUSD));
402 bool const bobsOfferGone =
404 STAmount const aliceBalanceUSD = env.balance(alice, USD);
407 if (aliceBalanceUSD.
signum() > 0)
409 BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
410 BEAST_EXPECT(env.balance(bob, USD) == USD(0));
411 BEAST_EXPECT(bobsOfferGone);
415 if (!bobsOfferGone && aliceBalanceUSD.
signum() == 0)
417 ++blockedOrderBookCount;
423 env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
426 if (
STAmount const aliceBalance = env.balance(alice, USD);
427 aliceBalance.signum() > 0)
428 env(
pay(alice, gw, aliceBalance));
430 if (
STAmount const bobBalance = env.balance(bob, USD);
432 env(
pay(bob, gw, bobBalance));
440 BEAST_EXPECT(blockedOrderBookCount == 0);
447 testcase(
"exercise underfunded IOU/IOU offer Q change");
452 using namespace std::chrono_literals;
453 auto const alice =
Account{
"alice"};
454 auto const bob =
Account{
"bob"};
457 auto const USD = gw[
"USD"];
458 auto const EUR = gw[
"EUR"];
460 STAmount const tinyUSD(USD.issue(), 1, -81);
465 env.fund(
XRP(10000), alice, bob, gw);
467 env.trust(USD(1000), alice, bob);
468 env.trust(EUR(1000), alice, bob);
471 EUR.issue(), 2957, -76);
473 USD.issue(), 7109, -76);
476 USD.issue(), 50, -81);
478 int blockedOrderBookCount = 0;
479 for (
STAmount initialBobUSD = tinyUSD; initialBobUSD <= endLoop;
480 initialBobUSD += tinyUSD)
483 env(
pay(gw, bob, initialBobUSD));
484 env(
pay(gw, alice, EUR(100)));
489 env(
offer(bob, eurOffer, usdOffer));
491 env.require(
offers(bob, 1));
495 env(
offer(alice, usdOffer, eurOffer));
500 bool const bobsOfferGone =
502 STAmount aliceBalanceUSD = env.balance(alice, USD);
505 <<
"bobs initial: " << initialBobUSD
506 <<
"; alice final: " << aliceBalanceUSD
507 <<
"; bobs offer: " << bobsOfferJson.toStyledString()
511 if (aliceBalanceUSD.
signum() > 0)
513 BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
514 BEAST_EXPECT(env.balance(bob, USD) == USD(0));
515 BEAST_EXPECT(bobsOfferGone);
519 if (!bobsOfferGone && aliceBalanceUSD.
signum() == 0)
521 ++blockedOrderBookCount;
528 env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}});
531 auto zeroBalance = [&env, &gw](
538 zeroBalance(alice, EUR);
539 zeroBalance(alice, USD);
540 zeroBalance(bob, EUR);
541 zeroBalance(bob, USD);
547 BEAST_EXPECT(blockedOrderBookCount == 0);
568 testcase(
"exercise tfSell partial cross old XRP/IOU offer Q change");
576 auto const USD = gw[
"USD"];
584 Env env{*
this, features};
585 env.fund(
XRP(10'000'000), gw, alice, bob, carol);
588 env(
trust(alice, USD(10'000'000)));
589 env(
trust(bob, USD(10'000'000)));
590 env(
trust(carol, USD(10'000'000)));
593 env(
pay(gw, alice, USD(10'000'000)));
594 env(
pay(gw, bob, USD(10'000'000)));
595 env(
pay(gw, carol, USD(10'000'000)));
602 auto exerciseOfferTrio =
603 [
this, &env, &alice, &bob, &carol, &USD](
604 Amounts
const& carolOffer) ->
unsigned int {
607 static Amounts
const aliceInitialOffer(USD(2),
drops(3382562));
608 env(
offer(alice, aliceInitialOffer.in, aliceInitialOffer.out));
612 env, alice, aliceOfferSeq)[jss::node]))
617 env(
offer(bob, USD(0.97086565812384),
drops(1642020)));
623 env(
offer(carol, carolOffer.in, carolOffer.out),
637 {{alice, aliceOfferSeq},
639 {carol, carolOfferSeq}});
644 unsigned int badRate = 1;
649 Amounts aliceReducedOffer =
652 BEAST_EXPECT(aliceReducedOffer.in < aliceInitialOffer.in);
653 BEAST_EXPECT(aliceReducedOffer.out < aliceInitialOffer.out);
655 Quality(aliceReducedOffer).rate();
656 badRate = inLedgerRate > initialRate ? 1 : 0;
666 aliceReducedOffer.in.issue(),
667 aliceReducedOffer.in.mantissa() + 1,
668 aliceReducedOffer.in.exponent(),
669 aliceReducedOffer.in.negative());
672 Amounts{aliceReducedOffer.in, tweakedTakerGets})
674 BEAST_EXPECT(tweakedRate > initialRate);
677 std::cout <<
"Placed rate: " << initialRate
678 <<
"; in-ledger rate: " << inLedgerRate
679 <<
"; TakerPays: " << aliceReducedOffer.in
680 <<
"; TakerGets: " << aliceReducedOffer.out
684 std::cout <<
"| " << aliceReducedOffer.in <<
"` | `"
685 << aliceReducedOffer.out <<
"` | `" << initialRate
686 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
695 {{alice, aliceOfferSeq},
697 {carol, carolOfferSeq}});
701 constexpr int loopCount = 100;
702 unsigned int blockedCount = 0;
706 for (
unsigned int i = 0; i < loopCount; ++i)
708 blockedCount += exerciseOfferTrio(
709 Amounts(
drops(1642020), USD(1) + increaseGets));
710 increaseGets += step;
719 if (features[fixReducedOffersV2])
721 BEAST_EXPECT(blockedCount == 0);
725 BEAST_EXPECT(blockedCount > 80);