43 testcase(
"exercise partial cross new XRP/IOU offer Q change");
47 auto const gw =
Account{
"gateway"};
48 auto const alice =
Account{
"alice"};
49 auto const bob =
Account{
"bob"};
50 auto const USD = gw[
"USD"];
56 env.fund(
XRP(10'000'000), gw, alice, bob);
59 env(
trust(alice, USD(10'000'000)));
60 env(
trust(bob, USD(10'000'000)));
63 env(
pay(gw, bob, USD(10'000'000)));
71 auto exerciseOfferPair = [
this, &env, &alice, &bob](
72 Amounts
const& inLedger, Amounts
const& newOffer) ->
unsigned int {
75 env(
offer(alice, inLedger.in, inLedger.out));
79 STAmount const initialRate = Quality(newOffer).rate();
81 STAmount const bobInitialBalance = env.balance(bob);
82 STAmount const bobsFee = env.current()->fees().base;
85 STAmount const bobFinalBalance = env.balance(bob);
95 unsigned int badRate = 1;
100 amountFromJson(sfTakerGets, bobOffer[jss::node][sfTakerGets.jsonName]);
102 amountFromJson(sfTakerPays, bobOffer[jss::node][sfTakerPays.jsonName]);
103 STAmount const bobGot = env.balance(bob) + bobsFee - bobInitialBalance;
104 BEAST_EXPECT(reducedTakerPays < newOffer.in);
105 BEAST_EXPECT(reducedTakerGets < newOffer.out);
106 STAmount const inLedgerRate = Quality(Amounts{reducedTakerPays, reducedTakerGets}).
rate();
108 badRate = inLedgerRate > initialRate ? 1 : 0;
117 STAmount const tweakedTakerPays = reducedTakerPays +
drops(1);
118 STAmount const tweakedRate = Quality(Amounts{tweakedTakerPays, reducedTakerGets}).
rate();
119 BEAST_EXPECT(tweakedRate > initialRate);
122 std::cout <<
"Placed rate: " << initialRate
123 <<
"; in-ledger rate: " << inLedgerRate
124 <<
"; TakerPays: " << reducedTakerPays
125 <<
"; TakerGets: " << reducedTakerGets
126 <<
"; bob already got: " << bobGot <<
std::endl;
129 inLedgerRate > initialRate ?
"**" :
" ";
130 std::cout <<
"| `" << reducedTakerGets <<
"` | `"
131 << reducedTakerPays <<
"` | `" << initialRate
132 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
149 unsigned int blockedCount = 0;
150 for (
std::uint64_t mantissaReduce = 1'000'000'000ull; mantissaReduce <= 5'000'000'000ull;
151 mantissaReduce += 20'000'000ull)
154 bobsOffer.out.
issue(), bobsOffer.out.mantissa() - mantissaReduce, bobsOffer.out.exponent()};
155 STAmount aliceXRP{bobsOffer.in.
issue(), bobsOffer.in.mantissa() - 1};
156 Amounts alicesOffer{aliceUSD, aliceXRP};
157 blockedCount += exerciseOfferPair(alicesOffer, bobsOffer);
162 BEAST_EXPECT(blockedCount == 0);
169 testcase(
"exercise partial cross old XRP/IOU offer Q change");
173 auto const gw =
Account{
"gateway"};
174 auto const alice =
Account{
"alice"};
175 auto const bob =
Account{
"bob"};
176 auto const USD = gw[
"USD"];
181 env.fund(
XRP(10'000'000), gw, alice, bob);
184 env(
trust(alice, USD(10'000'000)));
185 env(
trust(bob, USD(10'000'000)));
188 env(
pay(gw, alice, USD(10'000'000)));
195 auto exerciseOfferPair = [
this, &env, &alice, &bob](
196 Amounts
const& inLedger, Amounts
const& newOffer) ->
unsigned int {
199 STAmount const initialRate = Quality(inLedger).rate();
201 env(
offer(alice, inLedger.in, inLedger.out));
206 STAmount const aliceInitialBalance = env.balance(alice);
207 env(
offer(bob, newOffer.in, newOffer.out));
209 STAmount const aliceFinalBalance = env.balance(alice);
221 unsigned int badRate = 1;
226 amountFromJson(sfTakerGets, aliceOffer[jss::node][sfTakerGets.jsonName]);
228 amountFromJson(sfTakerPays, aliceOffer[jss::node][sfTakerPays.jsonName]);
229 STAmount const aliceGot = env.balance(alice) - aliceInitialBalance;
230 BEAST_EXPECT(reducedTakerPays < inLedger.in);
231 BEAST_EXPECT(reducedTakerGets < inLedger.out);
232 STAmount const inLedgerRate = Quality(Amounts{reducedTakerPays, reducedTakerGets}).
rate();
233 badRate = inLedgerRate > initialRate ? 1 : 0;
242 STAmount const tweakedTakerPays = reducedTakerPays +
drops(1);
243 STAmount const tweakedRate = Quality(Amounts{tweakedTakerPays, reducedTakerGets}).
rate();
244 BEAST_EXPECT(tweakedRate > initialRate);
247 std::cout <<
"Placed rate: " << initialRate
248 <<
"; in-ledger rate: " << inLedgerRate
249 <<
"; TakerPays: " << reducedTakerPays
250 <<
"; TakerGets: " << reducedTakerGets
251 <<
"; alice already got: " << aliceGot
255 std::cout <<
"| `" << reducedTakerGets <<
"` | `"
256 << reducedTakerPays <<
"` | `" << initialRate
257 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
258 << filler <<
" | `" << aliceGot <<
"` |"
275 unsigned int blockedCount = 0;
276 for (
std::uint64_t mantissaReduce = 1'000'000'000ull; mantissaReduce <= 4'000'000'000ull;
277 mantissaReduce += 20'000'000ull)
280 aliceOffer.out.
issue(), aliceOffer.out.mantissa() - mantissaReduce, aliceOffer.out.exponent()};
281 STAmount bobXRP{aliceOffer.in.
issue(), aliceOffer.in.mantissa() - 1};
282 Amounts bobsOffer{bobUSD, bobXRP};
284 blockedCount += exerciseOfferPair(aliceOffer, bobsOffer);
289 BEAST_EXPECT(blockedCount == 0);
296 testcase(
"exercise underfunded XRP/IOU offer Q change");
301 auto const alice =
Account{
"alice"};
302 auto const bob =
Account{
"bob"};
304 auto const USD = gw[
"USD"];
309 env.fund(
XRP(10000), alice, bob, gw);
311 env.trust(USD(1000), alice, bob);
313 int blockedOrderBookCount = 0;
314 for (
STAmount initialBobUSD = USD(0.45); initialBobUSD <= USD(1); initialBobUSD += USD(0.025))
317 env(
pay(gw, bob, initialBobUSD));
336 bool const bobsOfferGone = !
offerInLedger(env, bob, bobOfferSeq);
337 STAmount const aliceBalanceUSD = env.balance(alice, USD);
340 if (aliceBalanceUSD.
signum() > 0)
342 BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
343 BEAST_EXPECT(env.balance(bob, USD) == USD(0));
344 BEAST_EXPECT(bobsOfferGone);
348 if (!bobsOfferGone && aliceBalanceUSD.
signum() == 0)
350 ++blockedOrderBookCount;
358 if (
STAmount const aliceBalance = env.balance(alice, USD); aliceBalance.signum() > 0)
359 env(
pay(alice, gw, aliceBalance));
361 if (
STAmount const bobBalance = env.balance(bob, USD); bobBalance.
signum() > 0)
362 env(
pay(bob, gw, bobBalance));
370 BEAST_EXPECT(blockedOrderBookCount == 0);
377 testcase(
"exercise underfunded IOU/IOU offer Q change");
382 using namespace std::chrono_literals;
383 auto const alice =
Account{
"alice"};
384 auto const bob =
Account{
"bob"};
387 auto const USD = gw[
"USD"];
388 auto const EUR = gw[
"EUR"];
390 STAmount const tinyUSD(USD.issue(), 1, -81);
395 env.fund(
XRP(10000), alice, bob, gw);
397 env.trust(USD(1000), alice, bob);
398 env.trust(EUR(1000), alice, bob);
400 STAmount const eurOffer(EUR.issue(), 2957, -76);
401 STAmount const usdOffer(USD.issue(), 7109, -76);
403 STAmount const endLoop(USD.issue(), 50, -81);
405 int blockedOrderBookCount = 0;
406 for (
STAmount initialBobUSD = tinyUSD; initialBobUSD <= endLoop; initialBobUSD += tinyUSD)
409 env(
pay(gw, bob, initialBobUSD));
410 env(
pay(gw, alice, EUR(100)));
415 env(
offer(bob, eurOffer, usdOffer));
417 env.require(
offers(bob, 1));
421 env(
offer(alice, usdOffer, eurOffer));
426 bool const bobsOfferGone = !
offerInLedger(env, bob, bobOfferSeq);
427 STAmount aliceBalanceUSD = env.balance(alice, USD);
430 <<
"bobs initial: " << initialBobUSD
431 <<
"; alice final: " << aliceBalanceUSD
432 <<
"; bobs offer: " << bobsOfferJson.toStyledString()
436 if (aliceBalanceUSD.
signum() > 0)
438 BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
439 BEAST_EXPECT(env.balance(bob, USD) == USD(0));
440 BEAST_EXPECT(bobsOfferGone);
444 if (!bobsOfferGone && aliceBalanceUSD.
signum() == 0)
446 ++blockedOrderBookCount;
455 auto zeroBalance = [&env, &gw](
Account const& acct,
IOU const& iou) {
460 zeroBalance(alice, EUR);
461 zeroBalance(alice, USD);
462 zeroBalance(bob, EUR);
463 zeroBalance(bob, USD);
469 BEAST_EXPECT(blockedOrderBookCount == 0);
488 testcase(
"exercise tfSell partial cross old XRP/IOU offer Q change");
496 auto const USD = gw[
"USD"];
503 Env env{*
this, features};
504 env.fund(
XRP(10'000'000), gw, alice, bob, carol);
507 env(
trust(alice, USD(10'000'000)));
508 env(
trust(bob, USD(10'000'000)));
509 env(
trust(carol, USD(10'000'000)));
512 env(
pay(gw, alice, USD(10'000'000)));
513 env(
pay(gw, bob, USD(10'000'000)));
514 env(
pay(gw, carol, USD(10'000'000)));
521 auto exerciseOfferTrio =
522 [
this, &env, &alice, &bob, &carol, &USD](Amounts
const& carolOffer) ->
unsigned int {
525 static Amounts
const aliceInitialOffer(USD(2),
drops(3382562));
526 env(
offer(alice, aliceInitialOffer.in, aliceInitialOffer.out));
533 env(
offer(bob, USD(0.97086565812384),
drops(1642020)));
548 cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}, {carol, carolOfferSeq}});
553 unsigned int badRate = 1;
559 BEAST_EXPECT(aliceReducedOffer.in < aliceInitialOffer.in);
560 BEAST_EXPECT(aliceReducedOffer.out < aliceInitialOffer.out);
561 STAmount const inLedgerRate = Quality(aliceReducedOffer).rate();
562 badRate = inLedgerRate > initialRate ? 1 : 0;
572 aliceReducedOffer.in.issue(),
573 aliceReducedOffer.in.mantissa() + 1,
574 aliceReducedOffer.in.exponent(),
575 aliceReducedOffer.in.negative());
576 STAmount const tweakedRate = Quality(Amounts{aliceReducedOffer.in, tweakedTakerGets}).
rate();
577 BEAST_EXPECT(tweakedRate > initialRate);
580 std::cout <<
"Placed rate: " << initialRate
581 <<
"; in-ledger rate: " << inLedgerRate
582 <<
"; TakerPays: " << aliceReducedOffer.in
583 <<
"; TakerGets: " << aliceReducedOffer.out
587 std::cout <<
"| " << aliceReducedOffer.in <<
"` | `"
588 << aliceReducedOffer.out <<
"` | `" << initialRate
589 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
596 cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}, {carol, carolOfferSeq}});
600 constexpr int loopCount = 100;
601 unsigned int blockedCount = 0;
605 for (
unsigned int i = 0; i < loopCount; ++i)
607 blockedCount += exerciseOfferTrio(Amounts(
drops(1642020), USD(1) + increaseGets));
608 increaseGets += step;
617 if (features[fixReducedOffersV2])
619 BEAST_EXPECT(blockedCount == 0);
623 BEAST_EXPECT(blockedCount > 80);