mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-01 03:21:04 +00:00
fix: removes redundant global freeze checks
This commit is contained in:
@@ -72,6 +72,9 @@ isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const&
|
||||
[[nodiscard]] TER
|
||||
checkIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset);
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkIndividualDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset);
|
||||
|
||||
/**
|
||||
* isFrozen check is recursive for MPT shares in a vault, descending to
|
||||
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
|
||||
|
||||
@@ -79,6 +79,14 @@ checkIndividualFrozen(ReadView const& view, AccountID const& account, Asset cons
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
checkIndividualDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset)
|
||||
{
|
||||
if (isDeepFrozen(view, account, asset))
|
||||
return asset.holds<MPTIssue>() ? tecLOCKED : tecFROZEN;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, std::uint8_t depth)
|
||||
{
|
||||
@@ -176,25 +184,29 @@ checkWithdrawFreeze(
|
||||
isPseudoAccount(view, srcAcct),
|
||||
"xrpl::checkWithdrawFreeze : source must be a pseudo-account");
|
||||
|
||||
// No matter what, funds can be sent to the issuer
|
||||
// Funds can always be sent to the issuer
|
||||
if (dstAcct == asset.getIssuer())
|
||||
return tesSUCCESS;
|
||||
|
||||
// If the asset is globally frozen, other checks are redundant
|
||||
if (auto const ret = checkGlobalFrozen(view, asset))
|
||||
return ret;
|
||||
|
||||
// The transfer is from Submitter to Destination via Source (pseudo-account)
|
||||
// Both Source and Submitter must not be frozen to allow sending funds
|
||||
if (auto const ret = checkFrozen(view, srcAcct, asset))
|
||||
if (auto const ret = checkIndividualFrozen(view, srcAcct, asset))
|
||||
return ret;
|
||||
|
||||
// Check submitter's individual freeze only when Submitter != Destination (a regular freeze
|
||||
// should not block self-withdrawal).
|
||||
if (submitterAcct != dstAcct)
|
||||
{
|
||||
if (auto const ret = checkFrozen(view, submitterAcct, asset))
|
||||
if (auto const ret = checkIndividualFrozen(view, submitterAcct, asset))
|
||||
return ret;
|
||||
}
|
||||
|
||||
// The destination account must not be deep frozen to receive the funds
|
||||
return checkDeepFrozen(view, dstAcct, asset);
|
||||
return checkIndividualDeepFrozen(view, dstAcct, asset);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
@@ -208,12 +220,22 @@ checkDepositFreeze(
|
||||
isPseudoAccount(view, dstAcct),
|
||||
"xrpl::checkDepositFreeze : destination must be a pseudo-account");
|
||||
|
||||
if (auto const ret = checkFrozen(view, srcAcct, asset))
|
||||
// An Issuer cannot deposit when:
|
||||
// 1. Asset is globally frozen
|
||||
// 2. The trustline of the pseudo-account is frozen
|
||||
|
||||
if (auto const ret = checkGlobalFrozen(view, asset))
|
||||
return ret;
|
||||
|
||||
if (srcAcct != asset.getIssuer())
|
||||
{
|
||||
if (auto const ret = checkIndividualFrozen(view, srcAcct, asset))
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Unlike regular accounts, pseudo-accounts cannot receive deposits under a regular freeze
|
||||
// because those funds cannot be later withdrawn
|
||||
return checkFrozen(view, dstAcct, asset);
|
||||
return checkIndividualFrozen(view, dstAcct, asset);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -7462,24 +7462,41 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
// MPTLock is set
|
||||
usd.set({.flags = tfMPTLock});
|
||||
auto const fix330 = env.current()->rules().enabled(fixCleanup3_3_0);
|
||||
// carol can't withdraw the locked token; post-fixCleanup3_3_0 the
|
||||
// issuer can still redeem its own locked token.
|
||||
for (auto const& account : {carol, gw})
|
||||
{
|
||||
auto const lockErr =
|
||||
(fix330 && account == gw) ? Ter(tesSUCCESS) : Ter(tecLOCKED);
|
||||
amm.withdraw(
|
||||
{.account = account,
|
||||
.asset1Out = usd(1),
|
||||
.asset2Out = eur(1),
|
||||
.err = lockErr});
|
||||
amm.withdraw({.account = account, .tokens = 1'000, .err = lockErr});
|
||||
// can single withdraw another asset
|
||||
amm.withdraw(
|
||||
{.account = account,
|
||||
.asset1Out = eur(1),
|
||||
.assets = std::make_pair(eur, usd)});
|
||||
}
|
||||
|
||||
// carol can't withdraw the locked token (any withdrawal type)
|
||||
amm.withdraw(
|
||||
{.account = carol,
|
||||
.asset1Out = usd(1),
|
||||
.asset2Out = eur(1),
|
||||
.err = Ter(tecLOCKED)});
|
||||
amm.withdraw({.account = carol, .tokens = 1'000, .err = Ter(tecLOCKED)});
|
||||
// can single withdraw the non-locked asset
|
||||
amm.withdraw(
|
||||
{.account = carol, .asset1Out = eur(1), .assets = std::make_pair(eur, usd)});
|
||||
|
||||
// post-fixCleanup3_3_0 the issuer can redeem even when locked.
|
||||
// Each successful withdrawal burns LP tokens, so replenish between
|
||||
// each type to keep gw's LP balance stable.
|
||||
auto const gwLockErr = fix330 ? Ter(tesSUCCESS) : Ter(tecLOCKED);
|
||||
auto const replenish = [&](IOUAmount tokens) {
|
||||
usd.set({.flags = tfMPTUnlock});
|
||||
amm.deposit({.account = gw, .tokens = tokens});
|
||||
usd.set({.flags = tfMPTLock});
|
||||
};
|
||||
|
||||
amm.withdraw(
|
||||
{.account = gw, .asset1Out = usd(1), .asset2Out = eur(1), .err = gwLockErr});
|
||||
if (fix330)
|
||||
replenish(IOUAmount{1});
|
||||
|
||||
amm.withdraw({.account = gw, .tokens = 1'000, .err = gwLockErr});
|
||||
if (fix330)
|
||||
replenish(IOUAmount{1'000});
|
||||
|
||||
// can single withdraw the non-locked asset
|
||||
amm.withdraw(
|
||||
{.account = gw, .asset1Out = eur(1), .assets = std::make_pair(eur, usd)});
|
||||
|
||||
usd.set({.flags = tfMPTUnlock});
|
||||
|
||||
// MPTRequireAuth is set
|
||||
|
||||
Reference in New Issue
Block a user