Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 36 additions & 14 deletions XLS-0065-single-asset-vault/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
category: Amendment
requires: [XLS-33](../XLS-0033-multi-purpose-tokens/README.md)
created: 2024-04-12
updated: 2025-10-13
updated: 2025-12-16
</pre>

# Single Asset Vault
Expand Down Expand Up @@ -67,9 +67,9 @@ The specification includes the following transactions:
- **`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:
Additionally, a **Clawback** operation can be performed:

- **`VaultClawback`**: Allows the issuer of an IOU or MPT to claw back funds from the vault, as outlined in the [Clawback documentation](https://xrpl.org/docs/use-cases/tokenization/stablecoin-issuer#clawback).
- **`VaultClawback`**: Allows the issuer of an IOU or MPT to claw back funds from the vault, as outlined in the [Clawback documentation](https://xrpl.org/docs/use-cases/tokenization/stablecoin-issuer#clawback). Additionally, the Vault Owner can use this transaction to force burn worthless shares when both `Vault.AssetsTotal` and `Vault.AssetsAvailable` are zero.

#### 1.1.1 Vault Ownership and Management

Expand Down Expand Up @@ -401,7 +401,6 @@ The transaction creates an `AccountRoot` object for the `_pseudo-account_`. Ther
- The `Scale` parameter is provided.

- The `Asset` is `MPT`:
- The `Scale` parameter is provided.
- The `lsfMPTCanTransfer` is not set in the `MPTokenIssuance` object. (the asset is not transferable).
- The `lsfMPTLocked` flag is set in the `MPTokenIssuance` object. (the asset is locked).

Expand Down Expand Up @@ -652,34 +651,57 @@ In sections below assume the following variables:

#### 3.3.1 `VaultClawback` Transaction

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.
The `VaultClawback` transaction performs a Clawback from the Vault, exchanging the shares of an account.

The transaction can be submitted by:

1. **Asset Issuer**: The issuer of the Vault's asset (IOU or MPT) can clawback funds from any holder's shares, sending the assets to the Issuer's account.
2. **Vault Owner**: In the rare circumstance when both `Vault.AssetsTotal` and `Vault.AssetsAvailable` are zero, the Vault Owner can force burn the shares of depositors. This situation may arise when, for example, a Loan issued for the total of Vault's assets defaults. Without this mechanism, the Vault would become permanently stuck—deposits would not be able to settle the balance, and the Vault object would be non-deletable.

Conceptually, the transaction performs `VaultWithdraw` on behalf of the `Holder`, sending the funds to the `Issuer` account of the asset (when submitted by the Issuer). 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.

| Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
| ----------------- | :----------------: | :-------: | :-----------: | :-----------: | :------------------------------------------------------------------------------------------------------------- |
| `TransactionType` | :heavy_check_mark: | `string` | `UINT16` | `63` | Transaction type. |
| `VaultID` | :heavy_check_mark: | `string` | `HASH256` | `N/A` | The ID of the vault from which assets are withdrawn. |
| `Holder` | :heavy_check_mark: | `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. |
| `Amount` | | `number` | `STAmount` | 0 | The asset amount to clawback. When Amount is `0` clawback all funds, up to the total shares the `Holder` owns. |

##### 3.3.1.1 `Amount`

The `Amount` field is an `STAmount` that specifies the quantity to clawback. The type of the `Amount` determines its interpretation and must match the expected asset type based on who submits the transaction:

##### 3.3.1.1 Failure conditions
- **Asset Issuer**: The `Amount` must be specified as the Vault's asset type (IOU or MPT). The transaction will clawback up to `Amount` of assets from the `Holder`'s shares, sending the funds to the Issuer's account.

- **Vault Owner**: The `Amount` must be specified as the Vault's share type (MPT), where `mpt_issuance_id` matches `Vault.MPTokenIssuanceID`. Since the Vault Owner can only submit this transaction when `Vault.AssetsTotal` and `Vault.AssetsAvailable` are both zero, no assets are transferred—only shares are destroyed. Partial burns are not permitted, the Vault Owner must burn all shares held by the `Holder`. The `Amount` can be specified as either:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not make it simpler by just making amount absent in this case? This would imply burning all shares assuming all other conditions are met.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I improved the documentation to reflect that the Amount can either be inferred based on who is submitting the transaction (owner or issuer), or explicitly provided.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I improved the documentation to reflect that the Amount can either be inferred based on who is submitting the transaction (owner or issuer), or explicitly provided.

IIRC, Amount needs to be explicitly specified if the owner is the issuer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's right, see from the spec:

- If the Vault Owner and Asset Issuer are the same entity, the `Amount` must be explicitly provided.

- `0` - Burns all shares held by the `Holder`.
- The exact total shares held by the `Holder` (i.e., `MPToken(Vault.MPTokenIssuanceID, Holder).MPTAmount`).

When `Amount` is `0`, the transaction will clawback/burn all funds, up to the total shares the `Holder` owns.

##### 3.3.1.2 Failure conditions

- `Vault` object with the `VaultID` does not exist on the ledger.

- If `Vault.Asset` is `XRP`.
- The submitter is neither the Asset Issuer nor the Vault Owner.

- If the submitter is the **Vault Owner**:
- `Vault.AssetsTotal != 0` OR `Vault.AssetsAvailable != 0` (Vault Owner can only burn worthless shares).
- `Amount != 0` AND `Amount != MPToken(Vault.MPTokenIssuanceID, Holder).MPTAmount` (partial burns are not allowed).

- If the submitter is the **Asset Issuer** and `Vault.Asset` is an `XRP`.

- If `Vault.Asset` is an `IOU` and:
- The `Issuer` account is not the submitter of the transaction.
- If the submitter is the **Asset Issuer** and `Vault.Asset` is an `IOU`:
- If the `AccountRoot(Issuer)` object does not have `lsfAllowTrustLineClawback` flag set (the asset does not support clawback).
- If the `AccountRoot(Issuer)` has the `lsfNoFreeze` flag set (the asset cannot be frozen).

- If `Vault.Asset` is an `MPT` and:
- `MPTokenIssuance.Issuer` is not the submitter of the transaction.
- If the submitter is the **Asset Issuer** and `Vault.Asset` is an `MPT`:
- `MPTokenIssuance.lsfMPTCanClawback` flag is not set (the asset does not support clawback).
- If the `MPTokenIssuance.lsfMPTCanLock` flag is NOT set (the asset cannot be locked).

- The `MPToken` object for the `Vault.MPTokenIssuanceID` of the `Holder` `AccountRoot` does not exist OR `MPToken.MPTAmount == 0`.

##### 3.3.1.2 State Changes
##### 3.3.1.3 State Changes

- If the `Vault.Asset` is an `IOU`:
- Decrease the `RippleState` balance between the _pseudo-account_ `AccountRoot` and the `Issuer` `AccountRoot` by `min(Vault.AssetsAvailable`, $\Delta_{asset}$`)`.
Expand All @@ -696,7 +718,7 @@ The `VaultClawback` transaction performs a Clawback from the Vault, exchanging t

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

##### 3.3.1.3 Invariants
##### 3.3.1.4 Invariants

**TBD**

Expand Down