446 testcase(
"Rm small increased q offers MPT");
454 using namespace std::chrono_literals;
455 auto const alice =
Account{
"alice"};
456 auto const bob =
Account{
"bob"};
457 auto const carol =
Account{
"carol"};
460 auto test = [&](
auto&& issue1,
auto&& issue2) {
481 for (
auto crossBothOffers : {
false,
true})
483 Env env{*
this, features};
485 env.
fund(
XRP(10'000), alice, bob, carol, gw);
488 auto const usd = issue1(
492 .holders = {alice, bob, carol},
493 .
limit = 100'000'000});
494 auto const eur = issue2(
498 .holders = {alice, bob, carol},
499 .
limit = 100'000'000});
501 auto initialCarolUSD = tinyAmount(usd);
502 env(
pay(gw, carol, initialCarolUSD));
503 env(
pay(gw, bob, usd(100'000)));
504 env(
pay(gw, alice, eur(100'000)));
507 env(
offer(carol, eur(10), usd(10'000)));
510 env(
offer(bob, eur(10), usd(5'000), tfPassive));
517 auto aliceTakerGets = crossBothOffers ? eur(2) : eur(1);
518 env(
offer(alice, usd(1'000), aliceTakerGets));
526 auto const balanceCarolUSD = kIsEuriou ? usd(0) : initialCarolUSD;
537 auto const balanceAliceUSD = kIsEuriou ? usd(1) : usd(0);
543 for (
auto partialPayment : {
false,
true})
545 Env env{*
this, features};
547 env.
fund(
XRP(10'000), alice, bob, carol, gw);
550 auto const usd = issue1(
554 .holders = {alice, bob, carol},
555 .
limit = 100'000'000});
556 auto const eur = issue2(
560 .holders = {alice, bob, carol},
561 .
limit = 100'000'000});
563 auto const initialCarolUSD = tinyAmount(usd);
564 env(
pay(gw, carol, initialCarolUSD));
565 env(
pay(gw, bob, usd(100'000)));
566 env(
pay(gw, alice, eur(100'000)));
569 env(
offer(carol, eur(10), usd(2'000)));
571 env(
offer(bob, eur(20), usd(4'000), tfPassive));
576 partialPayment ? (tfNoRippleDirect | tfPartialPayment) : tfNoRippleDirect;
580 env(
pay(alice, bob, usd(5'000)),
594 auto const balanceCarolUSD = kIsEuriou ? usd(0) : initialCarolUSD;
2005 using namespace jtx;
2007 auto const gw =
Account(
"gateway");
2009 Env env{*
this, features};
2011 env.
fund(
XRP(10'000'000), gw);
2014 auto musd =
MPTTester({.env = env, .issuer = gw});
2015 MPT const usd = musd;
2018 auto const f = env.
current()->fees().base;
2021 enum class PreAuthType { NoPreAuth, AcctPreAuth };
2027 PreAuthType preAuth;
2038 TestData
const tests[]{
2040 {.account=
"ann", .fundXrp=
reserve(env, 0) + 0 * f, .bookAmount=1, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tecUNFUNDED_OFFER, .spentXrp=f, .balanceUsd=usd( 0), .offers=0, .owners=0},
2041 {.account=
"bev", .fundXrp=
reserve(env, 0) + 1 * f, .bookAmount=1, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tecUNFUNDED_OFFER, .spentXrp=f, .balanceUsd=usd( 0), .offers=0, .owners=0},
2042 {.account=
"cam", .fundXrp=
reserve(env, 0) + 2 * f, .bookAmount=0, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tecINSUF_RESERVE_OFFER, .spentXrp=f, .balanceUsd=usd( 0), .offers=0, .owners=0},
2043 {.account=
"deb", .fundXrp=
reserve(env, 0) + 2 * f, .bookAmount=1, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=2 * f, .balanceUsd=usd( 1), .offers=0, .owners=1, .scale=100000},
2044 {.account=
"eve", .fundXrp=
reserve(env, 1) + 0 * f, .bookAmount=0, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=f, .balanceUsd=usd( 0), .offers=1, .owners=1},
2045 {.account=
"flo", .fundXrp=
reserve(env, 1) + 0 * f, .bookAmount=1, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 1) + f, .balanceUsd=usd( 1), .offers=0, .owners=1},
2046 {.account=
"gay", .fundXrp=
reserve(env, 1) + 1 * f, .bookAmount=1000, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 50) + f, .balanceUsd=usd( 50), .offers=0, .owners=1},
2047 {.account=
"hye", .fundXrp=
XRP(1000) + 1 * f, .bookAmount=1000, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 800) + f, .balanceUsd=usd( 800), .offers=0, .owners=1},
2048 {.account=
"ivy", .fundXrp=
XRP( 1) +
reserve(env, 1) + 1 * f, .bookAmount=1, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 1) + f, .balanceUsd=usd( 1), .offers=0, .owners=1},
2049 {.account=
"joy", .fundXrp=
XRP( 1) +
reserve(env, 2) + 1 * f, .bookAmount=1, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 1) + f, .balanceUsd=usd( 1), .offers=1, .owners=2},
2050 {.account=
"kim", .fundXrp=
XRP( 900) +
reserve(env, 2) + 1 * f, .bookAmount=999, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 999) + f, .balanceUsd=usd( 999), .offers=0, .owners=1},
2051 {.account=
"liz", .fundXrp=
XRP( 998) +
reserve(env, 0) + 1 * f, .bookAmount=999, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 998) + f, .balanceUsd=usd( 998), .offers=0, .owners=1},
2052 {.account=
"meg", .fundXrp=
XRP( 998) +
reserve(env, 1) + 1 * f, .bookAmount=999, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 999) + f, .balanceUsd=usd( 999), .offers=0, .owners=1},
2053 {.account=
"nia", .fundXrp=
XRP( 998) +
reserve(env, 2) + 1 * f, .bookAmount=999, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 999) + f, .balanceUsd=usd( 999), .offers=1, .owners=2},
2054 {.account=
"ova", .fundXrp=
XRP( 999) +
reserve(env, 0) + 1 * f, .bookAmount=1000, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 999) + f, .balanceUsd=usd( 999), .offers=0, .owners=1},
2055 {.account=
"pam", .fundXrp=
XRP( 999) +
reserve(env, 1) + 1 * f, .bookAmount=1000, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP(1000) + f, .balanceUsd=usd( 1000), .offers=0, .owners=1},
2056 {.account=
"rae", .fundXrp=
XRP( 999) +
reserve(env, 2) + 1 * f, .bookAmount=1000, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP(1000) + f, .balanceUsd=usd( 1000), .offers=0, .owners=1},
2057 {.account=
"sue", .fundXrp=
XRP(1000) +
reserve(env, 2) + 1 * f, .bookAmount=0, .preAuth=PreAuthType::NoPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=f, .balanceUsd=usd( 0), .offers=1, .owners=1},
2060 {.account=
"ned", .fundXrp=
reserve(env, 1) + 0 * f, .bookAmount=1, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tecUNFUNDED_OFFER, .spentXrp=2 * f, .balanceUsd=usd( 0), .offers=0, .owners=1},
2061 {.account=
"ole", .fundXrp=
reserve(env, 1) + 1 * f, .bookAmount=1, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tecUNFUNDED_OFFER, .spentXrp=2 * f, .balanceUsd=usd( 0), .offers=0, .owners=1},
2062 {.account=
"pat", .fundXrp=
reserve(env, 1) + 2 * f, .bookAmount=0, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tecUNFUNDED_OFFER, .spentXrp=2 * f, .balanceUsd=usd( 0), .offers=0, .owners=1},
2063 {.account=
"quy", .fundXrp=
reserve(env, 1) + 2 * f, .bookAmount=1, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tecUNFUNDED_OFFER, .spentXrp=2 * f, .balanceUsd=usd( 0), .offers=0, .owners=1},
2064 {.account=
"ron", .fundXrp=
reserve(env, 1) + 3 * f, .bookAmount=0, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tecINSUF_RESERVE_OFFER, .spentXrp=2 * f, .balanceUsd=usd( 0), .offers=0, .owners=1},
2065 {.account=
"syd", .fundXrp=
reserve(env, 1) + 3 * f, .bookAmount=1, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=3 * f, .balanceUsd=usd( 1), .offers=0, .owners=1, .scale=100000},
2066 {.account=
"ted", .fundXrp=
XRP( 20) +
reserve(env, 1) + 2 * f, .bookAmount=1000, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP(20) + 2 * f, .balanceUsd=usd( 20), .offers=0, .owners=1},
2067 {.account=
"uli", .fundXrp=
reserve(env, 2) + 0 * f, .bookAmount=0, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tecINSUF_RESERVE_OFFER, .spentXrp=2 * f, .balanceUsd=usd( 0), .offers=0, .owners=1},
2068 {.account=
"vic", .fundXrp=
reserve(env, 2) + 0 * f, .bookAmount=1, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 1) + 2 * f, .balanceUsd=usd( 1), .offers=0, .owners=1},
2069 {.account=
"wes", .fundXrp=
reserve(env, 2) + 1 * f, .bookAmount=0, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=2 * f, .balanceUsd=usd( 0), .offers=1, .owners=2},
2070 {.account=
"xan", .fundXrp=
reserve(env, 2) + 1 * f, .bookAmount=1, .preAuth=PreAuthType::AcctPreAuth, .offerAmount=1000, .tec=
tesSUCCESS, .spentXrp=
XRP( 1) + 2 * f, .balanceUsd=usd( 1), .offers=1, .owners=2},
2074 for (
auto const& t :
tests)
2076 auto const acct =
Account(t.account);
2077 env.
fund(t.fundXrp, acct);
2084 auto const book = t.bookAmount;
2086 env(
offer(gw,
XRP(book), usd(book * t.scale)));
2093 if (t.preAuth == PreAuthType::AcctPreAuth)
2094 musd.authorize({.account = acct});
2099 auto const acctOffer = t.offerAmount;
2100 env(
offer(acct, usd(acctOffer * t.scale),
XRP(acctOffer)),
Ter(t.tec));
2105 auto const expBalanceUsd = [&]() {
2107 return t.balanceUsd;
2110 return usd(f.value() / 10);
2112 BEAST_EXPECT(env.
balance(acct, usd) == expBalanceUsd);
2113 BEAST_EXPECT(env.
balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2118 BEAST_EXPECT(acctOffers.size() == t.offers);
2119 if (!acctOffers.empty() && t.offers != 0)
2121 auto const& acctOffer = *(acctOffers.front());
2123 auto const leftover = t.offerAmount - t.bookAmount;
2124 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2125 BEAST_EXPECT(acctOffer[sfTakerPays] == usd(leftover));
2128 if (t.preAuth == PreAuthType::NoPreAuth)
2130 if (t.balanceUsd.value().signum() != 0)
2133 BEAST_EXPECT(env.
balance(acct, usd) == expBalanceUsd);
2460 using namespace jtx;
2462 auto const gw =
Account(
"gateway");
2464 Env env{*
this, features};
2466 env.
fund(
XRP(10'000'000), gw);
2468 auto musd =
MPTTester({.env = env, .issuer = gw});
2469 MPT const usd = musd;
2472 auto const f = env.
current()->fees().base;
2508 : account(std::move(account))
2509 , fundXrp(std::move(fundXrp))
2510 , fundUSD(std::move(fundUsd))
2511 , gwGets(std::move(gwGets))
2512 , gwPays(std::move(gwPays))
2513 , acctGets(std::move(acctGets))
2514 , acctPays(std::move(acctPays))
2516 , spentXrp(std::move(spentXrp))
2517 , finalUsd(std::move(finalUsd))
2520 , takerGets(std::move(takerGets))
2521 , takerPays(std::move(takerPays))
2559 TestData
const tests[]{
2562 {
"ann",
XRP(10) +
reserve(env, 0) + 1 * f, usd( 0),
XRP(10), usd( 5), usd(10),
XRP(10),
tecINSUF_RESERVE_OFFER,
XRP( 0) + (1 * f), usd( 0), 0, 0},
2563 {
"bev",
XRP(10) +
reserve(env, 1) + 1 * f, usd( 0),
XRP(10), usd( 5), usd(10),
XRP(10),
tesSUCCESS,
XRP( 0) + (1 * f), usd( 0), 1, 1,
XRP(10), usd(10)},
2564 {
"cam",
XRP(10) +
reserve(env, 0) + 1 * f, usd( 0),
XRP(10), usd(10), usd(10),
XRP(10),
tesSUCCESS,
XRP( 10) + (1 * f), usd(10), 0, 1},
2565 {
"deb",
XRP(10) +
reserve(env, 0) + 1 * f, usd( 0),
XRP(10), usd(20), usd(10),
XRP(10),
tesSUCCESS,
XRP( 10) + (1 * f), usd(20), 0, 1},
2566 {
"eve",
XRP(10) +
reserve(env, 0) + 1 * f, usd( 0),
XRP(10), usd(20), usd( 5),
XRP( 5),
tesSUCCESS,
XRP( 5) + (1 * f), usd(10), 0, 1},
2567 {
"flo",
XRP(10) +
reserve(env, 0) + 1 * f, usd( 0),
XRP(10), usd(20), usd(20),
XRP(20),
tesSUCCESS,
XRP( 10) + (1 * f), usd(20), 0, 1},
2568 {
"gay",
XRP(20) +
reserve(env, 1) + 1 * f, usd( 0),
XRP(10), usd(20), usd(20),
XRP(20),
tesSUCCESS,
XRP( 10) + (1 * f), usd(20), 0, 1},
2569 {
"hye",
XRP(20) +
reserve(env, 2) + 1 * f, usd( 0),
XRP(10), usd(20), usd(20),
XRP(20),
tesSUCCESS,
XRP( 10) + (1 * f), usd(20), 1, 2,
XRP(10), usd(10)},
2571 {
"meg",
reserve(env, 1) + 2 * f, usd(10), usd(10),
XRP( 5),
XRP(10), usd(10),
tecINSUF_RESERVE_OFFER,
XRP( 0) + (2 * f), usd(10), 0, 1},
2572 {
"nia",
reserve(env, 2) + 2 * f, usd(10), usd(10),
XRP( 5),
XRP(10), usd(10),
tesSUCCESS,
XRP( 0) + (2 * f), usd(10), 1, 2, usd(10),
XRP(10)},
2573 {
"ova",
reserve(env, 1) + 2 * f, usd(10), usd(10),
XRP(10),
XRP(10), usd(10),
tesSUCCESS,
XRP(-10) + (2 * f), usd( 0), 0, 1},
2574 {
"pam",
reserve(env, 1) + 2 * f, usd(10), usd(10),
XRP(20),
XRP(10), usd(10),
tesSUCCESS,
XRP(-20) + (2 * f), usd( 0), 0, 1},
2575 {
"qui",
reserve(env, 1) + 2 * f, usd(10), usd(20),
XRP(40),
XRP(10), usd(10),
tesSUCCESS,
XRP(-20) + (2 * f), usd( 0), 0, 1},
2576 {
"rae",
reserve(env, 2) + 2 * f, usd(10), usd( 5),
XRP( 5),
XRP(10), usd(10),
tesSUCCESS,
XRP( -5) + (2 * f), usd( 5), 1, 2, usd( 5),
XRP( 5)},
2577 {
"sue",
reserve(env, 2) + 2 * f, usd(10), usd( 5),
XRP(10),
XRP(10), usd(10),
tesSUCCESS,
XRP(-10) + (2 * f), usd( 5), 1, 2, usd( 5),
XRP( 5)},
2581 auto const zeroUsd = usd(0);
2582 for (
auto const& t :
tests)
2587 auto const acct =
Account(t.account);
2589 env.
fund(t.fundXrp, acct);
2595 if (t.fundUSD != zeroUsd)
2597 musd.authorize({.account = acct});
2599 env(
pay(gw, acct, t.fundUSD));
2603 env(
offer(gw, t.gwGets, t.gwPays));
2608 env(
offer(acct, t.acctGets, t.acctPays, tfSell),
Ter(t.tec));
2613 BEAST_EXPECT(env.
balance(acct, usd) == t.finalUsd);
2614 BEAST_EXPECT(env.
balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2621 if (!acctOffers.empty())
2623 BEAST_EXPECT(acctOffers.size() == 1);
2624 auto const& acctOffer = *(acctOffers.front());
2626 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2627 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2628 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
2723 using namespace jtx;
2724 auto const gw1 =
Account(
"gateway1");
2726 auto test = [&](
auto&& issue1,
auto&& issue2) {
2727 Env env{*
this, features};
2730 auto const fee = env.
current()->fees().base;
2736 issue1({.env = env, .token =
"USD", .issuer = gw1, .transferFee = 25'000});
2739 auto const ann =
Account(
"ann");
2740 auto const bob =
Account(
"bob");
2747 musd.authorize({.account = ann});
2748 musd.authorize({.account = bob});
2752 env(
trust(ann, usd(20'000)));
2753 env(
trust(bob, usd(20'000)));
2757 env(
pay(gw1, bob, usd(12'500)));
2766 env(
offer(bob,
XRP(1), usd(10'000)));
2769 env(
offer(ann, usd(10'000),
XRP(1)));
2784 auto const che =
Account(
"che");
2785 auto const deb =
Account(
"deb");
2792 musd.authorize({.account = che});
2793 musd.authorize({.account = deb});
2797 env(
trust(che, usd(20'000)));
2798 env(
trust(deb, usd(20'000)));
2802 env(
pay(gw1, deb, usd(12'500)));
2805 env(
offer(che, usd(10'000),
XRP(1)));
2808 env(
offer(deb,
XRP(1), usd(10'000)));
2820 auto const eve =
Account(
"eve");
2821 auto const fyn =
Account(
"fyn");
2823 env.
fund(
XRP(20'000) + (fee * 2), eve, fyn);
2829 musd.authorize({.account = eve});
2830 musd.authorize({.account = fyn});
2834 env(
trust(eve, usd(20'000)));
2835 env(
trust(fyn, usd(20'000)));
2839 env(
pay(gw1, eve, usd(10'000)));
2840 env(
pay(gw1, fyn, usd(10'000)));
2846 env(
offer(eve, usd(1'000),
XRP(4'000)));
2850 env(
offer(fyn,
XRP(2'000), usd(500)));
2856 BEAST_EXPECT(evesOffers.size() == 1);
2857 if (!evesOffers.empty())
2859 auto const& evesOffer = *(evesOffers.front());
2860 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
2861 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2'000));
2862 BEAST_EXPECT(evesOffer[sfTakerPays] == usd(500));
2871 auto const gw2 =
Account(
"gateway2");
2877 issue2({.env = env, .token =
"EUR", .issuer = gw2, .transferFee = 50'000});
2883 auto const gay =
Account(
"gay");
2884 auto const hal =
Account(
"hal");
2891 musd.authorize({.account = gay});
2892 musd.authorize({.account = hal});
2896 env(
trust(gay, usd(20'000)));
2897 env(
trust(hal, usd(20'000)));
2903 meur.authorize({.account = gay});
2904 meur.authorize({.account = hal});
2908 env(
trust(gay, eur(20'000)));
2909 env(
trust(hal, eur(20'000)));
2913 env(
pay(gw1, gay, usd(12'500)));
2914 env(
pay(gw2, hal, eur(150)));
2917 env(
offer(gay, eur(100), usd(10'000)));
2920 env(
offer(hal, usd(10'000), eur(100)));
2936 auto const ova =
Account(
"ova");
2937 auto const pat =
Account(
"pat");
2938 auto const qae =
Account(
"qae");
2948 musd.authorize({.account = ova});
2949 musd.authorize({.account = pat});
2950 musd.authorize({.account = qae});
2954 env(
trust(ova, usd(20'000)));
2955 env(
trust(pat, usd(20'000)));
2956 env(
trust(qae, usd(20'000)));
2962 meur.authorize({.account = ova});
2963 meur.authorize({.account = pat});
2964 meur.authorize({.account = qae});
2968 env(
trust(ova, eur(20'000)));
2969 env(
trust(pat, eur(20'000)));
2970 env(
trust(qae, eur(20'000)));
2974 env(
pay(gw1, ova, usd(12'500)));
2975 env(
pay(gw2, qae, eur(150)));
2978 env(
offer(ova,
XRP(2), usd(10'000)));
2982 env(
offer(qae, usd(10'000), eur(100)));
2991 if (!ovasOffers.empty())
2993 BEAST_EXPECT(ovasOffers.size() == 1);
2994 auto const& ovasOffer = *(ovasOffers.front());
2996 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
2997 BEAST_EXPECT(ovasOffer[sfTakerGets] == usd(0));
2998 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3019 auto const gw =
Account(
"gw_tr1");
3020 auto const alice =
Account(
"alice_tr1");
3021 auto const bob =
Account(
"bob_tr1");
3023 Env env{*
this, features};
3024 env.
fund(
XRP(10'000), gw, alice, bob);
3028 {.env = env, .issuer = gw, .holders = {alice, bob}, .transferFee = 25'000});
3031 env(
pay(gw, alice, usd(1'250)));
3033 env(
offer(bob, usd(1'000),
XRP(1'000)));
3044 BEAST_EXPECT(env.
balance(alice, usd) == usd(0));
3046 BEAST_EXPECT(env.
balance(bob, usd) == usd(1'000));
3056 auto const gw =
Account(
"gw_tr2");
3057 auto const gw2 =
Account(
"gw2_tr2");
3058 auto const alice =
Account(
"alice_tr2");
3059 auto const bob =
Account(
"bob_tr2");
3060 auto const carol =
Account(
"carol_tr2");
3062 Env env{*
this, features};
3063 env.
fund(
XRP(10'000), gw, gw2, alice, bob, carol);
3067 {.env = env, .issuer = gw, .holders = {bob, carol}, .transferFee = 25'000});
3068 auto const gusd = gw2[
"USD"];
3070 env(
trust(alice, gusd(10'000)));
3071 env(
trust(bob, gusd(10'000)));
3074 env(
pay(gw2, alice, gusd(1'000)));
3075 env(
pay(gw, bob, musd(1'000)));
3079 env(
offer(bob, gusd(1'000), musd(1'000)));
3081 env(
offer(carol, musd(800),
XRP(800)));
3093 BEAST_EXPECT(env.
balance(alice, gusd) == gusd(0));
3095 BEAST_EXPECT(env.
balance(bob, musd) == musd(0));
3097 BEAST_EXPECT(env.
balance(carol, musd) == musd(800));
4476 using namespace jtx;
4477 Account const issuer(
"issuer");
4481 auto test = [&](
auto&& issue1,
auto&& issue2) {
4482 Env env(*
this, features);
4485 env.
fund(
XRP(1'000), maker, taker);
4489 issue1({.env = env, .token =
"USD", .issuer = issuer, .holders = {maker, taker}});
4491 issue2({.env = env, .token =
"EUR", .issuer = issuer, .holders = {maker, taker}});
4493 env(
pay(issuer, maker, usd(1'000)));
4494 env(
pay(issuer, taker, usd(1'000)));
4495 env(
pay(issuer, maker, eur(1'000)));
4498 auto makerUSDBalance = env.
balance(maker, usd).
value();
4499 auto takerUSDBalance = env.
balance(taker, usd).
value();
4500 auto makerEURBalance = env.
balance(maker, eur).
value();
4501 auto takerEURBalance = env.
balance(taker, eur).
value();
4509 env(
offer(maker,
XRP(100), usd(100)));
4515 makerXRPBalance -=
txFee(env, 1);
4516 takerXRPBalance -=
txFee(env, 1);
4519 makerUSDBalance -= usd(100);
4520 takerUSDBalance += usd(100);
4521 makerXRPBalance +=
XRP(100).value();
4522 takerXRPBalance -=
XRP(100).value();
4526 env(
offer(maker, usd(100),
XRP(100)));
4532 makerXRPBalance -=
txFee(env, 1);
4533 takerXRPBalance -=
txFee(env, 1);
4536 makerUSDBalance += usd(100);
4537 takerUSDBalance -= usd(100);
4538 makerXRPBalance -=
XRP(100).value();
4539 takerXRPBalance +=
XRP(100).value();
4543 env(
offer(maker, usd(100), eur(100)));
4546 env(
offer(taker, eur(100), usd(101)),
Txflags(tfFillOrKill),
Ter(err));
4549 makerXRPBalance -=
txFee(env, 1);
4550 takerXRPBalance -=
txFee(env, 1);
4553 makerUSDBalance += usd(100);
4554 takerUSDBalance -= usd(100);
4555 makerEURBalance -= eur(100);
4556 takerEURBalance += eur(100);
4563 env(
offer(maker,
XRP(101), usd(101)));
4566 env(
offer(taker, usd(100),
XRP(101)),
Txflags(tfFillOrKill | tfSell));
4569 makerUSDBalance -= usd(101);
4570 takerUSDBalance += usd(101);
4571 makerXRPBalance +=
XRP(101).value() -
txFee(env, 1);
4572 takerXRPBalance -=
XRP(101).value() +
txFee(env, 1);
4575 env(
offer(maker, usd(101),
XRP(101)));
4578 env(
offer(taker,
XRP(100), usd(101)),
Txflags(tfFillOrKill | tfSell));
4581 makerUSDBalance += usd(101);
4582 takerUSDBalance -= usd(101);
4583 makerXRPBalance -=
XRP(101).value() +
txFee(env, 1);
4584 takerXRPBalance +=
XRP(101).value() -
txFee(env, 1);
4587 env(
offer(maker, usd(101), eur(101)));
4590 env(
offer(taker, eur(100), usd(101)),
Txflags(tfFillOrKill | tfSell));
4593 makerUSDBalance += usd(101);
4594 takerUSDBalance -= usd(101);
4595 makerEURBalance -= eur(101);
4596 takerEURBalance += eur(101);
4597 makerXRPBalance -=
txFee(env, 1);
4598 takerXRPBalance -=
txFee(env, 1);
4603 for (
auto const flags : {tfFillOrKill, tfFillOrKill + tfSell})
4605 env(
offer(maker,
XRP(100), usd(100)));
4611 makerXRPBalance -=
txFee(env, 1);
4612 takerXRPBalance -=
txFee(env, 1);
4615 env(
offer(maker, usd(100),
XRP(100)));
4621 makerXRPBalance -=
txFee(env, 1);
4622 takerXRPBalance -=
txFee(env, 1);
4625 env(
offer(maker, usd(100), eur(100)));
4631 makerXRPBalance -=
txFee(env, 1);
4632 takerXRPBalance -=
txFee(env, 1);
4637 env.
balance(maker, usd) == makerUSDBalance &&
4638 env.
balance(taker, usd) == takerUSDBalance &&
4639 env.
balance(maker, eur) == makerEURBalance &&
4640 env.
balance(taker, eur) == takerEURBalance &&
4641 env.
balance(maker,
XRP) == makerXRPBalance &&
4652 using namespace jtx;
4654 auto const gw =
Account{
"gateway"};
4655 auto const alice =
Account{
"alice"};
4660 auto const iou = gw[name];
4661 env(
trust(alice, iou(1'000)));
4662 env(
pay(gw, alice, iou(100)));
4668 MPTTester({.env = env, .issuer = gw, .holders = {alice}, .pay = 1'000'000'000});
4685 {.toAsset1 = getIOU, .toAsset2 = getIOU, .val1 = 10, .val2 = 30},
4686 {.toAsset1 = getIOU, .toAsset2 = getXRP, .val1 = 10, .val2 = 30'000'000},
4687 {.toAsset1 = getXRP, .toAsset2 = getIOU, .val1 = 10'000'000, .val2 = 30},
4688 {.toAsset1 = getMPT, .toAsset2 = getXRP, .val1 = 10'000'000, .val2 = 30'000'000},
4689 {.toAsset1 = getXRP, .toAsset2 = getMPT, .val1 = 10'000'000, .val2 = 30'000'000},
4690 {.toAsset1 = getIOU, .toAsset2 = getMPT, .val1 = 10, .val2 = 30'000'000},
4691 {.toAsset1 = getMPT, .toAsset2 = getIOU, .val1 = 10'000'000, .val2 = 30},
4692 {.toAsset1 = getMPT, .toAsset2 = getMPT, .val1 = 10'000'000, .val2 = 30'000'000}};
4693 for (TestInfo
const& t :
tests)
4695 Env env{*
this, features};
4696 env.
fund(
XRP(10'000), gw, alice);
4699 auto const xts = t.toAsset1(env);
4700 auto const xxx = t.toAsset2(env);
4703 return asset.raw().visit(
4704 [&](
Issue const& issue) {
return issue.
native() ?
"XRPIssue" :
"Issue"; },
4705 [&](
MPTIssue const&) {
return "MPTIssue"; });
4708 testcase <<
"offer: " << tokenType(xts) <<
"/" << tokenType(xxx);
4712 auto txn =
noop(gw);
4713 txn[sfTickSize.fieldName] = 5;
4715 BEAST_EXPECT((*env.
le(gw))[sfTickSize] == 5);
4718 env(
offer(alice, xts(t.val1), xxx(t.val2)));
4719 env(
offer(alice, xts(t.val2), xxx(t.val1)));
4720 env(
offer(alice, xts(t.val1), xxx(t.val2)),
Json(jss::Flags, tfSell));
4721 env(
offer(alice, xts(t.val2), xxx(t.val1)),
Json(jss::Flags, tfSell));
4725 if (sle->getType() == ltOFFER)
4729 std::make_pair((*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4734 auto it =
offers.begin();
4735 BEAST_EXPECT(it !=
offers.end());
4736 if (xxx.native() && !xts.holds<
MPTIssue>())
4739 it->second.first == xts(t.val1) && it->second.second ==
XRPAmount(29'999'400));
4741 else if (!xxx.integral())
4744 it->second.first == xts(t.val1) && it->second.second < xxx(t.val2) &&
4745 it->second.second >
STAmount(xxx, 29'9994, -4));
4749 BEAST_EXPECT(it->second.first == xts(t.val1) && it->second.second == xxx(t.val2));
4754 BEAST_EXPECT(it !=
offers.end());
4755 BEAST_EXPECT(it->second.first == xts(t.val2) && it->second.second == xxx(t.val1));
4759 BEAST_EXPECT(it !=
offers.end());
4760 if (xts.native() && !xxx.holds<
MPTIssue>())
4763 it->second.first ==
XRPAmount(10'000'200) && it->second.second == xxx(t.val2));
4765 else if (!xts.integral())
4768 it->second.first ==
STAmount(xts, 10'0002, -4) &&
4769 it->second.second == xxx(t.val2));
4773 BEAST_EXPECT(it->second.first == xts(t.val1) && it->second.second == xxx(t.val2));
4779 BEAST_EXPECT(it !=
offers.end());
4780 BEAST_EXPECT(it->second.first == xts(t.val2) && it->second.second == xxx(t.val1));
4782 BEAST_EXPECT(++it ==
offers.end());