Title: Single Asset Tokenized Vault Revision: 1 (2025-02-05)
Authors: Vytautas Vito Tumas Aanchal Malhotra Affiliation: Ripple
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. 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.
- 1. Introduction
- 2. Ledger Entries
- 3. Transactions
- 4. API
- Appendix
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.
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.
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.
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.
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.
- 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.
- Vault Owner: An account responsible for creating and deleting The Vault.
- Depositor: An entity that deposits and withdraws assets to and from 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.
The Vault
ledger entry describes the state of the tokenized vault.
The key of the Vault
object is the result of SHA512-Half
of the following values concatenated in order:
- The
Vault
space key0x0056
(capital V) - The
AccountID
(https://xrpl.org/docs/references/protocol/binary-format/#accountid-fields) of the account submitting theVaultSet
transaction, i.e.VaultOwner
. - The transaction
Sequence
number. If the transaction used a Ticket, use theTicketSequence
value.
A vault has the following fields:
Field Name | Modifiable? | Required? | JSON Type | Internal Type | Default Value | Description |
---|---|---|---|---|---|---|
LedgerEntryType |
N/A |
✔️ | string |
UINT16 |
0x0081 |
Ledger object type. |
LedgerIndex |
N/A |
✔️ | string |
UINT16 |
N/A |
Ledger object identifier. |
Flags |
Yes |
✔️ | string |
UINT32 |
0 | Ledger object flags. |
PreviousTxnID |
N/A |
✔️ | string |
HASH256 |
N/A |
Identifies the transaction ID that most recently modified this object. |
PreviousTxnLgrSeq |
N/A |
✔️ | number |
UINT32 |
N/A |
The sequence of the ledger that contains the transaction that most recently modified this object. |
Sequence |
N/A |
✔️ | number |
UINT32 |
N/A |
The transaction sequence number that created the vault. |
OwnerNode |
N/A |
✔️ | number |
UINT64 |
N/A |
Identifies the page where this item is referenced in the owner's directory. |
Owner |
No |
✔️ | string |
AccountID |
N/A |
The account address of the Vault Owner. |
Account |
N/A |
✔️ | string |
ACCOUNTID |
N/A |
The address of the Vaults pseudo-account. |
Data |
Yes |
string |
BLOB |
None | Arbitrary metadata about the Vault. Limited to 256 bytes. | |
Asset |
No |
✔️ | string or object |
ISSUE |
N/A |
The asset of the vault. The vault supports XRP , IOU and MPT . |
AssetTotal |
N/A |
✔️ | number |
NUMBER |
0 | The total value of the vault. |
AssetAvailable |
N/A |
✔️ | number |
NUMBER |
0 | The asset amount that is available in the vault. |
LossUnrealized |
N/A |
✔️ | number |
NUMBER |
0 | The potential loss amount that is not yet realized expressed as the vaults asset. |
AssetMaximum |
Yes |
number |
NUMBER |
0 | The maximum asset amount that can be held in the vault. Zero value 0 indicates there is no cap. |
|
MPTokenIssuanceID |
N/A |
✔️ | number |
UINT192 |
0 | The identifier of the share MPTokenIssuance object. |
WithdrawalPolicy |
No |
✔️ | string |
UINT8 |
N/A |
Indicates the withdrawal strategy used by the Vault. |
The Vault
object supports the following flags:
Flag Name | Flag Value | Modifiable? | Description |
---|---|---|---|
lsfVaultPrivate |
0x0001 |
No |
If set, indicates that the vault is private. |
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-64d specification for pseudo accounts. The AccountRoot
object is created when creating the Vault
object.
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
.
The Vault
object costs one reserve fee per object created:
- The
Vault
object itself. - The
MPTokenIssuance
associated with the shares of the Vault.
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.
The MPTokenIssuance
object represents the share on the ledger. It is created and deleted together with the Vault
object.
Here’s the table with the headings "Field," "Description," and "Value":
Field | Description | Value |
---|---|---|
Issuer |
The AccountID of the Vault's pseudo-account. | pseudo-account ID |
MaximumAmount |
No limit to the number of shares that can be issued. | 0xFFFFFFFFFFFFFFFF |
TransferFee |
The fee paid to transfer the shares. | 0 |
MPTokenMetadata |
Arbitrary metadata about the share MPT, in hex format. | - |
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 |
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.
The MPToken
values should be set as per the MPT
specification.
Condition | Transferable | Non-Transferable |
---|---|---|
Public Vault | No Flags | lsfMPTAuthorized |
Private Vault | lsfMPTAuthorized |
lsfMPTAuthorized |
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.
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.
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:
After the "paper loss" is cleared, the new effective exchange rate would be as follows:
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.
Variables
The following variables define the Vault balance:
-
$\Gamma_{share}$ - the total number of shares issued by the vault. -
$\Gamma_{asset}$ - the total assets in the vault, including any future yield. -
$\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. -
$\iota$ - the unrealized loss of the vault.
We compute the number of shares (
The following equations govern the updated vault composition after a successful deposit:
-
$\Gamma_{asset} = \Gamma_{asset} + \Delta_{asset}$ New balance of assets in the vault. -
$\Gamma_{share} = \Gamma_{share} + \Delta_{share}$ New share balance in the vault.
We compute the number of assets (
The following equations govern the updated vault composition after a successful redemption:
-
$\Gamma_{asset} = \Gamma_{asset} - \Delta_{asset}$ New balance of assets in the vault. -
$\Gamma_{share} = \Gamma_{share} - \Delta_{share}$ New share balance in the vault.
We compute the number of shares to burn to withdraw
The following equations govern the updated vault composition after a successful withdrawal:
-
$\Gamma_{asset} = \Gamma_{asset} - \Delta_{asset}$ New balance of assets in the vault. -
$\Gamma_{share} = \Gamma_{share} - \Delta_{share}$ New share balance in the vault.
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:
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.
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.
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.
All transactions introduced by this proposal incorporate the common transaction fields that are shared by all transactions. Standard fields are only documented in this proposal if needed because this proposal introduces new possible values for such fields.
The Vault
object is managed with VaultCreate
, VaultSet
and VaultDelete
transactions.
The VaultCreate
transaction creates a new Vault
object.
Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
---|---|---|---|---|---|
TransactionType |
✔️ | string |
Uint16 |
58 |
The transaction type. |
Flags |
✔️ | number |
Uint32 |
0 | Specifies the flags for the Vault. |
Data |
string |
Blob |
Arbitrary Vault metadata, limited to 256 bytes. | ||
Asset |
✔️ | string or object |
Issue |
N/A |
The asset (XRP , IOU or MPT ) of the Vault. |
AssetMaximum |
number |
Uint64 |
0 | The maximum asset amount that can be held in a vault. | |
MPTokenMetadata |
string |
Blob |
Arbitrary metadata about the share MPT , in hex format, limited to 1024 bytes. |
||
WithdrawalPolicy |
number |
UINT8 |
strFirstComeFirstServe |
Indicates the withdrawal strategy used by the Vault. | |
DomainID |
string |
Hash256 |
The PermissionedDomain object ID associated with the shares of this Vault. |
Flag Name | Flag Value | Description |
---|---|---|
tfVaultPrivate |
0x0001 |
Indicates that the vault is private. It can only be set during Vault creation. |
tfVaultShareNonTransferable |
0x0002 |
Indicates the vault share is non-transferable. It can only be set during Vault creation. |
The type indicates the withdrawal strategy supported by the vault. The following values are supported:
Strategy Name | Value | Description |
---|---|---|
strFirstComeFirstServe |
0x0001 |
Requests are processed on a first-come-first-serve basis. |
The transaction creates an AccountRoot
object for the _pseudo-account_
. Therefore, the transaction must destroy one incremental owner reserve amount.
-
The
Asset
isMPT
:- The
lsfMPTCanTransfer
is not set in theMPTokenIssuance
object. (the asset is not transferable). - The
lsfMPTLocked
flag is set in theMPTokenIssuance
object. (the asset is locked).
- The
-
The
Asset
is anIOU
:- The
lsfGlobalFreeze
flag is set on the issuing account (the asset is frozen).
- The
-
The
tfVaultPrivate
flag is not set and theDomainID
is provided. (The VaultOwner is attempting to create a public Vault with a PermissionedDomain) -
The
PermissionedDomain
object does not exist with the providedDomainID
. -
The
Data
field is larger than 256 bytes. -
The account submiting the transaction has insufficient
AccountRoot.Balance
for the Owner Reserve.
-
Create a new
Vault
ledger object. -
Create a new
MPTokenIssuance
ledger object for the vault shares.- If the
DomainID
is provided:MPTokenIssuance(Vault.MPTokenIssuanceID).DomainID = DomainID
(Set the Permissioned Domain ID).
- If the
-
Create a new
AccountRoot
pseudo-account object setting thePseudoOwner
toVaultID
. -
If
Vault.Asset
is anIOU
:- Create a
RippleState
object between the pseudo-accountAccountRoot
andIssuer
AccountRoot
.
- Create a
-
If
Vault.Asset
is anMPT
:- Create
MPToken
object for the pseudo-account for theAsset.MPTokenIssuance
.
- Create
TBD
The VaultSet
updates an existing Vault
ledger object.
Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
---|---|---|---|---|---|
TransactionType |
✔️ | string |
Uint16 |
59 |
The transaction type. |
VaultID |
✔️ | string |
Hash256 |
N/A |
The ID of the Vault to be modified. Must be included when updating the Vault. |
Data |
string |
Blob |
Arbitrary Vault metadata, limited to 256 bytes. | ||
AssetMaximum |
number |
Uint64 |
The maximum asset amount that can be held in a vault. The value cannot be lower than the current AssetTotal unless the value is 0 . |
||
DomainID |
string |
Hash256 |
The PermissionedDomain object ID associated with the shares of this Vault. |
Vault
object with the specifiedVaultID
does not exist on the ledger.- The submitting account is not the
Owner
of the vault. - The
Data
field is larger than 256 bytes. - If
Vault.AssetMaximum
>0
ANDAssetMaximum
> 0 AND:- The
AssetMaximum
<Vault.AssetTotal
(newAssetMaximum
cannot be lower than the currentAssetTotal
).
- The
- The
sfVaultPrivate
flag is not set and theDomainID
is provided (Vault Owner is attempting to set a PermissionedDomain to a public Vault). - The
PermissionedDomain
object does not exist with the providedDomainID
. - The transaction is attempting to modify an immutable field.
- The transaction does not specify any of the modifiable fields.
- Update mutable fields in the
Vault
ledger object. - If
DomainID
is provided:- Set
MPTokenIssuance(Vault.MPTokenIssuanceID).DomainID = DomainID
(Set the Permissioned Domain).
- Set
TBD
The VaultDelete
transaction deletes an existing vault object.
Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
---|---|---|---|---|---|
TransactionType |
✔️ | string |
Uint16 |
60 |
Transaction type. |
VaultID |
✔️ | string |
Hash256 |
N/A |
The ID of the vault to be deleted. |
Vault
object with theVaultID
does not exist on the ledger.- The submitting account is not the
Owner
of the vault. AssetTotal
,AssetAvailable
, orMPTokenIssuance(Vault.MPTokenIssuanceID).OutstandingAmount
are greater than zero.- The
OwnerDirectory
of the Vault pseudo-account contains pointers to objects other than theVault
, theMPTokenIssuance
for its shares, or anMPToken
or trust line for its asset.
- Delete the
MPTokenIssuance
object for the vault shares. - Delete the
MPToken
orRippleState
object corresponding to the vault's holding of the asset, if one exists. - Delete the
AccountRoot
object of the pseudo-account, and itsDirectoryNode
objects. - Release the Owner Reserve to the
Vault.Owner
account. - Delete the
Vault
object.
TBD
Depositors call the VaultDeposit
and VaultWithdraw
transactions to add or remove assets from the Tokenized Vault.
The VaultDeposit
transaction adds Liqudity in exchange for vault shares.
Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
---|---|---|---|---|---|
TransactionType |
✔️ | string |
UINT16 |
61 |
Transaction type. |
VaultID |
✔️ | string |
HASH256 |
N/A |
The ID of the vault to which the assets are deposited. |
Amount |
✔️ | string or object |
AMOUNT |
N/A |
Asset amount to deposit. |
-
Vault
object with theVaultID
does not exist on the ledger. -
The asset type of the vault does not match the asset type the depositor is depositing.
-
The depositor does not have sufficient funds to make a deposit.
-
Adding the
Amount
to theAssetTotal
of the vault would exceed theAssetMaximum
. -
The
Vault
lsfVaultPrivate
flag is set and theAccount
depositing the assets does not have credentials in the permissioned domain of the share. -
The
Vault.Asset
isMPT
:MPTokenIssuance.lsfMPTCanTransfer
is not set (the asset is not transferable).MPTokenIssuance.lsfMPTLocked
flag is set (the asset is globally locked).MPToken(MPTokenIssuanceID, AccountID).lsfMPTLocked
flag is set (the asset is locked for the depositor).MPToken(MPTokenIssuanceID, AccountID).MPTAmount
<Amount
(insufficient balance).
-
The
Asset
is anIOU
:- The
lsfGlobalFreeze
flag is set on the issuing account (the asset is frozen). - The
lsfHighFreeze
orlsfLowFreeze
flag is set on theRippleState
object between the AssetIssuer
and the depositor. - The
RippleState
objectBalance
<Amount
(insufficient balance).
- The
If no MPToken
object exists for the depositor, create one. For object details, see 3.4.2 MPToken
.
-
Increase the
MPTAmount
field of the shareMPToken
object of theAccount
by$\Delta_{share}$ . -
Increase the
OutstandingAmount
field of the shareMPTokenIssuance
object by$\Delta_{share}$ . -
Increase the
AssetTotal
andAssetAvailable
of theVault
byAmount
. -
If the
Vault.Asset
isXRP
:- Increase the
Balance
field of pseudo-accountAccountRoot
byAmount
. - Decrease the
Balance
field of the depositorAccountRoot
byAmount
.
- Increase the
-
If the
Vault.Asset
is anIOU
:- Increase the
RippleState
balance between the pseudo-accountAccountRoot
and theIssuer
AccountRoot
byAmount
. - Decrease the
RippleState
balance between the depositorAccountRoot
and theIssuer
AccountRoot
byAmount
.
- Increase the
-
If the
Vault.Asset
is anMPT
:- Increase the
MPToken.MPTAmount
byAmount
of the pseudo-accountMPToken
object for theVault.Asset
. - Decrease the
MPToken.MPTAmount
byAmount
of the depositorMPToken
object for theVault.Asset
.
- Increase the
TBD
The VaultWithdraw
transaction withdraws assets in exchange for the vault's shares.
Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
---|---|---|---|---|---|
TransactionType |
✔️ | string |
UINT16 |
62 |
Transaction type. |
VaultID |
✔️ | string |
HASH256 |
N/A |
The ID of the vault from which assets are withdrawn. |
Amount |
✔️ | number |
STAmount |
0 | The exact amount of Vault asset to withdraw. |
Destination |
string |
AccountID |
Empty | An account to receive the assets. It must be able to receive the asset. |
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}$ - the total assets in the vault, including any future yield. -
$\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.
-
Vault
object with theVaultID
does not exist on the ledger. -
The
Vault.Asset
isMPT
:-
MPTokenIssuance.lsfMPTCanTransfer
is not set (the asset is not transferable). -
MPTokenIssuance.lsfMPTLocked
flag is set (the asset is globally locked). -
MPToken(MPTokenIssuanceID, AccountID | Destination).lsfMPTLocked
flag is set (the asset is locked for the depositor or the destination).
-
-
The
Asset
is anIOU
:- The
lsfGlobalFreeze
flag is set on the issuing account (the asset is frozen). - The
lsfHighFreeze
orlsfLowFreeze
flag is set on theRippleState
object between the AssetIssuer
and theAccountRoot
of theAccountID
or theDestination
.
- The
-
The unit of
Amount
is not shares of the vault. -
The unit of
Amount
is not asset of the vault. -
There is insufficient liquidity in the vault to fill the request:
-
If
Amount
is the vaults share:-
MPTokenIssuance(Vault.MPTokenIssuanceID).OutstandingAmount
<Amount
(attempt to withdraw more shares than there are in total). - The shares
MPToken.MPTAmount
of theAccount
is less thanAmount
(attempt to withdraw more shares than owned). -
Vault.AssetAvailable
<$\Delta_{asset}$ (the vault has insufficient assets).
-
-
If
Amount
is the vaults asset:- The shares
MPToken.MPTAmount
of theAccount
is less than$\Delta_{share}$ (attempt to withdraw more shares than owned). -
Vault.AssetAvailable
<Amount
(the vault has insufficient assets).
- The shares
-
-
The
Destination
account is specified and it does not have permission to receive the asset.
-
If the
Vault.Asset
is XRP:- Decrease the
Balance
field of pseudo-accountAccountRoot
by$\Delta_{asset}$ . - Increase the
Balance
field of the depositorAccountRoot
by$\Delta_{asset}$ .
- Decrease the
-
If the
Vault.Asset
is anIOU
:-
If the Depositor (or Destination) account does not have a
RippleState
object for the Vaults Asset, create theRippleState
object. -
Decrease the
RippleState
balance between the pseudo-accountAccountRoot
and theIssuer
AccountRoot
by$\Delta_{asset}$ . -
Increase the
RippleState
balance between the depositorAccountRoot
and theIssuer
AccountRoot
by$\Delta_{asset}$ .
-
-
If the
Vault.Asset
is anMPT
:-
If the Depositor (or Destination) account does not have a
MPToken
object for the Vaults Asset, create theMPToken
object. -
Decrease the
MPToken.MPTAmount
by$\Delta_{asset}$ of the pseudo-accountMPToken
object for theVault.Asset
. -
Increase the
MPToken.MPTAmount
by$\Delta_{asset}$ of the depositorMPToken
object for theVault.Asset
.
-
-
Update the
MPToken
object for theVault.MPTokenIssuanceID
of the depositorAccountRoot
:- Decrease the
MPToken.MPTAmount
by$\Delta_{share}$ . - If
MPToken.MPTAmount == 0
, delete the object.
- Decrease the
-
Update the
MPTokenIssuance
object for theVault.MPTokenIssuanceID
:- Decrease the
OutstandingAmount
field of the shareMPTokenIssuance
object by$\Delta_{share}$ .
- Decrease the
-
Decrease the
AssetTotal
andAssetAvailable
by$\Delta_{asset}$
TBD
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.AssetAvailable
. The Clawback transaction must respect any future fees or penalties.
Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
---|---|---|---|---|---|
TransactionType |
✔️ | string |
UINT16 |
63 |
Transaction type. |
VaultID |
✔️ | string |
HASH256 |
N/A |
The ID of the vault from which assets are withdrawn. |
Holder |
✔️ | string |
AccountID |
N/A |
The account ID from which to clawback the assets. |
Amount |
number |
NUMBER |
0 | The asset amount to clawback. When Amount is 0 clawback all funds, up to the total shares the Holder owns. |
-
Vault
object with theVaultID
does not exist on the ledger. -
If
Vault.Asset
isXRP
. -
If
Vault.Asset
is anIOU
and:- The
Issuer
account is not the submitter of the transaction.
- The
-
If
Vault.Asset
is anMPT
and:MPTokenIssuance.Issuer
is not the submitter of the transaction.
-
The
MPToken
object for theVault.MPTokenIssuanceID
of theHolder
AccountRoot
does not exist ORMPToken.MPTAmount == 0
.
-
If the
Vault.Asset
is anIOU
:- Decrease the
RippleState
balance between the pseudo-accountAccountRoot
and theIssuer
AccountRoot
bymin(Vault.AssetAvailable
,$\Delta_{asset}$ )
.
- Decrease the
-
If the
Vault.Asset
is anMPT
:- Decrease the
MPToken.MPTAmount
bymin(Vault.AssetAvailable
,$\Delta_{asset}$ )
of the pseudo-accountMPToken
object for theVault.Asset
.
- Decrease the
-
Update the
MPToken
object for theVault.MPTokenIssuanceID
of the depositorAccountRoot
:- Decrease the
MPToken.MPTAmount
by$\Delta_{share}$ . - If
MPToken.MPTAmount == 0
, delete the object.
- Decrease the
-
Update the
MPTokenIssuance
object for theVault.MPTokenIssuanceID
:- Decrease the
OutstandingAmount
field of the shareMPTokenIssuance
object by$\Delta_{share}$ .
- Decrease the
-
Decrease the
AssetTotal
andAssetAvailable
bymin(Vault.AssetAvailable
,$\Delta_{asset}$ )
TBD
The Single Asset Vault does not introduce new Payment
transaction fields. However, it adds additional failure conditions and state changes when transfering Vault shares.
-
If
Payment.Amount
is aVault
share AND:-
The
Vault
lsfVaultPrivate
flag is set and thePayment.Destination
account does not have credentials in the permissioned domain of the Vaults Share. -
The
Vault
tfVaultShareNonTransferable
flag is set. -
The
Vault.Asset
isMPT
:MPTokenIssuance.lsfMPTCanTransfer
is not set (the asset is not transferable).MPTokenIssuance.lsfMPTLocked
flag is set (the asset is globally locked).MPToken(MPTokenIssuanceID, AccountID).lsfMPTLocked
flag is set (the asset is locked for the payer).MPToken(MPTokenIssuanceID, PseudoAccountID).lsfMPTLocked
flag is set (the asset is locked for thepseudo-account
).MPToken(MPTokenIssuanceID, Destination).lsfMPTLocked
flag is set (the asset is locked for the destination account).
-
The
Vault.Asset
is anIOU
:- The
lsfGlobalFreeze
flag is set on the issuing account (the asset is frozen). - The
lsfHighFreeze
orlsfLowFreeze
flag is set on theRippleState
object between the AssetIssuer
and the payer account. - The
lsfHighFreeze
orlsfLowFreeze
flag is set on theRippleState
object between the AssetIssuer
and the destination account. - The
lsfHighFreeze
orlsfLowFreeze
flag is set on theRippleState
object between the AssetIssuer
and thepseudo-account
.
- The
-
- If
MPToken
object for shares does not exist for the destination account, create one.
This method retrieves ledger object. In particular, it retrieves a Vault object by its ID. The specification purposefully ommits general fields. These can be found here.
We propose adding the following fields to the ledger_entry
method:
Field Name | Required? | JSON Type | Description |
---|---|---|---|
vault_id |
✔️ | string |
The object ID of the Vault to be returned. |
Field Name | Required? | JSON Type | Description |
---|---|---|---|
LedgerEntryType |
✔️ | string |
Ledger object type. |
LedgerIndex |
✔️ | string |
Ledger object identifier. |
Flags |
✔️ | string |
Ledger object flags. |
PreviousTxnID |
✔️ | string |
Identifies the transaction ID that most recently modified this object. |
PreviousTxnLgrSeq |
✔️ | number |
The sequence of the ledger that contains the transaction that most recently modified this object. |
Sequence |
✔️ | number |
The transaction sequence number that created the vault. |
OwnerNode |
✔️ | number |
Identifies the page where this item is referenced in the owner's directory. |
Owner |
✔️ | string |
The account address of the Vault Owner. |
Account |
✔️ | string |
The address of the Vaults pseudo-account. |
Data |
✔️ | string |
Arbitrary metadata about the Vault. Limited to 256 bytes. |
Asset |
✔️ | string or object |
The asset of the vault. The vault supports XRP , IOU and MPT . |
AssetTotal |
✔️ | number |
The total value of the vault. |
AssetAvailable |
✔️ | number |
The asset amount that is available in the vault. |
LossUnrealized |
✔️ | number |
The potential loss amount that is not yet realized expressed as the vaults asset. |
AssetMaximum |
✔️ | number |
The maximum asset amount that can be held in the vault. Zero value 0 indicates there is no cap. |
Share |
✔️ | object |
The MPT object of the vault share. |
WithdrawalPolicy |
✔️ | string |
Indicates the withdrawal strategy used by the Vault. |
{
"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"
},
"AssetTotal": 1000000,
"AssetAvailable": 800000,
"LossUnrealized": 200000,
"AssetMaximum": 0,
"Share": {
"mpt_issuance_id": "0000012FFD9EE5DA93AC614B4DB94D7E0FCE415CA51BED47",
"value": "1",
},
"ShareTotal": 5000,
"WithdrawalPolicy": "0x0001"
}
We chose this design in order to reduce the amount of off-chain math required to be implemented by XRPL users and/or developers
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.
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
.
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.