Add WithdrawalPolicy

This commit is contained in:
Bronek Kozicki
2025-02-25 19:06:58 +00:00
parent 3f5df80b47
commit a0632a0cb3
8 changed files with 50 additions and 6 deletions

View File

@@ -118,6 +118,9 @@ std::uint64_t constexpr maxMPTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull;
/** The maximum length of MPTokenMetadata */
std::size_t constexpr maxVaultDataLength = 256;
/** Vault withdrawal policies */
std::uint8_t constexpr vaultStrategyFirstComeFirstServe = 1;
/** A ledger index. */
using LedgerIndex = std::uint32_t;

View File

@@ -480,9 +480,9 @@ LEDGER_ENTRY(ltVAULT, 0x0083, Vault, vault, ({
{sfAssetMaximum, soeDEFAULT},
{sfLossUnrealized, soeDEFAULT},
{sfMPTokenIssuanceID, soeREQUIRED}, // sfShare
{sfWithdrawalPolicy, soeREQUIRED},
// no ShareTotal ever (use MPTIssuance.sfOutstandingAmount)
// no PermissionedDomainID (use MPTIssuance.sfDomainID)
// no WithdrawalPolicy yet
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
}))
#undef EXPAND

View File

@@ -42,6 +42,7 @@ TYPED_SFIELD(sfTickSize, UINT8, 16)
TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
TYPED_SFIELD(sfHookResult, UINT8, 18)
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
// 16-bit integers (common)
TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::sMD_Never)

View File

@@ -471,7 +471,7 @@ TRANSACTION(ttVAULT_CREATE, 64, VaultCreate, ({
{sfAssetMaximum, soeOPTIONAL},
{sfMPTokenMetadata, soeOPTIONAL},
{sfDomainID, soeOPTIONAL}, // PermissionedDomainID
// no WithdrawalPolicy yet
{sfWithdrawalPolicy, soeOPTIONAL},
{sfData, soeOPTIONAL},
}))
@@ -480,7 +480,6 @@ TRANSACTION(ttVAULT_SET, 65, VaultSet, ({
{sfVaultID, soeREQUIRED},
{sfAssetMaximum, soeOPTIONAL},
{sfDomainID, soeOPTIONAL}, // PermissionedDomainID
// no WithdrawalPolicy yet
{sfData, soeOPTIONAL},
}))

View File

@@ -287,6 +287,32 @@ class Vault_test : public beast::unit_test::suite
env(tx);
});
testCase([this](
Env& env,
Account const& issuer,
Account const& owner,
Account const& depositor,
Asset const& asset,
Vault& vault) {
auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
tx[sfWithdrawalPolicy] = 1;
testcase("explicitly select withdrawal policy");
env(tx);
});
testCase([this](
Env& env,
Account const& issuer,
Account const& owner,
Account const& depositor,
Asset const& asset,
Vault& vault) {
auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
tx[sfWithdrawalPolicy] = 0;
testcase("invalid withdrawal policy");
env(tx, ter(temMALFORMED));
});
testCase([this](
Env& env,
Account const& issuer,

View File

@@ -23,6 +23,7 @@
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/STNumber.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFlags.h>
@@ -51,6 +52,13 @@ VaultCreate::preflight(PreflightContext const& ctx)
return temMALFORMED;
}
if (auto const data = ctx.tx[~sfWithdrawalPolicy])
{
// Enforce valid withdrawal policy
if (*data != vaultStrategyFirstComeFirstServe)
return temMALFORMED;
}
if (auto const domain = ctx.tx[~sfDomainID])
{
if (*domain == beast::zero)
@@ -176,6 +184,11 @@ VaultCreate::doApply()
vault->at(sfMPTokenIssuanceID) = share;
if (auto value = tx[~sfData])
vault->at(sfData) = *value;
// Required field, default to vaultStrategyFirstComeFirstServe
if (auto value = tx[~sfWithdrawalPolicy])
vault->at(sfWithdrawalPolicy) = *value;
else
vault->at(sfWithdrawalPolicy) = vaultStrategyFirstComeFirstServe;
// No `LossUnrealized`.
view().insert(vault);

View File

@@ -51,6 +51,10 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx)
if (!vault)
return tecOBJECT_NOT_FOUND;
// Enforce valid withdrawal policy
if (vault->at(sfWithdrawalPolicy) != vaultStrategyFirstComeFirstServe)
return tefINTERNAL;
auto const assets = ctx.tx[sfAmount];
auto const asset = vault->at(sfAsset);
auto const share = vault->at(sfMPTokenIssuanceID);

View File

@@ -2531,7 +2531,6 @@ assetsToSharesWithdraw(
return shares;
Number shareTotal = getShareTotal(view, vault);
shares = shareTotal * (assets / assetTotal);
// TODO: Limit by withdrawal policy?
return shares;
}
@@ -2549,7 +2548,6 @@ sharesToAssetsWithdraw(
return assets;
Number shareTotal = getShareTotal(view, vault);
assets = assetTotal * (shares / shareTotal);
// TODO: Limit by withdrawal policy?
return assets;
}