3025 using namespace jtx;
3030 features = features - featureSingleAssetVault - featureLendingProtocol;
3036 [&](
AMM& ammAlice,
Env& env) {
3037 ammAlice.
deposit(carol, 1'000'000);
3038 env(ammAlice.
bid({.account = carol, .bidMin = 110}));
3051 [&](
AMM& ammAlice,
Env& env) {
3052 ammAlice.
deposit(carol, 1'000'000);
3055 {.account = carol, .bidMin = 110, .bidMax = 110}));
3061 {.account = alice, .bidMin = 180, .bidMax = 200}));
3064 XRP(11'000), USD(11'000),
IOUAmount{10'999'814'5, -1}));
3073 [&](
AMM& ammAlice,
Env& env) {
3074 ammAlice.
deposit(carol, 1'000'000);
3076 env(ammAlice.
bid({.account = carol, .bidMin = 110}));
3079 fund(env, gw, {bob}, {USD(10'000)}, Fund::Acct);
3080 ammAlice.
deposit(bob, 1'000'000);
3082 env(ammAlice.
bid({.account = bob}));
3093 env(ammAlice.
bid({.account = carol, .bidMax = 600}));
3107 {.account = carol, .bidMin = 100, .bidMax = 600}));
3118 [&](
AMM& ammAlice,
Env& env) {
3119 ammAlice.
deposit(carol, 1'000'000);
3121 fund(env, gw, {bob}, {USD(10'000)}, Fund::Acct);
3122 ammAlice.
deposit(bob, 1'000'000);
3123 if (!features[fixAMMv1_3])
3133 env(ammAlice.
bid({.account = carol, .bidMin = 110})).
close();
3137 env(ammAlice.
bid({.account = bob}));
3143 env(ammAlice.
bid({.account = carol}));
3149 env(ammAlice.
bid({.account = bob}));
3158 env(ammAlice.
bid({.account = carol, .bidMin = 110})).
close();
3162 if (!features[fixAMMv1_3])
3183 [&](
AMM& ammAlice,
Env& env) {
3186 fund(env, gw, {bob, dan, ed}, {USD(20'000)}, Fund::Acct);
3187 ammAlice.
deposit(bob, 1'000'000);
3188 ammAlice.
deposit(ed, 1'000'000);
3189 ammAlice.
deposit(carol, 500'000);
3190 ammAlice.
deposit(dan, 500'000);
3195 .authAccounts = {bob, ed},
3197 auto const slotPrice =
IOUAmount{5'200};
3198 ammTokens -= slotPrice;
3200 if (!features[fixAMMv1_3])
3202 XRP(13'000), USD(13'000), ammTokens));
3205 XRPAmount{13'000'000'003}, USD(13'000), ammTokens));
3207 for (
int i = 0; i < 10; ++i)
3209 auto tokens = ammAlice.
deposit(carol, USD(100));
3210 ammAlice.
withdraw(carol, tokens, USD(0));
3211 tokens = ammAlice.
deposit(bob, USD(100));
3212 ammAlice.
withdraw(bob, tokens, USD(0));
3213 tokens = ammAlice.
deposit(ed, USD(100));
3214 ammAlice.
withdraw(ed, tokens, USD(0));
3217 if (!features[fixAMMv1_1])
3221 STAmount(USD, UINT64_C(29'499'00572620545), -11));
3224 STAmount(USD, UINT64_C(18'999'00572616195), -11));
3227 STAmount(USD, UINT64_C(18'999'00572611841), -11));
3231 STAmount(USD, UINT64_C(13'002'98282151419), -11),
3238 STAmount(USD, UINT64_C(29'499'00572620544), -11));
3241 STAmount(USD, UINT64_C(18'999'00572616194), -11));
3244 STAmount(USD, UINT64_C(18'999'0057261184), -10));
3246 if (!features[fixAMMv1_3])
3249 STAmount(USD, UINT64_C(13'002'98282151422), -11),
3254 STAmount(USD, UINT64_C(13'002'98282151422), -11),
3259 for (
int i = 0; i < 10; ++i)
3261 auto const tokens = ammAlice.
deposit(dan, USD(100));
3262 ammAlice.
withdraw(dan, tokens, USD(0));
3267 if (!features[fixAMMv1_1])
3271 STAmount(USD, UINT64_C(19'490'056722744), -9));
3275 STAmount{USD, UINT64_C(13'012'92609877019), -11},
3278 ammAlice.
deposit(carol, USD(100));
3282 STAmount{USD, UINT64_C(13'112'92609877019), -11},
3284 env(pay(carol, bob, USD(100)),
3292 STAmount{USD, UINT64_C(13'012'92609877019), -11},
3297 if (!features[fixAMMv1_3])
3300 STAmount(USD, UINT64_C(19'490'05672274399), -11));
3304 STAmount(USD, UINT64_C(19'490'05672274398), -11));
3306 if (!features[fixAMMv1_3])
3309 STAmount{USD, UINT64_C(13'012'92609877023), -11},
3314 STAmount{USD, UINT64_C(13'012'92609877024), -11},
3317 ammAlice.
deposit(carol, USD(100));
3319 if (!features[fixAMMv1_3])
3322 STAmount{USD, UINT64_C(13'112'92609877023), -11},
3327 STAmount{USD, UINT64_C(13'112'92609877024), -11},
3329 env(pay(carol, bob, USD(100)),
3335 if (!features[fixAMMv1_3])
3338 STAmount{USD, UINT64_C(13'012'92609877023), -11},
3343 STAmount{USD, UINT64_C(13'012'92609877024), -11},
3352 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
3356 STAmount{USD, UINT64_C(13'114'03663047264), -11},
3359 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
3363 STAmount{USD, UINT64_C(13'114'03663047269), -11},
3370 STAmount{USD, UINT64_C(13'114'03663044937), -11},
3377 if (!features[fixAMMv1_1])
3380 STAmount(USD, UINT64_C(29'399'00572620545), -11));
3381 else if (!features[fixAMMv1_3])
3384 STAmount(USD, UINT64_C(29'399'00572620544), -11));
3386 for (
int i = 0; i < 10; ++i)
3388 auto const tokens = ammAlice.
deposit(carol, USD(100));
3389 ammAlice.
withdraw(carol, tokens, USD(0));
3393 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
3397 STAmount(USD, UINT64_C(29'389'06197177128), -11));
3400 STAmount{USD, UINT64_C(13'123'98038490681), -11},
3403 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
3407 STAmount(USD, UINT64_C(29'389'06197177124), -11));
3410 STAmount{USD, UINT64_C(13'123'98038490689), -11},
3417 STAmount(USD, UINT64_C(29'389'06197177129), -11));
3420 STAmount{USD, UINT64_C(13'123'98038488352), -11},
3428 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
3432 STAmount{USD, UINT64_C(13'023'98038490681), -11},
3435 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
3439 STAmount{USD, UINT64_C(13'023'98038490689), -11},
3446 STAmount{USD, UINT64_C(13'023'98038488352), -11},
3457 [&](AMM& ammAlice, Env& env) {
3460 Number{STAmount::cMinValue, STAmount::cMinOffset};
3462 {.account = alice, .bidMin = IOUAmount{tiny}}));
3465 BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{tiny}));
3467 BEAST_EXPECT(ammAlice.expectBalances(
3468 XRP(10'000), USD(10'000), ammAlice.tokens()));
3473 IOUAmount{STAmount::cMinValue, STAmount::cMinOffset},
3476 BEAST_EXPECT(ammAlice.expectAuctionSlot(
3477 0, 0, IOUAmount{tiny * Number{105, -2}}));
3480 BEAST_EXPECT(ammAlice.expectBalances(
3481 XRP(10'000), USD(10'000), ammAlice.tokens()));
3490 [&](AMM& ammAlice, Env& env) {
3493 .bidMin = IOUAmount{100},
3494 .authAccounts = {carol},
3496 BEAST_EXPECT(ammAlice.expectAuctionSlot({carol}));
3497 env(ammAlice.bid({.account = alice, .bidMin = IOUAmount{100}}));
3498 BEAST_EXPECT(ammAlice.expectAuctionSlot({}));
3501 fund(env, {bob, dan},
XRP(1'000));
3504 .bidMin = IOUAmount{100},
3505 .authAccounts = {bob, dan},
3507 BEAST_EXPECT(ammAlice.expectAuctionSlot({bob, dan}));
3516 Env env(*
this, features);
3517 fund(env, gw, {alice, bob},
XRP(2'000), {USD(2'000)});
3518 AMM amm(env, gw,
XRP(1'000), USD(1'010),
false, 1'000);
3519 auto const lpIssue =
amm.lptIssue();
3520 env.trust(STAmount{lpIssue, 500}, alice);
3521 env.trust(STAmount{lpIssue, 50}, bob);
3522 env(
pay(gw, alice, STAmount{lpIssue, 500}));
3523 env(
pay(gw, bob, STAmount{lpIssue, 50}));
3525 env(
amm.bid({.account = alice, .bidMin = 500}));
3526 BEAST_EXPECT(
amm.expectAuctionSlot(100, 0, IOUAmount{500}));
3527 BEAST_EXPECT(
expectHolding(env, alice, STAmount{lpIssue, 0}));
3530 env(
pay(alice, bob, USD(10)), path(~USD), sendmax(
XRP(11)));
3531 BEAST_EXPECT(
amm.expectBalances(
3532 XRPAmount{1'010'010'011},
3534 IOUAmount{1'004'487'562112089, -9}));
3536 env(
pay(bob, alice,
XRP(10)), path(~XRP), sendmax(USD(11)));
3537 if (!features[fixAMMv1_1])
3539 BEAST_EXPECT(
amm.expectBalances(
3540 XRPAmount{1'000'010'011},
3541 STAmount{USD, UINT64_C(1'010'10090898081), -11},
3542 IOUAmount{1'004'487'562112089, -9}));
3546 BEAST_EXPECT(
amm.expectBalances(
3547 XRPAmount{1'000'010'011},
3548 STAmount{USD, UINT64_C(1'010'100908980811), -12},
3549 IOUAmount{1'004'487'562112089, -9}));
3555 Env env(*
this, features);
3556 auto const baseFee = env.current()->fees().base;
3558 fund(env, gw, {alice, bob},
XRP(2'000), {USD(2'000)});
3559 AMM amm(env, gw,
XRP(1'000), USD(1'010),
false, 1'000);
3563 auto jtx = env.jt(tx, seq(1), fee(baseFee));
3564 env.app().config().features.erase(featureAMM);
3565 PreflightContext pfCtx(
3568 env.current()->rules(),
3571 auto pf = Transactor::invokePreflight<AMMBid>(pfCtx);
3572 BEAST_EXPECT(pf == temDISABLED);
3573 env.app().config().features.insert(featureAMM);
3577 auto jtx = env.jt(tx, seq(1), fee(baseFee));
3578 jtx.jv[
"TxnSignature"] =
"deadbeef";
3579 jtx.stx = env.ust(jtx);
3580 PreflightContext pfCtx(
3583 env.current()->rules(),
3586 auto pf = Transactor::invokePreflight<AMMBid>(pfCtx);
3587 BEAST_EXPECT(pf != tesSUCCESS);
3591 auto jtx = env.jt(tx, seq(1), fee(baseFee));
3592 jtx.jv[
"Asset2"][
"currency"] =
"XRP";
3593 jtx.jv[
"Asset2"].removeMember(
"issuer");
3594 jtx.stx = env.ust(jtx);
3595 PreflightContext pfCtx(
3598 env.current()->rules(),
3601 auto pf = Transactor::invokePreflight<AMMBid>(pfCtx);
3602 BEAST_EXPECT(pf == temBAD_AMM_TOKENS);
3773 testcase(
"Basic Payment");
3774 using namespace jtx;
3778 features = features - featureSingleAssetVault - featureLendingProtocol -
3779 featureLendingProtocol;
3784 [&](
AMM& ammAlice,
Env& env) {
3785 env.
fund(jtx::XRP(30'000), bob);
3787 env(pay(bob, carol, USD(100)),
3793 XRP(10'100), USD(10'000), ammAlice.
tokens()));
3798 env, bob,
XRP(30'000) -
XRP(100) -
txfee(env, 1)));
3800 {{
XRP(10'000), USD(10'100)}},
3807 [&](
AMM& ammAlice,
Env& env) {
3808 env.
fund(jtx::XRP(30'000), bob);
3810 env(pay(bob, carol, USD(100)),
sendmax(
XRP(100)));
3813 XRP(10'100), USD(10'000), ammAlice.
tokens()));
3818 env, bob,
XRP(30'000) -
XRP(100) -
txfee(env, 1)));
3820 {{
XRP(10'000), USD(10'100)}},
3828 [&](
AMM& ammAlice,
Env& env) {
3829 env.
fund(jtx::XRP(30'000), bob);
3834 XRP(10'100), USD(10'000), ammAlice.
tokens()));
3839 env, bob,
XRP(30'000) -
XRP(100) -
txfee(env, 1)));
3841 {{
XRP(10'000), USD(10'100)}},
3848 [&](
AMM& ammAlice,
Env& env) {
3849 env.
fund(jtx::XRP(30'000), bob);
3853 env(pay(bob, carol, USD(100)),
3860 XRP(10'010), USD(10'000), ammAlice.
tokens()));
3866 env, bob,
XRP(30'000) -
XRP(10) -
txfee(env, 1)));
3870 env(pay(bob, carol, USD(100)),
3878 {{
XRP(10'000), USD(10'010)}},
3885 [&](
AMM& ammAlice,
Env& env) {
3888 env.
fund(jtx::XRP(30'000), bob);
3893 env(pay(bob, carol, USD(100)),
3900 XRP(10'010), USD(10'000), ammAlice.
tokens()));
3905 STAmount{USD, UINT64_C(30'009'09090909091), -11}));
3907 env, bob,
XRP(30'000) -
XRP(10) -
txfee(env, 1)));
3909 {{
XRP(10'000), USD(10'010)}},
3916 [&](
AMM& ammAlice,
Env& env) {
3917 env.
fund(jtx::XRP(30'000), bob);
3919 env(pay(bob, carol, USD(100)),
3925 {{
XRP(10'000), USD(10'000)}},
3935 Env env(*
this, features);
3937 env, gw, {alice, carol}, {USD(30'000), EUR(30'000)}, Fund::All);
3941 auto ammEUR_XRP =
AMM(env, alice,
XRP(10'000), EUR(10'000));
3942 auto ammUSD_EUR =
AMM(env, alice, EUR(10'000), USD(10'000));
3945 env(pay(bob, carol, USD(100)),
3950 BEAST_EXPECT(ammEUR_XRP.expectBalances(
3952 STAmount(EUR, UINT64_C(9'970'007498125468), -12),
3953 ammEUR_XRP.tokens()));
3954 if (!features[fixAMMv1_1])
3956 BEAST_EXPECT(ammUSD_EUR.expectBalances(
3957 STAmount(USD, UINT64_C(9'970'097277662122), -12),
3958 STAmount(EUR, UINT64_C(10'029'99250187452), -11),
3959 ammUSD_EUR.tokens()));
3962 Amounts
const expectedAmounts =
3963 env.
closed()->rules().enabled(fixReducedOffersV2)
3964 ? Amounts{
XRPAmount(30'201'749),
STAmount(USD, UINT64_C(29'90272233787816), -14)}
3967 STAmount(USD, UINT64_C(29'90272233787818), -14)};
3969 BEAST_EXPECT(
expectOffers(env, alice, 1, {{expectedAmounts}}));
3973 BEAST_EXPECT(ammUSD_EUR.expectBalances(
3974 STAmount(USD, UINT64_C(9'970'097277662172), -12),
3975 STAmount(EUR, UINT64_C(10'029'99250187452), -11),
3976 ammUSD_EUR.tokens()));
3979 Amounts
const expectedAmounts =
3980 env.
closed()->rules().enabled(fixReducedOffersV2)
3981 ? Amounts{
XRPAmount(30'201'749),
STAmount(USD, UINT64_C(29'90272233782839), -14)}
3984 STAmount(USD, UINT64_C(29'90272233782840), -14)};
3986 BEAST_EXPECT(
expectOffers(env, alice, 1, {{expectedAmounts}}));
4002 [&](
AMM& ammAlice,
Env& env) {
4005 env.
trust(EUR(2'000), alice);
4007 env(pay(gw, alice, EUR(1'000)));
4012 env(pay(bob, carol, USD(100)),
4019 STAmount(USD, UINT64_C(9'950'01249687578), -11),
4027 STAmount(EUR, UINT64_C(49'98750312422), -11)},
4029 STAmount(EUR, UINT64_C(49'98750312422), -11),
4030 STAmount(USD, UINT64_C(49'98750312422), -11)}}}));
4035 STAmount{USD, UINT64_C(30'099'99999999999), -11}));
4052 [&](
AMM& ammAlice,
Env& env) {
4053 fund(env, gw, {bob}, {USD(100)}, Fund::Acct);
4057 env(pay(alice, carol, USD(200)),
4061 if (!features[fixAMMv1_1])
4064 XRP(10'100), USD(10'000), ammAlice.
tokens()));
4072 STAmount(USD, UINT64_C(10'000'00000000001), -11),
4077 STAmount(USD, UINT64_C(30'199'99999999999), -11)));
4085 ammCrtFee(env) -
txfee(env, 1)));
4088 {{
XRP(10'000), USD(10'100)}},
4097 Env env(*
this, features);
4098 fund(env, gw, {alice, bob, carol},
XRP(20'000), {USD(2'000)});
4102 AMM ammAlice(env, alice,
XRP(1'000), USD(1'050));
4103 env(pay(alice, carol, USD(200)),
4108 XRP(1'050), USD(1'000), ammAlice.
tokens()));
4115 [&](
AMM& ammAlice,
Env& env) {
4116 fund(env, gw, {bob}, {USD(1'000)}, Fund::Acct);
4118 env(offer(bob, USD(100),
XRP(100)));
4121 XRP(10'100), USD(10'000), ammAlice.
tokens()));
4126 env, bob,
XRP(30'000) -
XRP(100) -
txfee(env, 1)));
4129 {{
XRP(10'000), USD(10'100)}},
4137 [&](
AMM& ammAlice,
Env& env) {
4138 env(rate(gw, 1.25));
4144 env(offer(carol, EUR(100), GBP(100)));
4148 GBP(1'100), EUR(1'000), ammAlice.
tokens()));
4155 {{GBP(1'000), EUR(1'100)}},
4161 [&](
AMM& amm,
Env& env) {
4162 env(rate(gw, 1.001));
4164 env(offer(carol,
XRP(100), USD(55)));
4166 if (!features[fixAMMv1_1])
4176 amm.expectBalances(
XRP(1'000), USD(500), amm.tokens()));
4178 env, carol, 1, {{Amounts{
XRP(100), USD(55)}}}));
4189 BEAST_EXPECT(amm.expectBalances(
4191 STAmount{USD, UINT64_C(550'000000055), -9},
4200 STAmount{USD, 4'99999995, -8}}}}));
4204 STAmount(USD, UINT64_C(29'949'94999999494), -11));
4207 {{
XRP(1'000), USD(500)}},
4212 [&](
AMM& amm,
Env& env) {
4213 env(rate(gw, 1.001));
4215 env(offer(carol,
XRP(10), USD(5.5)));
4217 if (!features[fixAMMv1_1])
4219 BEAST_EXPECT(amm.expectBalances(
4221 STAmount{USD, UINT64_C(505'050505050505), -12},
4227 BEAST_EXPECT(amm.expectBalances(
4229 STAmount{USD, UINT64_C(505'0505050505051), -13},
4234 {{
XRP(1'000), USD(500)}},
4240 [&](
AMM& ammAlice,
Env& env) {
4247 {GBP(2'000), EUR(2'000)},
4249 env(rate(gw, 1.25));
4260 env(offer(carol, EUR(100), GBP(100)));
4262 if (!features[fixAMMv1_1])
4271 STAmount{GBP, UINT64_C(1'037'06583722133), -11},
4272 STAmount{EUR, UINT64_C(1'060'684828792831), -12},
4280 STAmount{EUR, UINT64_C(50'684828792831), -12},
4281 STAmount{GBP, UINT64_C(50'684828792831), -12}}}));
4293 STAmount{GBP, UINT64_C(29'941'16770347333), -11}));
4298 STAmount{EUR, UINT64_C(30'049'31517120716), -11}));
4310 STAmount{GBP, UINT64_C(1'060'684828792832), -12},
4311 STAmount{EUR, UINT64_C(1'037'06583722134), -11},
4319 STAmount{EUR, UINT64_C(27'06583722134028), -14},
4320 STAmount{GBP, UINT64_C(27'06583722134028), -14}}}));
4332 STAmount{GBP, UINT64_C(29'911'64396400896), -11}));
4337 STAmount{EUR, UINT64_C(30'072'93416277865), -11}));
4344 {{GBP(1'000), EUR(1'100)}},
4357 [&](
AMM& ammAlice,
Env& env) {
4358 fund(env, gw, {bob}, {GBP(200), EUR(200)}, Fund::Acct);
4359 env(rate(gw, 1.25));
4361 env(pay(bob, carol, EUR(100)),
4367 GBP(1'100), EUR(1'000), ammAlice.
tokens()));
4371 {{GBP(1'000), EUR(1'100)}},
4388 [&](
AMM& ammAlice,
Env& env) {
4391 auto const CAN = gw[
"CAN"];
4392 fund(env, gw, {dan}, {CAN(200), GBP(200)}, Fund::Acct);
4393 fund(env, gw, {ed}, {EUR(200), USD(200)}, Fund::Acct);
4394 fund(env, gw, {bob}, {CAN(195.3125)}, Fund::Acct);
4395 env(trust(carol, USD(100)));
4396 env(rate(gw, 1.25));
4398 env(offer(dan, CAN(200), GBP(200)));
4399 env(offer(ed, EUR(200), USD(200)));
4401 env(pay(bob, carol, USD(100)),
4402 path(~GBP, ~EUR, ~USD),
4407 BEAST_EXPECT(
expectHolding(env, dan, CAN(356.25), GBP(43.75)));
4409 GBP(10'125), EUR(10'000), ammAlice.
tokens()));
4413 {{GBP(10'000), EUR(10'125)}},
4420 [&](
AMM& ammAlice,
Env& env) {
4421 env(pay(alice, carol, USD(99.99)),
4426 env(pay(alice, carol, USD(100)),
4431 env(pay(alice, carol,
XRP(100)),
4442 {{
XRP(100), USD(100)}},
4449 Env env(*
this, features);
4450 auto const ETH = gw[
"ETH"];
4456 {EUR(50'000), BTC(50'000), ETH(50'000), USD(50'000)});
4457 fund(env, gw, {carol, bob},
XRP(1'000), {USD(200)}, Fund::Acct);
4458 AMM xrp_eur(env, alice,
XRP(10'100), EUR(10'000));
4459 AMM eur_btc(env, alice, EUR(10'000), BTC(10'200));
4460 AMM btc_usd(env, alice, BTC(10'100), USD(10'000));
4461 AMM xrp_usd(env, alice,
XRP(10'150), USD(10'200));
4462 AMM xrp_eth(env, alice,
XRP(10'000), ETH(10'100));
4463 AMM eth_eur(env, alice, ETH(10'900), EUR(11'000));
4464 AMM eur_usd(env, alice, EUR(10'100), USD(10'000));
4465 env(pay(bob, carol, USD(100)),
4466 path(~EUR, ~BTC, ~USD),
4468 path(~ETH, ~EUR, ~USD),
4470 if (!features[fixAMMv1_1])
4476 STAmount{ETH, UINT64_C(10'073'65779244494), -11},
4479 STAmount{ETH, UINT64_C(10'926'34220755506), -11},
4480 STAmount{EUR, UINT64_C(10'973'54232078752), -11},
4483 STAmount{EUR, UINT64_C(10'126'45767921248), -11},
4484 STAmount{USD, UINT64_C(9'973'93151712086), -11},
4490 STAmount{USD, UINT64_C(10'126'06848287914), -11},
4497 STAmount{ETH, UINT64_C(10'073'65779244461), -11},
4500 STAmount{ETH, UINT64_C(10'926'34220755539), -11},
4501 STAmount{EUR, UINT64_C(10'973'5423207872), -10},
4504 STAmount{EUR, UINT64_C(10'126'4576792128), -10},
4505 STAmount{USD, UINT64_C(9'973'93151712057), -11},
4511 STAmount{USD, UINT64_C(10'126'06848287943), -11},
4521 BEAST_EXPECT(xrp_eur.expectBalances(
4522 XRP(10'100), EUR(10'000), xrp_eur.tokens()));
4524 EUR(10'000), BTC(10'200), eur_btc.
tokens()));
4526 BTC(10'100), USD(10'000), btc_usd.
tokens()));
4533 Env env(*
this, features);
4534 auto const ETH = gw[
"ETH"];
4540 {EUR(50'000), BTC(50'000), ETH(50'000), USD(50'000)});
4541 fund(env, gw, {carol, bob},
XRP(1000), {USD(200)}, Fund::Acct);
4542 AMM xrp_eur(env, alice,
XRP(10'100), EUR(10'000));
4543 AMM eur_btc(env, alice, EUR(10'000), BTC(10'200));
4544 AMM btc_usd(env, alice, BTC(10'100), USD(10'000));
4545 AMM xrp_eth(env, alice,
XRP(10'000), ETH(10'100));
4546 AMM eth_eur(env, alice, ETH(10'900), EUR(11'000));
4547 env(pay(bob, carol, USD(100)),
4548 path(~EUR, ~BTC, ~USD),
4549 path(~ETH, ~EUR, ~BTC, ~USD),
4551 if (!features[fixAMMv1_1])
4555 BEAST_EXPECT(xrp_eur.expectBalances(
4557 STAmount{EUR, UINT64_C(9'981'544436337968), -12},
4560 STAmount{EUR, UINT64_C(10'101'16096785173), -11},
4561 STAmount{BTC, UINT64_C(10'097'91426968066), -11},
4564 STAmount{BTC, UINT64_C(10'202'08573031934), -11},
4569 STAmount{ETH, UINT64_C(10'017'41072778012), -11},
4572 STAmount{ETH, UINT64_C(10'982'58927221988), -11},
4573 STAmount{EUR, UINT64_C(10'917'2945958103), -10},
4578 BEAST_EXPECT(xrp_eur.expectBalances(
4580 STAmount{EUR, UINT64_C(9'981'544436337923), -12},
4583 STAmount{EUR, UINT64_C(10'101'16096785188), -11},
4584 STAmount{BTC, UINT64_C(10'097'91426968059), -11},
4587 STAmount{BTC, UINT64_C(10'202'08573031941), -11},
4592 STAmount{ETH, UINT64_C(10'017'41072777996), -11},
4595 STAmount{ETH, UINT64_C(10'982'58927222004), -11},
4596 STAmount{EUR, UINT64_C(10'917'2945958102), -10},
4605 [&](
AMM& ammAlice,
Env& env) {
4607 fund(env, gw, {bob}, {EUR(400)}, Fund::IOUOnly);
4608 env(trust(alice, EUR(200)));
4609 for (
int i = 0; i < 30; ++i)
4610 env(offer(alice, EUR(1.0 + 0.01 * i),
XRP(1)));
4613 env(offer(alice, EUR(140),
XRP(100)));
4614 env(pay(bob, carol, USD(100)),
4618 if (!features[fixAMMv1_1])
4623 STAmount{USD, UINT64_C(9'970'089730807577), -12},
4628 STAmount{USD, UINT64_C(30'029'91026919241), -11}));
4634 STAmount{USD, UINT64_C(9'970'089730807827), -12},
4639 STAmount{USD, UINT64_C(30'029'91026919217), -11}));
4650 [&](
AMM& ammAlice,
Env& env) {
4652 fund(env, gw, {bob}, {EUR(400)}, Fund::IOUOnly);
4653 env(trust(alice, EUR(200)));
4654 for (
int i = 0; i < 29; ++i)
4655 env(offer(alice, EUR(1.0 + 0.01 * i),
XRP(1)));
4658 env(offer(alice, EUR(140),
XRP(100)));
4659 env(pay(bob, carol, USD(100)),
4665 if (!features[fixAMMv1_1])
4671 STAmount{USD, UINT64_C(30'099'99999999999), -11}));
4681 {{{
STAmount{EUR, UINT64_C(39'1858572), -7},
4692 Env env(*
this, features);
4693 fund(env, gw, {alice, carol, bob},
XRP(30'000), {USD(30'000)});
4694 env(offer(bob,
XRP(100), USD(100.001)));
4695 AMM ammAlice(env, alice,
XRP(10'000), USD(10'100));
4696 env(offer(carol, USD(100),
XRP(100)));
4697 if (!features[fixAMMv1_1])
4701 STAmount{USD, UINT64_C(10'049'92586949302), -11},
4708 STAmount{USD, UINT64_C(50'07513050698), -11}}}}));
4714 STAmount{USD, UINT64_C(10'049'92587049303), -11},
4721 STAmount{USD, UINT64_C(50'07512950697), -11}}}}));
4728 [&](
AMM& ammAlice,
Env& env) {
4732 env(pay(alice, carol, USD(1)),
5028 testcase(
"Trading Fee");
5029 using namespace jtx;
5033 [&](
AMM& ammAlice,
Env& env) {
5035 ammAlice.
deposit(carol, USD(3'000));
5041 ammAlice.
vote(alice, 1'000);
5045 ammAlice.
deposit(carol, USD(3'000));
5047 carol,
IOUAmount{994'981155689671, -12}));
5050 ammAlice.
vote(alice, 0);
5056 STAmount{USD, UINT64_C(29'994'96220068281), -11}));
5058 {{USD(1'000), EUR(1'000)}},
5066 [&](
AMM& ammAlice,
Env& env) {
5068 auto tokensFee = ammAlice.
deposit(
5072 ammAlice.
vote(alice, 0);
5074 auto const tokensNoFee = ammAlice.
deposit(carol, deposit);
5077 BEAST_EXPECT(tokensFee ==
IOUAmount(485'636'0611129, -7));
5078 BEAST_EXPECT(tokensNoFee ==
IOUAmount(487'644'85901109, -8));
5088 [&](
AMM& ammAlice,
Env& env) {
5090 auto const tokensFee = ammAlice.
deposit(
5094 ammAlice.
vote(alice, 0);
5096 auto const tokensNoFee = ammAlice.
deposit(carol, deposit);
5099 BEAST_EXPECT(tokensFee ==
IOUAmount(98'000'00000002, -8));
5100 BEAST_EXPECT(tokensNoFee ==
IOUAmount(98'475'81871545, -8));
5109 [&](
AMM& ammAlice,
Env& env) {
5111 ammAlice.
deposit(carol, USD(3'000));
5116 ammAlice.
vote(alice, 1'000);
5123 STAmount{USD, UINT64_C(29'994'97487437186), -11}));
5125 {{USD(1'000), EUR(1'000)}},
5132 [&](
AMM& ammAlice,
Env& env) {
5133 ammAlice.
deposit(carol, 1'000'000);
5134 auto const tokensFee = ammAlice.
withdraw(
5137 auto const balanceAfterWithdraw = [&]() {
5138 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
5139 return STAmount(USD, UINT64_C(30'443'43891402715), -11);
5140 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
5141 return STAmount(USD, UINT64_C(30'443'43891402714), -11);
5143 return STAmount(USD, UINT64_C(30'443'43891402713), -11);
5145 BEAST_EXPECT(env.
balance(carol, USD) == balanceAfterWithdraw);
5147 auto const deposit = balanceAfterWithdraw - USD(29'000);
5148 ammAlice.
deposit(carol, deposit);
5150 ammAlice.
vote(alice, 0);
5152 auto const tokensNoFee = ammAlice.
withdraw(carol, deposit);
5153 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
5156 STAmount(USD, UINT64_C(30'443'43891402717), -11));
5157 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
5160 STAmount(USD, UINT64_C(30'443'43891402716), -11));
5164 STAmount(USD, UINT64_C(30'443'43891402713), -11));
5167 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
5169 tokensNoFee ==
IOUAmount(746'579'80779913, -8));
5170 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
5172 tokensNoFee ==
IOUAmount(746'579'80779912, -8));
5175 tokensNoFee ==
IOUAmount(746'579'80779911, -8));
5176 BEAST_EXPECT(tokensFee ==
IOUAmount(750'588'23529411, -8));
5185 [&](
AMM& ammAlice,
Env& env) {
5191 {USD(1'000), EUR(1'000)},
5198 env(pay(carol, alice, EUR(10)),
5209 ammAlice.
vote(alice, 1'000);
5212 env(pay(bob, carol, USD(10)),
5219 env, bob,
STAmount{EUR, UINT64_C(989'8989898989899), -13}));
5224 STAmount{EUR, UINT64_C(1'010'10101010101), -11},
5227 {{USD(1'000), EUR(1'010)}},
5234 [&](
AMM& ammAlice,
Env& env) {
5236 env(offer(carol, EUR(10), USD(10)));
5241 env(offer(carol, USD(10), EUR(10)));
5244 ammAlice.
vote(alice, 500);
5246 env(offer(carol, EUR(10), USD(10)));
5253 STAmount{USD, UINT64_C(29'995'02512562814), -11}));
5257 STAmount{EUR, UINT64_C(30'004'97487437186), -11}));
5263 STAmount{EUR, UINT64_C(5'025125628140703), -15},
5264 STAmount{USD, UINT64_C(5'025125628140703), -15}}}}));
5265 if (!features[fixAMMv1_1])
5268 STAmount{USD, UINT64_C(1'004'974874371859), -12},
5269 STAmount{EUR, UINT64_C(1'005'025125628141), -12},
5275 STAmount{USD, UINT64_C(1'004'97487437186), -11},
5276 STAmount{EUR, UINT64_C(1'005'025125628141), -12},
5280 {{USD(1'000), EUR(1'010)}},
5290 Env env(*
this, features);
5295 {alice, bob, carol, ed},
5297 {USD(2'000), EUR(2'000)});
5298 env(offer(carol, EUR(5), USD(5)));
5299 AMM ammAlice(env, alice, USD(1'005), EUR(1'000));
5300 env(pay(bob, ed, USD(10)),
5305 if (!features[fixAMMv1_1])
5309 USD(1'000), EUR(1'005), ammAlice.
tokens()));
5314 env, bob,
STAmount(EUR, UINT64_C(1989'999999999999), -12)));
5317 STAmount(EUR, UINT64_C(1005'000000000001), -12),
5326 Env env(*
this, features);
5331 {alice, bob, carol, ed},
5333 {USD(2'000), EUR(2'000)});
5334 env(offer(carol, EUR(5), USD(5)));
5336 AMM ammAlice(env, alice, USD(1'005), EUR(1'000),
false, 250);
5337 env(pay(bob, ed, USD(10)),
5342 if (!features[fixAMMv1_1])
5347 STAmount{EUR, UINT64_C(1'989'987453007618), -12}));
5350 STAmount{EUR, UINT64_C(1'005'012546992382), -12},
5358 STAmount{EUR, UINT64_C(1'989'987453007628), -12}));
5361 STAmount{EUR, UINT64_C(1'005'012546992372), -12},
5371 Env env(*
this, features);
5376 {alice, bob, carol, ed},
5378 {USD(2'000), EUR(2'000)});
5379 env(offer(carol, EUR(10), USD(10)));
5381 AMM ammAlice(env, alice, USD(1'005), EUR(1'000),
false, 1'000);
5382 env(pay(bob, ed, USD(10)),
5389 USD(1'005), EUR(1'000), ammAlice.
tokens()));
5398 Env env(*
this, features);
5403 {alice, bob, carol, ed},
5405 {USD(2'000), EUR(2'000)});
5406 env(offer(carol, EUR(9), USD(9)));
5408 AMM ammAlice(env, alice, USD(1'005), EUR(1'000),
false, 1'000);
5409 env(pay(bob, ed, USD(10)),
5415 env, bob,
STAmount{EUR, UINT64_C(1'989'993923296712), -12}));
5418 STAmount{EUR, UINT64_C(1'001'006076703288), -12},
5826 testcase(
"Offer/Strand Selection");
5827 using namespace jtx;
5830 auto const ETH = gw1[
"ETH"];
5831 auto const CAN = gw1[
"CAN"];
5837 auto prep = [&](
Env& env,
auto gwRate,
auto gw1Rate) {
5838 fund(env, gw, {alice, carol, bob, ed},
XRP(2'000), {USD(2'000)});
5843 {alice, carol, bob, ed},
5844 {ETH(2'000), CAN(2'000)},
5846 env(rate(gw, gwRate));
5847 env(rate(gw1, gw1Rate));
5851 for (
auto const& rates :
5866 for (
auto i = 0; i < 3; ++i)
5868 Env env(*
this, features);
5869 prep(env, rates.first, rates.second);
5871 if (i == 0 || i == 2)
5877 amm.emplace(env, ed, USD(1'000), ETH(1'000));
5878 env(pay(carol, bob, USD(100)),
5885 BEAST_EXPECT(amm->expectBalances(
5886 USD(1'000), ETH(1'000), amm->tokens()));
5889 q[i] = Quality(Amounts{
5890 ETH(2'000) - env.
balance(carol, ETH),
5891 env.
balance(bob, USD) - USD(2'000)});
5894 BEAST_EXPECT(q[0] > q[1]);
5896 BEAST_EXPECT(q[0] == q[2]);
5903 for (
auto i = 0; i < 3; ++i)
5905 Env env(*
this, features);
5906 prep(env, rates.first, rates.second);
5908 if (i == 0 || i == 2)
5914 amm.emplace(env, ed, USD(1'000), ETH(1'000));
5915 env(offer(alice, USD(400), ETH(400)));
5920 BEAST_EXPECT(amm->expectBalances(
5921 USD(1'000), ETH(1'000), amm->tokens()));
5923 if (i == 0 || i == 2)
5932 env, alice, 1, {Amounts{USD(400), ETH(400)}}));
5943 for (
auto i = 0; i < 3; ++i)
5945 Env env(*
this, features);
5946 prep(env, rates.first, rates.second);
5948 if (i == 0 || i == 2)
5954 amm.emplace(env, ed, USD(1'000), ETH(1'000));
5955 env(pay(carol, bob, USD(100)),
5962 BEAST_EXPECT(!amm->expectBalances(
5963 USD(1'000), ETH(1'000), amm->tokens()));
5965 if (i == 2 && !features[fixAMMv1_1])
5967 if (rates.first == 1.5)
5969 if (!features[fixAMMv1_1])
5977 UINT64_C(378'6327949540823),
5981 UINT64_C(283'9745962155617),
5991 UINT64_C(378'6327949540813),
5995 UINT64_C(283'974596215561),
6000 if (!features[fixAMMv1_1])
6008 UINT64_C(325'299461620749),
6012 UINT64_C(243'9745962155617),
6022 UINT64_C(325'299461620748),
6026 UINT64_C(243'974596215561),
6032 if (rates.first == 1.5)
6040 ETH, UINT64_C(378'6327949540812), -13},
6043 UINT64_C(283'9745962155609),
6054 ETH, UINT64_C(325'2994616207479), -13},
6057 UINT64_C(243'9745962155609),
6062 q[i] = Quality(Amounts{
6063 ETH(2'000) - env.
balance(carol, ETH),
6064 env.
balance(bob, USD) - USD(2'000)});
6067 BEAST_EXPECT(q[1] > q[0]);
6069 BEAST_EXPECT(q[2] > q[1]);
6073 for (
auto i = 0; i < 3; ++i)
6075 Env env(*
this, features);
6076 prep(env, rates.first, rates.second);
6078 if (i == 0 || i == 2)
6084 amm.emplace(env, ed, USD(1'000), ETH(1'000));
6085 env(offer(alice, USD(250), ETH(400)));
6090 BEAST_EXPECT(!amm->expectBalances(
6091 USD(1'000), ETH(1'000), amm->tokens()));
6097 if (rates.first == 1.5)
6099 if (!features[fixAMMv1_1])
6102 env, ed, 1, {{Amounts{ETH(400), USD(250)}}}));
6109 USD, UINT64_C(40'5694150420947), -13},
6111 ETH, UINT64_C(64'91106406735152), -14},
6125 ETH, UINT64_C(335'0889359326475), -13},
6127 USD, UINT64_C(209'4305849579047), -13},
6134 if (!features[fixAMMv1_1])
6143 ETH, UINT64_C(335'0889359326485), -13},
6145 USD, UINT64_C(209'4305849579053), -13},
6158 ETH, UINT64_C(335'0889359326475), -13},
6160 USD, UINT64_C(209'4305849579047), -13},
6186 for (
auto i = 0; i < 3; ++i)
6188 Env env(*
this, features);
6189 prep(env, rates.first, rates.second);
6192 if (i == 0 || i == 2)
6200 amm.emplace(env, ed, ETH(1'000), USD(1'000));
6202 env(pay(carol, bob, USD(100)),
6210 if (i == 2 && !features[fixAMMv1_1])
6212 if (rates.first == 1.5)
6215 BEAST_EXPECT(amm->expectBalances(
6216 STAmount{ETH, UINT64_C(1'176'66038955758), -11},
6222 BEAST_EXPECT(amm->expectBalances(
6224 ETH, UINT64_C(1'179'540094339627), -12},
6225 STAmount{USD, UINT64_C(847'7880529867501), -13},
6234 UINT64_C(343'3179205198749),
6238 UINT64_C(343'3179205198749),
6244 UINT64_C(362'2119470132499),
6248 UINT64_C(362'2119470132499),
6255 if (rates.first == 1.5)
6258 BEAST_EXPECT(amm->expectBalances(
6260 ETH, UINT64_C(1'176'660389557593), -12},
6266 BEAST_EXPECT(amm->expectBalances(
6267 STAmount{ETH, UINT64_C(1'179'54009433964), -11},
6268 STAmount{USD, UINT64_C(847'7880529867501), -13},
6277 UINT64_C(343'3179205198749),
6281 UINT64_C(343'3179205198749),
6287 UINT64_C(362'2119470132499),
6291 UINT64_C(362'2119470132499),
6296 q[i] = Quality(Amounts{
6297 ETH(2'000) - env.
balance(carol, ETH),
6298 env.
balance(bob, USD) - USD(2'000)});
6300 BEAST_EXPECT(q[1] > q[0]);
6301 BEAST_EXPECT(q[2] > q[0] && q[2] < q[1]);
6409 testcase(
"Fix changeSpotPriceQuality");
6410 using namespace jtx;
6415 SucceedShouldSucceedResize,
6427 auto const xrpIouAmounts10_100 =
6429 auto const iouXrpAmounts10_100 =
6434 {
"0.001519763260828713",
"1558701", Quality{5414253689393440221}, 1000, FailShouldSucceed},
6435 {
"0.01099814367603737",
"1892611", Quality{5482264816516900274}, 1000, FailShouldSucceed},
6436 {
"0.78",
"796599", Quality{5630392334958379008}, 1000, FailShouldSucceed},
6437 {
"105439.2955578965",
"49398693", Quality{5910869983721805038}, 400, FailShouldSucceed},
6438 {
"12408293.23445213",
"4340810521", Quality{5911611095910090752}, 997, FailShouldSucceed},
6439 {
"1892611",
"0.01099814367603737", Quality{6703103457950430139}, 1000, FailShouldSucceed},
6440 {
"423028.8508101858",
"3392804520", Quality{5837920340654162816}, 600, FailShouldSucceed},
6441 {
"44565388.41001027",
"73890647", Quality{6058976634606450001}, 1000, FailShouldSucceed},
6442 {
"66831.68494832662",
"16", Quality{6346111134641742975}, 0, FailShouldSucceed},
6443 {
"675.9287302203422",
"1242632304", Quality{5625960929244093294}, 300, FailShouldSucceed},
6444 {
"7047.112186735699",
"1649845866", Quality{5696855348026306945}, 504, FailShouldSucceed},
6445 {
"840236.4402981238",
"47419053", Quality{5982561601648018688}, 499, FailShouldSucceed},
6446 {
"992715.618909774",
"189445631733", Quality{5697835648288106944}, 815, SucceedShouldSucceedResize},
6447 {
"504636667521",
"185545883.9506651", Quality{6343802275337659280}, 503, SucceedShouldSucceedResize},
6448 {
"992706.7218636649",
"189447316000", Quality{5697835648288106944}, 797, SucceedShouldSucceedResize},
6449 {
"1.068737911388205",
"127860278877", Quality{5268604356368739396}, 293, SucceedShouldSucceedResize},
6450 {
"17932506.56880419",
"189308.6043676173", Quality{6206460598195440068}, 311, SucceedShouldSucceedResize},
6451 {
"1.066379294658174",
"128042251493", Quality{5268559341368739328}, 270, SucceedShouldSucceedResize},
6452 {
"350131413924",
"1576879.110907892", Quality{6487411636539049449}, 650,
Fail},
6453 {
"422093460",
"2.731797662057464", Quality{6702911108534394924}, 1000,
Fail},
6454 {
"76128132223",
"367172.7148422662", Quality{6487263463413514240}, 548,
Fail},
6455 {
"132701839250",
"280703770.7695443", Quality{6273750681188885075}, 562,
Fail},
6456 {
"994165.7604612011",
"189551302411", Quality{5697835592690668727}, 815,
Fail},
6457 {
"45053.33303227917",
"86612695359", Quality{5625695218943638190}, 500,
Fail},
6458 {
"199649.077043865",
"14017933007", Quality{5766034667318524880}, 324,
Fail},
6459 {
"27751824831.70903",
"78896950", Quality{6272538159621630432}, 500,
Fail},
6460 {
"225.3731275781907",
"156431793648", Quality{5477818047604078924}, 989,
Fail},
6461 {
"199649.077043865",
"14017933007", Quality{5766036094462806309}, 324,
Fail},
6462 {
"3.590272027140361",
"20677643641", Quality{5406056147042156356}, 808,
Fail},
6463 {
"1.070884664490231",
"127604712776", Quality{5268620608623825741}, 293,
Fail},
6464 {
"3272.448829820197",
"6275124076", Quality{5625710328924117902}, 81,
Fail},
6465 {
"0.009059512633902926",
"7994028", Quality{5477511954775533172}, 1000,
Fail},
6466 {
"1",
"1.0", Quality{0}, 100,
Fail},
6467 {
"1.0",
"1", Quality{0}, 100,
Fail},
6468 {
"10",
"10.0", Quality{xrpIouAmounts10_100}, 100,
Fail},
6469 {
"10.0",
"10", Quality{iouXrpAmounts10_100}, 100,
Fail},
6470 {
"69864389131",
"287631.4543025075", Quality{6487623473313516078}, 451, Succeed},
6471 {
"4328342973",
"12453825.99247381", Quality{6272522264364865181}, 997, Succeed},
6472 {
"32347017",
"7003.93031579449", Quality{6347261126087916670}, 1000, Succeed},
6473 {
"61697206161",
"36631.4583206413", Quality{6558965195382476659}, 500, Succeed},
6474 {
"1654524979",
"7028.659825511603", Quality{6487551345110052981}, 504, Succeed},
6475 {
"88621.22277293179",
"5128418948", Quality{5766347291552869205}, 380, Succeed},
6476 {
"1892611",
"0.01099814367603737", Quality{6703102780512015436}, 1000, Succeed},
6477 {
"4542.639373338766",
"24554809", Quality{5838994982188783710}, 0, Succeed},
6478 {
"5132932546",
"88542.99750172683", Quality{6419203342950054537}, 380, Succeed},
6479 {
"78929964.1549083",
"1506494795", Quality{5986890029845558688}, 589, Succeed},
6480 {
"10096561906",
"44727.72453735605", Quality{6487455290284644551}, 250, Succeed},
6481 {
"5092.219565514988",
"8768257694", Quality{5626349534958379008}, 503, Succeed},
6482 {
"1819778294",
"8305.084302902864", Quality{6487429398998540860}, 415, Succeed},
6483 {
"6970462.633911943",
"57359281", Quality{6054087899185946624}, 850, Succeed},
6484 {
"3983448845",
"2347.543644281467", Quality{6558965195382476659}, 856, Succeed},
6488 {
"771493171",
"1.243473020567508", Quality{6707566798038544272}, 100, SucceedShouldFail},
6492 boost::regex rx(
"^\\d+$");
6493 boost::smatch match;
6497 auto rules = env.
current()->rules();
6501 for (
auto const& t : tests)
6511 auto const poolInIsXRP =
6513 auto const poolOutIsXRP =
6515 assert(!(poolInIsXRP && poolOutIsXRP));
6516 auto const poolIn = getPool(
std::get<0>(t), poolInIsXRP);
6517 auto const poolOut = getPool(
std::get<1>(t), poolOutIsXRP);
6521 Amounts{poolIn, poolOut},
6528 if (status == SucceedShouldSucceedResize)
6530 if (!features[fixAMMv1_1])
6531 BEAST_EXPECT(Quality{*amounts} < quality);
6533 BEAST_EXPECT(Quality{*amounts} >= quality);
6535 else if (status == Succeed)
6537 if (!features[fixAMMv1_1])
6539 Quality{*amounts} >= quality ||
6541 Quality{*amounts}, quality,
Number{1, -7}));
6543 BEAST_EXPECT(Quality{*amounts} >= quality);
6545 else if (status == FailShouldSucceed)
6548 features[fixAMMv1_1] &&
6549 Quality{*amounts} >= quality);
6551 else if (status == SucceedShouldFail)
6554 !features[fixAMMv1_1] &&
6555 Quality{*amounts} < quality &&
6557 Quality{*amounts}, quality,
Number{1, -7}));
6566 if (status ==
Fail && quality != Quality{0})
6568 auto tinyOffer = [&]() {
6575 Amounts{poolIn, poolOut},
6579 else if (
isXRP(poolOut))
6584 Amounts{poolIn, poolOut},
6589 auto const takerPays = toAmount<STAmount>(
6594 Amounts{poolIn, poolOut}, takerPays, tfee)};
6596 BEAST_EXPECT(Quality(tinyOffer) < quality);
6598 else if (status == FailShouldSucceed)
6600 BEAST_EXPECT(!features[fixAMMv1_1]);
6602 else if (status == SucceedShouldFail)
6604 BEAST_EXPECT(features[fixAMMv1_1]);
6611 !strcmp(e.
what(),
"changeSpotPriceQuality failed"));
6613 !features[fixAMMv1_1] && status == FailShouldSucceed);
6622 BEAST_EXPECT(!res.has_value());
6688 using namespace jtx;
6694 Account const gatehub{
"gatehub"};
6695 Account const bitstamp{
"bitstamp"};
6696 Account const trader{
"trader"};
6697 auto const usdGH = gatehub[
"USD"];
6698 auto const btcGH = gatehub[
"BTC"];
6699 auto const usdBIT = bitstamp[
"USD"];
6703 char const* testCase;
6704 double const poolUsdBIT;
6705 double const poolUsdGH;
6718 double const offer1BtcGH = 0.1;
6719 double const offer2BtcGH = 0.1;
6720 double const offer2UsdGH = 1;
6721 double const rateBIT = 0.0;
6722 double const rateGH = 0.0;
6727 for (
auto const& input : {
6729 .testCase =
"Test Fix Overflow Offer",
6732 .sendMaxUsdBIT{usdBIT(50)},
6733 .sendUsdGH{usdGH,
uint64_t(272'455089820359), -12},
6736 .failUsdBIT{usdBIT,
uint64_t(46'47826086956522), -14},
6737 .failUsdBITr{usdBIT,
uint64_t(46'47826086956521), -14},
6738 .goodUsdGH{usdGH,
uint64_t(96'7543114220382), -13},
6739 .goodUsdGHr{usdGH,
uint64_t(96'7543114222965), -13},
6740 .goodUsdBIT{usdBIT,
uint64_t(8'464739069120721), -15},
6741 .goodUsdBITr{usdBIT,
uint64_t(8'464739069098152), -15},
6742 .lpTokenBalance = {28'61817604250837, -14},
6743 .lpTokenBalanceAlt =
IOUAmount{28'61817604250836, -14},
6751 .testCase =
"Overflow test {1, 100, 0.111}",
6754 .sendMaxUsdBIT{usdBIT(0.111)},
6755 .sendUsdGH{usdGH, 100},
6758 .failUsdBIT{usdBIT,
uint64_t(1'111), -3},
6759 .failUsdBITr{usdBIT,
uint64_t(1'111), -3},
6760 .goodUsdGH{usdGH,
uint64_t(90'04347888284115), -14},
6761 .goodUsdGHr{usdGH,
uint64_t(90'04347888284201), -14},
6762 .goodUsdBIT{usdBIT,
uint64_t(1'111), -3},
6763 .goodUsdBITr{usdBIT,
uint64_t(1'111), -3},
6764 .lpTokenBalance{10, 0},
6765 .offer1BtcGH = 1e-5,
6767 .offer2UsdGH = 1e-5,
6772 .testCase =
"Overflow test {1, 100, 1.00}",
6775 .sendMaxUsdBIT{usdBIT(1.00)},
6776 .sendUsdGH{usdGH, 100},
6779 .failUsdBIT{usdBIT,
uint64_t(2), 0},
6780 .failUsdBITr{usdBIT,
uint64_t(2), 0},
6781 .goodUsdGH{usdGH,
uint64_t(52'94379354424079), -14},
6782 .goodUsdGHr{usdGH,
uint64_t(52'94379354424135), -14},
6783 .goodUsdBIT{usdBIT,
uint64_t(2), 0},
6784 .goodUsdBITr{usdBIT,
uint64_t(2), 0},
6785 .lpTokenBalance{10, 0},
6786 .offer1BtcGH = 1e-5,
6788 .offer2UsdGH = 1e-5,
6793 .testCase =
"Overflow test {1, 100, 4.6432}",
6796 .sendMaxUsdBIT{usdBIT(4.6432)},
6797 .sendUsdGH{usdGH, 100},
6800 .failUsdBIT{usdBIT,
uint64_t(5'6432), -4},
6801 .failUsdBITr{usdBIT,
uint64_t(5'6432), -4},
6802 .goodUsdGH{usdGH,
uint64_t(35'44113971506987), -14},
6803 .goodUsdGHr{usdGH,
uint64_t(35'44113971506987), -14},
6804 .goodUsdBIT{usdBIT,
uint64_t(2'821579689703915), -15},
6805 .goodUsdBITr{usdBIT,
uint64_t(2'821579689703954), -15},
6806 .lpTokenBalance{10, 0},
6807 .offer1BtcGH = 1e-5,
6809 .offer2UsdGH = 1e-5,
6814 .testCase =
"Overflow test {1, 100, 10}",
6817 .sendMaxUsdBIT{usdBIT(10)},
6818 .sendUsdGH{usdGH, 100},
6821 .failUsdBIT{usdBIT,
uint64_t(11), 0},
6822 .failUsdBITr{usdBIT,
uint64_t(11), 0},
6823 .goodUsdGH{usdGH,
uint64_t(35'44113971506987), -14},
6824 .goodUsdGHr{usdGH,
uint64_t(35'44113971506987), -14},
6825 .goodUsdBIT{usdBIT,
uint64_t(2'821579689703915), -15},
6826 .goodUsdBITr{usdBIT,
uint64_t(2'821579689703954), -15},
6827 .lpTokenBalance{10, 0},
6828 .offer1BtcGH = 1e-5,
6830 .offer2UsdGH = 1e-5,
6835 .testCase =
"Overflow test {50, 100, 5.55}",
6838 .sendMaxUsdBIT{usdBIT(5.55)},
6839 .sendUsdGH{usdGH, 100},
6842 .failUsdBIT{usdBIT,
uint64_t(55'55), -2},
6843 .failUsdBITr{usdBIT,
uint64_t(55'55), -2},
6844 .goodUsdGH{usdGH,
uint64_t(90'04347888284113), -14},
6845 .goodUsdGHr{usdGH,
uint64_t(90'0434788828413), -13},
6846 .goodUsdBIT{usdBIT,
uint64_t(55'55), -2},
6847 .goodUsdBITr{usdBIT,
uint64_t(55'55), -2},
6848 .lpTokenBalance{
uint64_t(70'71067811865475), -14},
6849 .offer1BtcGH = 1e-5,
6851 .offer2UsdGH = 1e-5,
6856 .testCase =
"Overflow test {50, 100, 50.00}",
6859 .sendMaxUsdBIT{usdBIT(50.00)},
6860 .sendUsdGH{usdGH, 100},
6861 .failUsdGH{usdGH,
uint64_t(52'94379354424081), -14},
6862 .failUsdGHr{usdGH,
uint64_t(52'94379354424092), -14},
6863 .failUsdBIT{usdBIT,
uint64_t(100), 0},
6864 .failUsdBITr{usdBIT,
uint64_t(100), 0},
6865 .goodUsdGH{usdGH,
uint64_t(52'94379354424081), -14},
6866 .goodUsdGHr{usdGH,
uint64_t(52'94379354424092), -14},
6867 .goodUsdBIT{usdBIT,
uint64_t(100), 0},
6868 .goodUsdBITr{usdBIT,
uint64_t(100), 0},
6869 .lpTokenBalance{
uint64_t(70'71067811865475), -14},
6870 .offer1BtcGH = 1e-5,
6872 .offer2UsdGH = 1e-5,
6877 .testCase =
"Overflow test {50, 100, 232.16}",
6880 .sendMaxUsdBIT{usdBIT(232.16)},
6881 .sendUsdGH{usdGH, 100},
6884 .failUsdBIT{usdBIT,
uint64_t(282'16), -2},
6885 .failUsdBITr{usdBIT,
uint64_t(282'16), -2},
6886 .goodUsdGH{usdGH,
uint64_t(35'44113971506987), -14},
6887 .goodUsdGHr{usdGH,
uint64_t(35'44113971506987), -14},
6888 .goodUsdBIT{usdBIT,
uint64_t(141'0789844851958), -13},
6889 .goodUsdBITr{usdBIT,
uint64_t(141'0789844851962), -13},
6890 .lpTokenBalance{70'71067811865475, -14},
6891 .offer1BtcGH = 1e-5,
6893 .offer2UsdGH = 1e-5,
6898 .testCase =
"Overflow test {50, 100, 500}",
6901 .sendMaxUsdBIT{usdBIT(500)},
6902 .sendUsdGH{usdGH, 100},
6905 .failUsdBIT{usdBIT,
uint64_t(550), 0},
6906 .failUsdBITr{usdBIT,
uint64_t(550), 0},
6907 .goodUsdGH{usdGH,
uint64_t(35'44113971506987), -14},
6908 .goodUsdGHr{usdGH,
uint64_t(35'44113971506987), -14},
6909 .goodUsdBIT{usdBIT,
uint64_t(141'0789844851958), -13},
6910 .goodUsdBITr{usdBIT,
uint64_t(141'0789844851962), -13},
6911 .lpTokenBalance{70'71067811865475, -14},
6912 .offer1BtcGH = 1e-5,
6914 .offer2UsdGH = 1e-5,
6920 testcase(input.testCase);
6921 for (
auto const& features :
6922 {all - fixAMMOverflowOffer - fixAMMv1_1 - fixAMMv1_3, all})
6926 env.
fund(
XRP(5'000), gatehub, bitstamp, trader);
6929 if (input.rateGH != 0.0)
6930 env(rate(gatehub, input.rateGH));
6931 if (input.rateBIT != 0.0)
6932 env(rate(bitstamp, input.rateBIT));
6934 env(trust(trader, usdGH(10'000'000)));
6935 env(trust(trader, usdBIT(10'000'000)));
6936 env(trust(trader, btcGH(10'000'000)));
6939 env(pay(gatehub, trader, usdGH(100'000)));
6940 env(pay(gatehub, trader, btcGH(100'000)));
6941 env(pay(bitstamp, trader, usdBIT(100'000)));
6947 usdGH(input.poolUsdGH),
6948 usdBIT(input.poolUsdBIT)};
6952 amm.getLPTokensBalance();
6954 env(offer(trader, usdBIT(1), btcGH(input.offer1BtcGH)));
6957 btcGH(input.offer2BtcGH),
6958 usdGH(input.offer2UsdGH)));
6961 env(pay(trader, trader, input.sendUsdGH),
6963 path(~btcGH, ~usdGH),
6968 auto const failUsdGH =
6969 features[fixAMMv1_1] ? input.failUsdGHr : input.failUsdGH;
6970 auto const failUsdBIT =
6971 features[fixAMMv1_1] ? input.failUsdBITr : input.failUsdBIT;
6972 auto const goodUsdGH =
6973 features[fixAMMv1_1] ? input.goodUsdGHr : input.goodUsdGH;
6974 auto const goodUsdBIT =
6975 features[fixAMMv1_1] ? input.goodUsdBITr : input.goodUsdBIT;
6976 auto const lpTokenBalance =
6977 env.
enabled(fixAMMv1_3) && input.lpTokenBalanceAlt
6978 ? *input.lpTokenBalanceAlt
6979 : input.lpTokenBalance;
6980 if (!features[fixAMMOverflowOffer])
6982 BEAST_EXPECT(amm.expectBalances(
6983 failUsdGH, failUsdBIT, lpTokenBalance));
6987 BEAST_EXPECT(amm.expectBalances(
6988 goodUsdGH, goodUsdBIT, lpTokenBalance));
6993 amm.getLPTokensBalance() == preSwapLPTokenBalance);
6997 Number const sqrtPoolProduct =
6998 root2(goodUsdGH * goodUsdBIT);
7009 (sqrtPoolProduct +
Number{1, -14} >=
7010 input.lpTokenBalance));