20 #include <ripple/protocol/Feature.h>
21 #include <ripple/protocol/Quality.h>
22 #include <ripple/protocol/jss.h>
37 jvParams[jss::offer][jss::account] = acct.
human();
38 jvParams[jss::offer][jss::seq] = offer_seq;
40 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
52 ledgerOffer[jss::error].
asString() ==
"entryNotFound");
73 testcase(
"exercise partial cross new XRP/IOU offer Q change");
77 auto const gw =
Account{
"gateway"};
78 auto const alice =
Account{
"alice"};
79 auto const bob =
Account{
"bob"};
80 auto const USD = gw[
"USD"];
87 Env env{*
this, features};
90 env.fund(
XRP(10
'000'000), gw, alice, bob);
93 env(trust(alice, USD(10
'000'000)));
94 env(trust(bob, USD(10
'000'000)));
97 env(pay(gw, bob, USD(10
'000'000)));
105 auto exerciseOfferPair =
106 [
this, &env, &alice, &bob](
107 Amounts
const& inLedger,
108 Amounts
const& newOffer) ->
unsigned int {
111 env(offer(alice, inLedger.in, inLedger.out));
115 STAmount const initialRate = Quality(newOffer).rate();
117 STAmount const bobInitialBalance = env.balance(bob);
119 env(offer(bob, newOffer.in, newOffer.out,
tfSell),
122 STAmount const bobFinalBalance = env.balance(bob);
126 if (!BEAST_EXPECT(!
offerInLedger(env, alice, aliceOfferSeq)))
132 unsigned int badRate = 1;
142 env.balance(bob) + bobsFee - bobInitialBalance;
143 BEAST_EXPECT(reducedTakerPays < newOffer.in);
144 BEAST_EXPECT(reducedTakerGets < newOffer.out);
146 Quality(Amounts{reducedTakerPays, reducedTakerGets})
149 badRate = inLedgerRate > initialRate ? 1 : 0;
159 reducedTakerPays +
drops(1);
161 Quality(Amounts{tweakedTakerPays, reducedTakerGets})
163 BEAST_EXPECT(tweakedRate > initialRate);
166 std::cout <<
"Placed rate: " << initialRate
167 <<
"; in-ledger rate: " << inLedgerRate
168 <<
"; TakerPays: " << reducedTakerPays
169 <<
"; TakerGets: " << reducedTakerGets
170 <<
"; bob already got: " << bobGot <<
std::endl;
173 inLedgerRate > initialRate ?
"**" :
" ";
174 std::cout <<
"| `" << reducedTakerGets <<
"` | `"
175 << reducedTakerPays <<
"` | `" << initialRate
176 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
188 Amounts
const bobsOffer{
194 unsigned int blockedCount = 0;
196 mantissaReduce <= 5'000
'000'000ull;
197 mantissaReduce += 20
'000'000ull)
200 bobsOffer.out.
issue(),
201 bobsOffer.out.mantissa() - mantissaReduce,
202 bobsOffer.out.exponent()};
204 bobsOffer.in.
issue(), bobsOffer.in.mantissa() - 1};
205 Amounts alicesOffer{aliceUSD, aliceXRP};
206 blockedCount += exerciseOfferPair(alicesOffer, bobsOffer);
216 BEAST_EXPECT(blockedCount == 0);
220 BEAST_EXPECT(blockedCount >= 170);
228 testcase(
"exercise partial cross old XRP/IOU offer Q change");
232 auto const gw =
Account{
"gateway"};
233 auto const alice =
Account{
"alice"};
234 auto const bob =
Account{
"bob"};
235 auto const USD = gw[
"USD"];
243 Env env{*
this, features};
244 env.fund(
XRP(10
'000'000), gw, alice, bob);
247 env(trust(alice, USD(10
'000'000)));
248 env(trust(bob, USD(10
'000'000)));
251 env(pay(gw, alice, USD(10
'000'000)));
258 auto exerciseOfferPair =
259 [
this, &env, &alice, &bob](
260 Amounts
const& inLedger,
261 Amounts
const& newOffer) ->
unsigned int {
264 STAmount const initialRate = Quality(inLedger).rate();
266 env(offer(alice, inLedger.in, inLedger.out));
271 STAmount const aliceInitialBalance = env.balance(alice);
272 env(offer(bob, newOffer.in, newOffer.out));
274 STAmount const aliceFinalBalance = env.balance(alice);
282 env, alice, bob, aliceOfferSeq, bobOfferSeq);
287 unsigned int badRate = 1;
299 env.balance(alice) - aliceInitialBalance;
300 BEAST_EXPECT(reducedTakerPays < inLedger.in);
301 BEAST_EXPECT(reducedTakerGets < inLedger.out);
303 Quality(Amounts{reducedTakerPays, reducedTakerGets})
305 badRate = inLedgerRate > initialRate ? 1 : 0;
315 reducedTakerPays +
drops(1);
317 Quality(Amounts{tweakedTakerPays, reducedTakerGets})
319 BEAST_EXPECT(tweakedRate > initialRate);
322 std::cout <<
"Placed rate: " << initialRate
323 <<
"; in-ledger rate: " << inLedgerRate
324 <<
"; TakerPays: " << reducedTakerPays
325 <<
"; TakerGets: " << reducedTakerGets
326 <<
"; alice already got: " << aliceGot
330 std::cout <<
"| `" << reducedTakerGets <<
"` | `"
331 << reducedTakerPays <<
"` | `" << initialRate
332 <<
"` | " << filler <<
"`" << inLedgerRate <<
"`"
333 << filler <<
" | `" << aliceGot <<
"` |"
345 Amounts
const aliceOffer{
351 unsigned int blockedCount = 0;
353 mantissaReduce <= 4'000
'000'000ull;
354 mantissaReduce += 20
'000'000ull)
357 aliceOffer.out.
issue(),
358 aliceOffer.out.mantissa() - mantissaReduce,
359 aliceOffer.out.exponent()};
361 aliceOffer.in.
issue(), aliceOffer.in.mantissa() - 1};
362 Amounts bobsOffer{bobUSD, bobXRP};
364 blockedCount += exerciseOfferPair(aliceOffer, bobsOffer);
374 BEAST_EXPECT(blockedCount == 0);
378 BEAST_EXPECT(blockedCount > 10);
386 testcase(
"exercise underfunded XRP/IOU offer Q change");
394 auto const alice =
Account{
"alice"};
395 auto const bob =
Account{
"bob"};
397 auto const USD = gw[
"USD"];
404 Env env{*
this, features};
406 env.fund(
XRP(10000), alice, bob, gw);
408 env.trust(USD(1000), alice, bob);
410 int blockedOrderBookCount = 0;
411 for (
STAmount initialBobUSD = USD(0.45); initialBobUSD <= USD(1);
412 initialBobUSD += USD(0.025))
415 env(pay(gw, bob, initialBobUSD));
419 env(offer(bob,
drops(2), USD(1)));
425 env(offer(alice, USD(1),
drops(2)));
434 bool const bobsOfferGone =
436 STAmount const aliceBalanceUSD = env.balance(alice, USD);
439 if (aliceBalanceUSD.
signum() > 0)
441 BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
442 BEAST_EXPECT(env.balance(bob, USD) == USD(0));
443 BEAST_EXPECT(bobsOfferGone);
447 if (!bobsOfferGone && aliceBalanceUSD.
signum() == 0)
449 ++blockedOrderBookCount;
455 env, alice, bob, aliceOfferSeq, bobOfferSeq);
458 if (
STAmount const aliceBalance = env.balance(alice, USD);
459 aliceBalance.
signum() > 0)
460 env(pay(alice, gw, aliceBalance));
462 if (
STAmount const bobBalance = env.balance(bob, USD);
464 env(pay(bob, gw, bobBalance));
477 BEAST_EXPECT(blockedOrderBookCount == 0);
481 BEAST_EXPECT(blockedOrderBookCount > 15);
489 testcase(
"exercise underfunded IOU/IOU offer Q change");
497 using namespace std::chrono_literals;
498 auto const alice =
Account{
"alice"};
499 auto const bob =
Account{
"bob"};
502 auto const USD = gw[
"USD"];
503 auto const EUR = gw[
"EUR"];
505 STAmount const tinyUSD(USD.issue(), 1, -81);
512 Env env{*
this, features};
514 env.fund(
XRP(10000), alice, bob, gw);
516 env.trust(USD(1000), alice, bob);
517 env.trust(EUR(1000), alice, bob);
520 EUR.issue(), 2957, -76);
522 USD.issue(), 7109, -76);
525 USD.issue(), 50, -81);
527 int blockedOrderBookCount = 0;
528 for (
STAmount initialBobUSD = tinyUSD; initialBobUSD <= endLoop;
529 initialBobUSD += tinyUSD)
532 env(pay(gw, bob, initialBobUSD));
533 env(pay(gw, alice, EUR(100)));
538 env(offer(bob, eurOffer, usdOffer));
540 env.require(
offers(bob, 1));
544 env(offer(alice, usdOffer, eurOffer));
549 bool const bobsOfferGone =
551 STAmount aliceBalanceUSD = env.balance(alice, USD);
554 <<
"bobs initial: " << initialBobUSD
555 <<
"; alice final: " << aliceBalanceUSD
556 <<
"; bobs offer: " << bobsOfferJson.toStyledString()
560 if (aliceBalanceUSD.
signum() > 0)
562 BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
563 BEAST_EXPECT(env.balance(bob, USD) == USD(0));
564 BEAST_EXPECT(bobsOfferGone);
568 if (!bobsOfferGone && aliceBalanceUSD.
signum() == 0)
570 ++blockedOrderBookCount;
579 auto zeroBalance = [&env, &gw](
586 zeroBalance(alice, EUR);
587 zeroBalance(alice, USD);
588 zeroBalance(bob, EUR);
589 zeroBalance(bob, USD);
600 BEAST_EXPECT(blockedOrderBookCount == 0);
604 BEAST_EXPECT(blockedOrderBookCount > 20);