XRP Ledger Standards

XLS-0065
Draft
  xls: 65
  title: Single Asset Tokenized Vault
  description: On-chain primitive for aggregating assets from depositors using Multi-Purpose-Tokens for ownership shares
  author: Vytautas Vito Tumas , Aanchal Malhotra 
  proposal-from: https://github.com/XRPLF/XRPL-Standards/discussions/192
  status: Draft
  category: Amendment
  requires: [XLS-33](./XLS-0033-multi-purpose-tokens.html)
  created: 2024-04-12
  updated: 2026-09-15

Single Asset Vault

1. Abstract

A Single Asset Vault is a new on-chain primitive for aggregating assets from one or more depositors, and making the assets available for other on-chain protocols. The Single Asset Vault uses Multi-Purpose-Token to represent ownership shares of the Vault. A Vault may be open-ended, with ongoing deposits and withdrawals, or closed-ended, with fixed Subscription, Investment, and Redemption phases. The Vault serves diverse purposes, such as lending markets, aggregators, yield-bearing tokens, asset management, etc. The Single Asset Vault decouples the liquidity provision functionality from the specific protocol logic.

2. Introduction

The Single Asset Vault is an on-chain object that aggregates assets from one or more depositors and represents ownership through shares. Other protocols, such as the Lending Protocol, can access these assets via the vault, whether or not they generate yield. Currently, other protocols must be created by the same Account that created the Vault. However, this may change in the future.

The specification introduces a new Vault ledger entry, which contains key details such as available assets, shares, total value, and other relevant information.

2.1. Transactions

The specification includes the following transactions:

Vault Management:

  • VaultCreate: Creates a new Vault object.
  • VaultSet: Updates an existing Vault object.
  • VaultDelete: Deletes an existing Vault object.

Asset Management:

  • VaultDeposit: Deposits a specified number of assets into the Vault in exchange for shares.
  • VaultWithdraw: Withdraws a specified number of assets from the Vault in exchange for shares.

Additionally, an issuer can perform a Clawback operation:

  • VaultClawback: Allows the issuer of an IOU or MPT to claw back funds from the vault, as outlined in the Clawback documentation.

2.2. Vault Ownership and Management

A Single Asset Vault is owned and managed by an account called the Vault Owner. The account is reponsible for creating, updating and deleting the Vault object.

2.3. Access Control

A Single Asset Vault can be either public or private. Any depositor can deposit and redeem liquidity from a public vault, provided they own sufficient shares. In contrast, access to private shares is controlled via Permissioned Domains, which use on-chain Credentials to manage access to the vault. Only depositors with the necessary credentials can deposit assets to a private vault. To prevent Vault Owner from locking away depositor funds, any shareholder can withdraw funds. Furthermore, the Vault Owner has an implicit permission to deposit and withdraw assets to and from the Vault. I.e. they do not have to have credentials in the Permissioned Domain.

2.4. Yield Bearing Shares

Shares represent the ownership of a portion of the vault's assets. On-chain shares are represented by a Multi-Purpose Token. When creating the vault, the Vault Owner can configure the shares to be non-transferable. Non-transferable shares cannot be transferred to any other account -- they can only be redeemed. If the vault is private, shares can be transferred and used in other DeFi protocols as long as the receiving account is authorized to hold the shares. The vault's shares may be yield-bearing, depending on the protocol connected to the vault, meaning that a holder may be able to withdraw more (or less) liquidity than they initially deposited.

2.5. Vault Kinds

Under LendingProtocolV1_1, a Vault is either open-ended or closed-ended. The kind is chosen at creation (VaultKind) and cannot change afterward.

An open-ended Vault is the original Single Asset Vault. Depositors may deposit and withdraw whenever the other Vault rules allow. It has no subscription window, no investment lock-up, and no redemption date. Absence of VaultKind, or VaultKind = 0, means open-ended.

A closed-ended Vault is a fixed-term fund. It raises capital for a limited period, holds that capital for a fixed investment term, then opens for redemption. Once investment has begun, new deposits are rejected and withdrawals are blocked until redemption starts. The schedule is set at creation by two immutable timestamps:

  • SubscriptionDate — last moment of fundraising. After it, the Vault enters investment and the pool size is fixed.
  • RedemptionDate — first moment of wind-down. From then on, depositors may withdraw again; new deposits remain closed.

Between those dates the Vault is in Investment: capital stays in place so a connected protocol (for example the Lending Protocol) can deploy a known amount for a known term. The current phase is derived from the parent ledger close time; it is not a stored field. Open-ended Vaults have no phase. The closed-ended lifecycle, field rules, and deposit/withdraw gates are specified in XLS-65.1.4.

2.6. Terminology

  • Vault: A ledger entry for aggregating liquidity and providing this liquidity to one or more accessors.
  • Asset: The currency of a vault. It is either XRP, a Fungible Token or a Multi-Purpose Token.
  • Share: Shares represent the depositors' portion of the vault's assets. Shares are a Multi-Purpose Token created by the pseudo-account of the vault.
  • Open-ended Vault: A Vault with no fixed fundraising or lock-up schedule. Deposit and withdraw timing follow only the other Vault rules.
  • Closed-ended Vault: A Vault with immutable SubscriptionDate and RedemptionDate, moving through Subscription, Investment, and Redemption.
  • Subscription: The fundraising phase of a closed-ended Vault. Deposits and withdrawals are both allowed.
  • Investment: The lock-up phase. Deposits and withdrawals are both rejected so deployed capital stays in place.
  • Redemption: The wind-down phase. Withdrawals are allowed again; deposits remain rejected.

2.7. Actors

  • Vault Owner: An account responsible for creating and deleting The Vault.
  • Depositor: An entity that deposits and withdraws assets to and from the vault.

2.8. Connecting to the Vault

A protocol connecting to a Vault must track its debt. Furthermore, the updates to the Vault state when funds are removed or added back must be handled in the transactors of the protocol. For an example, please refer to the Lending Protocol specification.

2.9. Amendments

  • SingleAssetVault (featureSingleAssetVault): the original vault amendment. It introduced the Vault ledger entry and the vault transactions; that behaviour is the parent of the patches below.
  • LendingProtocolV1_1, as described in XLS-65.1:
  • 65.1.1 Unmodifiable Vault Fields: makes Sequence, OwnerNode, Owner, WithdrawalPolicy, Scale and LEVersion immutable on the Vault once set
  • 65.1.2 Vault Deletion Memo: adds an optional MemoData field to VaultDelete that, if present, must be 1–256 bytes
  • 65.1.4 Closed-Ended Vault: adds the ClosedEnded vault kind with SubscriptionDate and RedemptionDate, and phase-gates VaultDeposit and VaultWithdraw on such vaults
  • fixCleanup3_4_0, as described in XLS-65.2:
  • admits one unit of rounding slack in the LossUnrealized invariant and in IOU accounting and state-change deltas for VaultDeposit, VaultWithdraw and VaultClawback, requires LossUnrealized to be non-negative, and narrows VaultSet cap enforcement to transactions that supply AssetsMaximum or otherwise change the cap

3. Specification

3.1 Ledger Entry: Vault

The Vault ledger entry describes the state of the tokenized vault.

3.1.1 Object Identifier

The key of the Vault object is the result of SHA512-Half of the following values concatenated in order:

  • The Vault space key 0x0056 (capital V)
  • The AccountID of the account submitting the VaultSettransaction, i.e.VaultOwner.
  • The transaction Sequence number. If the transaction used a Ticket, use the TicketSequence value.
3.1.2 Fields

A vault has the following fields:

Field Name Constant Required JSON Type Internal Type Default Value Description
LedgerEntryType No Yes string UINT16 0x0084 Ledger object type.
LedgerIndex No Yes string UINT16 N/A Ledger object identifier.
Flags Yes Yes string UINT32 0 Ledger object flags.
PreviousTxnID No Yes string HASH256 N/A Identifies the transaction ID that most recently modified this object.
PreviousTxnLgrSeq No Yes number UINT32 N/A The sequence of the ledger that contains the transaction that most recently modified this object.
Sequence No Yes number UINT32 N/A The transaction sequence number that created the vault.
OwnerNode No Yes number UINT64 N/A Identifies the page where this item is referenced in the owner's directory.
Owner No Yes string AccountID N/A The account address of the Vault Owner.
Account No Yes string AccountID N/A The address of the Vaults pseudo-account.
Data Yes No string BLOB None Arbitrary metadata about the Vault. Limited to 256 bytes.
Asset No Yes string or object ISSUE N/A The asset of the vault. The vault supports XRP, IOU and MPT.
AssetsTotal No Yes number NUMBER 0 The total value of the vault.
AssetsAvailable No Yes number NUMBER 0 The asset amount that is available in the vault.
LossUnrealized No Yes number NUMBER 0 The potential loss amount that is not yet realized expressed as the vaults asset.
AssetsMaximum Yes No number NUMBER 0 The maximum asset amount that can be held in the vault. Zero value 0 indicates there is no cap.
ShareMPTID No Yes number UINT192 0 The identifier of the share MPTokenIssuance object.
WithdrawalPolicy No Yes string UINT8 N/A Indicates the withdrawal strategy used by the Vault.
Scale No Yes number UINT8 6 The Scale specifies the power of 10 (\(10^{\text{scale}}\)) to multiply an asset's value by when converting it into an integer-based number of shares.
VaultKind Yes No number UINT8 0 LendingProtocolV1_1: Vault kind. Absent or 0 is open-ended; 1 is closed-ended.
SubscriptionDate Yes Conditional number UINT32 N/A LendingProtocolV1_1: End of Subscription and start of Investment; required for a closed-ended Vault.
RedemptionDate Yes Conditional number UINT32 N/A LendingProtocolV1_1: Start of Redemption; required for a closed-ended Vault.
3.1.2.1 Flags

