Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fixAMMv1_2 amendment #5176

Merged
merged 8 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/xrpl/protocol/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 81;
static constexpr std::size_t numFeatures = 82;

/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
Expand Down
1 change: 1 addition & 0 deletions include/xrpl/protocol/detail/features.macro
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.

XRPL_FIX (AMMv1_2, Supported::yes, VoteBehavior::DefaultNo)
// InvariantsV1_1 will be changes to Supported::yes when all the
// invariants expected to be included under it are complete.
XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo)
Expand Down
51 changes: 51 additions & 0 deletions src/test/app/AMM_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7064,6 +7064,55 @@ struct AMM_test : public jtx::AMMTest
}
}

void
testFixReserveCheckOnWithdrawal(FeatureBitset features)
{
testcase("Fix Reserve Check On Withdrawal");
using namespace jtx;

auto const err = features[fixAMMv1_2] ? ter(tecINSUFFICIENT_RESERVE)
: ter(tesSUCCESS);

auto test = [&](auto&& cb) {
Env env(*this, features);
auto const starting_xrp =
reserve(env, 2) + env.current()->fees().base * 5;
env.fund(starting_xrp, gw);
env.fund(starting_xrp, alice);
env.trust(USD(2'000), alice);
env.close();
env(pay(gw, alice, USD(2'000)));
env.close();
AMM amm(env, gw, EUR(1'000), USD(1'000));
amm.deposit(alice, USD(1));
cb(amm);
};

// Equal withdraw
test([&](AMM& amm) { amm.withdrawAll(alice, std::nullopt, err); });

// Equal withdraw with a limit
test([&](AMM& amm) {
amm.withdraw(WithdrawArg{
.account = alice,
.asset1Out = EUR(0.1),
.asset2Out = USD(0.1),
.err = err});
amm.withdraw(WithdrawArg{
.account = alice,
.asset1Out = USD(0.1),
.asset2Out = EUR(0.1),
.err = err});
});

// Single withdraw
test([&](AMM& amm) {
amm.withdraw(WithdrawArg{
.account = alice, .asset1Out = EUR(0.1), .err = err});
amm.withdraw(WithdrawArg{.account = alice, .asset1Out = USD(0.1)});
});
}

void
run() override
{
Expand Down Expand Up @@ -7117,6 +7166,8 @@ struct AMM_test : public jtx::AMMTest
testAMMDepositWithFrozenAssets(all);
testAMMDepositWithFrozenAssets(all - featureAMMClawback);
testAMMDepositWithFrozenAssets(all - fixAMMv1_1 - featureAMMClawback);
testFixReserveCheckOnWithdrawal(all);
testFixReserveCheckOnWithdrawal(all - fixAMMv1_2);
}
};

Expand Down
7 changes: 7 additions & 0 deletions src/xrpld/app/paths/detail/AMMLiquidity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ AMMLiquidity<TIn, TOut>::getOffer(
return AMMOffer<TIn, TOut>(
*this, *amounts, balances, Quality{*amounts});
}
else if (view.rules().enabled(fixAMMv1_2))
{
if (auto const maxAMMOffer = maxOffer(balances, view.rules());
maxAMMOffer &&
Quality{maxAMMOffer->amount()} > *clobQuality)
return maxAMMOffer;
}
}
catch (std::overflow_error const& e)
{
Expand Down
3 changes: 3 additions & 0 deletions src/xrpld/app/tx/detail/AMMClawback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ AMMClawback::applyGuts(Sandbox& sb)
0,
FreezeHandling::fhIGNORE_FREEZE,
WithdrawAll::Yes,
mPriorBalance,
ctx_.journal);
else
std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) =
Expand Down Expand Up @@ -267,6 +268,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
0,
FreezeHandling::fhIGNORE_FREEZE,
WithdrawAll::Yes,
mPriorBalance,
ctx_.journal);

// Because we are doing a two-asset withdrawal,
Expand All @@ -284,6 +286,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
0,
FreezeHandling::fhIGNORE_FREEZE,
WithdrawAll::No,
mPriorBalance,
ctx_.journal);
}

