mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-20 02:25:53 +00:00
Add fixAMMv1_2 amendment (#5176)
* Add reserve check on AMM Withdraw * Try AMM max offer if changeSpotPriceQuality() fails
This commit is contained in:
@@ -80,7 +80,7 @@ namespace detail {
|
|||||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
// 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
|
// 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.
|
// the actual number of amendments. A LogicError on startup will verify this.
|
||||||
static constexpr std::size_t numFeatures = 104;
|
static constexpr std::size_t numFeatures = 105;
|
||||||
|
|
||||||
/** Amendments that this server supports and the default voting behavior.
|
/** Amendments that this server supports and the default voting behavior.
|
||||||
Whether they are enabled depends on the Rules defined in the validated
|
Whether they are enabled depends on the Rules defined in the validated
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||||
// in include/xrpl/protocol/Feature.h.
|
// 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
|
// InvariantsV1_1 will be changes to Supported::yes when all the
|
||||||
// invariants expected to be included under it are complete.
|
// invariants expected to be included under it are complete.
|
||||||
XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo)
|
XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo)
|
||||||
|
|||||||
@@ -7064,6 +7064,55 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
@@ -7117,6 +7166,8 @@ private:
|
|||||||
testAMMDepositWithFrozenAssets(all);
|
testAMMDepositWithFrozenAssets(all);
|
||||||
testAMMDepositWithFrozenAssets(all - featureAMMClawback);
|
testAMMDepositWithFrozenAssets(all - featureAMMClawback);
|
||||||
testAMMDepositWithFrozenAssets(all - fixAMMv1_1 - featureAMMClawback);
|
testAMMDepositWithFrozenAssets(all - fixAMMv1_1 - featureAMMClawback);
|
||||||
|
testFixReserveCheckOnWithdrawal(all);
|
||||||
|
testFixReserveCheckOnWithdrawal(all - fixAMMv1_2);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -211,6 +211,13 @@ AMMLiquidity<TIn, TOut>::getOffer(
|
|||||||
return AMMOffer<TIn, TOut>(
|
return AMMOffer<TIn, TOut>(
|
||||||
*this, *amounts, balances, Quality{*amounts});
|
*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)
|
catch (std::overflow_error const& e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ AMMClawback::applyGuts(Sandbox& sb)
|
|||||||
0,
|
0,
|
||||||
FreezeHandling::fhIGNORE_FREEZE,
|
FreezeHandling::fhIGNORE_FREEZE,
|
||||||
WithdrawAll::Yes,
|
WithdrawAll::Yes,
|
||||||
|
mPriorBalance,
|
||||||
ctx_.journal);
|
ctx_.journal);
|
||||||
else
|
else
|
||||||
std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) =
|
std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) =
|
||||||
@@ -267,6 +268,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
|
|||||||
0,
|
0,
|
||||||
FreezeHandling::fhIGNORE_FREEZE,
|
FreezeHandling::fhIGNORE_FREEZE,
|
||||||
WithdrawAll::Yes,
|
WithdrawAll::Yes,
|
||||||
|
mPriorBalance,
|
||||||
ctx_.journal);
|
ctx_.journal);
|
||||||
|
|
||||||
// Because we are doing a two-asset withdrawal,
|
// Because we are doing a two-asset withdrawal,
|
||||||
@@ -284,6 +286,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
|
|||||||
0,
|
0,
|
||||||
FreezeHandling::fhIGNORE_FREEZE,
|
FreezeHandling::fhIGNORE_FREEZE,
|
||||||
WithdrawAll::No,
|
WithdrawAll::No,
|
||||||
|
mPriorBalance,
|
||||||
ctx_.journal);
|
ctx_.journal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -472,6 +472,7 @@ AMMWithdraw::withdraw(
|
|||||||
tfee,
|
tfee,
|
||||||
FreezeHandling::fhZERO_IF_FROZEN,
|
FreezeHandling::fhZERO_IF_FROZEN,
|
||||||
isWithdrawAll(ctx_.tx),
|
isWithdrawAll(ctx_.tx),
|
||||||
|
mPriorBalance,
|
||||||
j_);
|
j_);
|
||||||
return {ter, newLPTokenBalance};
|
return {ter, newLPTokenBalance};
|
||||||
}
|
}
|
||||||
@@ -490,6 +491,7 @@ AMMWithdraw::withdraw(
|
|||||||
std::uint16_t tfee,
|
std::uint16_t tfee,
|
||||||
FreezeHandling freezeHandling,
|
FreezeHandling freezeHandling,
|
||||||
WithdrawAll withdrawAll,
|
WithdrawAll withdrawAll,
|
||||||
|
XRPAmount const& priorBalance,
|
||||||
beast::Journal const& journal)
|
beast::Journal const& journal)
|
||||||
{
|
{
|
||||||
auto const lpTokens = ammLPHolds(view, ammSle, account, journal);
|
auto const lpTokens = ammLPHolds(view, ammSle, account, journal);
|
||||||
@@ -589,6 +591,33 @@ AMMWithdraw::withdraw(
|
|||||||
return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}};
|
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
|
// Withdraw amountWithdraw
|
||||||
auto res = accountSend(
|
auto res = accountSend(
|
||||||
view,
|
view,
|
||||||
@@ -609,6 +638,10 @@ AMMWithdraw::withdraw(
|
|||||||
// Withdraw amount2Withdraw
|
// Withdraw amount2Withdraw
|
||||||
if (amount2WithdrawActual)
|
if (amount2WithdrawActual)
|
||||||
{
|
{
|
||||||
|
if (auto const err = sufficientReserve(amount2WithdrawActual->issue());
|
||||||
|
err != tesSUCCESS)
|
||||||
|
return {err, STAmount{}, STAmount{}, STAmount{}};
|
||||||
|
|
||||||
res = accountSend(
|
res = accountSend(
|
||||||
view,
|
view,
|
||||||
ammAccount,
|
ammAccount,
|
||||||
@@ -676,6 +709,7 @@ AMMWithdraw::equalWithdrawTokens(
|
|||||||
tfee,
|
tfee,
|
||||||
FreezeHandling::fhZERO_IF_FROZEN,
|
FreezeHandling::fhZERO_IF_FROZEN,
|
||||||
isWithdrawAll(ctx_.tx),
|
isWithdrawAll(ctx_.tx),
|
||||||
|
mPriorBalance,
|
||||||
ctx_.journal);
|
ctx_.journal);
|
||||||
return {ter, newLPTokenBalance};
|
return {ter, newLPTokenBalance};
|
||||||
}
|
}
|
||||||
@@ -725,6 +759,7 @@ AMMWithdraw::equalWithdrawTokens(
|
|||||||
std::uint16_t tfee,
|
std::uint16_t tfee,
|
||||||
FreezeHandling freezeHanding,
|
FreezeHandling freezeHanding,
|
||||||
WithdrawAll withdrawAll,
|
WithdrawAll withdrawAll,
|
||||||
|
XRPAmount const& priorBalance,
|
||||||
beast::Journal const& journal)
|
beast::Journal const& journal)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -745,6 +780,7 @@ AMMWithdraw::equalWithdrawTokens(
|
|||||||
tfee,
|
tfee,
|
||||||
freezeHanding,
|
freezeHanding,
|
||||||
WithdrawAll::Yes,
|
WithdrawAll::Yes,
|
||||||
|
priorBalance,
|
||||||
journal);
|
journal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -773,6 +809,7 @@ AMMWithdraw::equalWithdrawTokens(
|
|||||||
tfee,
|
tfee,
|
||||||
freezeHanding,
|
freezeHanding,
|
||||||
withdrawAll,
|
withdrawAll,
|
||||||
|
priorBalance,
|
||||||
journal);
|
journal);
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public:
|
|||||||
* @param lpTokensWithdraw amount of tokens to withdraw
|
* @param lpTokensWithdraw amount of tokens to withdraw
|
||||||
* @param tfee trading fee in basis points
|
* @param tfee trading fee in basis points
|
||||||
* @param withdrawAll if withdrawing all lptokens
|
* @param withdrawAll if withdrawing all lptokens
|
||||||
|
* @param priorBalance balance before fees
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
|
static std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
|
||||||
@@ -112,6 +113,7 @@ public:
|
|||||||
std::uint16_t tfee,
|
std::uint16_t tfee,
|
||||||
FreezeHandling freezeHanding,
|
FreezeHandling freezeHanding,
|
||||||
WithdrawAll withdrawAll,
|
WithdrawAll withdrawAll,
|
||||||
|
XRPAmount const& priorBalance,
|
||||||
beast::Journal const& journal);
|
beast::Journal const& journal);
|
||||||
|
|
||||||
/** Withdraw requested assets and token from AMM into LP account.
|
/** Withdraw requested assets and token from AMM into LP account.
|
||||||
@@ -127,6 +129,7 @@ public:
|
|||||||
* @param lpTokensWithdraw amount of lptokens to withdraw
|
* @param lpTokensWithdraw amount of lptokens to withdraw
|
||||||
* @param tfee trading fee in basis points
|
* @param tfee trading fee in basis points
|
||||||
* @param withdrawAll if withdraw all lptokens
|
* @param withdrawAll if withdraw all lptokens
|
||||||
|
* @param priorBalance balance before fees
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
|
static std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
|
||||||
@@ -143,6 +146,7 @@ public:
|
|||||||
std::uint16_t tfee,
|
std::uint16_t tfee,
|
||||||
FreezeHandling freezeHandling,
|
FreezeHandling freezeHandling,
|
||||||
WithdrawAll withdrawAll,
|
WithdrawAll withdrawAll,
|
||||||
|
XRPAmount const& priorBalance,
|
||||||
beast::Journal const& journal);
|
beast::Journal const& journal);
|
||||||
|
|
||||||
static std::pair<TER, bool>
|
static std::pair<TER, bool>
|
||||||
|
|||||||
Reference in New Issue
Block a user