The Vault object supports the following flags:

Flag Name Flag Value Modifiable? Description
lsfVaultPrivate 0x00010000 No If set, indicates that the vault is private.
3.1.2.2 Vault Kind and Phase Derivation

VaultKind selects the lifecycle. Under LendingProtocolV1_1:

  • Absent or 0 (OpenEnded): the Vault behaves as before this amendment. It has no phase (NoPhase). SubscriptionDate and RedemptionDate must be absent.
  • 1 (ClosedEnded): the Vault is a fixed-term fund. Both dates are required and immutable. Deposits are allowed only through the end of Subscription; withdrawals are blocked for the whole Investment interval and allowed again from Redemption onward.

VaultCreate rejects an unknown VaultKind. Other logic that encounters a future, unknown kind already stored on the ledger treats it as OpenEnded and therefore as NoPhase.

The phase is not stored. For a closed-ended Vault it is derived from the parent ledger close time, now:

Condition Phase
now <= SubscriptionDate Subscription
SubscriptionDate < now < RedemptionDate Investment
now >= RedemptionDate Redemption

SubscriptionDate is the last second of Subscription. RedemptionDate is the first second of Redemption. Investment is the open interval between them. See XLS-65.1.4 for the full closed-ended rules.

3.1.3 Pseudo-Account

An AccountRoot entry holds the XRP, IOU or MPT deposited into the vault. It also acts as the issuer of the vault's shares. The pseudo-account follows the XLS-64 specification for pseudo accounts. The AccountRoot object is created when creating the Vault object.

3.1.4 Ownership

The Vault objects are stored in the ledger and tracked in an Owner Directory owned by the account submitting the VaultSet transaction. Furthermore, to facilitate Vault object lookup from the vault shares, the object is also tracked in the OwnerDirectory of the pseudo-account.

3.1.5 Owner Reserve

The Vault object costs one reserve fee per object created:

  • The Vault object itself.
  • The MPTokenIssuance associated with the shares of the Vault.
3.1.6 Vault Shares

Shares represent the portion of the Vault assets a depositor owns. Vault Owners set the currency code of the share and whether the token is transferable during the vault's creation. These two values are immutable. The share is represented by a Multi-Purpose Token. The MPT is issued by the vault's pseudo-account.

3.1.6.1 Scale

The Scale field enables the vault to accurately represent fractional asset values using integer-only MPT shares, which prevents the loss of value from decimal truncation. It defines a scaling factor, calculated as \(10^{\text{Scale}}\), that converts a decimal asset amount into a corresponding whole number of shares. For example, with a Scale of 6, a deposit of 20.3 assets is multiplied by \(10^6\) and credited as 20,300,000 shares.

As a general rule, all calculations involving MPTs are executed with a precision of a single MPT, treating them as indivisible units. If a calculation results in a fractional amount, it will be rounded up, down or to the nearest whole number depending on the context. Crucially, the rounding direction is determined by the protocol and is not controlled by the transaction submitter, which may lead to unexpected results.

3.1.6.1.1 IOU

When a vault holds an IOU, the Scale is configurable by the Vault Owner at the time of the vault's creation. The value can range from 0 to a maximum of 18, with a default of 6. This flexibility allows issuers to set a level of precision appropriate for their specific token.

3.1.6.1.2 XRP

When a vault holds XRP, the Scale is fixed at 0. This aligns with XRP's native structure, where one share represents one drop (the smallest unit of XRP), and one XRP equals 1,000,000 drops. Therefore, a deposit of 10 XRP to an empty Vault will result in the issuance of 10,000,000 shares (\(10 \times 10^6\)).

3.1.6.1.3 MPT

When a vault holds MPT, its Scale is fixed at 0. This creates a 1-to-1 relationship between deposited MPT units and the shares issued (for example, depositing 10 MPTs to an empty Vault issues 10 shares). The value of a single MPT is determined at the issuer's discretion. If an MPT is set to represent a large value, the vault owner and the depositor must be cautious. Since only whole MPT units are used in calculations, any value that is not a multiple of a single MPT's value may be lost due to rounding during a transaction.

3.1.6.2 MPTokenIssuance

The MPTokenIssuance object represents the share on the ledger. It is created and deleted together with the Vault object.

3.1.6.2.1 MPTokenIssuance Values
Field Description Value
Issuer The AccountID of the Vault's pseudo-account. pseudo-account ID
MaximumAmount Not set, so the number of shares that can be issued is bounded only by the protocol maximum. absent
TransferFee The fee paid to transfer the shares. 0
MPTokenMetadata Arbitrary metadata about the share MPT, in hex format. -
AssetScale Represents orders of magnitude between the standard and the MPT unit. For IOUs it is set to Vault.Scale, otherwise it is 0. Vault.Scale

VaultCreate omits MaximumAmount on the share issuance rather than storing an explicit cap. The number of shares in issue is therefore bounded by the protocol maximum for an MPTokenIssuance, 0x7FFFFFFFFFFFFFFF, as defined in XLS-33 §2.1.1.2.5.

3.1.6.2.2 Flags

The following flags are set based on whether the shares are transferable and if the vault is public or private.

Condition Transferable Non-Transferable
Public Vault lsfMPTCanEscrow
lsfMPTCanTrade
lsfMPTCanTransfer
No Flags
Private Vault lsfMPTCanEscrow
lsfMPTCanTrade
lsfMPTCanTransfer
lsfMPTRequireAuth
lsfMPTRequireAuth
3.1.6.3 MPToken

The MPToken object represents the amount of shares held by a depositor. It is created when the account deposits liquidity into the vault and is deleted when a depositor redeems (or transfers) all shares.

3.1.6.3.1 MPToken Values

The MPToken values should be set as per the MPT specification.

Condition Transferable Non-Transferable
Public Vault No Flags lsfMPTAuthorized
Private Vault lsfMPTAuthorized lsfMPTAuthorized
3.1.7 Exchange Algorithm

Exchange Algorithm refers to the logic that is used to exchange assets into shares and shares into assets. This logic is executed when depositing or redeeming liquidity. A Vault comes with the default exchange algorithm, which is detailed below.

3.1.7.1 Unrealized Loss

A well-informed depositor may learn of an incoming loss and redeem their shares early, causing the remaining depositors to bear the full loss. To discourage such behaviour, we introduce a concept of "paper loss," captured by the Vault object's LossUnrealized attribute. The "paper loss" captures a potential loss the vault may experience and thus temporarily decreases the vault value. Only a protocol connected to the Vault may increase or decrease the LossUnrealized attribute; for the Lending Protocol that means LoanManage and LoanPay alone.

The "paper loss" temporarily decreases the vault value. A malicious depositor may take advantage of this to deposit assets at a lowered price and withdraw them once the price increases.

Consider a vault with a total value of $1.0m and total shares of $1.0m. Assume the "paper loss" for the vault is $900k. The new exchange rate is as follows:

\[ exchangeRate = \frac{AssetsTotal - LossUnrealized}{SharesTotal} \]

\[ exchangeRate = \frac{1,000,000 - 900,000}{1,000,000} = 0.1 \]

After the "paper loss" is cleared, the new effective exchange rate would be as follows:

\[ exchangeRate = \frac{AssetsTotal}{SharesTotal} \]

\[ exchangeRate = \frac{1,000,000}{1,000,000} = 1.0 \]

A depositor could deposit $100k assets at a 0.1 exchange rate and get 1.0m shares. Once the "paper loss" is cleared, their shares would be worth $1.0m.

To account for this problem, the Vault must use two different exchange rate models: one for depositing assets and one for withdrawing them.

3.1.7.2 Exchange Rate Algorithms

This section details the algorithms used to calculate the exchange between assets and shares for deposits, redemptions, and withdrawals.

The following are the key variables used in the calculations:

  • \(\Gamma_{assets}\): The total balance of assets held within the vault.
  • \(\Gamma_{shares}\): The total number of shares currently issued by the vault.
  • \(\Delta_{assets}\): The amount of assets being deposited, withdrawn, or redeemed.
  • \(\Delta_{shares}\): The number of shares being issued or burned.
  • \(\iota\): The vault's total unrealized loss.
  • \(\sigma\): The scaling factor derived from Scale, used to convert fractional assets into integer shares.
3.1.7.2.1 Deposit

The deposit function calculates the number of shares a user receives for their assets.

Calculation Logic

The calculation depends on whether the vault is empty.

  • Initial Deposit: For the first deposit into an empty vault, shares are calculated using a scaling factor, \(\sigma = 10^{\text{Scale}}\), to properly represent fractional assets as whole numbers. \[\Delta_{shares} = \Delta_{assets} \times \sigma\]

  • Subsequent Deposits: For all other deposits, shares are calculated proportionally. The resulting \(\Delta_{shares}\) value is rounded down to the nearest integer. \[\Delta_{shares} = \frac{\Delta_{assets} \times \Gamma_{shares}}{\Gamma_{assets}}\]

