mirror of
https://github.com/XRPLF/rippled.git
synced 2026-09-27 15:28:03 +00:00
feat: Add FixedPrecision vault scale helpers and Open-zone deposit checks
New vaults created under V1.2 stay on a lifetime base grid so optional inflows cannot coarsen AssetsTotal, while pre-V1.2 vaults keep the dynamic scale they were created with.
This commit is contained in:
@@ -17,6 +17,69 @@ namespace xrpl {
|
||||
|
||||
class STTx;
|
||||
|
||||
/**
|
||||
* Return the Vault's current live exponent.
|
||||
*
|
||||
* Legacy and CashBasis Vaults use the exponent of AssetsTotal. FixedPrecision
|
||||
* Vaults floor that exponent at their lifetime base exponent.
|
||||
*/
|
||||
[[nodiscard]] int
|
||||
getVaultScale(SLE::const_ref vault);
|
||||
|
||||
/**
|
||||
* Return the Vault's base exponent.
|
||||
*
|
||||
* Legacy and CashBasis Vaults use their current live exponent. FixedPrecision
|
||||
* Vaults use -Scale, or 0 for integral assets.
|
||||
*/
|
||||
[[nodiscard]] int
|
||||
getVaultBaseScale(SLE::const_ref vault);
|
||||
|
||||
/**
|
||||
* Return the Vault's posterior live exponent after applying an unrounded delta.
|
||||
*/
|
||||
[[nodiscard]] int
|
||||
getPosteriorVaultScale(SLE::const_ref vault, STAmount const& delta);
|
||||
|
||||
/**
|
||||
* Round an amount at the Vault's current live exponent.
|
||||
*
|
||||
* Reserved for LoanPay. Vault deposit, withdraw, and clawback round at the
|
||||
* posterior live exponent instead.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
roundToVaultScale(SLE::const_ref vault, STAmount const& amount, Number::RoundingMode roundingMode);
|
||||
|
||||
/**
|
||||
* Round an amount at the Vault's posterior live exponent.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
roundToPosteriorVaultScale(
|
||||
SLE::const_ref vault,
|
||||
STAmount const& amount,
|
||||
Number::RoundingMode roundingMode);
|
||||
|
||||
/**
|
||||
* Open-zone capacity ceiling: 9 * 10^(15 + baseScale).
|
||||
*
|
||||
* Defined only for FixedPrecision Vaults, where this is 9 * 10^(15 - P).
|
||||
*/
|
||||
[[nodiscard]] Number
|
||||
getVaultOpenLimit(SLE::const_ref vault);
|
||||
|
||||
/**
|
||||
* Check whether `amount` is an admissible optional inflow.
|
||||
*
|
||||
* Legacy and CashBasis Vaults always succeed. FixedPrecision Vaults must
|
||||
* remain at their base scale after applying the rounded amount, and the
|
||||
* posterior capacity (AssetsTotal + YieldUnrealized + rounded amount) must
|
||||
* stay within the Open zone.
|
||||
*
|
||||
* The amount is rounded toward zero at the posterior live exponent.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkOptionalVaultInflow(SLE::const_ref vault, STAmount const& amount);
|
||||
|
||||
/**
|
||||
* From the perspective of a vault, return the number of shares to give
|
||||
* depositor when they offer a fixed amount of assets. Note, since shares are
|
||||
@@ -53,9 +116,10 @@ sharesToAssetsDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount co
|
||||
* Rounding strategy:
|
||||
* - Debits (withdrawals): Rounds down `|delta|` on the new scale to prevent
|
||||
* paying out more than requested.
|
||||
* - Credits (deposits): Floors the resulting total asset balance and returns the
|
||||
* difference from the current total. This prevents crediting the vault with
|
||||
* more assets than the user deposited.
|
||||
* - Legacy/CashBasis credits: Floors the resulting total asset balance and
|
||||
* returns the difference from the current total.
|
||||
* - FixedPrecision credits: Rounds the delta toward zero at the posterior live
|
||||
* scale.
|
||||
*
|
||||
* Key rules:
|
||||
* - The returned magnitude never exceeds `|delta|`.
|
||||
|
||||
@@ -319,14 +319,20 @@ constexpr std::uint8_t kVaultDefaultIouScale = 6;
|
||||
constexpr std::uint8_t kVaultMaximumIouScale = 18;
|
||||
|
||||
/**
|
||||
* Vault ledger-entry schema versions. Assigned to newly created
|
||||
* Vaults once featureLendingProtocolV1_1 is enabled. Vaults created before
|
||||
* activation are left without LEVersion (implicit legacy version 0,
|
||||
* Maximum fixed-precision IOU scale factor for a Vault.
|
||||
*/
|
||||
constexpr std::uint8_t kVaultMaximumFixedIouScale = 10;
|
||||
|
||||
/**
|
||||
* Vault ledger-entry schema versions. Assigned to newly created Vaults by
|
||||
* featureLendingProtocolV1_1 and later protocol amendments. Vaults created
|
||||
* before activation are left without LEVersion (implicit legacy version 0,
|
||||
* accrual-basis accounting).
|
||||
*/
|
||||
enum class VaultVersion : uint8_t {
|
||||
Legacy = 0,
|
||||
CashBasis,
|
||||
FixedPrecision,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FEATURE(SmartEscrow, Supported::No, VoteBehavior::DefaultNo)
|
||||
// Requires LendingProtocolV1_1. New vaults take FixedPrecision plus cash-basis.
|
||||
XRPL_FEATURE(LendingProtocolV1_2, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (Cleanup3_5_0, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(ConfidentialMPTKeyRotation, Supported::No, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -513,6 +513,7 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
{sfAssetsAvailable, SoeDefault},
|
||||
{sfAssetsMaximum, SoeDefault},
|
||||
{sfLossUnrealized, SoeDefault},
|
||||
{sfYieldUnrealized, SoeDefault},
|
||||
{sfShareMPTID, SoeRequired},
|
||||
{sfWithdrawalPolicy, SoeRequired},
|
||||
{sfScale, SoeDefault},
|
||||
|
||||
@@ -239,6 +239,7 @@ TYPED_SFIELD(sfPrincipalRequested, NUMBER, 14)
|
||||
TYPED_SFIELD(sfTotalValueOutstanding, NUMBER, 15, SField::kSmdNeedsAsset | SField::kSmdDefault)
|
||||
TYPED_SFIELD(sfPeriodicPayment, NUMBER, 16)
|
||||
TYPED_SFIELD(sfManagementFeeOutstanding, NUMBER, 17, SField::kSmdNeedsAsset | SField::kSmdDefault)
|
||||
TYPED_SFIELD(sfYieldUnrealized, NUMBER, 18, SField::kSmdNeedsAsset | SField::kSmdDefault)
|
||||
|
||||
// 32-bit signed (common)
|
||||
TYPED_SFIELD(sfLoanScale, INT32, 1)
|
||||
|
||||
@@ -242,6 +242,30 @@ public:
|
||||
return this->sle_->isFieldPresent(sfLossUnrealized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfYieldUnrealized (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_NUMBER::type::value_type>
|
||||
getYieldUnrealized() const
|
||||
{
|
||||
if (hasYieldUnrealized())
|
||||
return this->sle_->at(sfYieldUnrealized);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfYieldUnrealized is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasYieldUnrealized() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfYieldUnrealized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfShareMPTID (SoeRequired)
|
||||
* @return The field value.
|
||||
@@ -571,6 +595,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfYieldUnrealized (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
VaultBuilder&
|
||||
setYieldUnrealized(std::decay_t<typename SF_NUMBER::type::value_type> const& value)
|
||||
{
|
||||
object_[sfYieldUnrealized] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfShareMPTID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
|
||||
Reference in New Issue
Block a user