3032 using namespace jtx;
3039 [&](
AMM& ammAlice,
Env& env) {
3040 ammAlice.
deposit(carol, 1'000'000);
3041 env(ammAlice.
bid({.account = carol, .bidMin = 110}));
3054 [&](
AMM& ammAlice,
Env& env) {
3055 ammAlice.
deposit(carol, 1'000'000);
3058 {.account = carol, .bidMin = 110, .bidMax = 110}));
3064 {.account = alice, .bidMin = 180, .bidMax = 200}));
3067 XRP(11'000), USD(11'000),
IOUAmount{10'999'814'5, -1}));
3076 [&](
AMM& ammAlice,
Env& env) {
3077 ammAlice.
deposit(carol, 1'000'000);
3079 env(ammAlice.
bid({.account = carol, .bidMin = 110}));
3082 fund(env, gw, {bob}, {USD(10'000)}, Fund::Acct);
3083 ammAlice.
deposit(bob, 1'000'000);
3085 env(ammAlice.
bid({.account = bob}));
3096 env(ammAlice.
bid({.account = carol, .bidMax = 600}));
3110 {.account = carol, .bidMin = 100, .bidMax = 600}));
3121 [&](
AMM& ammAlice,
Env& env) {
3122 ammAlice.
deposit(carol, 1'000'000);
3124 fund(env, gw, {bob}, {USD(10'000)}, Fund::Acct);
3125 ammAlice.
deposit(bob, 1'000'000);
3126 if (!features[fixAMMv1_3])
3136 env(ammAlice.
bid({.account = carol, .bidMin = 110})).
close();
3140 env(ammAlice.
bid({.account = bob}));
3146 env(ammAlice.
bid({.account = carol}));
3152 env(ammAlice.
bid({.account = bob}));
3161 env(ammAlice.
bid({.account = carol, .bidMin = 110})).
close();
3165 if (!features[fixAMMv1_3])
3186 [&](
AMM& ammAlice,
Env& env) {
3189 fund(env, gw, {bob, dan, ed}, {USD(20'000)}, Fund::Acct);
3190 ammAlice.
deposit(bob, 1'000'000);
3191 ammAlice.
deposit(ed, 1'000'000);
3192 ammAlice.
deposit(carol, 500'000);
3193 ammAlice.
deposit(dan, 500'000);
3198 .authAccounts = {bob, ed},
3200 auto const slotPrice =
IOUAmount{5'200};
3201 ammTokens -= slotPrice;
3203 if (!features[fixAMMv1_3])
3205 XRP(13'000), USD(13'000), ammTokens));
3208 XRPAmount{13'000'000'003}, USD(13'000), ammTokens));
3210 for (
int i = 0; i < 10; ++i)
3212 auto tokens = ammAlice.
deposit(carol, USD(100));
3213 ammAlice.
withdraw(carol, tokens, USD(0));
3214 tokens = ammAlice.
deposit(bob, USD(100));
3215 ammAlice.
withdraw(bob, tokens, USD(0));
3216 tokens = ammAlice.
deposit(ed, USD(100));
3217 ammAlice.
withdraw(ed, tokens, USD(0));
3220 if (!features[fixAMMv1_1])
3224 STAmount(USD, UINT64_C(29'499'00572620545), -11));
3227 STAmount(USD, UINT64_C(18'999'00572616195), -11));
3230 STAmount(USD, UINT64_C(18'999'00572611841), -11));
3234 STAmount(USD, UINT64_C(13'002'98282151419), -11),
3241 STAmount(USD, UINT64_C(29'499'00572620544), -11));
3244 STAmount(USD, UINT64_C(18'999'00572616194), -11));
3247 STAmount(USD, UINT64_C(18'999'0057261184), -10));
3249 if (!features[fixAMMv1_3])
3252 STAmount(USD, UINT64_C(13'002'98282151422), -11),
3257 STAmount(USD, UINT64_C(13'002'98282151422), -11),
3262 for (
int i = 0; i < 10; ++i)
3264 auto const tokens = ammAlice.
deposit(dan, USD(100));
3265 ammAlice.
withdraw(dan, tokens, USD(0));
3270 if (!features[fixAMMv1_1])
3274 STAmount(USD, UINT64_C(19'490'056722744), -9));
3278 STAmount{USD, UINT64_C(13'012'92609877019), -11},
3281 ammAlice.
deposit(carol, USD(100));
3285 STAmount{USD, UINT64_C(13'112'92609877019), -11},
3287 env(pay(carol, bob, USD(100)),
3295 STAmount{USD, UINT64_C(13'012'92609877019), -11},
3300 if (!features[fixAMMv1_3])
3303 STAmount(USD, UINT64_C(19'490'05672274399), -11));
3307 STAmount(USD, UINT64_C(19'490'05672274398), -11));
3309 if (!features[fixAMMv1_3])
3312 STAmount{USD, UINT64_C(13'012'92609877023), -11},
3317 STAmount{USD, UINT64_C(13'012'92609877024), -11},
3320 ammAlice.
deposit(carol, USD(100));
3322 if (!features[fixAMMv1_3])
3325 STAmount{USD, UINT64_C(13'112'92609877023), -11},
3330 STAmount{USD, UINT64_C(13'112'92609877024), -11},
3332 env(pay(carol, bob, USD(100)),
3338 if (!features[fixAMMv1_3])
3341 STAmount{USD, UINT64_C(13'012'92609877023), -11},
3346 STAmount{USD, UINT64_C(13'012'92609877024), -11},
3355 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
3359 STAmount{USD, UINT64_C(13'114'03663047264), -11},
3362 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
3366 STAmount{USD, UINT64_C(13'114'03663047269), -11},
3373 STAmount{USD, UINT64_C(13'114'03663044937), -11},
3380 if (!features[fixAMMv1_1])
3383 STAmount(USD, UINT64_C(29'399'00572620545), -11));
3384 else if (!features[fixAMMv1_3])
3387 STAmount(USD, UINT64_C(29'399'00572620544), -11));
3389 for (
int i = 0; i < 10; ++i)
3391 auto const tokens = ammAlice.
deposit(carol, USD(100));
3392 ammAlice.
withdraw(carol, tokens, USD(0));
3396 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
3400 STAmount(USD, UINT64_C(29'389'06197177128), -11));
3403 STAmount{USD, UINT64_C(13'123'98038490681), -11},
3406 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
3410 STAmount(USD, UINT64_C(29'389'06197177124), -11));
3413 STAmount{USD, UINT64_C(13'123'98038490689), -11},
3420 STAmount(USD, UINT64_C(29'389'06197177129), -11));
3423 STAmount{USD, UINT64_C(13'123'98038488352), -11},
3431 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
3435 STAmount{USD, UINT64_C(13'023'98038490681), -11},
3438 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
3442 STAmount{USD, UINT64_C(13'023'98038490689), -11},
3449 STAmount{USD, UINT64_C(13'023'98038488352), -11},
3460 [&](AMM& ammAlice, Env& env) {
3463 Number{STAmount::cMinValue, STAmount::cMinOffset};
3465 {.account = alice, .bidMin = IOUAmount{tiny}}));
3468 BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{tiny}));
3470 BEAST_EXPECT(ammAlice.expectBalances(
3471 XRP(10'000), USD(10'000), ammAlice.tokens()));
3476 IOUAmount{STAmount::cMinValue, STAmount::cMinOffset},
3479 BEAST_EXPECT(ammAlice.expectAuctionSlot(
3480 0, 0, IOUAmount{tiny * Number{105, -2}}));
3483 BEAST_EXPECT(ammAlice.expectBalances(
3484 XRP(10'000), USD(10'000), ammAlice.tokens()));
3493 [&](AMM& ammAlice, Env& env) {
3496 .bidMin = IOUAmount{100},
3497 .authAccounts = {carol},
3499 BEAST_EXPECT(ammAlice.expectAuctionSlot({carol}));
3500 env(ammAlice.bid({.account = alice, .bidMin = IOUAmount{100}}));
3501 BEAST_EXPECT(ammAlice.expectAuctionSlot({}));
3504 fund(env, {bob, dan},
XRP(1'000));
3507 .bidMin = IOUAmount{100},
3508 .authAccounts = {bob, dan},
3510 BEAST_EXPECT(ammAlice.expectAuctionSlot({bob, dan}));
3519 Env env(*
this, features);
3520 fund(env, gw, {alice, bob},
XRP(2'000), {USD(2'000)});
3521 AMM amm(env, gw,
XRP(1'000), USD(1'010),
false, 1'000);
3522 auto const lpIssue =
amm.lptIssue();
3523 env.trust(STAmount{lpIssue, 500}, alice);
3524 env.trust(STAmount{lpIssue, 50}, bob);
3525 env(
pay(gw, alice, STAmount{lpIssue, 500}));
3526 env(
pay(gw, bob, STAmount{lpIssue, 50}));
3528 env(
amm.bid({.account = alice, .bidMin = 500}));
3529 BEAST_EXPECT(
amm.expectAuctionSlot(100, 0, IOUAmount{500}));
3530 BEAST_EXPECT(
expectLine(env, alice, STAmount{lpIssue, 0}));
3533 env(
pay(alice, bob, USD(10)), path(~USD), sendmax(
XRP(11)));
3534 BEAST_EXPECT(
amm.expectBalances(
3535 XRPAmount{1'010'010'011},
3537 IOUAmount{1'004'487'562112089, -9}));
3539 env(
pay(bob, alice,
XRP(10)), path(~XRP), sendmax(USD(11)));
3540 if (!features[fixAMMv1_1])
3542 BEAST_EXPECT(
amm.expectBalances(
3543 XRPAmount{1'000'010'011},
3544 STAmount{USD, UINT64_C(1'010'10090898081), -11},
3545 IOUAmount{1'004'487'562112089, -9}));
3549 BEAST_EXPECT(
amm.expectBalances(
3550 XRPAmount{1'000'010'011},
3551 STAmount{USD, UINT64_C(1'010'100908980811), -12},
3552 IOUAmount{1'004'487'562112089, -9}));
3558 Env env(*
this, features);
3559 auto const baseFee = env.current()->fees().base;
3561 fund(env, gw, {alice, bob},
XRP(2'000), {USD(2'000)});
3562 AMM amm(env, gw,
XRP(1'000), USD(1'010),
false, 1'000);
3566 auto jtx = env.jt(tx, seq(1), fee(baseFee));
3567 env.app().config().features.erase(featureAMM);
3568 PreflightContext pfctx(
3571 env.current()->rules(),
3574 auto pf = AMMBid::preflight(pfctx);
3575 BEAST_EXPECT(pf == temDISABLED);
3576 env.app().config().features.insert(featureAMM);
3580 auto jtx = env.jt(tx, seq(1), fee(baseFee));
3581 jtx.jv[
"TxnSignature"] =
"deadbeef";
3582 jtx.stx = env.ust(jtx);
3583 PreflightContext pfctx(
3586 env.current()->rules(),
3589 auto pf = AMMBid::preflight(pfctx);
3590 BEAST_EXPECT(pf != tesSUCCESS);
3594 auto jtx = env.jt(tx, seq(1), fee(baseFee));
3595 jtx.jv[
"Asset2"][
"currency"] =
"XRP";
3596 jtx.jv[
"Asset2"].removeMember(
"issuer");
3597 jtx.stx = env.ust(jtx);
3598 PreflightContext pfctx(
3601 env.current()->rules(),
3604 auto pf = AMMBid::preflight(pfctx);
3605 BEAST_EXPECT(pf == temBAD_AMM_TOKENS);
3776 testcase(
"Basic Payment");
3777 using namespace jtx;
3782 [&](
AMM& ammAlice,
Env& env) {
3783 env.
fund(jtx::XRP(30'000), bob);
3785 env(pay(bob, carol, USD(100)),
3791 XRP(10'100), USD(10'000), ammAlice.
tokens()));
3793 BEAST_EXPECT(
expectLine(env, carol, USD(30'100)));
3796 env, bob,
XRP(30'000) -
XRP(100) -
txfee(env, 1)));
3798 {{
XRP(10'000), USD(10'100)}},
3805 [&](
AMM& ammAlice,
Env& env) {
3806 env.
fund(jtx::XRP(30'000), bob);
3808 env(pay(bob, carol, USD(100)),
sendmax(
XRP(100)));
3811 XRP(10'100), USD(10'000), ammAlice.
tokens()));
3813 BEAST_EXPECT(
expectLine(env, carol, USD(30'100)));
3816 env, bob,
XRP(30'000) -
XRP(100) -
txfee(env, 1)));
3818 {{
XRP(10'000), USD(10'100)}},
3826 [&](
AMM& ammAlice,
Env& env) {
3827 env.
fund(jtx::XRP(30'000), bob);
3832 XRP(10'100), USD(10'000), ammAlice.
tokens()));
3834 BEAST_EXPECT(
expectLine(env, carol, USD(30'100)));
3837 env, bob,
XRP(30'000) -
XRP(100) -
txfee(env, 1)));
3839 {{
XRP(10'000), USD(10'100)}},
3846 [&](
AMM& ammAlice,
Env& env) {
3847 env.
fund(jtx::XRP(30'000), bob);
3851 env(pay(bob, carol, USD(100)),
3858 XRP(10'010), USD(10'000), ammAlice.
tokens()));
3860 BEAST_EXPECT(
expectLine(env, carol, USD(30'010)));
3864 env, bob,
XRP(30'000) -
XRP(10) -
txfee(env, 1)));
3868 env(pay(bob, carol, USD(100)),
3876 {{
XRP(10'000), USD(10'010)}},
3883 [&](
AMM& ammAlice,
Env& env) {
3886 env.
fund(jtx::XRP(30'000), bob);
3891 env(pay(bob, carol, USD(100)),
3898 XRP(10'010), USD(10'000), ammAlice.
tokens()));
3903 STAmount{USD, UINT64_C(30'009'09090909091), -11}));
3905 env, bob,
XRP(30'000) -
XRP(10) -
txfee(env, 1)));
3907 {{
XRP(10'000), USD(10'010)}},
3914 [&](
AMM& ammAlice,
Env& env) {
3915 env.
fund(jtx::XRP(30'000), bob);
3917 env(pay(bob, carol, USD(100)),
3923 {{
XRP(10'000), USD(10'000)}},
3933 Env env(*
this, features);
3935 env, gw, {alice, carol}, {USD(30'000), EUR(30'000)}, Fund::All);
3939 auto ammEUR_XRP =
AMM(env, alice,
XRP(10'000), EUR(10'000));
3940 auto ammUSD_EUR =
AMM(env, alice, EUR(10'000), USD(10'000));
3943 env(pay(bob, carol, USD(100)),
3948 BEAST_EXPECT(ammEUR_XRP.expectBalances(
3950 STAmount(EUR, UINT64_C(9'970'007498125468), -12),
3951 ammEUR_XRP.tokens()));
3952 if (!features[fixAMMv1_1])
3954 BEAST_EXPECT(ammUSD_EUR.expectBalances(
3955 STAmount(USD, UINT64_C(9'970'097277662122), -12),
3956 STAmount(EUR, UINT64_C(10'029'99250187452), -11),
3957 ammUSD_EUR.tokens()));
3960 Amounts
const expectedAmounts =
3961 env.
closed()->rules().enabled(fixReducedOffersV2)
3962 ? Amounts{
XRPAmount(30'201'749),
STAmount(USD, UINT64_C(29'90272233787816), -14)}
3965 STAmount(USD, UINT64_C(29'90272233787818), -14)};
3967 BEAST_EXPECT(
expectOffers(env, alice, 1, {{expectedAmounts}}));
3971 BEAST_EXPECT(ammUSD_EUR.expectBalances(
3972 STAmount(USD, UINT64_C(9'970'097277662172), -12),
3973 STAmount(EUR, UINT64_C(10'029'99250187452), -11),
3974 ammUSD_EUR.tokens()));
3977 Amounts
const expectedAmounts =
3978 env.
closed()->rules().enabled(fixReducedOffersV2)
3979 ? Amounts{
XRPAmount(30'201'749),
STAmount(USD, UINT64_C(29'90272233782839), -14)}
3982 STAmount(USD, UINT64_C(29'90272233782840), -14)};
3984 BEAST_EXPECT(
expectOffers(env, alice, 1, {{expectedAmounts}}));
4000 [&](
AMM& ammAlice,
Env& env) {
4003 env.
trust(EUR(2'000), alice);
4005 env(pay(gw, alice, EUR(1'000)));
4010 env(pay(bob, carol, USD(100)),
4017 STAmount(USD, UINT64_C(9'950'01249687578), -11),
4025 STAmount(EUR, UINT64_C(49'98750312422), -11)},
4027 STAmount(EUR, UINT64_C(49'98750312422), -11),
4028 STAmount(USD, UINT64_C(49'98750312422), -11)}}}));
4033 STAmount{USD, UINT64_C(30'099'99999999999), -11}));
4050 [&](
AMM& ammAlice,
Env& env) {
4051 fund(env, gw, {bob}, {USD(100)}, Fund::Acct);
4055 env(pay(alice, carol, USD(200)),
4059 if (!features[fixAMMv1_1])
4062 XRP(10'100), USD(10'000), ammAlice.
tokens()));
4064 BEAST_EXPECT(
expectLine(env, carol, USD(30'200)));
4070 STAmount(USD, UINT64_C(10'000'00000000001), -11),
4075 STAmount(USD, UINT64_C(30'199'99999999999), -11)));
4083 ammCrtFee(env) -
txfee(env, 1)));
4086 {{
XRP(10'000), USD(10'100)}},
4095 Env env(*
this, features);
4096 fund(env, gw, {alice, bob, carol},
XRP(20'000), {USD(2'000)});
4100 AMM ammAlice(env, alice,
XRP(1'000), USD(1'050));
4101 env(pay(alice, carol, USD(200)),
4106 XRP(1'050), USD(1'000), ammAlice.
tokens()));
4107 BEAST_EXPECT(
expectLine(env, carol, USD(2'200)));
4113 [&](
AMM& ammAlice,
Env& env) {
4114 fund(env, gw, {bob}, {USD(1'000)}, Fund::Acct);
4116 env(offer(bob, USD(100),
XRP(100)));
4119 XRP(10'100), USD(10'000), ammAlice.
tokens()));
4121 BEAST_EXPECT(
expectLine(env, bob, USD(1'100)));
4124 env, bob,
XRP(30'000) -
XRP(100) -
txfee(env, 1)));
4127 {{
XRP(10'000), USD(10'100)}},
4135 [&](
AMM& ammAlice,
Env& env) {
4136 env(rate(gw, 1.25));
4142 env(offer(carol, EUR(100), GBP(100)));
4146 GBP(1'100), EUR(1'000), ammAlice.
tokens()));
4148 BEAST_EXPECT(
expectLine(env, carol, GBP(29'875)));
4150 BEAST_EXPECT(
expectLine(env, carol, EUR(30'100)));
4153 {{GBP(1'000), EUR(1'100)}},
4159 [&](
AMM& amm,
Env& env) {
4160 env(rate(gw, 1.001));
4162 env(offer(carol,
XRP(100), USD(55)));
4164 if (!features[fixAMMv1_1])
4174 amm.expectBalances(
XRP(1'000), USD(500), amm.tokens()));
4176 env, carol, 1, {{Amounts{
XRP(100), USD(55)}}}));
4187 BEAST_EXPECT(amm.expectBalances(
4189 STAmount{USD, UINT64_C(550'000000055), -9},
4198 STAmount{USD, 4'99999995, -8}}}}));
4202 STAmount(USD, UINT64_C(29'949'94999999494), -11));
4205 {{
XRP(1'000), USD(500)}},
4210 [&](
AMM& amm,
Env& env) {
4211 env(rate(gw, 1.001));
4213 env(offer(carol,
XRP(10), USD(5.5)));
4215 if (!features[fixAMMv1_1])
4217 BEAST_EXPECT(amm.expectBalances(
4219 STAmount{USD, UINT64_C(505'050505050505), -12},
4225 BEAST_EXPECT(amm.expectBalances(
4227 STAmount{USD, UINT64_C(505'0505050505051), -13},
4232 {{
XRP(1'000), USD(500)}},
4238 [&](
AMM& ammAlice,
Env& env) {
4245 {GBP(2'000), EUR(2'000)},
4247 env(rate(gw, 1.25));
4258 env(offer(carol, EUR(100), GBP(100)));
4260 if (!features[fixAMMv1_1])
4269 STAmount{GBP, UINT64_C(1'037'06583722133), -11},
4270 STAmount{EUR, UINT64_C(1'060'684828792831), -12},
4278 STAmount{EUR, UINT64_C(50'684828792831), -12},
4279 STAmount{GBP, UINT64_C(50'684828792831), -12}}}));
4291 STAmount{GBP, UINT64_C(29'941'16770347333), -11}));
4296 STAmount{EUR, UINT64_C(30'049'31517120716), -11}));
4308 STAmount{GBP, UINT64_C(1'060'684828792832), -12},
4309 STAmount{EUR, UINT64_C(1'037'06583722134), -11},
4317 STAmount{EUR, UINT64_C(27'06583722134028), -14},
4318 STAmount{GBP, UINT64_C(27'06583722134028), -14}}}));
4330 STAmount{GBP, UINT64_C(29'911'64396400896), -11}));
4335 STAmount{EUR, UINT64_C(30'072'93416277865), -11}));
4338 BEAST_EXPECT(
expectLine(env, bob, GBP(2'010)));
4340 BEAST_EXPECT(
expectLine(env, ed, EUR(1'987.5)));
4342 {{GBP(1'000), EUR(1'100)}},
4355 [&](
AMM& ammAlice,
Env& env) {
4356 fund(env, gw, {bob}, {GBP(200), EUR(200)}, Fund::Acct);
4357 env(rate(gw, 1.25));
4359 env(pay(bob, carol, EUR(100)),
4365 GBP(1'100), EUR(1'000), ammAlice.
tokens()));
4367 BEAST_EXPECT(
expectLine(env, carol, EUR(30'080)));
4369 {{GBP(1'000), EUR(1'100)}},
4386 [&](
AMM& ammAlice,
Env& env) {
4389 auto const CAN = gw[
"CAN"];
4390 fund(env, gw, {dan}, {CAN(200), GBP(200)}, Fund::Acct);
4391 fund(env, gw, {ed}, {EUR(200), USD(200)}, Fund::Acct);
4392 fund(env, gw, {bob}, {CAN(195.3125)}, Fund::Acct);
4393 env(trust(carol, USD(100)));
4394 env(rate(gw, 1.25));
4396 env(offer(dan, CAN(200), GBP(200)));
4397 env(offer(ed, EUR(200), USD(200)));
4399 env(pay(bob, carol, USD(100)),
4400 path(~GBP, ~EUR, ~USD),
4405 BEAST_EXPECT(
expectLine(env, dan, CAN(356.25), GBP(43.75)));
4407 GBP(10'125), EUR(10'000), ammAlice.
tokens()));
4408 BEAST_EXPECT(
expectLine(env, ed, EUR(300), USD(100)));
4409 BEAST_EXPECT(
expectLine(env, carol, USD(80)));
4411 {{GBP(10'000), EUR(10'125)}},
4418 [&](
AMM& ammAlice,
Env& env) {
4419 env(pay(alice, carol, USD(99.99)),
4424 env(pay(alice, carol, USD(100)),
4429 env(pay(alice, carol,
XRP(100)),
4440 {{
XRP(100), USD(100)}},
4447 Env env(*
this, features);
4448 auto const ETH = gw[
"ETH"];
4454 {EUR(50'000), BTC(50'000), ETH(50'000), USD(50'000)});
4455 fund(env, gw, {carol, bob},
XRP(1'000), {USD(200)}, Fund::Acct);
4456 AMM xrp_eur(env, alice,
XRP(10'100), EUR(10'000));
4457 AMM eur_btc(env, alice, EUR(10'000), BTC(10'200));
4458 AMM btc_usd(env, alice, BTC(10'100), USD(10'000));
4459 AMM xrp_usd(env, alice,
XRP(10'150), USD(10'200));
4460 AMM xrp_eth(env, alice,
XRP(10'000), ETH(10'100));
4461 AMM eth_eur(env, alice, ETH(10'900), EUR(11'000));
4462 AMM eur_usd(env, alice, EUR(10'100), USD(10'000));
4463 env(pay(bob, carol, USD(100)),
4464 path(~EUR, ~BTC, ~USD),
4466 path(~ETH, ~EUR, ~USD),
4468 if (!features[fixAMMv1_1])
4474 STAmount{ETH, UINT64_C(10'073'65779244494), -11},
4477 STAmount{ETH, UINT64_C(10'926'34220755506), -11},
4478 STAmount{EUR, UINT64_C(10'973'54232078752), -11},
4481 STAmount{EUR, UINT64_C(10'126'45767921248), -11},
4482 STAmount{USD, UINT64_C(9'973'93151712086), -11},
4488 STAmount{USD, UINT64_C(10'126'06848287914), -11},
4495 STAmount{ETH, UINT64_C(10'073'65779244461), -11},
4498 STAmount{ETH, UINT64_C(10'926'34220755539), -11},
4499 STAmount{EUR, UINT64_C(10'973'5423207872), -10},
4502 STAmount{EUR, UINT64_C(10'126'4576792128), -10},
4503 STAmount{USD, UINT64_C(9'973'93151712057), -11},
4509 STAmount{USD, UINT64_C(10'126'06848287943), -11},
4519 BEAST_EXPECT(xrp_eur.expectBalances(
4520 XRP(10'100), EUR(10'000), xrp_eur.tokens()));
4522 EUR(10'000), BTC(10'200), eur_btc.
tokens()));
4524 BTC(10'100), USD(10'000), btc_usd.
tokens()));
4526 BEAST_EXPECT(
expectLine(env, carol, USD(300)));
4531 Env env(*
this, features);
4532 auto const ETH = gw[
"ETH"];
4538 {EUR(50'000), BTC(50'000), ETH(50'000), USD(50'000)});
4539 fund(env, gw, {carol, bob},
XRP(1000), {USD(200)}, Fund::Acct);
4540 AMM xrp_eur(env, alice,
XRP(10'100), EUR(10'000));
4541 AMM eur_btc(env, alice, EUR(10'000), BTC(10'200));
4542 AMM btc_usd(env, alice, BTC(10'100), USD(10'000));
4543 AMM xrp_eth(env, alice,
XRP(10'000), ETH(10'100));
4544 AMM eth_eur(env, alice, ETH(10'900), EUR(11'000));
4545 env(pay(bob, carol, USD(100)),
4546 path(~EUR, ~BTC, ~USD),
4547 path(~ETH, ~EUR, ~BTC, ~USD),
4549 if (!features[fixAMMv1_1])
4553 BEAST_EXPECT(xrp_eur.expectBalances(
4555 STAmount{EUR, UINT64_C(9'981'544436337968), -12},
4558 STAmount{EUR, UINT64_C(10'101'16096785173), -11},
4559 STAmount{BTC, UINT64_C(10'097'91426968066), -11},
4562 STAmount{BTC, UINT64_C(10'202'08573031934), -11},
4567 STAmount{ETH, UINT64_C(10'017'41072778012), -11},
4570 STAmount{ETH, UINT64_C(10'982'58927221988), -11},
4571 STAmount{EUR, UINT64_C(10'917'2945958103), -10},
4576 BEAST_EXPECT(xrp_eur.expectBalances(
4578 STAmount{EUR, UINT64_C(9'981'544436337923), -12},
4581 STAmount{EUR, UINT64_C(10'101'16096785188), -11},
4582 STAmount{BTC, UINT64_C(10'097'91426968059), -11},
4585 STAmount{BTC, UINT64_C(10'202'08573031941), -11},
4590 STAmount{ETH, UINT64_C(10'017'41072777996), -11},
4593 STAmount{ETH, UINT64_C(10'982'58927222004), -11},
4594 STAmount{EUR, UINT64_C(10'917'2945958102), -10},
4597 BEAST_EXPECT(
expectLine(env, carol, USD(300)));
4603 [&](
AMM& ammAlice,
Env& env) {
4605 fund(env, gw, {bob}, {EUR(400)}, Fund::IOUOnly);
4606 env(trust(alice, EUR(200)));
4607 for (
int i = 0; i < 30; ++i)
4608 env(offer(alice, EUR(1.0 + 0.01 * i),
XRP(1)));
4611 env(offer(alice, EUR(140),
XRP(100)));
4612 env(pay(bob, carol, USD(100)),
4616 if (!features[fixAMMv1_1])
4621 STAmount{USD, UINT64_C(9'970'089730807577), -12},
4626 STAmount{USD, UINT64_C(30'029'91026919241), -11}));
4632 STAmount{USD, UINT64_C(9'970'089730807827), -12},
4637 STAmount{USD, UINT64_C(30'029'91026919217), -11}));
4648 [&](
AMM& ammAlice,
Env& env) {
4650 fund(env, gw, {bob}, {EUR(400)}, Fund::IOUOnly);
4651 env(trust(alice, EUR(200)));
4652 for (
int i = 0; i < 29; ++i)
4653 env(offer(alice, EUR(1.0 + 0.01 * i),
XRP(1)));
4656 env(offer(alice, EUR(140),
XRP(100)));
4657 env(pay(bob, carol, USD(100)),
4663 if (!features[fixAMMv1_1])
4669 STAmount{USD, UINT64_C(30'099'99999999999), -11}));
4673 BEAST_EXPECT(
expectLine(env, carol, USD(30'100)));
4679 {{{
STAmount{EUR, UINT64_C(39'1858572), -7},
4690 Env env(*
this, features);
4691 fund(env, gw, {alice, carol, bob},
XRP(30'000), {USD(30'000)});
4692 env(offer(bob,
XRP(100), USD(100.001)));
4693 AMM ammAlice(env, alice,
XRP(10'000), USD(10'100));
4694 env(offer(carol, USD(100),
XRP(100)));
4695 if (!features[fixAMMv1_1])
4699 STAmount{USD, UINT64_C(10'049'92586949302), -11},
4706 STAmount{USD, UINT64_C(50'07513050698), -11}}}}));
4712 STAmount{USD, UINT64_C(10'049'92587049303), -11},
4719 STAmount{USD, UINT64_C(50'07512950697), -11}}}}));
4720 BEAST_EXPECT(
expectLine(env, carol, USD(30'100)));
4726 [&](
AMM& ammAlice,
Env& env) {
4730 env(pay(alice, carol, USD(1)),
5026 testcase(
"Trading Fee");
5027 using namespace jtx;
5031 [&](
AMM& ammAlice,
Env& env) {
5033 ammAlice.
deposit(carol, USD(3'000));
5037 BEAST_EXPECT(
expectLine(env, carol, USD(30'000)));
5039 ammAlice.
vote(alice, 1'000);
5043 ammAlice.
deposit(carol, USD(3'000));
5045 carol,
IOUAmount{994'981155689671, -12}));
5046 BEAST_EXPECT(
expectLine(env, carol, USD(27'000)));
5048 ammAlice.
vote(alice, 0);
5054 STAmount{USD, UINT64_C(29'994'96220068281), -11}));
5056 {{USD(1'000), EUR(1'000)}},
5064 [&](
AMM& ammAlice,
Env& env) {
5066 auto tokensFee = ammAlice.
deposit(
5070 ammAlice.
vote(alice, 0);
5072 auto const tokensNoFee = ammAlice.
deposit(carol, deposit);
5075 BEAST_EXPECT(tokensFee ==
IOUAmount(485'636'0611129, -7));
5076 BEAST_EXPECT(tokensNoFee ==
IOUAmount(487'644'85901109, -8));
5086 [&](
AMM& ammAlice,
Env& env) {
5088 auto const tokensFee = ammAlice.
deposit(
5092 ammAlice.
vote(alice, 0);
5094 auto const tokensNoFee = ammAlice.
deposit(carol, deposit);
5097 BEAST_EXPECT(tokensFee ==
IOUAmount(98'000'00000002, -8));
5098 BEAST_EXPECT(tokensNoFee ==
IOUAmount(98'475'81871545, -8));
5107 [&](
AMM& ammAlice,
Env& env) {
5109 ammAlice.
deposit(carol, USD(3'000));
5112 BEAST_EXPECT(
expectLine(env, carol, USD(27'000)));
5114 ammAlice.
vote(alice, 1'000);
5121 STAmount{USD, UINT64_C(29'994'97487437186), -11}));
5123 {{USD(1'000), EUR(1'000)}},
5130 [&](
AMM& ammAlice,
Env& env) {
5131 ammAlice.
deposit(carol, 1'000'000);
5132 auto const tokensFee = ammAlice.
withdraw(
5135 auto const balanceAfterWithdraw = [&]() {
5136 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
5137 return STAmount(USD, UINT64_C(30'443'43891402715), -11);
5138 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
5139 return STAmount(USD, UINT64_C(30'443'43891402714), -11);
5141 return STAmount(USD, UINT64_C(30'443'43891402713), -11);
5143 BEAST_EXPECT(env.
balance(carol, USD) == balanceAfterWithdraw);
5145 auto const deposit = balanceAfterWithdraw - USD(29'000);
5146 ammAlice.
deposit(carol, deposit);
5148 ammAlice.
vote(alice, 0);
5150 auto const tokensNoFee = ammAlice.
withdraw(carol, deposit);
5151 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
5154 STAmount(USD, UINT64_C(30'443'43891402717), -11));
5155 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
5158 STAmount(USD, UINT64_C(30'443'43891402716), -11));
5162 STAmount(USD, UINT64_C(30'443'43891402713), -11));
5165 if (!features[fixAMMv1_1] && !features[fixAMMv1_3])
5167 tokensNoFee ==
IOUAmount(746'579'80779913, -8));
5168 else if (features[fixAMMv1_1] && !features[fixAMMv1_3])
5170 tokensNoFee ==
IOUAmount(746'579'80779912, -8));
5173 tokensNoFee ==
IOUAmount(746'579'80779911, -8));
5174 BEAST_EXPECT(tokensFee ==
IOUAmount(750'588'23529411, -8));
5183 [&](
AMM& ammAlice,
Env& env) {
5189 {USD(1'000), EUR(1'000)},
5192 BEAST_EXPECT(
expectLine(env, alice, EUR(28'990)));
5193 BEAST_EXPECT(
expectLine(env, alice, USD(29'000)));
5194 BEAST_EXPECT(
expectLine(env, carol, USD(30'000)));
5196 env(pay(carol, alice, EUR(10)),
5202 BEAST_EXPECT(
expectLine(env, alice, EUR(29'000)));
5203 BEAST_EXPECT(
expectLine(env, alice, USD(29'000)));
5204 BEAST_EXPECT(
expectLine(env, carol, USD(29'990)));
5207 ammAlice.
vote(alice, 1'000);
5210 env(pay(bob, carol, USD(10)),
5217 env, bob,
STAmount{EUR, UINT64_C(989'8989898989899), -13}));
5219 BEAST_EXPECT(
expectLine(env, carol, USD(30'000)));
5222 STAmount{EUR, UINT64_C(1'010'10101010101), -11},
5225 {{USD(1'000), EUR(1'010)}},
5232 [&](
AMM& ammAlice,
Env& env) {
5234 env(offer(carol, EUR(10), USD(10)));
5236 BEAST_EXPECT(
expectLine(env, carol, USD(29'990)));
5237 BEAST_EXPECT(
expectLine(env, carol, EUR(30'010)));
5239 env(offer(carol, USD(10), EUR(10)));
5242 ammAlice.
vote(alice, 500);
5244 env(offer(carol, EUR(10), USD(10)));
5251 STAmount{USD, UINT64_C(29'995'02512562814), -11}));
5255 STAmount{EUR, UINT64_C(30'004'97487437186), -11}));
5261 STAmount{EUR, UINT64_C(5'025125628140703), -15},
5262 STAmount{USD, UINT64_C(5'025125628140703), -15}}}}));
5263 if (!features[fixAMMv1_1])
5266 STAmount{USD, UINT64_C(1'004'974874371859), -12},
5267 STAmount{EUR, UINT64_C(1'005'025125628141), -12},
5273 STAmount{USD, UINT64_C(1'004'97487437186), -11},
5274 STAmount{EUR, UINT64_C(1'005'025125628141), -12},
5278 {{USD(1'000), EUR(1'010)}},
5288 Env env(*
this, features);
5293 {alice, bob, carol, ed},
5295 {USD(2'000), EUR(2'000)});
5296 env(offer(carol, EUR(5), USD(5)));
5297 AMM ammAlice(env, alice, USD(1'005), EUR(1'000));
5298 env(pay(bob, ed, USD(10)),
5302 BEAST_EXPECT(
expectLine(env, ed, USD(2'010)));
5303 if (!features[fixAMMv1_1])
5305 BEAST_EXPECT(
expectLine(env, bob, EUR(1'990)));
5307 USD(1'000), EUR(1'005), ammAlice.
tokens()));
5312 env, bob,
STAmount(EUR, UINT64_C(1989'999999999999), -12)));
5315 STAmount(EUR, UINT64_C(1005'000000000001), -12),
5324 Env env(*
this, features);
5329 {alice, bob, carol, ed},
5331 {USD(2'000), EUR(2'000)});
5332 env(offer(carol, EUR(5), USD(5)));
5334 AMM ammAlice(env, alice, USD(1'005), EUR(1'000),
false, 250);
5335 env(pay(bob, ed, USD(10)),
5339 BEAST_EXPECT(
expectLine(env, ed, USD(2'010)));
5340 if (!features[fixAMMv1_1])
5345 STAmount{EUR, UINT64_C(1'989'987453007618), -12}));
5348 STAmount{EUR, UINT64_C(1'005'012546992382), -12},
5356 STAmount{EUR, UINT64_C(1'989'987453007628), -12}));
5359 STAmount{EUR, UINT64_C(1'005'012546992372), -12},
5369 Env env(*
this, features);
5374 {alice, bob, carol, ed},
5376 {USD(2'000), EUR(2'000)});
5377 env(offer(carol, EUR(10), USD(10)));
5379 AMM ammAlice(env, alice, USD(1'005), EUR(1'000),
false, 1'000);
5380 env(pay(bob, ed, USD(10)),
5384 BEAST_EXPECT(
expectLine(env, ed, USD(2'010)));
5385 BEAST_EXPECT(
expectLine(env, bob, EUR(1'990)));
5387 USD(1'005), EUR(1'000), ammAlice.
tokens()));
5396 Env env(*
this, features);
5401 {alice, bob, carol, ed},
5403 {USD(2'000), EUR(2'000)});
5404 env(offer(carol, EUR(9), USD(9)));
5406 AMM ammAlice(env, alice, USD(1'005), EUR(1'000),
false, 1'000);
5407 env(pay(bob, ed, USD(10)),
5411 BEAST_EXPECT(
expectLine(env, ed, USD(2'010)));
5413 env, bob,
STAmount{EUR, UINT64_C(1'989'993923296712), -12}));
5416 STAmount{EUR, UINT64_C(1'001'006076703288), -12},
5824 testcase(
"Offer/Strand Selection");
5825 using namespace jtx;
5828 auto const ETH = gw1[
"ETH"];
5829 auto const CAN = gw1[
"CAN"];
5835 auto prep = [&](
Env& env,
auto gwRate,
auto gw1Rate) {
5836 fund(env, gw, {alice, carol, bob, ed},
XRP(2'000), {USD(2'000)});
5841 {alice, carol, bob, ed},
5842 {ETH(2'000), CAN(2'000)},
5844 env(rate(gw, gwRate));
5845 env(rate(gw1, gw1Rate));
5849 for (
auto const& rates :
5864 for (
auto i = 0; i < 3; ++i)
5866 Env env(*
this, features);
5867 prep(env, rates.first, rates.second);
5869 if (i == 0 || i == 2)
5875 amm.emplace(env, ed, USD(1'000), ETH(1'000));
5876 env(pay(carol, bob, USD(100)),
5883 BEAST_EXPECT(amm->expectBalances(
5884 USD(1'000), ETH(1'000), amm->tokens()));
5886 BEAST_EXPECT(
expectLine(env, bob, USD(2'100)));
5887 q[i] = Quality(Amounts{
5888 ETH(2'000) - env.
balance(carol, ETH),
5889 env.
balance(bob, USD) - USD(2'000)});
5892 BEAST_EXPECT(q[0] > q[1]);
5894 BEAST_EXPECT(q[0] == q[2]);
5901 for (
auto i = 0; i < 3; ++i)
5903 Env env(*
this, features);
5904 prep(env, rates.first, rates.second);
5906 if (i == 0 || i == 2)
5912 amm.emplace(env, ed, USD(1'000), ETH(1'000));
5913 env(offer(alice, USD(400), ETH(400)));
5918 BEAST_EXPECT(amm->expectBalances(
5919 USD(1'000), ETH(1'000), amm->tokens()));
5921 if (i == 0 || i == 2)
5930 env, alice, 1, {Amounts{USD(400), ETH(400)}}));
5941 for (
auto i = 0; i < 3; ++i)
5943 Env env(*
this, features);
5944 prep(env, rates.first, rates.second);
5946 if (i == 0 || i == 2)
5952 amm.emplace(env, ed, USD(1'000), ETH(1'000));
5953 env(pay(carol, bob, USD(100)),
5960 BEAST_EXPECT(!amm->expectBalances(
5961 USD(1'000), ETH(1'000), amm->tokens()));
5963 if (i == 2 && !features[fixAMMv1_1])
5965 if (rates.first == 1.5)
5967 if (!features[fixAMMv1_1])
5975 UINT64_C(378'6327949540823),
5979 UINT64_C(283'9745962155617),
5989 UINT64_C(378'6327949540813),
5993 UINT64_C(283'974596215561),
5998 if (!features[fixAMMv1_1])
6006 UINT64_C(325'299461620749),
6010 UINT64_C(243'9745962155617),
6020 UINT64_C(325'299461620748),
6024 UINT64_C(243'974596215561),
6030 if (rates.first == 1.5)
6038 ETH, UINT64_C(378'6327949540812), -13},
6041 UINT64_C(283'9745962155609),
6052 ETH, UINT64_C(325'2994616207479), -13},
6055 UINT64_C(243'9745962155609),
6059 BEAST_EXPECT(
expectLine(env, bob, USD(2'100)));
6060 q[i] = Quality(Amounts{
6061 ETH(2'000) - env.
balance(carol, ETH),
6062 env.
balance(bob, USD) - USD(2'000)});
6065 BEAST_EXPECT(q[1] > q[0]);
6067 BEAST_EXPECT(q[2] > q[1]);
6071 for (
auto i = 0; i < 3; ++i)
6073 Env env(*
this, features);
6074 prep(env, rates.first, rates.second);
6076 if (i == 0 || i == 2)
6082 amm.emplace(env, ed, USD(1'000), ETH(1'000));
6083 env(offer(alice, USD(250), ETH(400)));
6088 BEAST_EXPECT(!amm->expectBalances(
6089 USD(1'000), ETH(1'000), amm->tokens()));
6095 if (rates.first == 1.5)
6097 if (!features[fixAMMv1_1])
6100 env, ed, 1, {{Amounts{ETH(400), USD(250)}}}));
6107 USD, UINT64_C(40'5694150420947), -13},
6109 ETH, UINT64_C(64'91106406735152), -14},
6123 ETH, UINT64_C(335'0889359326475), -13},
6125 USD, UINT64_C(209'4305849579047), -13},
6132 if (!features[fixAMMv1_1])
6141 ETH, UINT64_C(335'0889359326485), -13},
6143 USD, UINT64_C(209'4305849579053), -13},
6156 ETH, UINT64_C(335'0889359326475), -13},
6158 USD, UINT64_C(209'4305849579047), -13},
6184 for (
auto i = 0; i < 3; ++i)
6186 Env env(*
this, features);
6187 prep(env, rates.first, rates.second);
6190 if (i == 0 || i == 2)
6198 amm.emplace(env, ed, ETH(1'000), USD(1'000));
6200 env(pay(carol, bob, USD(100)),
6206 BEAST_EXPECT(
expectLine(env, bob, USD(2'100)));
6208 if (i == 2 && !features[fixAMMv1_1])
6210 if (rates.first == 1.5)
6213 BEAST_EXPECT(amm->expectBalances(
6214 STAmount{ETH, UINT64_C(1'176'66038955758), -11},
6220 BEAST_EXPECT(amm->expectBalances(
6222 ETH, UINT64_C(1'179'540094339627), -12},
6223 STAmount{USD, UINT64_C(847'7880529867501), -13},
6232 UINT64_C(343'3179205198749),
6236 UINT64_C(343'3179205198749),
6242 UINT64_C(362'2119470132499),
6246 UINT64_C(362'2119470132499),
6253 if (rates.first == 1.5)
6256 BEAST_EXPECT(amm->expectBalances(
6258 ETH, UINT64_C(1'176'660389557593), -12},
6264 BEAST_EXPECT(amm->expectBalances(
6265 STAmount{ETH, UINT64_C(1'179'54009433964), -11},
6266 STAmount{USD, UINT64_C(847'7880529867501), -13},
6275 UINT64_C(343'3179205198749),
6279 UINT64_C(343'3179205198749),
6285 UINT64_C(362'2119470132499),
6289 UINT64_C(362'2119470132499),
6294 q[i] = Quality(Amounts{
6295 ETH(2'000) - env.
balance(carol, ETH),
6296 env.
balance(bob, USD) - USD(2'000)});
6298 BEAST_EXPECT(q[1] > q[0]);
6299 BEAST_EXPECT(q[2] > q[0] && q[2] < q[1]);
6407 testcase(
"Fix changeSpotPriceQuality");
6408 using namespace jtx;
6413 SucceedShouldSucceedResize,
6425 auto const xrpIouAmounts10_100 =
6427 auto const iouXrpAmounts10_100 =
6432 {
"0.001519763260828713",
"1558701", Quality{5414253689393440221}, 1000, FailShouldSucceed},
6433 {
"0.01099814367603737",
"1892611", Quality{5482264816516900274}, 1000, FailShouldSucceed},
6434 {
"0.78",
"796599", Quality{5630392334958379008}, 1000, FailShouldSucceed},
6435 {
"105439.2955578965",
"49398693", Quality{5910869983721805038}, 400, FailShouldSucceed},
6436 {
"12408293.23445213",
"4340810521", Quality{5911611095910090752}, 997, FailShouldSucceed},
6437 {
"1892611",
"0.01099814367603737", Quality{6703103457950430139}, 1000, FailShouldSucceed},
6438 {
"423028.8508101858",
"3392804520", Quality{5837920340654162816}, 600, FailShouldSucceed},
6439 {
"44565388.41001027",
"73890647", Quality{6058976634606450001}, 1000, FailShouldSucceed},
6440 {
"66831.68494832662",
"16", Quality{6346111134641742975}, 0, FailShouldSucceed},
6441 {
"675.9287302203422",
"1242632304", Quality{5625960929244093294}, 300, FailShouldSucceed},
6442 {
"7047.112186735699",
"1649845866", Quality{5696855348026306945}, 504, FailShouldSucceed},
6443 {
"840236.4402981238",
"47419053", Quality{5982561601648018688}, 499, FailShouldSucceed},
6444 {
"992715.618909774",
"189445631733", Quality{5697835648288106944}, 815, SucceedShouldSucceedResize},
6445 {
"504636667521",
"185545883.9506651", Quality{6343802275337659280}, 503, SucceedShouldSucceedResize},
6446 {
"992706.7218636649",
"189447316000", Quality{5697835648288106944}, 797, SucceedShouldSucceedResize},
6447 {
"1.068737911388205",
"127860278877", Quality{5268604356368739396}, 293, SucceedShouldSucceedResize},
6448 {
"17932506.56880419",
"189308.6043676173", Quality{6206460598195440068}, 311, SucceedShouldSucceedResize},
6449 {
"1.066379294658174",
"128042251493", Quality{5268559341368739328}, 270, SucceedShouldSucceedResize},
6450 {
"350131413924",
"1576879.110907892", Quality{6487411636539049449}, 650,
Fail},
6451 {
"422093460",
"2.731797662057464", Quality{6702911108534394924}, 1000,
Fail},
6452 {
"76128132223",
"367172.7148422662", Quality{6487263463413514240}, 548,
Fail},
6453 {
"132701839250",
"280703770.7695443", Quality{6273750681188885075}, 562,
Fail},
6454 {
"994165.7604612011",
"189551302411", Quality{5697835592690668727}, 815,
Fail},
6455 {
"45053.33303227917",
"86612695359", Quality{5625695218943638190}, 500,
Fail},
6456 {
"199649.077043865",
"14017933007", Quality{5766034667318524880}, 324,
Fail},
6457 {
"27751824831.70903",
"78896950", Quality{6272538159621630432}, 500,
Fail},
6458 {
"225.3731275781907",
"156431793648", Quality{5477818047604078924}, 989,
Fail},
6459 {
"199649.077043865",
"14017933007", Quality{5766036094462806309}, 324,
Fail},
6460 {
"3.590272027140361",
"20677643641", Quality{5406056147042156356}, 808,
Fail},
6461 {
"1.070884664490231",
"127604712776", Quality{5268620608623825741}, 293,
Fail},
6462 {
"3272.448829820197",
"6275124076", Quality{5625710328924117902}, 81,
Fail},
6463 {
"0.009059512633902926",
"7994028", Quality{5477511954775533172}, 1000,
Fail},
6464 {
"1",
"1.0", Quality{0}, 100,
Fail},
6465 {
"1.0",
"1", Quality{0}, 100,
Fail},
6466 {
"10",
"10.0", Quality{xrpIouAmounts10_100}, 100,
Fail},
6467 {
"10.0",
"10", Quality{iouXrpAmounts10_100}, 100,
Fail},
6468 {
"69864389131",
"287631.4543025075", Quality{6487623473313516078}, 451, Succeed},
6469 {
"4328342973",
"12453825.99247381", Quality{6272522264364865181}, 997, Succeed},
6470 {
"32347017",
"7003.93031579449", Quality{6347261126087916670}, 1000, Succeed},
6471 {
"61697206161",
"36631.4583206413", Quality{6558965195382476659}, 500, Succeed},
6472 {
"1654524979",
"7028.659825511603", Quality{6487551345110052981}, 504, Succeed},
6473 {
"88621.22277293179",
"5128418948", Quality{5766347291552869205}, 380, Succeed},
6474 {
"1892611",
"0.01099814367603737", Quality{6703102780512015436}, 1000, Succeed},
6475 {
"4542.639373338766",
"24554809", Quality{5838994982188783710}, 0, Succeed},
6476 {
"5132932546",
"88542.99750172683", Quality{6419203342950054537}, 380, Succeed},
6477 {
"78929964.1549083",
"1506494795", Quality{5986890029845558688}, 589, Succeed},
6478 {
"10096561906",
"44727.72453735605", Quality{6487455290284644551}, 250, Succeed},
6479 {
"5092.219565514988",
"8768257694", Quality{5626349534958379008}, 503, Succeed},
6480 {
"1819778294",
"8305.084302902864", Quality{6487429398998540860}, 415, Succeed},
6481 {
"6970462.633911943",
"57359281", Quality{6054087899185946624}, 850, Succeed},
6482 {
"3983448845",
"2347.543644281467", Quality{6558965195382476659}, 856, Succeed},
6486 {
"771493171",
"1.243473020567508", Quality{6707566798038544272}, 100, SucceedShouldFail},
6490 boost::regex rx(
"^\\d+$");
6491 boost::smatch match;
6495 auto rules = env.
current()->rules();
6497 for (
auto const& t : tests)
6507 auto const poolInIsXRP =
6509 auto const poolOutIsXRP =
6511 assert(!(poolInIsXRP && poolOutIsXRP));
6512 auto const poolIn = getPool(
std::get<0>(t), poolInIsXRP);
6513 auto const poolOut = getPool(
std::get<1>(t), poolOutIsXRP);
6517 Amounts{poolIn, poolOut},
6524 if (status == SucceedShouldSucceedResize)
6526 if (!features[fixAMMv1_1])
6527 BEAST_EXPECT(Quality{*amounts} < quality);
6529 BEAST_EXPECT(Quality{*amounts} >= quality);
6531 else if (status == Succeed)
6533 if (!features[fixAMMv1_1])
6535 Quality{*amounts} >= quality ||
6537 Quality{*amounts}, quality,
Number{1, -7}));
6539 BEAST_EXPECT(Quality{*amounts} >= quality);
6541 else if (status == FailShouldSucceed)
6544 features[fixAMMv1_1] &&
6545 Quality{*amounts} >= quality);
6547 else if (status == SucceedShouldFail)
6550 !features[fixAMMv1_1] &&
6551 Quality{*amounts} < quality &&
6553 Quality{*amounts}, quality,
Number{1, -7}));
6562 if (status ==
Fail && quality != Quality{0})
6564 auto tinyOffer = [&]() {
6571 Amounts{poolIn, poolOut},
6575 else if (
isXRP(poolOut))
6580 Amounts{poolIn, poolOut},
6585 auto const takerPays = toAmount<STAmount>(
6590 Amounts{poolIn, poolOut}, takerPays, tfee)};
6592 BEAST_EXPECT(Quality(tinyOffer) < quality);
6594 else if (status == FailShouldSucceed)
6596 BEAST_EXPECT(!features[fixAMMv1_1]);
6598 else if (status == SucceedShouldFail)
6600 BEAST_EXPECT(features[fixAMMv1_1]);
6607 !strcmp(e.
what(),
"changeSpotPriceQuality failed"));
6609 !features[fixAMMv1_1] && status == FailShouldSucceed);
6618 BEAST_EXPECT(!res.has_value());
6684 using namespace jtx;
6690 Account const gatehub{
"gatehub"};
6691 Account const bitstamp{
"bitstamp"};
6692 Account const trader{
"trader"};
6693 auto const usdGH = gatehub[
"USD"];
6694 auto const btcGH = gatehub[
"BTC"];
6695 auto const usdBIT = bitstamp[
"USD"];
6699 char const* testCase;
6700 double const poolUsdBIT;
6701 double const poolUsdGH;
6714 double const offer1BtcGH = 0.1;
6715 double const offer2BtcGH = 0.1;
6716 double const offer2UsdGH = 1;
6717 double const rateBIT = 0.0;
6718 double const rateGH = 0.0;
6723 for (
auto const& input : {
6725 .testCase =
"Test Fix Overflow Offer",
6728 .sendMaxUsdBIT{usdBIT(50)},
6729 .sendUsdGH{usdGH,
uint64_t(272'455089820359), -12},
6732 .failUsdBIT{usdBIT,
uint64_t(46'47826086956522), -14},
6733 .failUsdBITr{usdBIT,
uint64_t(46'47826086956521), -14},
6734 .goodUsdGH{usdGH,
uint64_t(96'7543114220382), -13},
6735 .goodUsdGHr{usdGH,
uint64_t(96'7543114222965), -13},
6736 .goodUsdBIT{usdBIT,
uint64_t(8'464739069120721), -15},
6737 .goodUsdBITr{usdBIT,
uint64_t(8'464739069098152), -15},
6738 .lpTokenBalance = {28'61817604250837, -14},
6739 .lpTokenBalanceAlt =
IOUAmount{28'61817604250836, -14},
6747 .testCase =
"Overflow test {1, 100, 0.111}",
6750 .sendMaxUsdBIT{usdBIT(0.111)},
6751 .sendUsdGH{usdGH, 100},
6754 .failUsdBIT{usdBIT,
uint64_t(1'111), -3},
6755 .failUsdBITr{usdBIT,
uint64_t(1'111), -3},
6756 .goodUsdGH{usdGH,
uint64_t(90'04347888284115), -14},
6757 .goodUsdGHr{usdGH,
uint64_t(90'04347888284201), -14},
6758 .goodUsdBIT{usdBIT,
uint64_t(1'111), -3},
6759 .goodUsdBITr{usdBIT,
uint64_t(1'111), -3},
6760 .lpTokenBalance{10, 0},
6761 .offer1BtcGH = 1e-5,
6763 .offer2UsdGH = 1e-5,
6768 .testCase =
"Overflow test {1, 100, 1.00}",
6771 .sendMaxUsdBIT{usdBIT(1.00)},
6772 .sendUsdGH{usdGH, 100},
6775 .failUsdBIT{usdBIT,
uint64_t(2), 0},
6776 .failUsdBITr{usdBIT,
uint64_t(2), 0},
6777 .goodUsdGH{usdGH,
uint64_t(52'94379354424079), -14},
6778 .goodUsdGHr{usdGH,
uint64_t(52'94379354424135), -14},
6779 .goodUsdBIT{usdBIT,
uint64_t(2), 0},
6780 .goodUsdBITr{usdBIT,
uint64_t(2), 0},
6781 .lpTokenBalance{10, 0},
6782 .offer1BtcGH = 1e-5,
6784 .offer2UsdGH = 1e-5,
6789 .testCase =
"Overflow test {1, 100, 4.6432}",
6792 .sendMaxUsdBIT{usdBIT(4.6432)},
6793 .sendUsdGH{usdGH, 100},
6796 .failUsdBIT{usdBIT,
uint64_t(5'6432), -4},
6797 .failUsdBITr{usdBIT,
uint64_t(5'6432), -4},
6798 .goodUsdGH{usdGH,
uint64_t(35'44113971506987), -14},
6799 .goodUsdGHr{usdGH,
uint64_t(35'44113971506987), -14},
6800 .goodUsdBIT{usdBIT,
uint64_t(2'821579689703915), -15},
6801 .goodUsdBITr{usdBIT,
uint64_t(2'821579689703954), -15},
6802 .lpTokenBalance{10, 0},
6803 .offer1BtcGH = 1e-5,
6805 .offer2UsdGH = 1e-5,
6810 .testCase =
"Overflow test {1, 100, 10}",
6813 .sendMaxUsdBIT{usdBIT(10)},
6814 .sendUsdGH{usdGH, 100},
6817 .failUsdBIT{usdBIT,
uint64_t(11), 0},
6818 .failUsdBITr{usdBIT,
uint64_t(11), 0},
6819 .goodUsdGH{usdGH,
uint64_t(35'44113971506987), -14},
6820 .goodUsdGHr{usdGH,
uint64_t(35'44113971506987), -14},
6821 .goodUsdBIT{usdBIT,
uint64_t(2'821579689703915), -15},
6822 .goodUsdBITr{usdBIT,
uint64_t(2'821579689703954), -15},
6823 .lpTokenBalance{10, 0},
6824 .offer1BtcGH = 1e-5,
6826 .offer2UsdGH = 1e-5,
6831 .testCase =
"Overflow test {50, 100, 5.55}",
6834 .sendMaxUsdBIT{usdBIT(5.55)},
6835 .sendUsdGH{usdGH, 100},
6838 .failUsdBIT{usdBIT,
uint64_t(55'55), -2},
6839 .failUsdBITr{usdBIT,
uint64_t(55'55), -2},
6840 .goodUsdGH{usdGH,
uint64_t(90'04347888284113), -14},
6841 .goodUsdGHr{usdGH,
uint64_t(90'0434788828413), -13},
6842 .goodUsdBIT{usdBIT,
uint64_t(55'55), -2},
6843 .goodUsdBITr{usdBIT,
uint64_t(55'55), -2},
6844 .lpTokenBalance{
uint64_t(70'71067811865475), -14},
6845 .offer1BtcGH = 1e-5,
6847 .offer2UsdGH = 1e-5,
6852 .testCase =
"Overflow test {50, 100, 50.00}",
6855 .sendMaxUsdBIT{usdBIT(50.00)},
6856 .sendUsdGH{usdGH, 100},
6857 .failUsdGH{usdGH,
uint64_t(52'94379354424081), -14},
6858 .failUsdGHr{usdGH,
uint64_t(52'94379354424092), -14},
6859 .failUsdBIT{usdBIT,
uint64_t(100), 0},
6860 .failUsdBITr{usdBIT,
uint64_t(100), 0},
6861 .goodUsdGH{usdGH,
uint64_t(52'94379354424081), -14},
6862 .goodUsdGHr{usdGH,
uint64_t(52'94379354424092), -14},
6863 .goodUsdBIT{usdBIT,
uint64_t(100), 0},
6864 .goodUsdBITr{usdBIT,
uint64_t(100), 0},
6865 .lpTokenBalance{
uint64_t(70'71067811865475), -14},
6866 .offer1BtcGH = 1e-5,
6868 .offer2UsdGH = 1e-5,
6873 .testCase =
"Overflow test {50, 100, 232.16}",
6876 .sendMaxUsdBIT{usdBIT(232.16)},
6877 .sendUsdGH{usdGH, 100},
6880 .failUsdBIT{usdBIT,
uint64_t(282'16), -2},
6881 .failUsdBITr{usdBIT,
uint64_t(282'16), -2},
6882 .goodUsdGH{usdGH,
uint64_t(35'44113971506987), -14},
6883 .goodUsdGHr{usdGH,
uint64_t(35'44113971506987), -14},
6884 .goodUsdBIT{usdBIT,
uint64_t(141'0789844851958), -13},
6885 .goodUsdBITr{usdBIT,
uint64_t(141'0789844851962), -13},
6886 .lpTokenBalance{70'71067811865475, -14},
6887 .offer1BtcGH = 1e-5,
6889 .offer2UsdGH = 1e-5,
6894 .testCase =
"Overflow test {50, 100, 500}",
6897 .sendMaxUsdBIT{usdBIT(500)},
6898 .sendUsdGH{usdGH, 100},
6901 .failUsdBIT{usdBIT,
uint64_t(550), 0},
6902 .failUsdBITr{usdBIT,
uint64_t(550), 0},
6903 .goodUsdGH{usdGH,
uint64_t(35'44113971506987), -14},
6904 .goodUsdGHr{usdGH,
uint64_t(35'44113971506987), -14},
6905 .goodUsdBIT{usdBIT,
uint64_t(141'0789844851958), -13},
6906 .goodUsdBITr{usdBIT,
uint64_t(141'0789844851962), -13},
6907 .lpTokenBalance{70'71067811865475, -14},
6908 .offer1BtcGH = 1e-5,
6910 .offer2UsdGH = 1e-5,
6916 testcase(input.testCase);
6917 for (
auto const& features :
6918 {all - fixAMMOverflowOffer - fixAMMv1_1 - fixAMMv1_3, all})
6922 env.
fund(
XRP(5'000), gatehub, bitstamp, trader);
6925 if (input.rateGH != 0.0)
6926 env(rate(gatehub, input.rateGH));
6927 if (input.rateBIT != 0.0)
6928 env(rate(bitstamp, input.rateBIT));
6930 env(trust(trader, usdGH(10'000'000)));
6931 env(trust(trader, usdBIT(10'000'000)));
6932 env(trust(trader, btcGH(10'000'000)));
6935 env(pay(gatehub, trader, usdGH(100'000)));
6936 env(pay(gatehub, trader, btcGH(100'000)));
6937 env(pay(bitstamp, trader, usdBIT(100'000)));
6943 usdGH(input.poolUsdGH),
6944 usdBIT(input.poolUsdBIT)};
6948 amm.getLPTokensBalance();
6950 env(offer(trader, usdBIT(1), btcGH(input.offer1BtcGH)));
6953 btcGH(input.offer2BtcGH),
6954 usdGH(input.offer2UsdGH)));
6957 env(pay(trader, trader, input.sendUsdGH),
6959 path(~btcGH, ~usdGH),
6964 auto const failUsdGH =
6965 features[fixAMMv1_1] ? input.failUsdGHr : input.failUsdGH;
6966 auto const failUsdBIT =
6967 features[fixAMMv1_1] ? input.failUsdBITr : input.failUsdBIT;
6968 auto const goodUsdGH =
6969 features[fixAMMv1_1] ? input.goodUsdGHr : input.goodUsdGH;
6970 auto const goodUsdBIT =
6971 features[fixAMMv1_1] ? input.goodUsdBITr : input.goodUsdBIT;
6972 auto const lpTokenBalance =
6973 env.
enabled(fixAMMv1_3) && input.lpTokenBalanceAlt
6974 ? *input.lpTokenBalanceAlt
6975 : input.lpTokenBalance;
6976 if (!features[fixAMMOverflowOffer])
6978 BEAST_EXPECT(amm.expectBalances(
6979 failUsdGH, failUsdBIT, lpTokenBalance));
6983 BEAST_EXPECT(amm.expectBalances(
6984 goodUsdGH, goodUsdBIT, lpTokenBalance));
6989 amm.getLPTokensBalance() == preSwapLPTokenBalance);
6993 Number const sqrtPoolProduct =
6994 root2(goodUsdGH * goodUsdBIT);
7005 (sqrtPoolProduct +
Number{1, -14} >=
7006 input.lpTokenBalance));