Because the share amount is rounded down, the actual assets taken from the depositor (\(\Delta_{assets'}\)) are recalculated.

\[\Delta_{assets'} = \frac{\Delta_{shares} \times \Gamma_{assets}}{\Gamma_{shares}}\]

3.1.7.2.1.1 Vault State Update

The vault's totals are updated with the final calculated amounts.

  • New Total Assets: \(\Gamma_{assets} \leftarrow \Gamma_{assets} + \Delta_{assets'}\)
  • New Total Shares: \(\Gamma_{shares} \leftarrow \Gamma_{shares} + \Delta_{shares}\)
3.1.7.2.2 Redeem

The redeem function calculates the asset payout for a user burning a specific number of shares.

Calculation Logic

The amount of assets a user receives is calculated by finding the proportional value of their shares relative to the vault's total holdings, accounting for any unrealized loss (\(\iota\)).

\[\Delta_{assets} = \frac{\Delta_{shares} \times (\Gamma_{assets} - \iota)}{\Gamma_{shares}}\]

Vault State Update

The vault's totals are reduced after the redemption.

  • New Total Assets: \(\Gamma_{assets} \leftarrow \Gamma_{assets} - \Delta_{assets}\)
  • New Total Shares: \(\Gamma_{shares} \leftarrow \Gamma_{shares} - \Delta_{shares}\)
3.1.7.2.3 Withdraw

The withdraw function handles a request for a specific amount of assets, which involves a two-step process to determine the final payout.

First, the requested asset amount (\(\Delta_{assets_requested}\)) is converted into the equivalent number of shares to burn, based on the vault's real value.

\[\Delta_{shares} = \frac{\Delta_{assets_requested} \times \Gamma_{shares}}{(\Gamma_{assets} - \iota)}\]

This calculated \(\Delta_{shares}\) amount is rounded to the nearest whole number.

Next, the rounded number of shares from Step 1 is used to calculate the final asset payout (\(\Delta_{assets_out}\)), using the same logic as a redemption.

\[\Delta_{assets_out} = \frac{\Delta_{shares} \times (\Gamma_{assets} - \iota)}{\Gamma_{shares}}\]

Due to the rounding in Step 1, this final payout may differ slightly from the user's requested amount.

Vault State Update

The vault's totals are reduced by the final calculated amounts.

  • New Total Assets: \(\Gamma_{assets} \leftarrow \Gamma_{assets} - \Delta_{assets_out}\)
  • New Total Shares: \(\Gamma_{shares} \leftarrow \Gamma_{shares} - \Delta_{shares}\)
3.1.7.3 Withdrawal Policy

Withdrawal policy controls the logic used when removing liquidity from a vault. Each strategy has its own implementation, but it can be used in multiple vaults once implemented. Therefore, different vaults may have different withdrawal policies. The specification introduces the following options:

3.1.7.3.1 first-come-first-serve

The First Come, First Serve strategy treats all requests equally, allowing a depositor to redeem any amount of assets provided they have a sufficient number of shares.

3.1.8 Frozen Assets

The issuer of the Vaults asset may enact a freeze either through a Global Freeze for IOUs or locking MPT. When the vaults asset is frozen, it can only be withdrawn by specifying the Destination account as the Issuer of the asset. Similarly, a frozen asset may not be deposited into a vault. Furthermore, when the asset of a vault is frozen, the shares corresponding to the asset may not be transferred.

3.1.9 Transfer Fees

The Vault does not apply the Transfer Fee to VaultDeposit and VaultWithdraw transactions. Furthermore, whenever a protocol moves assets from or to a Vault, the Transfer Fee must not be charged.

3.1.10 Invariants
  1. Vault.AssetsAvailable >= 0.
  2. Vault.AssetsTotal >= 0.
  3. Vault.AssetsMaximum >= 0.
  4. Vault.AssetsAvailable <= Vault.AssetsTotal.
    • SingleAssetVault: Vault.LossUnrealized <= (Vault.AssetsTotal - Vault.AssetsAvailable).
  5. fixCleanup3_4_0: If Vault.Asset is an IOU, Vault.LossUnrealized <= (Vault.AssetsTotal - Vault.AssetsAvailable) + 1 unit at the scale of Vault.AssetsTotal. For XRP and MPT the comparison remains strict <=.
    • SingleAssetVault: The check does not apply.
  6. fixCleanup3_4_0: Vault.LossUnrealized >= 0, for every asset type.
  7. If MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount == 0: Vault.AssetsTotal == 0 and Vault.AssetsAvailable == 0.
  8. The MPTokenIssuance identified by Vault.ShareMPTID must exist, and its OutstandingAmount must not exceed its MaximumAmount. VaultCreate leaves MaximumAmount absent (§3.1.6.2.1), in which case the bound is the protocol maximum 0x7FFFFFFFFFFFFFFF.
  9. On creation, Vault.AssetsTotal, Vault.AssetsAvailable, Vault.LossUnrealized and the share MPTokenIssuance.OutstandingAmount are all zero. The share issuance has Issuer == Vault.Account, and AccountRoot(Vault.Account) is a pseudo-account whose VaultID points to the new vault. Only VaultCreate may create a Vault.
  10. Only VaultDelete may delete a Vault. It must also delete the share MPTokenIssuance, and the deleted vault must have AssetsTotal == 0, AssetsAvailable == 0 and no outstanding shares.
  11. There is no invariant requiring Vault.AssetsTotal <= Vault.AssetsMaximum to hold on every modification of the entry, because Vault.AssetsTotal grows with accrued interest and interest is not a deposit. The cap is instead enforced per transaction, by the checks in items 12 and 13 and, unchanged by either amendment, by LoanSet, which fails when Vault.AssetsMaximum is non-zero and either Vault.AssetsTotal >= Vault.AssetsMaximum or Vault.AssetsTotal + InterestDue > Vault.AssetsMaximum (see the Lending Protocol §3.8.5.2):
  12. VaultDeposit fails when Vault.AssetsMaximum is non-zero and the post-deposit Vault.AssetsTotal exceeds it.
    • SingleAssetVault: VaultSet fails when Vault.AssetsMaximum is non-zero and Vault.AssetsTotal exceeds it.
    • fixCleanup3_4_0: VaultSet fails when Vault.AssetsMaximum is non-zero, Vault.AssetsTotal exceeds it, and the transaction supplies AssetsMaximum or the cap otherwise changes. A cap already exceeded by accrued interest no longer blocks a VaultSet that omits AssetsMaximum and does not otherwise change the cap.
    • SingleAssetVault: Vault.Asset, Vault.Account and Vault.ShareMPTID are immutable once set.
    • LendingProtocolV1_1: Vault.Sequence, Vault.OwnerNode, Vault.Owner, Vault.WithdrawalPolicy, Vault.Scale, Vault.LEVersion, Vault.VaultKind, Vault.SubscriptionDate, Vault.RedemptionDate, Vault.Asset, Vault.Account and Vault.ShareMPTID are immutable once set. If Vault.LEVersion, Vault.VaultKind, Vault.SubscriptionDate or Vault.RedemptionDate is absent, it remains absent, except when the transaction creates the entry.
  13. Vault.LossUnrealized may only be changed by LoanManage and LoanPay. Every other transaction that modifies the entry must leave it unchanged.
  14. A Vault is modified only by a transaction type that declares a vault privilege — VaultCreate, VaultSet, VaultDelete, VaultDeposit, VaultWithdraw, VaultClawback, LoanSet, LoanPay and LoanManage — and at most one Vault is modified per transaction. LoanManage has MayModifyVault and may succeed without modifying one; each other listed transaction has MustModifyVault and must create, modify or delete one.
  15. LendingProtocolV1_1: A closed-ended Vault has both SubscriptionDate and RedemptionDate, and 180 <= RedemptionDate - SubscriptionDate < 946708560.

3.2 Transaction: VaultCreate

The VaultCreate transaction creates a new Vault object.

3.2.1 Fields
Field Name Required JSON Type Internal Type Default Value Description
TransactionType Yes string UINT16 65 The transaction type (ttVAULT_CREATE).
Flags Yes number UINT32 0 Specifies the flags for the Vault.
Data No string BLOB Arbitrary Vault metadata, limited to 256 bytes.
Asset Yes string or object ISSUE N/A The asset (XRP, IOU or MPT) of the Vault.
AssetsMaximum No number NUMBER 0 The maximum asset amount that can be held in a vault.
MPTokenMetadata No string BLOB Arbitrary metadata about the share MPT, in hex format, limited to 1024 bytes.
WithdrawalPolicy No number UINT8 "FirstComeFirstServe" Indicates the withdrawal strategy used by the Vault.
DomainID No string HASH256 The PermissionedDomain object ID associated with the shares of this Vault.
Scale No number UINT8 6 The Scale specifies the power of 10 (\(10^{\text{scale}}\)) to multiply an asset's value by when converting it into an integer-based number of shares.
VaultKind No number UINT8 0 LendingProtocolV1_1: 0 is open-ended and 1 is closed-ended.
SubscriptionDate Conditional number UINT32 N/A LendingProtocolV1_1: End of Subscription and start of Investment; required for a closed-ended Vault.
RedemptionDate Conditional number UINT32 N/A LendingProtocolV1_1: Start of Redemption; required for a closed-ended Vault.
3.2.2 Flags
Flag Name Flag Value Description
tfVaultPrivate 0x00010000 Indicates that the vault is private. It can only be set during Vault creation.
tfVaultShareNonTransferable 0x00020000 Indicates the vault share is non-transferable. It can only be set during Vault creation.
3.2.3 WithdrawalPolicy

The type indicates the withdrawal strategy supported by the vault. The following values are supported:

Strategy Name Value Description
vaultStrategyFirstComeFirstServe 0x0001 Requests are processed on a first-come-first-serve basis.
3.2.4 Transaction Fees

The transaction creates an AccountRoot object for the _pseudo-account_. Therefore, the transaction must destroy one incremental owner reserve amount.

3.2.5 Failure Conditions
3.2.5.1 Data Verification
    • SingleAssetVault: VaultKind, SubscriptionDate and RedemptionDate are not accepted. (temDISABLED)
  1. LendingProtocolV1_1: The check does not apply.
  2. LendingProtocolV1_1: VaultKind has an unrecognized value. (temMALFORMED)
  3. LendingProtocolV1_1: VaultKind is absent or OpenEnded, but SubscriptionDate or RedemptionDate is present. (temMALFORMED)
  4. LendingProtocolV1_1: VaultKind is ClosedEnded, but either date is absent. (temMALFORMED)
  5. LendingProtocolV1_1: VaultKind is ClosedEnded and SubscriptionDate + 180 > RedemptionDate or RedemptionDate >= SubscriptionDate + 946708560. (temMALFORMED)

The sums in check 5 must be computed without 32-bit overflow.

3.2.5.2 Protocol-Level Failures
  1. The Asset is XRP:
  2. The Scale parameter is provided.

  3. The Asset is MPT:

  4. The Scale parameter is provided.
  5. The lsfMPTCanTransfer is not set in the MPTokenIssuance object (the asset is not transferable).
  6. The lsfMPTLocked flag is set in the MPTokenIssuance object (the asset is locked).

  7. The Asset is an IOU:

  8. The lsfGlobalFreeze flag is set on the issuing account (the asset is frozen).
  9. The Scale parameter is provided, and is less than 0 or greater than 18.

  10. The tfVaultPrivate flag is not set and the DomainID is provided (the Vault Owner is attempting to create a public Vault with a PermissionedDomain)

  11. The PermissionedDomain object does not exist with the provided DomainID.

  12. The Data field is larger than 256 bytes.

  13. The account submitting the transaction has insufficient AccountRoot.Balance for the Owner Reserve.
  14. LendingProtocolV1_1: VaultKind is ClosedEnded and SubscriptionDate is not strictly after the parent ledger close time. (tecEXPIRED)
  15. LendingProtocolV1_1: VaultKind is ClosedEnded and RedemptionDate is not strictly after the parent ledger close time. (tecEXPIRED)
3.2.6 State Changes
  1. Create a new Vault ledger object.
  2. SingleAssetVault: VaultKind, SubscriptionDate, and RedemptionDate are absent.
  3. LendingProtocolV1_1: If VaultKind == ClosedEnded, store all three fields; otherwise leave all three absent.
  4. Create a new MPTokenIssuance ledger object for the vault shares, and assign its MPTID to Vault.ShareMPTID.
  5. If the DomainID is provided:
    1. MPTokenIssuance(Vault.ShareMPTID).DomainID = DomainID (Set the Permissioned Domain ID).
  6. Create an MPToken object for the Vault Owner to hold Vault Shares.
  7. Create a new AccountRoot pseudo-account object with VaultID set to the new Vault's ID.

  8. If Vault.Asset is an IOU:

  9. Create a RippleState object between the pseudo-account AccountRoot and Issuer AccountRoot.

  10. If Vault.Asset is an MPT:

  11. Create MPToken object for the pseudo-account for the Asset.MPTokenIssuance.
3.2.7 Invariants
  1. A newly created vault has zero AssetsTotal, AssetsAvailable, LossUnrealized and outstanding shares.
  2. The share MPTokenIssuance.Issuer equals Vault.Account, and that account is a pseudo-account whose VaultID points to the new vault.
  3. Only VaultCreate may create a Vault; it must create rather than update one.
  4. LendingProtocolV1_1: A newly created closed-ended Vault has both phase dates and satisfies 180 <= RedemptionDate - SubscriptionDate < 946708560.

3.3 Transaction: VaultSet

The VaultSet updates an existing Vault ledger object.

3.3.1 Fields
Field Name Required JSON Type Internal Type Default Value Description
TransactionType Yes string UINT16 66 The transaction type (ttVAULT_SET).
VaultID Yes string HASH256 N/A The ID of the Vault to be modified. Must be included when updating the Vault.
Data No string BLOB Arbitrary Vault metadata, limited to 256 bytes.
AssetsMaximum No number NUMBER The maximum asset amount that can be held in a vault. The value cannot be lower than the current AssetsTotal unless the value is 0.
DomainID No string HASH256 The PermissionedDomain object ID associated with the shares of this Vault.
3.3.2 Failure Conditions
3.3.2.1 Data Verification
  1. The VaultID field is zero. (temMALFORMED)
  2. The Data field, if provided, is empty or exceeds 256 bytes. (temMALFORMED)
  3. The AssetsMaximum field, if provided, is negative. (temMALFORMED)
  4. None of Data, AssetsMaximum, or DomainID are provided (nothing to update). (temMALFORMED)
3.3.2.2 Protocol-Level Failures
  1. The Vault object with the specified VaultID does not exist on the ledger. (tecNO_ENTRY)
  2. The submitting account is not the Owner of the vault. (tecNO_PERMISSION)
  3. The DomainID field is provided and the vault does not have lsfVaultPrivate set. (tecNO_PERMISSION)
  4. The DomainID field is provided, is non-zero, and the referenced PermissionedDomain object does not exist. (tecOBJECT_NOT_FOUND)
  5. The AssetsMaximum field is supplied, is non-zero, and is less than the current Vault.AssetsTotal. (tecLIMIT_EXCEEDED)
  6. The resulting Vault.AssetsMaximum is non-zero and the current Vault.AssetsTotal exceeds it. (tecINVARIANT_FAILED)
  7. SingleAssetVault: This applies to every VaultSet, including one that supplies neither AssetsMaximum nor any other change to the cap.
  8. fixCleanup3_4_0: This applies only when the transaction supplies AssetsMaximum or otherwise changes the cap. A VaultSet that omits AssetsMaximum and leaves the cap unchanged succeeds even when accrued interest has pushed Vault.AssetsTotal past the cap.
3.3.3 State Changes
  1. Update the mutable fields Data and AssetsMaximum in the Vault ledger object, if provided.
  2. If DomainID is provided and non-zero: set MPTokenIssuance(Vault.ShareMPTID).DomainID = DomainID.
  3. If DomainID is provided and is zero: remove DomainID from MPTokenIssuance(Vault.ShareMPTID).
3.3.4 Invariants
  1. VaultSet must not change the vault pseudo-account's asset balance.
  2. VaultSet must not change Vault.AssetsTotal or Vault.AssetsAvailable.
  3. VaultSet must not change MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount.
    • SingleAssetVault: If Vault.AssetsMaximum > 0: Vault.AssetsTotal <= Vault.AssetsMaximum.
  4. fixCleanup3_4_0: This is checked only if the transaction supplies AssetsMaximum or otherwise changes the cap.

3.4 Transaction: VaultDelete

The VaultDelete transaction deletes an existing vault object.

3.4.1 Fields
Field Name Required JSON Type Internal Type Default Value Description
TransactionType Yes string UINT16 67 Transaction type (ttVAULT_DELETE in rippled).
VaultID Yes string HASH256 N/A The ID of the vault to be deleted.
MemoData No string BLOB N/A A hexadecimal-encoded opaque reason for the deletion. When present, the decoded value must be 1–256 bytes. Requires LendingProtocolV1_1.
3.4.2 Failure Conditions
3.4.2.1 Data Verification
  1. The VaultID field is zero. (temMALFORMED)
    • SingleAssetVault: The MemoData field is present. (temDISABLED)
  2. LendingProtocolV1_1: The check does not apply.
    • LendingProtocolV1_1: The MemoData field is present and is empty or longer than 256 bytes. (temMALFORMED)
3.4.2.2 Protocol-Level Failures
  1. The Vault object with the VaultID does not exist on the ledger. (tecNO_ENTRY)
  2. The submitting account is not the Owner of the vault. (tecNO_PERMISSION)
  3. Vault.AssetsAvailable is greater than zero. (tecHAS_OBLIGATIONS)
  4. Vault.AssetsTotal is greater than zero. (tecHAS_OBLIGATIONS)
  5. MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount is greater than zero (outstanding shares remain). (tecHAS_OBLIGATIONS)
  6. The pseudo-account's OwnerDirectory still contains objects after cleanup (unexpected obligations remain). (tecHAS_OBLIGATIONS)
3.4.3 State Changes
  1. Delete the MPToken or RippleState object corresponding to the vault's holding of the asset, if one exists.
  2. Delete the vault owner's MPToken for vault shares, if one exists.
  3. Delete the MPTokenIssuance object for the vault shares.
  4. Delete the AccountRoot object of the pseudo-account, and its DirectoryNode objects.
  5. Remove the Vault object from the Vault.Owner's DirectoryNode and decrement OwnerCount by 2.
  6. Delete the Vault object.
3.4.4 Invariants
  1. Only a VaultDelete transaction may delete a Vault object; only VaultDelete may succeed without an after-state for the vault.
  2. VaultDelete must also delete the share MPTokenIssuance.
  3. At deletion: Vault.AssetsTotal == 0, Vault.AssetsAvailable == 0, and MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount == 0.

3.5 Transaction: VaultDeposit

The VaultDeposit transaction adds Liqudity in exchange for vault shares.

3.5.1 Fields
Field Name Required JSON Type Internal Type Default Value Description
TransactionType Yes string UINT16 68 Transaction type (ttVAULT_DEPOSIT).
VaultID Yes string HASH256 N/A The ID of the vault to which the assets are deposited.
Amount Yes string or object STAmount N/A Asset amount to deposit.
3.5.2 Failure Conditions
3.5.2.1 Data Verification
  1. The VaultID field is zero. (temMALFORMED)
  2. The Amount field is zero or negative. (temBAD_AMOUNT)
3.5.2.2 Protocol-Level Failures

The order below reflects the evaluation order in VaultDeposit.cpp (preclaim, then doApply).

  1. The Vault object with the VaultID does not exist on the ledger. (tecNO_ENTRY)
  2. The Amount asset does not match Vault.Asset. (tecWRONG_ASSET)

  3. If Vault.Asset is an MPT:

  4. The lsfMPTCanTransfer flag is not set in the MPTokenIssuance object (the asset is not transferable). (tecNO_AUTH)
  5. The asset is globally or individually locked for the depositor. (tecLOCKED)

  6. If Vault.Asset is an IOU:

  7. The asset is globally frozen, or the depositor's trust line is frozen. (tecFROZEN)

  8. The vault shares are locked for the depositor. (tecLOCKED)

  9. If the vault has lsfVaultPrivate set and the depositor is not the vault owner:

  10. No PermissionedDomain is configured on MPTokenIssuance(Vault.ShareMPTID). (tecNO_AUTH)
  11. The depositor is not a valid member of the permissioned domain. (tecNO_AUTH)

  12. The depositor does not have a required authorized holding for the vault asset (e.g., missing MPToken for a restricted MPT). (tecNO_AUTH)

  13. The Amount rounds to zero at the vault's precision scale. (tecPRECISION_LOSS)
  14. The depositor has insufficient balance to cover the deposit. (tecINSUFFICIENT_FUNDS)
  15. The Amount rounds to zero at the depositor's trust line scale (IOU only). (tecPRECISION_LOSS)
  16. The computed number of shares for the deposit is zero. (tecPRECISION_LOSS)
  17. fixCleanup3_4_0: The deposit rounds down to zero at the posterior Vault.AssetsTotal scale, i.e. a non-zero \(\Delta_{asset}\) that would credit the vault nothing at that scale, as described in XLS-65.2. (tecPRECISION_LOSS)
  18. Arithmetic overflow during share calculation. (tecPATH_DRY)
  19. Vault.AssetsMaximum is non-zero and adding the deposited amount to Vault.AssetsTotal would exceed it. (tecLIMIT_EXCEEDED)
    • SingleAssetVault: The check does not apply.
    • LendingProtocolV1_1: The Vault is closed-ended and the parent ledger close time is greater than Vault.SubscriptionDate. (tecEXPIRED)
3.5.3 State Changes
  1. If no share MPToken object exists for the depositor, create one. For private vaults, the MPToken is created only after domain authorization is verified.
  2. Increase the MPTAmount field of the depositor's share MPToken by \(\Delta_{share}\).
  3. Increase the OutstandingAmount field of the share MPTokenIssuance by \(\Delta_{share}\).
  4. Increase Vault.AssetsTotal and Vault.AssetsAvailable by \(\Delta_{asset}\).

  5. If Vault.Asset is XRP:

  6. Increase the Balance field of the pseudo-account AccountRoot by \(\Delta_{asset}\).
  7. Decrease the Balance field of the depositor AccountRoot by \(\Delta_{asset}\).

  8. If Vault.Asset is an IOU:

  9. Increase the RippleState balance between the pseudo-account AccountRoot and the Issuer AccountRoot by \(\Delta_{asset}\).
  10. Decrease the RippleState balance between the depositor AccountRoot and the Issuer AccountRoot by \(\Delta_{asset}\).

  11. If Vault.Asset is an MPT:

  12. Increase the MPToken.MPTAmount of the pseudo-account MPToken for Vault.Asset by \(\Delta_{asset}\).
  13. Decrease the MPToken.MPTAmount of the depositor MPToken for Vault.Asset by \(\Delta_{asset}\).

Note: \(\Delta_{asset}\) is the actual asset amount transferred, which may be slightly less than the requested Amount due to scale rounding for IOU assets.

  • SingleAssetVault: The vault accounting increases and both asset-balance moves use that same \(\Delta_{asset}\). Where the depositor is the issuer of a non-XRP Vault.Asset it holds no balance of the asset — the transfer creates the asset at the issuer instead — so only the vault accounting fields and the vault's asset balance move. This is the issuer exception of invariant 2 below.
  • fixCleanup3_4_0: For an IOU, the persisted vault accounting deltas and the persisted asset-balance deltas may differ from each other by at most one unit at the comparison scale in XLS-65.2. For XRP and MPT they remain equal.
3.5.4 Invariants
  1. The vault pseudo-account's asset balance must increase by a positive amount not exceeding the transaction Amount.
    • SingleAssetVault: Unless the depositor is the asset issuer, the depositor's asset balance must decrease by the same amount as the vault increases.
  2. fixCleanup3_4_0: Unless the depositor is the asset issuer, for an IOU the comparison admits one unit at the comparison scale. For XRP and MPT it remains exact. The issuer exemption is unchanged.
  3. The depositor's share MPToken.MPTAmount must increase by a positive amount.
  4. The increase in MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount must equal the increase in the depositor's share balance.
    • SingleAssetVault: Vault.AssetsTotal and Vault.AssetsAvailable must each increase by the vault's asset balance increase.
  5. fixCleanup3_4_0: For an IOU, each comparison admits one unit at the comparison scale. For XRP and MPT it remains exact.
    • SingleAssetVault: If Vault.AssetsMaximum is non-zero, Vault.AssetsTotal <= Vault.AssetsMaximum after the deposit.
  6. fixCleanup3_4_0: Unchanged. The cap remains a deposit invariant; the amendment only narrows VaultSet cap enforcement.
  7. LendingProtocolV1_1: A deposit succeeds only when the Vault phase is Subscription or NoPhase.

3.6 Transaction: VaultWithdraw

The VaultWithdraw transaction withdraws assets in exchange for the vault's shares.

3.6.1 Fields
Field Name Required JSON Type Internal Type Default Value Description
TransactionType Yes string UINT16 69 Transaction type (ttVAULT_WITHDRAW).
VaultID Yes string HASH256 N/A The ID of the vault from which assets are withdrawn.
Amount Yes number STAmount 0 The exact amount of Vault asset to withdraw.
Destination No string AccountID Empty An account to receive the assets. It must be able to receive the asset.
DestinationTag No number UINT32 Empty Arbitrary tag identifying the reason for the withdrawal to the destination.
  • If Amount is the Vaults asset, calculate the share cost using the Withdraw formula.
  • If Amount is the Vaults share, calculate the assets amount using the Redeem formula.

In sections below assume the following variables:

  • \(\Gamma_{share}\) - the total number of shares issued by the vault.
  • \(\Gamma_{asset}\) - Vault.AssetsTotal - Vault.LossUnrealized. Exception: if the withdrawer is the sole outstanding shareholder, the LossUnrealized deduction is waived and \(\Gamma_{asset}\) = Vault.AssetsTotal, since the sole holder is entitled to the vault's full realized and unrealized value.

  • \(\Delta_{asset}\) - the change in the total amount of assets after a deposit, withdrawal, or redemption.

  • \(\Delta_{share}\) - che change in the total amount of shares after a deposit, withdrawal, or redemption.
3.6.2 Failure Conditions
3.6.2.1 Data Verification
  1. The VaultID field is zero. (temMALFORMED)
  2. The Amount field is zero or negative. (temBAD_AMOUNT)
  3. The Destination field, if provided, is zero. (temMALFORMED)
3.6.2.2 Protocol-Level Failures
  1. The Vault object with the VaultID does not exist on the ledger. (tecNO_ENTRY)
  2. The Amount asset is neither Vault.Asset nor the vault share (Vault.ShareMPTID). (tecWRONG_ASSET)
  3. If Vault.Asset is an IOU:
  4. The asset is globally frozen, or the destination account's trust line is frozen. (tecFROZEN)

  5. If Vault.Asset is an MPT:

  6. The asset is globally or individually locked for the destination account. (tecLOCKED)

  7. The vault shares are frozen or locked for the submitting account. (tecFROZEN / tecLOCKED)

  8. The destination account does not have a required authorized holding for the vault asset. (tecNO_AUTH)
  9. The Destination account, if specified, does not exist on the ledger. (tecNO_DST)
  10. The Destination account, if specified, requires a destination tag but none is provided. (tecDST_TAG_NEEDED)
  11. The Destination account, if specified, requires deposit authorization and the sender is not authorized. (tecNO_PERMISSION)

  12. There is insufficient liquidity to fill the request:

    1. If Amount is shares: the submitter holds fewer shares than Amount. (tecINSUFFICIENT_FUNDS)
    2. If Amount is shares: Vault.AssetsAvailable is less than the computed \(\Delta_{asset}\). (tecINSUFFICIENT_FUNDS)
    3. If Amount is the vault asset: the submitter holds insufficient shares to cover the withdrawal. (tecINSUFFICIENT_FUNDS)
    4. If Amount is the vault asset: Vault.AssetsAvailable < Amount. (tecINSUFFICIENT_FUNDS)
  13. The computed share amount for the withdrawal is zero. (tecPRECISION_LOSS)

  14. fixCleanup3_4_0: The withdrawal would move shares while moving no assets: a non-zero \(\Delta_{asset}\) that leaves the stored Vault.AssetsTotal unchanged at its precision, or that rounds down to zero at the posterior Vault.AssetsTotal scale, as described in XLS-65.2. A fixed-share withdrawal whose pre-transaction Vault.AssetsTotal == Vault.LossUnrealized is exempt and may redeem shares for zero assets. (tecPRECISION_LOSS)
  15. Arithmetic overflow during share/asset calculation. (tecPATH_DRY)
    • SingleAssetVault: The check does not apply.
    • LendingProtocolV1_1: The Vault is closed-ended and SubscriptionDate < parent ledger close time < RedemptionDate. (tecTOO_SOON)
3.6.3 State Changes
  1. Decrease the MPToken.MPTAmount of the submitter's share MPToken by \(\Delta_{share}\).
  2. Decrease the OutstandingAmount of the share MPTokenIssuance by \(\Delta_{share}\).
  3. If the submitter is not the vault owner and their share MPToken.MPTAmount reaches zero, delete the MPToken object.
  4. Decrease Vault.AssetsTotal and Vault.AssetsAvailable by \(\Delta_{asset}\).

  5. If Vault.Asset is XRP:

  6. Decrease the Balance field of the pseudo-account AccountRoot by \(\Delta_{asset}\).
  7. Increase the Balance field of the destination AccountRoot by \(\Delta_{asset}\).

  8. If Vault.Asset is an IOU:

  9. If the destination does not have a RippleState object for the vault asset, create one.
  10. Decrease the RippleState balance between the pseudo-account AccountRoot and the Issuer AccountRoot by \(\Delta_{asset}\).
  11. Increase the RippleState balance between the destination AccountRoot and the Issuer AccountRoot by \(\Delta_{asset}\).

  12. If Vault.Asset is an MPT:

  13. If the destination does not have an MPToken object for the vault asset, create one.
  14. Decrease the MPToken.MPTAmount of the pseudo-account MPToken for Vault.Asset by \(\Delta_{asset}\).
  15. Increase the MPToken.MPTAmount of the destination MPToken for Vault.Asset by \(\Delta_{asset}\).

Note: "destination" is the Destination field if provided, otherwise the submitting Account.

  • SingleAssetVault: The vault accounting decreases and both asset-balance moves use that same \(\Delta_{asset}\), except that an unrepresentable sub-ULP IOU remainder may remain between vault outflow and destination inflow. Where the destination is the issuer of a non-XRP Vault.Asset it holds no balance of the asset — the transfer destroys the asset at the issuer instead — so only the vault accounting fields and the vault's asset balance move. This is the issuer exception of invariant 2 below.
  • fixCleanup3_4_0: For an IOU, the persisted vault accounting deltas and the persisted asset-balance deltas may differ from each other by at most one unit at the comparison scale in XLS-65.2. For XRP and MPT they remain equal. That one unit and the sub-ULP remainder above are alternative tolerances, not cumulative: the vault-to-destination comparison is satisfied by either.
3.6.4 Invariants
    • SingleAssetVault: The vault pseudo-account's asset balance must decrease by a positive amount.
    • fixCleanup3_4_0: A fixed-share withdrawal may instead move zero assets when the pre-transaction Vault.AssetsTotal == Vault.LossUnrealized.
  1. Unless the destination is the asset issuer, the destination's asset balance must increase (within sub-ULP precision tolerance for IOU assets at a coarser trust line scale). The zero-asset exception in invariant 1 may leave the destination balance unchanged.
    • SingleAssetVault: The vault outflow and destination inflow must match in magnitude, except for an unrepresentable sub-ULP IOU remainder at the destination scale.
    • fixCleanup3_4_0: For an IOU, the comparison is also satisfied when the two magnitudes agree within one unit at the comparison scale. That tolerance and the sub-ULP remainder are alternatives, not cumulative. For XRP and MPT it remains exact.
  2. The submitter's share MPToken.MPTAmount must decrease by a positive amount.
  3. The decrease in MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount must equal the decrease in the submitter's share balance.
    • SingleAssetVault: Vault.AssetsTotal and Vault.AssetsAvailable must each decrease by the vault's asset balance decrease.
    • fixCleanup3_4_0: For an IOU, each comparison admits one unit at the comparison scale. For XRP and MPT it remains exact.
  4. LendingProtocolV1_1: A withdrawal does not succeed while the Vault phase is Investment.

3.7 Transaction: VaultClawback

The VaultClawback transaction performs a Clawback from the Vault, exchanging the shares of an account. Conceptually, the transaction performs VaultWithdraw on behalf of the Holder, sending the funds to the Issuer account of the asset. In case there are insufficient funds for the entire Amount the transaction will perform a partial Clawback, up to the Vault.AssetsAvailable. The Clawback transaction must respect any future fees or penalties.

3.7.1 Fields
Field Name Required JSON Type Internal Type Default Value Description
TransactionType Yes string UINT16 70 Transaction type (ttVAULT_CLAWBACK).
VaultID Yes string HASH256 N/A The ID of the vault from which assets are withdrawn.
Holder Yes string AccountID N/A The account ID from which to clawback the assets.
Amount No number NUMBER 0 The asset amount to clawback. When Amount is 0 clawback all funds, up to the total shares the Holder owns.
3.7.2 Failure Conditions
3.7.2.1 Data Verification

None.

3.7.2.2 Protocol-Level Failures
  1. Vault object with the VaultID does not exist on the ledger.

  2. If Vault.Asset is XRP.

  3. If Vault.Asset is an IOU and:

  4. The Issuer account is not the submitter of the transaction.
  5. If the AccountRoot(Issuer) object does not have lsfAllowTrustLineClawback flag set (the asset does not support clawback).
  6. If the AccountRoot(Issuer) has the lsfNoFreeze flag set (the asset cannot be frozen).

  7. If Vault.Asset is an MPT and:

  8. MPTokenIssuance.Issuer is not the submitter of the transaction.
  9. MPTokenIssuance.lsfMPTCanClawback flag is not set (the asset does not support clawback).
  10. If the MPTokenIssuance.lsfMPTCanLock flag is NOT set (the asset cannot be locked).

  11. The MPToken object for the Vault.ShareMPTID of the Holder AccountRoot does not exist OR MPToken.MPTAmount == 0.

  12. fixCleanup3_4_0: The clawback would burn shares while moving no assets: a non-zero \(\Delta_{asset}\) that leaves the stored Vault.AssetsTotal unchanged at its precision, or that rounds down to zero at the posterior Vault.AssetsTotal scale, as described in XLS-65.2. A clawback against an already-empty vault is unaffected, because its \(\Delta_{asset}\) is zero to begin with. (tecPRECISION_LOSS)

3.7.3 State Changes
  1. If the Vault.Asset is an IOU:
  2. Decrease the RippleState balance between the pseudo-account AccountRoot and the Issuer AccountRoot by min(Vault.AssetsAvailable, \(\Delta_{asset}\)).

  3. If the Vault.Asset is an MPT:

  4. Decrease the MPToken.MPTAmount by min(Vault.AssetsAvailable, \(\Delta_{asset}\)) of the pseudo-account MPToken object for the Vault.Asset.

  5. Update the MPToken object for the Vault.ShareMPTID of the depositor AccountRoot:

  6. Decrease the MPToken.MPTAmount by \(\Delta_{share}\).
  7. If MPToken.MPTAmount == 0, delete the object.

  8. Update the MPTokenIssuance object for the Vault.ShareMPTID:

  9. Decrease the OutstandingAmount field of the share MPTokenIssuance object by \(\Delta_{share}\).

  10. Decrease the AssetsTotal and AssetsAvailable by min(Vault.AssetsAvailable, \(\Delta_{asset}\))

  • SingleAssetVault: The vault accounting decreases and the vault asset-balance decrease use that same amount.
  • fixCleanup3_4_0: For an IOU, the persisted vault accounting deltas and the persisted vault asset-balance delta may differ from each other by at most one unit at the comparison scale in XLS-65.2. For MPT they remain equal.
3.7.4 Invariants
  1. The vault pseudo-account's asset balance must decrease, unless the Vault was already empty.
    • SingleAssetVault: Vault.AssetsTotal and Vault.AssetsAvailable must each decrease by the vault's asset balance decrease.
  2. fixCleanup3_4_0: For an IOU, each comparison admits one unit at the comparison scale. For XRP and MPT it remains exact.
  3. The holder's share MPToken.MPTAmount must decrease by a positive amount.
  4. The decrease in MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount must equal the decrease in the holder's share balance.
  5. The transaction must be submitted by the asset issuer.

3.8 Transaction: Payment

The Single Asset Vault does not introduce new Payment transaction fields. However, it adds additional failure conditions and state changes when transferring Vault shares.

3.8.1 Fields

The Single Asset Vault does not introduce or modify any Payment transaction fields. Refer to the existing Payment transaction fields.

3.8.2 Failure Conditions
3.8.2.1 Data Verification

None.

3.8.2.2 Protocol-Level Failures
  1. If Payment.Amount is a Vault share AND:
  2. The Vault lsfVaultPrivate flag is set and the Payment.Destination account is not a member of the permissioned domain specified at MPTokenIssuance(Vault.ShareMPTID).DomainID.
  3. The Vault tfVaultShareNonTransferable flag is set.

  4. If the Vault.Asset is MPT:

    1. MPTokenIssuance.lsfMPTCanTransfer is not set (the asset is not transferable).
    2. MPTokenIssuance.lsfMPTLocked flag is set (the asset is globally locked).
    3. MPToken(MPTokenIssuanceID, AccountID).lsfMPTLocked flag is set (the asset is locked for the payer).
    4. MPToken(MPTokenIssuanceID, AccountID).lsfMPTLocked flag is set (the asset is locked for the pseudo-account).
    5. MPToken(MPTokenIssuanceID, Destination).lsfMPTLocked flag is set (the asset is locked for the destination account).
  5. If the Vault.Asset is an IOU:

    1. The lsfGlobalFreeze flag is set on the issuing account (the asset is frozen).
    2. The lsfHighFreeze or lsfLowFreeze flag is set on the RippleState object between the Asset Issuer and the payer account.
    3. The lsfHighFreeze or lsfLowFreeze flag is set on the RippleState object between the Asset Issuer and the destination account.
    4. The lsfHighFreeze or lsfLowFreeze flag is set on the RippleState object between the Asset Issuer and the pseudo-account.
3.8.3 State Changes
  1. If MPTokenobject for shares does not exist for the destination account, create one.

3.9 RPC: vault_info

This RPC retrieves the Vault ledger entry and the IDs associated with it.

3.9.1 Request Fields
Field Name Required? JSON Type Description
vault Yes string The object ID of the Vault to be returned.
3.9.2 Response Fields
Field Name Always Present? JSON Type Description
vault Yes object Root object representing the vault.
vault.Account Yes string The pseudo-account ID of the vault.
vault.Asset Yes object Object representing the asset held in the vault.
vault.Asset.currency Yes string Currency code of the asset stored in the vault.
vault.Asset.issuer No string Issuer address of the asset.
vault.AssetsAvailable Yes string Amount of assets currently available for withdrawal.
vault.AssetsTotal Yes string Total amount of assets in the vault.
vault.Flags No number Bit-field flags associated with the vault.
vault.LedgerEntryType Yes string Ledger entry type, always "Vault".
vault.LossUnrealized No string Unrealized loss associated with the vault.
vault.Owner Yes string ID of the Vault Owner account.
vault.OwnerNode No string Identifier for the owner node in the ledger tree.
vault.PreviousTxnID Yes string Transaction ID of the last modification to this vault.
vault.PreviousTxnLgrSeq Yes number Ledger sequence number of the last transaction modifying this vault.
vault.Sequence Yes number Sequence number of the vault entry.
vault.ShareMPTID No string Multi-purpose token ID associated with this vault.
vault.WithdrawalPolicy No number Policy defining withdrawal conditions.
vault.index Yes string Unique index of the vault ledger entry.
vault.shares Yes object Object containing details about issued shares.
vault.shares.Flags No number Bit-field flags associated with the shares issuance.
vault.shares.Issuer Yes string The ID of the Issuer of the Share. It will always be the pseudo-account ID.
vault.shares.LedgerEntryType Yes string Ledger entry type, always "MPTokenIssuance".
vault.shares.OutstandingAmount Yes string Total outstanding shares issued.
vault.shares.OwnerNode No string Identifier for the owner node of the shares.
vault.shares.PreviousTxnID Yes string Transaction ID of the last modification to the shares issuance.
vault.shares.PreviousTxnLgrSeq Yes number Ledger sequence number of the last transaction modifying the shares issuance.
vault.shares.Sequence Yes number Sequence number of the shares issuance entry.
vault.shares.index Yes string Unique index of the shares ledger entry.
vault.shares.mpt_issuance_id No string The ID of the MPTokenIssuance object. It will always be equal to vault.ShareMPTID.
vault.Scale Yes number The Scale specifies the power of 10 (\(10^{\text{scale}}\)) to multiply an asset's value by when converting it into an integer-based number of shares.
vault.VaultKind No number LendingProtocolV1_1: Vault kind; absent means open-ended and 1 means closed-ended.
vault.SubscriptionDate No number LendingProtocolV1_1: End of Subscription and start of Investment; present only for closed-ended Vaults.
vault.RedemptionDate No number LendingProtocolV1_1: Start of Redemption; present only for closed-ended Vaults.

The standard ledger_entry RPC returns the same Vault ledger object. Under LendingProtocolV1_1, its object may therefore include VaultKind, SubscriptionDate, and RedemptionDate with the same meanings and presence rules: all three are present for a closed-ended Vault, while their collective absence means open-ended.

3.9.3 Failure Conditions

TBD

3.9.4 Example Request

TBD

3.9.5 Example Response

Vault holding an IOU:

 "result" :
 {
  "ledger_current_index" : 7,
  "status" : "success",
  "validated" : false,
  "vault" :
  {
   "Account" : "rKwvc1mgHLyHKY3yRUqVwffWtsxYb3QLWf",
   "Asset" :
   {
    "currency" : "IOU",
    "issuer" : "r9cZ5oHbdL4Z9Maj6TdnfAos35nVzYuNds"
   },
   "AssetsAvailable" : "100",
   "AssetsTotal" : "100",
   "Flags" : 0,
   "LedgerEntryType" : "Vault",
   "LossUnrealized" : "0",
   "Owner" : "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu",
   "OwnerNode" : "0",
   "PreviousTxnID" : "1484794AE38DBB7C6F4E0B7536CC560B418135BEDB0F8904349F7F8A3B496826",
   "PreviousTxnLgrSeq" : 6,
   "Sequence" : 5,
   "ShareMPTID" : "00000001C752C42A1EBD6BF2403134F7CFD2F1D835AFD26E",
   "WithdrawalPolicy" : 1,
   "index" : "2DE64CA41250EF3CB7D2B127D6CEC31F747492CAE2BD1628CA02EA1FFE7475B3",
   "shares" :
   {
    "DomainID" : "3B61A239626565A3FBEFC32863AFBF1AD3325BD1669C2C9BC92954197842B564",
    "Flags" : 0,
    "Issuer" : "rKwvc1mgHLyHKY3yRUqVwffWtsxYb3QLWf",
    "LedgerEntryType" : "MPTokenIssuance",
    "OutstandingAmount" : "100",
    "OwnerNode" : "0",
    "PreviousTxnID" : "1484794AE38DBB7C6F4E0B7536CC560B418135BEDB0F8904349F7F8A3B496826",
    "PreviousTxnLgrSeq" : 6,
    "Sequence" : 1,
    "index" : "F84AE266C348540D7134F1A683392C3B97C3EEFDE9FEF6F2055B3B92550FB44A",
    "mpt_issuance_id" : "00000001C752C42A1EBD6BF2403134F7CFD2F1D835AFD26E"
   },
   "Scale": 6,
  }
}

Vault holding an MPT:

{
  "LedgerEntryType": "Vault",
  "LedgerIndex": "E123F4567890ABCDE123F4567890ABCDEF1234567890ABCDEF1234567890ABCD",
  "Flags": "0",
  "PreviousTxnID": "9A8765B4321CDE987654321CDE987654321CDE987654321CDE987654321CDE98",
  "PreviousTxnLgrSeq": 12345678,
  "Sequence": 1,
  "OwnerNode": 2,
  "Owner": "rEXAMPLE9AbCdEfGhIjKlMnOpQrStUvWxYz",
  "Account": "rPseudoAcc1234567890abcdef1234567890abcdef",
  "Data": "5468697320697320617262697472617279206D657461646174612061626F757420746865207661756C742E",
  "Asset": {
    "currency": "USD",
    "issuer": "rIssuer1234567890abcdef1234567890abcdef",
    "value": "1000"
  },
  "AssetsTotal": 1000000,
  "AssetsAvailable": 800000,
  "LossUnrealized": 200000,
  "AssetsMaximum": 0,
  "Share": {
    "mpt_issuance_id": "0000012FFD9EE5DA93AC614B4DB94D7E0FCE415CA51BED47",
    "value": "1"
  },
  "ShareTotal": 5000,
  "WithdrawalPolicy": "0x0001",
  "Scale": 0
}

Vault holding XRP:

{
  "result": {
    "ledger_hash": "6FFF56DF92D54D01EE3D5487787F4430D66F89C6BC74B00C276262A0207B2FAD",
    "ledger_index": 6,
    "status": "success",
    "validated": true,
    "vault": {
      "Account": "rBVxExjRR6oDMWCeQYgJP7q4JBLGeLBPyv",
      "Asset": {
        "currency": "XRP"
      },
      "AssetsAvailable": "0",
      "AssetsTotal": "0",
      "Flags": 0,
      "LedgerEntryType": "Vault",
      "LossUnrealized": "0",
      "Owner": "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu",
      "OwnerNode": "0",
      "PreviousTxnID": "25C3C8BF2C9EE60DFCDA02F3919D0C4D6BF2D0A4AC9354EFDA438F2ECDDA65E4",
      "PreviousTxnLgrSeq": 5,
      "Sequence": 4,
      "ShareMPTID": "00000001732B0822A31109C996BCDD7E64E05D446E7998EE",
      "WithdrawalPolicy": 1,
      "index": "C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52",
      "shares": {
        "DomainID": "3B61A239626565A3FBEFC32863AFBF1AD3325BD1669C2C9BC92954197842B564",
        "Flags": 56,
        "Issuer": "rBVxExjRR6oDMWCeQYgJP7q4JBLGeLBPyv",
        "LedgerEntryType": "MPTokenIssuance",
        "OutstandingAmount": "0",
        "OwnerNode": "0",
        "PreviousTxnID": "25C3C8BF2C9EE60DFCDA02F3919D0C4D6BF2D0A4AC9354EFDA438F2ECDDA65E4",
        "PreviousTxnLgrSeq": 5,
        "Sequence": 1,
        "index": "4B25BDE141E248E5D585FEB6100E137D3C2475CEE62B28446391558F0BEA23B5",
        "mpt_issuance_id": "00000001732B0822A31109C996BCDD7E64E05D446E7998EE"
      },
      "Scale": 0
    }
  }
}

4.2 RPC vault_list (Clio-only)

This RPC retrieves all Vaults created for a given asset. The asset can be XRP, an IOU, or an MPT.

Given an asset, this handler scans all Vault ledger objects and returns those whose Asset field matches the request. For each matching vault found, a summary is returned containing the vault ID, pseudo-account, owner, total assets, total shares, status, and flags.

The matching strategy depends on the asset type:

  • MPT: Returns all Vault objects whose Asset.mpt_issuance_id equals the provided mpt_issuance_id.
  • IOU: Returns all Vault objects whose Asset.currency and Asset.issuer match the provided values.
  • XRP: Returns all Vault objects whose Asset.currency is "XRP".
4.2.1 Request Fields
Field Name Required? JSON Type Description
asset :heavy_check_mark: string or object The asset to search for. Supports three formats: XRP — { "currency": "XRP" }; IOU — { "currency": "<code>", "issuer": "<address>" }; MPT — { "mpt_issuance_id": "<UINT192 hex>" }.
ledger_hash string A 20-byte hex string for the ledger version to use.
ledger_index string or number The ledger index of the ledger to use, or a shortcut string to choose a ledger automatically.
limit number Limit the number of Vaults returned. Min 10, max 400, default 200.
marker string Value from a previous paginated response. Resume retrieving data where that response left off.
4.2.2 Response
Field Name Required? JSON Type Description
asset yes string or object The asset provided in the request, echoed back.
ledger_hash yes string The identifying hash of the ledger version used to generate this response.
ledger_index yes number The ledger index of the ledger version used to generate this response.
validated yes boolean If true, the information comes from a validated ledger version.
limit yes number The limit used in the request (after clamping).
marker no string Server-defined value indicating the response is paginated. Pass this to the next call to resume where this left off.
vaults yes array Array of vault summary objects.
vaults[].vault_id yes string Unique index of the Vault ledger entry (hex).
vaults[].account yes string The address of the Vault's pseudo-account.
vaults[].owner yes string The account address of the Vault Owner.
vaults[].total_assets yes string The total value of the vault (AssetsTotal).
vaults[].total_shares yes number Total outstanding shares issued (OutstandingAmount from the share MPTokenIssuance).
vaults[].status yes string Status of the vault. "active" if flags are 0, otherwise "modified".
vaults[].flags yes number Bit-field flags associated with the vault.
4.2.3 Failure Conditions
  • invalidParams: The asset field is missing, malformed, or not a valid asset object.
  • entryNotFound: The asset references a ledger object that does not exist. This applies when the asset is an MPT and the MPTokenIssuance object identified by mpt_issuance_id does not exist, or the asset is an IOU and the issuer account does not exist in the specified ledger.
  • Standard ledger selection errors apply if ledger_hash or ledger_index reference an unavailable ledger.

Note: If the specified asset is valid and exists on the ledger, but no Vaults have been created for it, the response returns an empty vaults array. This is not an error condition.

4.2.4 Example Request (MPT)
{
  "method": "vault_list",
  "params": [
    {
      "asset": {
        "mpt_issuance_id": "00000001C752C42A1EBD6BF2403134F7CFD2F1D835AFD26E"
      },
      "limit": 50
    }
  ]
}
4.2.5 Example Response (MPT)
{
  "result": {
    "asset": {
      "mpt_issuance_id": "00000001C752C42A1EBD6BF2403134F7CFD2F1D835AFD26E"
    },
    "ledger_hash": "6FFF56DF92D54D01EE3D5487787F4430D66F89C6BC74B00C276262A0207B2FAD",
    "ledger_index": 6,
    "validated": true,
    "limit": 50,
    "vaults": [
      {
        "vault_id": "2DE64CA41250EF3CB7D2B127D6CEC31F747492CAE2BD1628CA02EA1FFE7475B3",
        "account": "rKwvc1mgHLyHKY3yRUqVwffWtsxYb3QLWf",
        "owner": "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu",
        "total_assets": "100",
        "total_shares": 100,
        "status": "active",
        "flags": 0
      },
      {
        "vault_id": "C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52",
        "account": "rBVxExjRR6oDMWCeQYgJP7q4JBLGeLBPyv",
        "owner": "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu",
        "total_assets": "500",
        "total_shares": 500,
        "status": "active",
        "flags": 0
      }
    ]
  }
}
4.2.6 Example Request (IOU)
{
  "method": "vault_list",
  "params": [
    {
      "asset": {
        "currency": "USD",
        "issuer": "r9cZ5oHbdL4Z9Maj6TdnfAos35nVzYuNds"
      },
      "limit": 20
    }
  ]
}
4.2.7 Example Response (IOU)
{
  "result": {
    "asset": {
      "currency": "USD",
      "issuer": "r9cZ5oHbdL4Z9Maj6TdnfAos35nVzYuNds"
    },
    "ledger_hash": "AB12CD34EF5678901234567890ABCDEF1234567890ABCDEF1234567890ABCDEF",
    "ledger_index": 42,
    "validated": true,
    "limit": 20,
    "vaults": [
      {
        "vault_id": "A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2",
        "account": "rPqR7tSzR8v1M3K2pNqL5xW9Y4Z6A8B0CD",
        "owner": "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu",
        "total_assets": "1000.50",
        "total_shares": 1000500000,
        "status": "active",
        "flags": 0
      }
    ]
  }
}
4.2.8 Example Request (XRP)
{
  "method": "vault_list",
  "params": [
    {
      "asset": {
        "currency": "XRP"
      },
      "limit": 100
    }
  ]
}
4.2.9 Example Response (XRP)
{
  "result": {
    "asset": {
      "currency": "XRP"
    },
    "ledger_hash": "6FFF56DF92D54D01EE3D5487787F4430D66F89C6BC74B00C276262A0207B2FAD",
    "ledger_index": 6,
    "validated": true,
    "limit": 100,
    "vaults": [
      {
        "vault_id": "C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52",
        "account": "rBVxExjRR6oDMWCeQYgJP7q4JBLGeLBPyv",
        "owner": "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu",
        "total_assets": "10000000",
        "total_shares": 10000000,
        "status": "active",
        "flags": 0
      }
    ]
  }
}

4. Rationale

TBD

5. Security Considerations

Closed-ended Vaults intentionally lock depositor capital during Investment: VaultWithdraw is rejected after Subscription and before Redemption. Depositors must inspect the immutable SubscriptionDate and RedemptionDate before depositing. VaultClawback remains available throughout Investment so an issuer's compliance controls are not blocked by the depositor withdrawal gate. See XLS-65.1.4 for the full lifecycle and threat analysis.

Appendix

Appendix A: FAQ

A.1 Why does the specification allow both Withdraw and Redeem and not just one of them?

We chose this design in order to reduce the amount of off-chain math required to be implemented by XRPL users and/or developers

A.2 Why can any account that holds Vaults shares submit a VaultWithdraw transaction?

The VaultWithdraw transaction does not respect the permissioned domain rules. In other words, any account that holds the shares of the Vault can withdraw them.

The decision was made to avoid a situation where a depositor deposits assets to a private vault to then have their access revoked by invalidating their credentials, and thus loosing access to their funds.

A.3 How can a depositor transfer shares to another account?

Vault shares are a first-class assets, meaning that they can be transfered and used in other on-ledger protocols that support MPTokens. However, the payee (or the receiver) of the shares must have permissions to hold the shares and the assset that the shares represent. For example, if the shares are for a private Vault containing USDC the destination account must be in the permissioned domain of the Vault, and have permissions to hold USDC.

In addion, any compliance mechanisms applied to USDC will also apply to the share. For example, if the Issuer of USDC freezes the Trustline of the payee, then the payee will not be able to receive any shares representing USDC.

A.4 What is the difference between the VaultOwner and the pseudo-account?

XRP Ledger is an account based blockchain. That means that assets (XRP, IOU and MPT) must be held by an account. The Vault Object (or any other object, such as the AMM) cannot hold assets directly. Therefore, a pseudo-account is created that holds the assets on behalf of that object. The pseudo-account is a stand-alone account, that cannot receive funds, it cannot send transactions, it is there to only hold assets. So for example, when a depositor deposits assets into a vault, in reality this transaction moves the assets from the depositor account to the pseudo-account. Furthermore, the Vault pseudo-account is the Issuer of the Vault shares.

A.5 Do VaultDeposit or VaultWithdraw transactions charge transfer fees?

No, neither of the transactions charge transfer fees when depositing or withdrawing assets to and from the Vault.

Appendix B: Changelog