refactor: Extract vault helper functions into VaultHelpers module

Move vault share/asset conversion functions (assetsToSharesDeposit,
sharesToAssetsDeposit, assetsToSharesWithdraw, sharesToAssetsWithdraw)
and isVaultInsolvent from View.h/View.cpp into a dedicated
VaultHelpers.h/VaultHelpers.cpp module. Reorder includes in Vault
transactor .cpp files to place own header first. Fix VaultSet flag
validation logic.
This commit is contained in:
Vito
2026-02-24 12:56:51 +01:00
parent 884530e415
commit 8732e84e54
13 changed files with 194 additions and 152 deletions

View File

@@ -945,51 +945,6 @@ deleteAMMTrustLine(
std::optional<AccountID> const& ammAccountID,
beast::Journal j);
// From the perspective of a vault, return the number of shares to give the
// depositor when they deposit a fixed amount of assets. Since shares are MPT
// this number is integral and always truncated in this calculation.
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets);
// From the perspective of a vault, return the number of assets to take from
// depositor when they receive a fixed amount of shares. Note, since shares are
// MPT, they are always an integral number.
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares);
enum class TruncateShares : bool { no = false, yes = true };
// From the perspective of a vault, return the number of shares to demand from
// the depositor when they ask to withdraw a fixed amount of assets. Since
// shares are MPT this number is integral, and it will be rounded to nearest
// unless explicitly requested to be truncated instead.
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets,
TruncateShares truncate = TruncateShares::no);
// From the perspective of a vault, return the number of assets to give the
// depositor when they redeem a fixed amount of shares. Note, since shares are
// MPT, they are always an integral number.
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares);
// Determine if a vault is insolvent. A vault is considered insolvent when
// the total assets in the vault are zero, and outstanding shares are non-zero.
[[nodiscard]] bool
isVaultInsolvent(std::shared_ptr<SLE const> const& vault, std::shared_ptr<SLE const> const& shareIssuance);
/** Has the specified time passed?
@param now the current time

View File

@@ -1,6 +1,7 @@
#pragma once
#include <xrpl/tx/Transactor.h>
#include <xrpl/tx/transactors/Vault/VaultHelpers.h>
namespace xrpl {

View File

@@ -1,6 +1,7 @@
#pragma once
#include <xrpl/tx/Transactor.h>
#include <xrpl/tx/transactors/Vault/VaultHelpers.h>
namespace xrpl {

View File

@@ -0,0 +1,54 @@
#pragma once
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STNumber.h>
namespace xrpl {
enum class TruncateShares : bool { no = false, yes = true };
// From the perspective of a vault, return the number of shares to give the
// depositor when they deposit a fixed amount of assets. Since shares are MPT
// this number is integral and always truncated in this calculation.
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets);
// From the perspective of a vault, return the number of assets to take from
// depositor when they receive a fixed amount of shares. Note, since shares are
// MPT, they are always an integral number.
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares);
// From the perspective of a vault, return the number of shares to demand from
// the depositor when they ask to withdraw a fixed amount of assets. Since
// shares are MPT this number is integral, and it will be rounded to nearest
// unless explicitly requested to be truncated instead.
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets,
TruncateShares truncate = TruncateShares::no);
// From the perspective of a vault, return the number of assets to give the
// depositor when they redeem a fixed amount of shares. Note, since shares are
// MPT, they are always an integral number.
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares);
// Determine if a vault is insolvent. A vault is considered insolvent when
// the total assets in the vault are zero, and outstanding shares are non-zero.
[[nodiscard]] bool
isVaultInsolvent(std::shared_ptr<SLE const> const& vault, std::shared_ptr<SLE const> const& shareIssuance);
} // namespace xrpl

View File

@@ -1,6 +1,7 @@
#pragma once
#include <xrpl/tx/Transactor.h>
#include <xrpl/tx/transactors/Vault/VaultHelpers.h>
namespace xrpl {

View File

@@ -3103,94 +3103,6 @@ rippleCredit(
saAmount.asset().value());
}
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets)
{
XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets");
XRPL_ASSERT(assets.asset() == vault->at(sfAsset), "xrpl::assetsToSharesDeposit : assets and vault match");
if (assets.negative() || assets.asset() != vault->at(sfAsset))
return std::nullopt; // LCOV_EXCL_LINE
Number const assetTotal = vault->at(sfAssetsTotal);
STAmount shares{vault->at(sfShareMPTID)};
if (assetTotal == 0)
return STAmount{shares.asset(), Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)).truncate()};
Number const shareTotal = issuance->at(sfOutstandingAmount);
shares = ((shareTotal * assets) / assetTotal).truncate();
return shares;
}
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares)
{
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares");
XRPL_ASSERT(shares.asset() == vault->at(sfShareMPTID), "xrpl::sharesToAssetsDeposit : shares and vault match");
if (shares.negative() || shares.asset() != vault->at(sfShareMPTID))
return std::nullopt; // LCOV_EXCL_LINE
Number const assetTotal = vault->at(sfAssetsTotal);
STAmount assets{vault->at(sfAsset)};
if (assetTotal == 0)
return STAmount{assets.asset(), shares.mantissa(), shares.exponent() - vault->at(sfScale), false};
Number const shareTotal = issuance->at(sfOutstandingAmount);
assets = (assetTotal * shares) / shareTotal;
return assets;
}
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets,
TruncateShares truncate)
{
XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets");
XRPL_ASSERT(assets.asset() == vault->at(sfAsset), "xrpl::assetsToSharesWithdraw : assets and vault match");
if (assets.negative() || assets.asset() != vault->at(sfAsset))
return std::nullopt; // LCOV_EXCL_LINE
Number assetTotal = vault->at(sfAssetsTotal);
assetTotal -= vault->at(sfLossUnrealized);
STAmount shares{vault->at(sfShareMPTID)};
if (assetTotal == 0)
return shares;
Number const shareTotal = issuance->at(sfOutstandingAmount);
Number result = (shareTotal * assets) / assetTotal;
if (truncate == TruncateShares::yes)
result = result.truncate();
shares = result;
return shares;
}
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares)
{
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares");
XRPL_ASSERT(shares.asset() == vault->at(sfShareMPTID), "xrpl::sharesToAssetsWithdraw : shares and vault match");
if (shares.negative() || shares.asset() != vault->at(sfShareMPTID))
return std::nullopt; // LCOV_EXCL_LINE
Number assetTotal = vault->at(sfAssetsTotal);
assetTotal -= vault->at(sfLossUnrealized);
STAmount assets{vault->at(sfAsset)};
if (assetTotal == 0)
return assets;
Number const shareTotal = issuance->at(sfOutstandingAmount);
assets = (assetTotal * shares) / shareTotal;
return assets;
}
TER
rippleLockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount, beast::Journal j)
{
@@ -3438,13 +3350,4 @@ after(NetClock::time_point now, std::uint32_t mark)
return now.time_since_epoch().count() > mark;
}
[[nodiscard]] bool
isVaultInsolvent(std::shared_ptr<SLE const> const& vault, std::shared_ptr<SLE const> const& shareIssuance)
{
auto const assetsTotal = vault->at(sfAssetsTotal);
auto const sharesOutstanding = shareIssuance->at(sfOutstandingAmount);
return assetsTotal == 0 && sharesOutstanding > 0;
}
} // namespace xrpl

View File

@@ -1,4 +1,5 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/tx/transactors/Vault/VaultClawback.h>
//
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/MPTIssue.h>
@@ -8,7 +9,6 @@
#include <xrpl/protocol/STTakesAsset.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/Vault/VaultClawback.h>
#include <optional>

View File

@@ -1,3 +1,5 @@
#include <xrpl/tx/transactors/Vault/VaultCreate.h>
//
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
@@ -12,7 +14,6 @@
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/MPT/MPTokenAuthorize.h>
#include <xrpl/tx/transactors/MPT/MPTokenIssuanceCreate.h>
#include <xrpl/tx/transactors/Vault/VaultCreate.h>
namespace xrpl {

View File

@@ -1,3 +1,5 @@
#include <xrpl/tx/transactors/Vault/VaultDelete.h>
//
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/MPTIssue.h>
@@ -5,7 +7,6 @@
#include <xrpl/protocol/STTakesAsset.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/Vault/VaultDelete.h>
namespace xrpl {

View File

@@ -1,3 +1,5 @@
#include <xrpl/tx/transactors/Vault/VaultDeposit.h>
//
#include <xrpl/ledger/CredentialHelpers.h>
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/Feature.h>
@@ -10,7 +12,6 @@
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/MPT/MPTokenAuthorize.h>
#include <xrpl/tx/transactors/Vault/VaultDeposit.h>
namespace xrpl {

View File

@@ -0,0 +1,123 @@
#include <xrpl/tx/transactors/Vault/VaultHelpers.h>
namespace xrpl {
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::assetsToSharesDeposit : Vault sle");
XRPL_ASSERT(
issuance && issuance->getType() == ltMPTOKEN_ISSUANCE, "xrpl::assetsToSharesDeposit : MPTokenIssuance sle");
XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets");
XRPL_ASSERT(assets.asset() == vault->at(sfAsset), "xrpl::assetsToSharesDeposit : assets and vault match");
if (assets.negative() || assets.asset() != vault->at(sfAsset))
return std::nullopt; // LCOV_EXCL_LINE
Number const assetTotal = vault->at(sfAssetsTotal);
STAmount shares{vault->at(sfShareMPTID)};
if (assetTotal == 0)
return STAmount{shares.asset(), Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)).truncate()};
Number const shareTotal = issuance->at(sfOutstandingAmount);
shares = ((shareTotal * assets) / assetTotal).truncate();
return shares;
}
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::sharesToAssetsDeposit : Vault sle");
XRPL_ASSERT(
issuance && issuance->getType() == ltMPTOKEN_ISSUANCE, "xrpl::sharesToAssetsDeposit : MPTokenIssuance sle");
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares");
XRPL_ASSERT(shares.asset() == vault->at(sfShareMPTID), "xrpl::sharesToAssetsDeposit : shares and vault match");
if (shares.negative() || shares.asset() != vault->at(sfShareMPTID))
return std::nullopt; // LCOV_EXCL_LINE
Number const assetTotal = vault->at(sfAssetsTotal);
STAmount assets{vault->at(sfAsset)};
if (assetTotal == 0)
return STAmount{assets.asset(), shares.mantissa(), shares.exponent() - vault->at(sfScale), false};
Number const shareTotal = issuance->at(sfOutstandingAmount);
assets = (assetTotal * shares) / shareTotal;
return assets;
}
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets,
TruncateShares truncate)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::assetsToSharesWithdraw : Vault sle");
XRPL_ASSERT(
issuance && issuance->getType() == ltMPTOKEN_ISSUANCE, "xrpl::assetsToSharesWithdraw : MPTokenIssuance sle");
XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets");
XRPL_ASSERT(assets.asset() == vault->at(sfAsset), "xrpl::assetsToSharesWithdraw : assets and vault match");
if (assets.negative() || assets.asset() != vault->at(sfAsset))
return std::nullopt; // LCOV_EXCL_LINE
Number assetTotal = vault->at(sfAssetsTotal);
assetTotal -= vault->at(sfLossUnrealized);
STAmount shares{vault->at(sfShareMPTID)};
if (assetTotal == 0)
return shares;
Number const shareTotal = issuance->at(sfOutstandingAmount);
Number result = (shareTotal * assets) / assetTotal;
if (truncate == TruncateShares::yes)
result = result.truncate();
shares = result;
return shares;
}
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::sharesToAssetsWithdraw : Vault sle");
XRPL_ASSERT(
issuance && issuance->getType() == ltMPTOKEN_ISSUANCE, "xrpl::sharesToAssetsWithdraw : MPTokenIssuance sle");
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares");
XRPL_ASSERT(shares.asset() == vault->at(sfShareMPTID), "xrpl::sharesToAssetsWithdraw : shares and vault match");
if (shares.negative() || shares.asset() != vault->at(sfShareMPTID))
return std::nullopt; // LCOV_EXCL_LINE
Number assetTotal = vault->at(sfAssetsTotal);
assetTotal -= vault->at(sfLossUnrealized);
STAmount assets{vault->at(sfAsset)};
if (assetTotal == 0)
return assets;
Number const shareTotal = issuance->at(sfOutstandingAmount);
assets = (assetTotal * shares) / shareTotal;
return assets;
}
[[nodiscard]] bool
isVaultInsolvent(std::shared_ptr<SLE const> const& vault, std::shared_ptr<SLE const> const& shareIssuance)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::isVaultInsolvent : Vault sle");
XRPL_ASSERT(
shareIssuance && shareIssuance->getType() == ltMPTOKEN_ISSUANCE,
"xrpl::isVaultInsolvent : MPTokenIssuance sle");
auto const assetsTotal = vault->at(sfAssetsTotal);
auto const sharesOutstanding = shareIssuance->at(sfOutstandingAmount);
return assetsTotal == 0 && sharesOutstanding > 0;
}
} // namespace xrpl

View File

@@ -34,13 +34,13 @@ VaultSet::getFlagsMask(PreflightContext const& ctx)
static bool
isValidVaultUpdate(PreflightContext const& ctx)
{
auto const shouldCheckFlags = ctx.rules.enabled(fixLendingProtocolV1_1);
auto const atLeastOneFieldPresent =
ctx.tx.isFieldPresent(sfDomainID) || ctx.tx.isFieldPresent(sfAssetsMaximum) || ctx.tx.isFieldPresent(sfData);
return atLeastOneFieldPresent ||
(shouldCheckFlags && (ctx.tx.isFlag(tfVaultDepositBlock) || ctx.tx.isFlag(tfVaultDepositUnblock)));
auto const shouldCheckFlags = ctx.rules.enabled(fixLendingProtocolV1_1);
auto const expectedFlags = ~(VaultSet::getFlagsMask(ctx) | tfUniversal);
return atLeastOneFieldPresent || (shouldCheckFlags && (ctx.tx.getFlags() & expectedFlags));
}
NotTEC

View File

@@ -1,3 +1,5 @@
#include <xrpl/tx/transactors/Vault/VaultWithdraw.h>
//
#include <xrpl/ledger/CredentialHelpers.h>
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/AccountID.h>
@@ -7,7 +9,6 @@
#include <xrpl/protocol/STTakesAsset.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/Vault/VaultWithdraw.h>
namespace xrpl {