xrpld
Loading...
Searching...
No Matches
VaultHelpers.cpp
1#include <xrpl/ledger/helpers/VaultHelpers.h>
2
3#include <xrpl/basics/Number.h>
4#include <xrpl/beast/utility/instrumentation.h>
5#include <xrpl/ledger/ReadView.h>
6#include <xrpl/ledger/View.h>
7#include <xrpl/protocol/AccountID.h>
8#include <xrpl/protocol/Indexes.h>
9#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
10#include <xrpl/protocol/Protocol.h>
11#include <xrpl/protocol/SField.h>
12#include <xrpl/protocol/STAmount.h>
13#include <xrpl/protocol/STLedgerEntry.h>
14#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
15#include <xrpl/protocol/STTx.h>
16
17#include <cstdint>
18#include <optional>
19#include <utility>
20
21namespace xrpl {
22
23[[nodiscard]] std::optional<STAmount>
25{
26 XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets");
27 XRPL_ASSERT(
28 assets.asset() == vault->at(sfAsset),
29 "xrpl::assetsToSharesDeposit : assets and vault match");
30 if (assets.negative() || assets.asset() != vault->at(sfAsset))
31 return std::nullopt; // LCOV_EXCL_LINE
32
33 Number const assetTotal = vault->at(sfAssetsTotal);
34 STAmount shares{vault->at(sfShareMPTID)};
35 if (assetTotal == 0)
36 {
37 return STAmount{
38 shares.asset(),
39 Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)).truncate()};
40 }
41
42 Number const shareTotal = issuance->at(sfOutstandingAmount);
43 shares = ((shareTotal * assets) / assetTotal).truncate();
44 return shares;
45}
46
47[[nodiscard]] std::optional<STAmount>
49{
50 XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares");
51 XRPL_ASSERT(
52 shares.asset() == vault->at(sfShareMPTID),
53 "xrpl::sharesToAssetsDeposit : shares and vault match");
54 if (shares.negative() || shares.asset() != vault->at(sfShareMPTID))
55 return std::nullopt; // LCOV_EXCL_LINE
56
57 Number const assetTotal = vault->at(sfAssetsTotal);
58 STAmount assets{vault->at(sfAsset)};
59 if (assetTotal == 0)
60 {
61 return STAmount{
62 assets.asset(), shares.mantissa(), shares.exponent() - vault->at(sfScale), false};
63 }
64
65 Number const shareTotal = issuance->at(sfOutstandingAmount);
66 assets = (assetTotal * shares) / shareTotal;
67 return assets;
68}
69
70[[nodiscard]] std::optional<STAmount>
72 SLE::const_ref vault,
73 SLE::const_ref issuance,
74 STAmount const& assets,
75 TruncateShares truncate,
77{
78 XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesWithdraw : non-negative assets");
79 XRPL_ASSERT(
80 assets.asset() == vault->at(sfAsset),
81 "xrpl::assetsToSharesWithdraw : assets and vault match");
82 if (assets.negative() || assets.asset() != vault->at(sfAsset))
83 return std::nullopt; // LCOV_EXCL_LINE
84
85 Number assetTotal = vault->at(sfAssetsTotal);
86 if (waive == WaiveUnrealizedLoss::No)
87 assetTotal -= vault->at(sfLossUnrealized);
88 STAmount shares{vault->at(sfShareMPTID)};
89 if (assetTotal == 0)
90 return shares;
91 Number const shareTotal = issuance->at(sfOutstandingAmount);
92 Number result = (shareTotal * assets) / assetTotal;
93 if (truncate == TruncateShares::Yes)
94 result = result.truncate();
95 shares = result;
96 return shares;
97}
98
99[[nodiscard]] std::optional<STAmount>
101 SLE::const_ref vault,
102 SLE::const_ref issuance,
103 STAmount const& shares,
105{
106 XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsWithdraw : non-negative shares");
107 XRPL_ASSERT(
108 shares.asset() == vault->at(sfShareMPTID),
109 "xrpl::sharesToAssetsWithdraw : shares and vault match");
110 if (shares.negative() || shares.asset() != vault->at(sfShareMPTID))
111 return std::nullopt; // LCOV_EXCL_LINE
112
113 Number assetTotal = vault->at(sfAssetsTotal);
114 if (waive == WaiveUnrealizedLoss::No)
115 assetTotal -= vault->at(sfLossUnrealized);
116 STAmount assets{vault->at(sfAsset)};
117 if (assetTotal == 0)
118 return assets;
119 Number const shareTotal = issuance->at(sfOutstandingAmount);
120 assets = (assetTotal * shares) / shareTotal;
121 return assets;
122}
123
124[[nodiscard]] bool
125isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref issuance)
126{
127 XRPL_ASSERT(
128 issuance && issuance->getType() == ltMPTOKEN_ISSUANCE,
129 "xrpl::isSoleShareholder : valid issuance SLE");
130
131 std::uint64_t const outstanding = issuance->at(sfOutstandingAmount);
132 if (outstanding == 0)
133 return false;
134
135 auto const shareMPTID =
136 makeMptID(issuance->getFieldU32(sfSequence), issuance->getAccountID(sfIssuer));
137 auto const sleToken = view.read(keylet::mptoken(shareMPTID, account));
138 if (!sleToken)
139 return false; // LCOV_EXCL_LINE
140
141 return sleToken->getFieldU64(sfMPTAmount) == outstanding;
142}
143
144[[nodiscard]] VaultVersion
146{
147 XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::getVaultVersion : valid Vault sle");
148 if (!vault->isFieldPresent(sfLEVersion))
150
151 auto const version = vault->at(sfLEVersion);
152 if (version > std::to_underlying(VaultVersion::CashBasis))
153 {
154 // LCOV_EXCL_START
155 UNREACHABLE("xrpl::getVaultVersion : invalid vault version");
157 // LCOV_EXCL_STOP
158 }
159 return static_cast<VaultVersion>(version);
160}
161
162namespace {
163
164[[nodiscard]] VaultKind
165decodeVaultKind(std::optional<std::uint8_t> vaultKind)
166{
167 if (vaultKind && *vaultKind == std::to_underlying(VaultKind::ClosedEnded))
170}
171
172} // namespace
173
174[[nodiscard]] VaultKind
176{
177 XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::getVaultKind : valid Vault sle");
178 return decodeVaultKind(vault->at(~sfVaultKind));
179}
180
181[[nodiscard]] VaultKind
183{
184 return decodeVaultKind(tx[~sfVaultKind]);
185}
186
187[[nodiscard]] bool
189{
190 auto const kindField = tx[~sfVaultKind];
191 if (!kindField)
192 return true;
193 return *kindField == std::to_underlying(VaultKind::OpenEnded) ||
194 *kindField == std::to_underlying(VaultKind::ClosedEnded);
195}
196
197[[nodiscard]] bool
199{
200 auto const s = static_cast<std::int64_t>(sub);
201 auto const r = static_cast<std::int64_t>(red);
202 return r >= s + kMinInvestmentPeriod && r < s + kMaxInvestmentPeriod;
203}
204
205[[nodiscard]] VaultPhase
207{
208 XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::getVaultPhase : valid Vault sle");
209 return getVaultPhase(
210 view, (*vault)[~sfVaultKind], (*vault)[~sfSubscriptionDate], (*vault)[~sfRedemptionDate]);
211}
212
213[[nodiscard]] VaultPhase
215 ReadView const& view,
217 std::optional<std::uint32_t> subscriptionDate,
218 std::optional<std::uint32_t> redemptionDate)
219{
220 if (!vaultKind || *vaultKind != std::to_underlying(VaultKind::ClosedEnded))
221 return VaultPhase::NoPhase;
222
223 // Subscription includes now == SubscriptionDate; Investment starts
224 // strictly after SubscriptionDate.
225 if (!hasExpired(view, subscriptionDate, ExpiryComparison::Exclusive))
227 if (!hasExpired(view, redemptionDate))
230}
231
232} // namespace xrpl
Number is a floating point type that can represent a wide range of values.
Definition Number.h:351
Number truncate() const noexcept
A view into a ledger.
Definition ReadView.h:41
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
std::uint64_t mantissa() const noexcept
Definition STAmount.h:490
bool negative() const noexcept
Definition STAmount.h:484
Asset const & asset() const
Definition STAmount.h:496
int exponent() const noexcept
Definition STAmount.h:459
std::shared_ptr< STLedgerEntry const > const & const_ref
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:543
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
VaultPhase
Lifecycle phase of a vault.
Definition Protocol.h:344
std::optional< STAmount > assetsToSharesWithdraw(SLE::const_ref vault, SLE::const_ref issuance, STAmount const &assets, TruncateShares truncate=TruncateShares::No, WaiveUnrealizedLoss waive=WaiveUnrealizedLoss::No)
From the perspective of a vault, return the number of shares to demand from the depositor when they a...
VaultKind getVaultKind(SLE::const_ref vault)
Resolves the VaultKind of a vault SLE.
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp, ExpiryComparison comparison=ExpiryComparison::Inclusive)
Determines whether the given expiration time has passed.
Definition View.cpp:48
bool isValidClosedEndedGap(std::uint32_t sub, std::uint32_t red)
Returns true iff the (SubscriptionDate, RedemptionDate) gap of a closed-ended vault satisfies kMinInv...
VaultPhase getVaultPhase(ReadView const &view, SLE::const_ref vault)
Returns the current lifecycle phase of a vault.
constexpr std::uint32_t kMaxInvestmentPeriod
Definition Protocol.h:359
std::optional< STAmount > sharesToAssetsWithdraw(SLE::const_ref vault, SLE::const_ref issuance, STAmount const &shares, WaiveUnrealizedLoss waive=WaiveUnrealizedLoss::No)
From the perspective of a vault, return the number of assets to give the depositor when they redeem a...
VaultKind
Vault kind.
Definition Protocol.h:335
TruncateShares
Controls whether to truncate shares instead of rounding.
VaultVersion
Vault ledger-entry schema versions.
Definition Protocol.h:326
std::optional< STAmount > sharesToAssetsDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount const &shares)
From the perspective of a vault, return the number of assets to take from depositor when they receive...
MPTID makeMptID(std::uint32_t const sequence, AccountID const &account)
Definition Indexes.cpp:184
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:34
bool isSoleShareholder(ReadView const &view, AccountID const &account, SLE::const_ref issuance)
Returns true iff account holds all of the vault's outstanding shares — i.e.
bool isValidVaultKind(STTx const &tx)
Returns true iff sfVaultKind is either absent from tx or is present and equal to a recognised VaultKi...
VaultVersion getVaultVersion(SLE::const_ref vault)
Resolves a Vault's LEVersion, the single point every accounting touch point should call to determine ...
constexpr std::uint32_t kMinInvestmentPeriod
Bounds on the length of a closed-ended vault's Investment phase (RedemptionDate - SubscriptionDate).
Definition Protocol.h:356
std::optional< STAmount > assetsToSharesDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount const &assets)
From the perspective of a vault, return the number of shares to give depositor when they offer a fixe...
WaiveUnrealizedLoss
Controls whether the withdraw conversion helpers (assetsToSharesWithdraw and sharesToAssetsWithdraw) ...