47 testcase(
"exercise partial cross new XRP/IOU offer Q change");
51 auto const gw =
Account{
"gateway"};
52 auto const alice =
Account{
"alice"};
53 auto const bob =
Account{
"bob"};
54 auto const USD = gw[
"USD"];
60 env.fund(
XRP(10'000'000), gw, alice, bob);
63 env(
trust(alice, USD(10'000'000)));
64 env(
trust(bob, USD(10'000'000)));
67 env(
pay(gw, bob, USD(10'000'000)));
75 auto exerciseOfferPair = [
this, &env, &alice, &bob](
76 Amounts
const& inLedger,
77 Amounts
const& newOffer) ->
unsigned int {
80 env(
offer(alice, inLedger.in, inLedger.out));
84 STAmount const initialRate = Quality(newOffer).rate();
86 STAmount const bobInitialBalance = env.balance(bob);
87 STAmount const bobFee = env.current()->fees().base;
88 env(
offer(bob, newOffer.in, newOffer.out, tfSell),
fee(bobFee));
90 STAmount const bobFinalBalance = env.balance(bob);
102 unsigned int badRate = 1;
107 amountFromJson(sfTakerGets, bobOffer[jss::node][sfTakerGets.jsonName]);
109 amountFromJson(sfTakerPays, bobOffer[jss::node][sfTakerPays.jsonName]);
110 STAmount const bobGot = env.balance(bob) + bobFee - bobInitialBalance;
111 BEAST_EXPECT(reducedTakerPays < newOffer.in);
112 BEAST_EXPECT(reducedTakerGets < newOffer.out);
114 Quality(Amounts{reducedTakerPays, reducedTakerGets}).
rate();
116 badRate = inLedgerRate > initialRate ? 1 : 0;
125 STAmount const tweakedTakerPays = reducedTakerPays +
drops(1);
127 Quality(Amounts{tweakedTakerPays, reducedTakerGets}).
rate();
128 BEAST_EXPECT(tweakedRate > initialRate);
131 std::cout <<
"Placed rate: " << initialRate
132 <<
"; in-ledger rate: " << inLedgerRate
133 <<
"; TakerPays: " << reducedTakerPays
134 <<
"; TakerGets: " << reducedTakerGets
135 <<
"; bob already got: " << bobGot <<
std::endl;
138 inLedgerRate > initialRate ?
"**" :
" ";
139 std::cout <<
"| `" << reducedTakerGets <<
"` | `"
140 << reducedTakerPays <<
"` | `" << initialRate
141 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
158 unsigned int blockedCount = 0;
160 mantissaReduce <= 5'000'000'000ull;
161 mantissaReduce += 20'000'000ull)
164 bobOffer.out.
issue(),
165 bobOffer.out.mantissa() - mantissaReduce,
166 bobOffer.out.exponent()};
167 STAmount const aliceXRP{bobOffer.in.
issue(), bobOffer.in.mantissa() - 1};
168 Amounts
const aliceOffer{aliceUSD, aliceXRP};
169 blockedCount += exerciseOfferPair(aliceOffer, bobOffer);
174 BEAST_EXPECT(blockedCount == 0);
181 testcase(
"exercise partial cross old XRP/IOU offer Q change");
185 auto const gw =
Account{
"gateway"};
186 auto const alice =
Account{
"alice"};
187 auto const bob =
Account{
"bob"};
188 auto const USD = gw[
"USD"];
193 env.fund(
XRP(10'000'000), gw, alice, bob);
196 env(
trust(alice, USD(10'000'000)));
197 env(
trust(bob, USD(10'000'000)));
200 env(
pay(gw, alice, USD(10'000'000)));
207 auto exerciseOfferPair = [
this, &env, &alice, &bob](
208 Amounts
const& inLedger,
209 Amounts
const& newOffer) ->
unsigned int {
212 STAmount const initialRate = Quality(inLedger).rate();
214 env(
offer(alice, inLedger.in, inLedger.out));
219 STAmount const aliceInitialBalance = env.balance(alice);
220 env(
offer(bob, newOffer.in, newOffer.out));
222 STAmount const aliceFinalBalance = env.balance(alice);
234 unsigned int badRate = 1;
239 amountFromJson(sfTakerGets, aliceOffer[jss::node][sfTakerGets.jsonName]);
241 amountFromJson(sfTakerPays, aliceOffer[jss::node][sfTakerPays.jsonName]);
242 STAmount const aliceGot = env.balance(alice) - aliceInitialBalance;
243 BEAST_EXPECT(reducedTakerPays < inLedger.in);
244 BEAST_EXPECT(reducedTakerGets < inLedger.out);
246 Quality(Amounts{reducedTakerPays, reducedTakerGets}).
rate();
247 badRate = inLedgerRate > initialRate ? 1 : 0;
256 STAmount const tweakedTakerPays = reducedTakerPays +
drops(1);
258 Quality(Amounts{tweakedTakerPays, reducedTakerGets}).
rate();
259 BEAST_EXPECT(tweakedRate > initialRate);
262 std::cout <<
"Placed rate: " << initialRate
263 <<
"; in-ledger rate: " << inLedgerRate
264 <<
"; TakerPays: " << reducedTakerPays
265 <<
"; TakerGets: " << reducedTakerGets
266 <<
"; alice already got: " << aliceGot
270 std::cout <<
"| `" << reducedTakerGets <<
"` | `"
271 << reducedTakerPays <<
"` | `" << initialRate
272 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
273 << filler <<
" | `" << aliceGot <<
"` |"
290 unsigned int blockedCount = 0;
292 mantissaReduce <= 4'000'000'000ull;
293 mantissaReduce += 20'000'000ull)
296 aliceOffer.out.
issue(),
297 aliceOffer.out.mantissa() - mantissaReduce,
298 aliceOffer.out.exponent()};
299 STAmount const bobXRP{aliceOffer.in.
issue(), aliceOffer.in.mantissa() - 1};
300 Amounts
const bobOffer{bobUSD, bobXRP};
302 blockedCount += exerciseOfferPair(aliceOffer, bobOffer);
307 BEAST_EXPECT(blockedCount == 0);
314 testcase(
"exercise underfunded XRP/IOU offer Q change");
319 auto const alice =
Account{
"alice"};
320 auto const bob =
Account{
"bob"};
322 auto const USD = gw[
"USD"];
327 env.fund(
XRP(10000), alice, bob, gw);
329 env.trust(USD(1000), alice, bob);
331 int blockedOrderBookCount = 0;
332 for (
STAmount initialBobUSD = USD(0.45); initialBobUSD <= USD(1);
333 initialBobUSD += USD(0.025))
336 env(
pay(gw, bob, initialBobUSD));
355 bool const bobOfferGone = !
offerInLedger(env, bob, bobOfferSeq);
356 STAmount const aliceBalanceUSD = env.balance(alice, USD);
359 if (aliceBalanceUSD.
signum() > 0)
361 BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
362 BEAST_EXPECT(env.balance(bob, USD) == USD(0));
363 BEAST_EXPECT(bobOfferGone);
367 if (!bobOfferGone && aliceBalanceUSD.
signum() == 0)
369 ++blockedOrderBookCount;
377 if (
STAmount const aliceBalance = env.balance(alice, USD);
378 aliceBalance.signum() > 0)
379 env(
pay(alice, gw, aliceBalance));
381 if (
STAmount const bobBalance = env.balance(bob, USD); bobBalance.
signum() > 0)
382 env(
pay(bob, gw, bobBalance));
390 BEAST_EXPECT(blockedOrderBookCount == 0);
397 testcase(
"exercise underfunded IOU/IOU offer Q change");
402 using namespace std::chrono_literals;
403 auto const alice =
Account{
"alice"};
404 auto const bob =
Account{
"bob"};
407 auto const USD = gw[
"USD"];
408 auto const EUR = gw[
"EUR"];
410 STAmount const tinyUSD(USD.issue(), 1, -81);
415 env.fund(
XRP(10000), alice, bob, gw);
417 env.trust(USD(1000), alice, bob);
418 env.trust(EUR(1000), alice, bob);
420 STAmount const eurOffer(EUR.issue(), 2957, -76);
421 STAmount const usdOffer(USD.issue(), 7109, -76);
423 STAmount const endLoop(USD.issue(), 50, -81);
425 int blockedOrderBookCount = 0;
426 for (
STAmount initialBobUSD = tinyUSD; initialBobUSD <= endLoop;
427 initialBobUSD += tinyUSD)
430 env(
pay(gw, bob, initialBobUSD));
431 env(
pay(gw, alice, EUR(100)));
436 env(
offer(bob, eurOffer, usdOffer));
438 env.require(
offers(bob, 1));
442 env(
offer(alice, usdOffer, eurOffer));
447 bool const bobOfferGone = !
offerInLedger(env, bob, bobOfferSeq);
448 STAmount const aliceBalanceUSD = env.balance(alice, USD);
451 <<
"bob initial: " << initialBobUSD
452 <<
"; alice final: " << aliceBalanceUSD
453 <<
"; bob offer: " << bobOfferJson.toStyledString()
457 if (aliceBalanceUSD.
signum() > 0)
459 BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
460 BEAST_EXPECT(env.balance(bob, USD) == USD(0));
461 BEAST_EXPECT(bobOfferGone);
465 if (!bobOfferGone && aliceBalanceUSD.
signum() == 0)
467 ++blockedOrderBookCount;
476 auto zeroBalance = [&env, &gw](
Account const& acct,
IOU const& iou) {
481 zeroBalance(alice, EUR);
482 zeroBalance(alice, USD);
483 zeroBalance(bob, EUR);
484 zeroBalance(bob, USD);
490 BEAST_EXPECT(blockedOrderBookCount == 0);
509 testcase(
"exercise tfSell partial cross old XRP/IOU offer Q change");
517 auto const USD = gw[
"USD"];
525 Env env{*
this, features};
526 env.fund(
XRP(10'000'000), gw, alice, bob, carol);
529 env(
trust(alice, USD(10'000'000)));
530 env(
trust(bob, USD(10'000'000)));
531 env(
trust(carol, USD(10'000'000)));
534 env(
pay(gw, alice, USD(10'000'000)));
535 env(
pay(gw, bob, USD(10'000'000)));
536 env(
pay(gw, carol, USD(10'000'000)));
543 auto exerciseOfferTrio = [
this, &env, &alice, &bob, &carol, &USD](
544 Amounts
const& carolOffer) ->
unsigned int {
547 static Amounts
const aliceInitialOffer(USD(2),
drops(3382562));
548 env(
offer(alice, aliceInitialOffer.in, aliceInitialOffer.out));
551 env, alice, aliceOfferSeq)[jss::node]))
556 env(
offer(bob, USD(0.97086565812384),
drops(1642020)));
562 env(
offer(carol, carolOffer.in, carolOffer.out),
txflags(tfSell));
574 env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}, {carol, carolOfferSeq}});
579 unsigned int badRate = 1;
585 BEAST_EXPECT(aliceReducedOffer.in < aliceInitialOffer.in);
586 BEAST_EXPECT(aliceReducedOffer.out < aliceInitialOffer.out);
587 STAmount const inLedgerRate = Quality(aliceReducedOffer).rate();
588 badRate = inLedgerRate > initialRate ? 1 : 0;
598 aliceReducedOffer.in.issue(),
599 aliceReducedOffer.in.mantissa() + 1,
600 aliceReducedOffer.in.exponent(),
601 aliceReducedOffer.in.negative());
603 Quality(Amounts{aliceReducedOffer.in, tweakedTakerGets}).
rate();
604 BEAST_EXPECT(tweakedRate > initialRate);
607 std::cout <<
"Placed rate: " << initialRate
608 <<
"; in-ledger rate: " << inLedgerRate
609 <<
"; TakerPays: " << aliceReducedOffer.in
610 <<
"; TakerGets: " << aliceReducedOffer.out
614 std::cout <<
"| " << aliceReducedOffer.in <<
"` | `"
615 << aliceReducedOffer.out <<
"` | `" << initialRate
616 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
624 env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}, {carol, carolOfferSeq}});
628 constexpr int loopCount = 100;
629 unsigned int blockedCount = 0;
633 for (
unsigned int i = 0; i < loopCount; ++i)
636 exerciseOfferTrio(Amounts(
drops(1642020), USD(1) + increaseGets));
637 increaseGets += step;
646 if (features[fixReducedOffersV2])
648 BEAST_EXPECT(blockedCount == 0);
652 BEAST_EXPECT(blockedCount > 80);