mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-24 07:30:30 +00:00
adds BLockDeposit flagsto VaultSet
This commit is contained in:
@@ -296,7 +296,7 @@ constexpr std::uint32_t const tfLoanManageMask = ~(tfUniversal | tfLoanDefault |
|
||||
// VaultSet flags:
|
||||
constexpr std::uint32_t const tfVaultDepositBlock = 0x00010000;
|
||||
constexpr std::uint32_t const tfVaultDepositUnblock = 0x00020000;
|
||||
constexpr std::uint32_t const tfVaultManageMask = ~(tfUniversal | tfVaultDepositBlock | tfVaultDepositUnblock);
|
||||
constexpr std::uint32_t const tfVaultSetMask = ~(tfUniversal | tfVaultDepositBlock | tfVaultDepositUnblock);
|
||||
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -4990,6 +4990,97 @@ class Vault_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testVaultSetVaultDepositFlagValidation()
|
||||
{
|
||||
using namespace test::jtx;
|
||||
|
||||
auto const all = testable_amendments();
|
||||
|
||||
{
|
||||
testcase("VaultSet VaultDepositBlock fixLendingProtocolV1_1 disabled");
|
||||
Env env{*this, all - fixLendingProtocolV1_1};
|
||||
|
||||
Account owner{"owner"};
|
||||
env.fund(XRP(1'000'000), owner);
|
||||
env.close();
|
||||
|
||||
PrettyAsset asset = xrpIssue();
|
||||
Vault vault{env};
|
||||
|
||||
auto const [tx, keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
|
||||
env(tx, ter(tesSUCCESS), THISLINE);
|
||||
env.close();
|
||||
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositBlock}),
|
||||
ter(temDISABLED),
|
||||
THISLINE);
|
||||
env.close();
|
||||
}
|
||||
|
||||
{
|
||||
std::string const prefix = "VaultSet(VaultDepositBlock): ";
|
||||
Env env{*this, all | fixLendingProtocolV1_1};
|
||||
|
||||
Account owner{"owner"};
|
||||
env.fund(XRP(1'000'000), owner);
|
||||
env.close();
|
||||
|
||||
PrettyAsset asset = xrpIssue();
|
||||
Vault vault{env};
|
||||
|
||||
auto const [tx, keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
|
||||
env(tx, ter(tesSUCCESS), THISLINE);
|
||||
env.close();
|
||||
|
||||
{
|
||||
testcase(prefix + "invalid flags");
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositBlock | tfVaultDepositUnblock}),
|
||||
ter(temMALFORMED),
|
||||
THISLINE);
|
||||
env.close();
|
||||
}
|
||||
|
||||
{
|
||||
testcase(prefix + "unblock already unblocked vault");
|
||||
// Cannot unblock an already unblocked vault
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositUnblock}),
|
||||
ter(tecNO_PERMISSION),
|
||||
THISLINE);
|
||||
}
|
||||
|
||||
{
|
||||
testcase(prefix + "set and clear vault flag");
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositBlock}),
|
||||
ter(tesSUCCESS),
|
||||
THISLINE);
|
||||
|
||||
auto sleVault = env.le(keylet);
|
||||
if (!BEAST_EXPECT(sleVault))
|
||||
return;
|
||||
|
||||
if (!BEAST_EXPECT(sleVault->isFlag(lsfVaultDepositBlocked)))
|
||||
return;
|
||||
|
||||
// Cannot block an already blocked vault
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositBlock}),
|
||||
ter(tecNO_PERMISSION),
|
||||
THISLINE);
|
||||
|
||||
// Cannot unblock an already unblocked vault
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositUnblock}),
|
||||
ter(tesSUCCESS),
|
||||
THISLINE);
|
||||
|
||||
sleVault = env.le(keylet);
|
||||
if (!BEAST_EXPECT(sleVault))
|
||||
return;
|
||||
|
||||
BEAST_EXPECT(!sleVault->isFlag(lsfVaultDepositBlocked));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
@@ -5011,6 +5102,7 @@ public:
|
||||
testVaultClawbackBurnShares();
|
||||
testVaultClawbackAssets();
|
||||
testAssetsMaximum();
|
||||
testVaultSetVaultDepositFlagValidation();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ Vault::set(SetArgs const& args)
|
||||
jv[jss::TransactionType] = jss::VaultSet;
|
||||
jv[jss::Account] = args.owner.human();
|
||||
jv[sfVaultID] = to_string(args.id);
|
||||
if (args.flags)
|
||||
jv[jss::Flags] = *args.flags;
|
||||
return jv;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ struct Vault
|
||||
{
|
||||
Account owner;
|
||||
uint256 id;
|
||||
std::optional<std::uint32_t> flags{};
|
||||
};
|
||||
|
||||
Json::Value
|
||||
|
||||
@@ -21,9 +21,34 @@ VaultSet::checkExtraFeatures(PreflightContext const& ctx)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
VaultSet::getFlagsMask(PreflightContext const& ctx)
|
||||
{
|
||||
return tfVaultSetMask;
|
||||
}
|
||||
|
||||
static bool
|
||||
isValidVaultUpdate(PreflightContext const& ctx)
|
||||
{
|
||||
auto const checkFlags = ctx.rules.enabled(fixLendingProtocolV1_1);
|
||||
|
||||
auto const atLeastOneFieldPresent =
|
||||
ctx.tx.isFieldPresent(sfDomainID) || ctx.tx.isFieldPresent(sfAssetsMaximum) || ctx.tx.isFieldPresent(sfData);
|
||||
|
||||
return atLeastOneFieldPresent ||
|
||||
(checkFlags && (ctx.tx.isFlag(tfVaultDepositBlock) || ctx.tx.isFlag(tfVaultDepositUnblock)));
|
||||
}
|
||||
|
||||
NotTEC
|
||||
VaultSet::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if ((ctx.tx.isFlag(tfVaultDepositBlock) || ctx.tx.isFlag(tfVaultDepositUnblock)) &&
|
||||
!ctx.rules.enabled(fixLendingProtocolV1_1))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: flags not supported without fixLendingProtocolV1_1.";
|
||||
return temDISABLED;
|
||||
}
|
||||
|
||||
if (ctx.tx[sfVaultID] == beast::zero)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: zero/empty vault ID.";
|
||||
@@ -48,12 +73,18 @@ VaultSet::preflight(PreflightContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.tx.isFieldPresent(sfDomainID) && !ctx.tx.isFieldPresent(sfAssetsMaximum) && !ctx.tx.isFieldPresent(sfData))
|
||||
if (!isValidVaultUpdate(ctx))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: nothing is being updated.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (ctx.tx.isFlag(tfVaultDepositBlock) && ctx.tx.isFlag(tfVaultDepositUnblock))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: cannot set tfVaultDepositBlock and tfVaultDepositUnblock simultaneously.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -107,6 +138,21 @@ VaultSet::preclaim(PreclaimContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.view.rules().enabled(fixLendingProtocolV1_1))
|
||||
{
|
||||
if (vault->isFlag(lsfVaultDepositBlocked) && ctx.tx.isFlag(tfVaultDepositBlock))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: vault deposit is already blocked";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
if (!vault->isFlag(lsfVaultDepositBlocked) && ctx.tx.isFlag(tfVaultDepositUnblock))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: vault deposit is already unblocked";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -164,6 +210,15 @@ VaultSet::doApply()
|
||||
view().update(sleIssuance);
|
||||
}
|
||||
|
||||
if (view().rules().enabled(fixLendingProtocolV1_1))
|
||||
{
|
||||
if (tx.isFlag(tfVaultDepositBlock))
|
||||
vault->setFlag(lsfVaultDepositBlocked);
|
||||
|
||||
if (tx.isFlag(tfVaultDepositUnblock))
|
||||
vault->clearFlag(lsfVaultDepositBlocked);
|
||||
}
|
||||
|
||||
// Note, we must update Vault object even if only DomainID is being updated
|
||||
// in Issuance object. Otherwise it's really difficult for Vault invariants
|
||||
// to verify the operation.
|
||||
|
||||
@@ -13,6 +13,9 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user