Expand Down
37 changes: 37 additions & 0 deletions src/xrpld/app/tx/detail/AMMWithdraw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ AMMWithdraw::withdraw(
tfee,
FreezeHandling::fhZERO_IF_FROZEN,
isWithdrawAll(ctx_.tx),
mPriorBalance,
j_);
return {ter, newLPTokenBalance};
}
Expand All @@ -490,6 +491,7 @@ AMMWithdraw::withdraw(
std::uint16_t tfee,
FreezeHandling freezeHandling,
WithdrawAll withdrawAll,
XRPAmount const& priorBalance,
beast::Journal const& journal)
{
auto const lpTokens = ammLPHolds(view, ammSle, account, journal);
Expand Down Expand Up @@ -589,6 +591,33 @@ AMMWithdraw::withdraw(
return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}};
}

// Check the reserve in case a trustline has to be created
bool const enabledFixAMMv1_2 = view.rules().enabled(fixAMMv1_2);
auto sufficientReserve = [&](Issue const& issue) -> TER {
if (!enabledFixAMMv1_2 || isXRP(issue))
return tesSUCCESS;
if (!view.exists(keylet::line(account, issue)))
{
auto const sleAccount = view.read(keylet::account(account));
if (!sleAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const balance = (*sleAccount)[sfBalance].xrp();
std::uint32_t const ownerCount = sleAccount->at(sfOwnerCount);

// See also SetTrust::doApply()
XRPAmount const reserve(
(ownerCount < 2) ? XRPAmount(beast::zero)
: view.fees().accountReserve(ownerCount + 1));

if (std::max(priorBalance, balance) < reserve)
return tecINSUFFICIENT_RESERVE;
}
return tesSUCCESS;
};

if (auto const err = sufficientReserve(amountWithdrawActual.issue()))
return {err, STAmount{}, STAmount{}, STAmount{}};

// Withdraw amountWithdraw
auto res = accountSend(
view,
Expand All @@ -609,6 +638,10 @@ AMMWithdraw::withdraw(
// Withdraw amount2Withdraw
if (amount2WithdrawActual)
{
if (auto const err = sufficientReserve(amount2WithdrawActual->issue());
err != tesSUCCESS)
return {err, STAmount{}, STAmount{}, STAmount{}};

res = accountSend(
view,
ammAccount,
Expand Down Expand Up @@ -676,6 +709,7 @@ AMMWithdraw::equalWithdrawTokens(
tfee,
FreezeHandling::fhZERO_IF_FROZEN,
isWithdrawAll(ctx_.tx),
mPriorBalance,
ctx_.journal);
return {ter, newLPTokenBalance};
}
Expand Down Expand Up @@ -725,6 +759,7 @@ AMMWithdraw::equalWithdrawTokens(
std::uint16_t tfee,
FreezeHandling freezeHanding,
WithdrawAll withdrawAll,
XRPAmount const& priorBalance,
beast::Journal const& journal)
{
try
Expand All @@ -745,6 +780,7 @@ AMMWithdraw::equalWithdrawTokens(
tfee,
freezeHanding,
WithdrawAll::Yes,
priorBalance,
journal);
}

Expand Down Expand Up @@ -773,6 +809,7 @@ AMMWithdraw::equalWithdrawTokens(
tfee,
freezeHanding,
withdrawAll,
priorBalance,
journal);
}
// LCOV_EXCL_START
Expand Down
4 changes: 4 additions & 0 deletions src/xrpld/app/tx/detail/AMMWithdraw.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class AMMWithdraw : public Transactor
* @param lpTokensWithdraw amount of tokens to withdraw
* @param tfee trading fee in basis points
* @param withdrawAll if withdrawing all lptokens
* @param priorBalance balance before fees
* @return
*/
static std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
Expand All @@ -112,6 +113,7 @@ class AMMWithdraw : public Transactor
std::uint16_t tfee,
FreezeHandling freezeHanding,
WithdrawAll withdrawAll,
XRPAmount const& priorBalance,
beast::Journal const& journal);

/** Withdraw requested assets and token from AMM into LP account.
Expand All @@ -127,6 +129,7 @@ class AMMWithdraw : public Transactor
* @param lpTokensWithdraw amount of lptokens to withdraw
* @param tfee trading fee in basis points
* @param withdrawAll if withdraw all lptokens
* @param priorBalance balance before fees
* @return
*/
static std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
Expand All @@ -143,6 +146,7 @@ class AMMWithdraw : public Transactor
std::uint16_t tfee,
FreezeHandling freezeHandling,
WithdrawAll withdrawAll,
XRPAmount const& priorBalance,
beast::Journal const& journal);

static std::pair<TER, bool>
Expand Down
Loading