mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 17:27:00 +00:00
148 lines
5.0 KiB
C++
148 lines
5.0 KiB
C++
#include <xrpl/ledger/helpers/VaultHelpers.h>
|
|
|
|
#include <xrpl/basics/Number.h>
|
|
#include <xrpl/beast/utility/instrumentation.h>
|
|
#include <xrpl/ledger/ReadView.h>
|
|
#include <xrpl/protocol/AccountID.h>
|
|
#include <xrpl/protocol/Indexes.h>
|
|
#include <xrpl/protocol/LedgerFormats.h>
|
|
#include <xrpl/protocol/SField.h>
|
|
#include <xrpl/protocol/STAmount.h>
|
|
#include <xrpl/protocol/STLedgerEntry.h>
|
|
#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <optional>
|
|
|
|
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(!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,
|
|
WaiveUnrealizedLoss waive)
|
|
{
|
|
XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesWithdraw : 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);
|
|
if (waive == WaiveUnrealizedLoss::No)
|
|
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,
|
|
WaiveUnrealizedLoss waive)
|
|
{
|
|
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsWithdraw : 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);
|
|
if (waive == WaiveUnrealizedLoss::No)
|
|
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
|
|
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref issuance)
|
|
{
|
|
XRPL_ASSERT(
|
|
issuance && issuance->getType() == ltMPTOKEN_ISSUANCE,
|
|
"xrpl::isSoleShareholder : valid issuance SLE");
|
|
|
|
std::uint64_t const outstanding = issuance->at(sfOutstandingAmount);
|
|
if (outstanding == 0)
|
|
return false;
|
|
|
|
auto const shareMPTID =
|
|
makeMptID(issuance->getFieldU32(sfSequence), issuance->getAccountID(sfIssuer));
|
|
auto const sleToken = view.read(keylet::mptoken(shareMPTID, account));
|
|
if (!sleToken)
|
|
return false; // LCOV_EXCL_LINE
|
|
|
|
return sleToken->getFieldU64(sfMPTAmount) == outstanding;
|
|
}
|
|
|
|
} // namespace xrpl
|