From bdcd2c068f34eba73eac3f6c416caee973529b72 Mon Sep 17 00:00:00 2001 From: Maria Shodunke Date: Thu, 28 Aug 2025 13:25:53 +0100 Subject: [PATCH] Move Single Asset Vault docs from opensource --- docs/_snippets/common-links.md | 9 + docs/concepts/accounts/pseudo-accounts.md | 27 ++ docs/concepts/tokens/single-asset-vault.md | 206 +++++++++++++ docs/img/single-asset-vault-img.svg | 1 + .../public-api-methods/index.md | 5 + .../public-api-methods/vault-methods/index.md | 9 + .../vault-methods/vault_info.md | 283 ++++++++++++++++++ .../ledger-data/ledger-entry-types/vault.md | 100 +++++++ .../transactions/types/vaultclawback.md | 66 ++++ .../transactions/types/vaultcreate.md | 99 ++++++ .../transactions/types/vaultdelete.md | 59 ++++ .../transactions/types/vaultdeposit.md | 95 ++++++ .../protocol/transactions/types/vaultset.md | 71 +++++ .../transactions/types/vaultwithdraw.md | 81 +++++ resources/known-amendments.md | 5 +- sidebars.yaml | 14 + 16 files changed, 1127 insertions(+), 3 deletions(-) create mode 100644 docs/concepts/accounts/pseudo-accounts.md create mode 100644 docs/concepts/tokens/single-asset-vault.md create mode 100644 docs/img/single-asset-vault-img.svg create mode 100644 docs/references/http-websocket-apis/public-api-methods/vault-methods/index.md create mode 100644 docs/references/http-websocket-apis/public-api-methods/vault-methods/vault_info.md create mode 100644 docs/references/protocol/ledger-data/ledger-entry-types/vault.md create mode 100644 docs/references/protocol/transactions/types/vaultclawback.md create mode 100644 docs/references/protocol/transactions/types/vaultcreate.md create mode 100644 docs/references/protocol/transactions/types/vaultdelete.md create mode 100644 docs/references/protocol/transactions/types/vaultdeposit.md create mode 100644 docs/references/protocol/transactions/types/vaultset.md create mode 100644 docs/references/protocol/transactions/types/vaultwithdraw.md diff --git a/docs/_snippets/common-links.md b/docs/_snippets/common-links.md index d141f30b86e..150ff7ab565 100644 --- a/docs/_snippets/common-links.md +++ b/docs/_snippets/common-links.md @@ -250,6 +250,13 @@ [UNLModify pseudo-transaction]: /docs/references/protocol/transactions/pseudo-transaction-types/unlmodify.md [UNLModify pseudo-transactions]: /docs/references/protocol/transactions/pseudo-transaction-types/unlmodify.md [UNLModify]: /docs/references/protocol/transactions/pseudo-transaction-types/unlmodify.md +[Vault entry]: /docs/references/protocol/ledger-data/ledger-entry-types/vault.md +[VaultCreate transaction]: /docs/references/protocol/transactions/types/vaultcreate.md +[VaultDelete transaction]: /docs/references/protocol/transactions/types/vaultdelete.md +[VaultDeposit transaction]: /docs/references/protocol/transactions/types/vaultdeposit.md +[VaultSet transaction]: /docs/references/protocol/transactions/types/vaultset.md +[VaultWithdraw transaction]: /docs/references/protocol/transactions/types/vaultwithdraw.md +[VaultClawback transaction]: /docs/references/protocol/transactions/types/vaultclawback.md [XChainAddAccountCreateAttestation transaction]: /docs/references/protocol/transactions/types/xchainaddaccountcreateattestation.md [XChainAddAccountCreateAttestation transactions]: /docs/references/protocol/transactions/types/xchainaddaccountcreateattestation.md [XChainAddAccountCreateAttestation]: /docs/references/protocol/transactions/types/xchainaddaccountcreateattestation.md @@ -452,5 +459,7 @@ [validator_list_sites method]: /docs/references/http-websocket-apis/admin-api-methods/status-and-debugging-methods/validator_list_sites.md [validators command]: /docs/references/http-websocket-apis/admin-api-methods/status-and-debugging-methods/validators.md [validators method]: /docs/references/http-websocket-apis/admin-api-methods/status-and-debugging-methods/validators.md +[vault_info command]: /docs/references/http-websocket-apis/public-api-methods/vault-methods/vault_info.md +[vault_info method]: /docs/references/http-websocket-apis/public-api-methods/vault-methods/vault_info.md [wallet_propose command]: /docs/references/http-websocket-apis/admin-api-methods/key-generation-methods/wallet_propose.md [wallet_propose method]: /docs/references/http-websocket-apis/admin-api-methods/key-generation-methods/wallet_propose.md diff --git a/docs/concepts/accounts/pseudo-accounts.md b/docs/concepts/accounts/pseudo-accounts.md new file mode 100644 index 00000000000..25c4ae813d8 --- /dev/null +++ b/docs/concepts/accounts/pseudo-accounts.md @@ -0,0 +1,27 @@ +--- +seo: + description: A pseudo-account is a special type of XRPL account that holds assets on behalf of an on-chain protocol. +labels: + - Single Asset Vault +status: not_enabled +--- + +# Pseudo-Accounts + +The XRP Ledger is an account-based blockchain where assets like XRP, Fungible Tokens, and Multi-Purpose Tokens (MPTs) are held by accounts, and are represented on-chain by an [AccountRoot](https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/accountroot) ledger entry. However, certain use cases require assets to be transferable to and from an object, which is why a pseudo-account is needed. + +A pseudo-account is a special type of account that holds assets on behalf of an on-chain protocol, and is used in the following use cases: + +- **Automated Market Makers (AMM)**: The [XLS-30 amendment](https://xrpl.org/resources/known-amendments#amm) introduced pseudo-accounts for AMMs by adding the `AMMID` field to the `AccountRoot` ledger entry. This field links a pseudo-account to an AMM instance, allowing it to track XRP and token balances in the pool and issue `LPTokens` on behalf of the AMM instance. + +- **Single Asset Vaults**: A single asset vault pseudo-account is used to store deposited funds and issue MPT shares. A new `VaultID` field is introduced in the `AccountRoot` ledger entry, which links the pseudo-account with the vault. + +- **Lending Protocol**: While still in development, this protocol is expected to use pseudo-accounts to hold loan funds. + +A pseudo-account has strict limitations. It cannot receive payments from other accounts, cannot send transactions since it has no signing authority, and exists solely to store or issue assets. + +## Transaction Cost + +A transaction that creates a pseudo-account incurs a higher than usual [transaction cost](https://xrpl.org/docs/concepts/transactions/transaction-cost) to deter ledger spam. Instead of the standard minimum of 0.00001 XRP, the transaction must destroy an [incremental owner reserve](https://xrpl.org/docs/concepts/accounts/reserves#base-reserve-and-owner-reserve), currently 0.2 XRP. + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/concepts/tokens/single-asset-vault.md b/docs/concepts/tokens/single-asset-vault.md new file mode 100644 index 00000000000..e932c3a5090 --- /dev/null +++ b/docs/concepts/tokens/single-asset-vault.md @@ -0,0 +1,206 @@ +--- +seo: + description: A single asset vault aggregates assets from multiple depositors and makes them available to other on-chain protocols. +labels: + - Single Asset Vault +status: not_enabled +--- + +# Single Asset Vault + +A single asset vault is an XRP Ledger primitive that aggregates assets from multiple depositors and makes them available to other on-chain protocols, such as the Lending Protocol (currently in development). A vault asset can be [XRP](../../introduction/what-is-xrp.md), a [Fungible Token](../tokens/fungible-tokens/index.md), or an [MPT (Multi-Purpose Token)](../tokens/fungible-tokens/multi-purpose-tokens.md). + +A Vault Owner account manages the vault and can create, update, or delete it as needed. When creating a vault, the Vault Owner can also specify whether shares are transferable or non-transferable. Non-transferable shares cannot be transferred to any other account, and can only be redeemed. + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%}.)_ + +## Public vs. Private Vaults + +A vault can be **public** or **private**, depending on the required level of access control. + +In a public vault, anyone can deposit or redeem liquidity as long as they hold sufficient shares. In contrast, a private vault restricts access, allowing only depositors with the necessary [Credentials](../../concepts/decentralized-storage/credentials.md), managed through [Permissioned Domains](../../concepts/tokens/decentralized-exchange/permissioned-domains.md), to deposit assets. + +{% admonition type="warning" name="Warning" %} +If a depositor's credentials expire, they can no longer deposit assets in a private vault, but can always redeem their existing shares. +{% /admonition %} + +To prevent the Vault Owner from locking funds away, any shareholder in a private vault can redeem their shares for assets. + +Choosing between a public or private vault depends on your use case. For example, if depositor identity verification is required, use a private vault and issue credentials only to verified accounts. + +## Vault Share Distribution and Redemption + +Depositors can deposit assets to receive shares, which represent their proportional ownership of the vault, or redeem shares for assets. + +[{% inline-svg file="../../img/single-asset-vault-img.svg" /%}](../../img/single-asset-vault-img.svg "Diagram: an example of an asset being deposited into the vault and shares being redeemed.") + +Since the XRP Ledger is an account-based blockchain, all assets must be held by an account. A `Vault` ledger entry cannot hold assets directly, so a [pseudo-account](../accounts/pseudo-accounts.md) is created to hold assets on its behalf. This stand-alone account cannot receive funds or send transactions, and exists solely to store assets and issue shares. + +Each share is represented on-chain as an MPT, issued by the vault's pseudo-account. + +Depending on the connected protocol, vault shares may be yield-bearing, meaning shareholders could redeem shares for more or less liquidity than they originally deposited. This is because the total asset balance in the vault can grow or shrink over time, affecting the value of each share. However, the vault asset (e.g., USDC or XRP) does not generate yield on its own. + +The value of each share depends on the total assets in the vault: + +- If the vault earns yield over time, shares represent a larger claim, allowing depositors to redeem them for more assets. +- If the vault incurs losses, shares hold less value, resulting in lower redemptions. + +A vault could generate yield through mechanisms like lending or staking, with yield paid in the same asset deposited. The specific logic for this depends on how the connected on-chain protocol generates yield. For example, if a vault is used by a lending protocol, it could earn yield from interest paid by borrowers. + +### Exchange Algorithm + +A single asset vault uses an **exchange algorithm** to define how assets convert into shares during deposits and how shares convert back into assets during redemptions. + +A vault's total value can fluctuate due to factors like _unrealized losses_, which impact the exchange rate for deposits and redemptions. To ensure fairness, the algorithm adjusts the exchange rate dynamically, so depositors receive shares or redeem them for assets at a rate that accurately reflects the vault’s true value. + +#### Unrealized Loss + +To prevent depositors from exploiting potential losses by redeeming shares early and shifting the full loss onto the remaining depositors, the vault tracks unrealized losses (or paper loss) using the `LossUnrealized` attribute in the `Vault` ledger entry. + +Because the unrealized loss temporarily decreases the vault's value, a malicious depositor may take advantage of this by depositing assets at a lowered price and redeeming shares once the price increases. + +For example, consider a vault with a total value of $1.0m and total shares of $1.0m. Let's assume the unrealized loss for the vault is $900k: + +1. The new exchange rate is calculated as: + + ```js + // ExchangeRate = (AssetsTotal - LossUnrealized) / SharesTotal + exchangeRate = (1,000,000 - 900,000) / 1,000,000 + ``` + + The exchange rate value is now **0.1**. + +2. After the unrealized loss is cleared, the new effective exchange rate would be: + + ```js + // ExchangeRate = AssetsTotal / SharesTotal + exchangeRate = 1,000,000 / 1,000,000 + ``` + + The exchange rate is now **1.0**. + +A depositor could deposit $100k assets at a 0.1 exchange rate and get 1.0m shares. Once the unrealized loss is cleared, their shares would be worth $1.0m. + +To mitigate this, the vault uses separate exchange rates for deposits and redemptions. + +#### Exchange Rates + +A single asset vault uses **two distinct exchange rates**: + +- **Deposit Exchange Rate**: When a depositor adds assets to the vault, they receive shares based on the current exchange rate. This ensures that new deposits do not unfairly impact the value of existing shares. + +- **Withdrawal Exchange Rate**: When shares are redeemed, the vault ensures that unrealized losses are accounted for, so depositors cannot withdraw more than the vault’s true asset value. + - **Redemptions**: If a depositor redeems a specific number of shares, the vault calculates the asset amount based on the ratio of _total assets_ to _total shares_, adjusted for unrealized losses. + - **Withdrawals**: If a depositor requests a specific asset amount, the vault determines how many shares must be _burned_ to fulfill the request, ensuring that unrealized losses are accounted for in the calculation. + +These exchange rates ensure fairness and prevent manipulation, maintaining the integrity of deposits and redemptions. + +To understand how the exchange rates are applied, here are the key variables used in the calculations: + +- `T_share`: The total number of shares issued by the vault. +- `T_asset`: The total assets in the vault, including any future yield. +- `Δ_asset`: The change in the total amount of assets after a deposit, withdrawal, or redemption. +- `Δ_share`: The change in the total amount of shares after a deposit, withdrawal, or redemption. +- `l`: The unrealized loss of the vault. + +{% tabs %} + {% tab label="Deposit" %} + The vault computes the number of shares a depositor will receive as follows: + + ```js + Δ_share = Δ_asset * (T_share / T_asset) + ``` + + After a successful deposit, the _total asset_ and _total share_ values are updated like so: + + ```js + T_asset = T_asset + Δ_asset // New balance of assets in the vault. + T_share = T_share + Δ_share // New share balance in the vault. + ``` + {% /tab %} + + {% tab label="Redeem" %} + The vault computes the number of assets returned by burning shares as follows: + + ```js + Δ_asset = Δ_share * ((T_asset - l) / T_share) + ``` + + After a successful redemption, the _total asset_ and _total share_ values are updated like so: + + ```js + T_asset = T_asset - Δ_asset // New balance of assets in the vault. + T_share = T_share - Δ_share // New share balance in the vault. + ``` + + {% /tab %} + + {% tab label="Withdraw" %} + The vault computes the number of shares to burn for a withdrawal as follows: + + ```js + Δ_share = Δ_asset * (T_share / (T_asset - l)) + ``` + + After a successful withdrawal, the _total asset_ and _total share_ values are updated like so: + + ```js + T_asset = T_asset - Δ_asset // New balance of assets in the vault. + T_share = T_share - Δ_share // New share balance in the vault. + ``` + {% /tab %} +{% /tabs %} + +### Can a Depositor Transfer Shares to Another Account? + +Vault shares are a first-class asset, meaning that they can be transferred and used in other on-ledger protocols that support MPTs. However, the payee (or the receiver) must have permission to hold both the shares and the underlying asset. + +For example, if a private vault holds USDC, the destination account must belong to the vault’s Permissioned Domain and have permission to hold USDC. Any compliance mechanisms applied to USDC also apply to the shares. If the USDC issuer freezes the payee’s trust line, the payee cannot receive shares representing USDC. + +It is important to remember that a vault must be configured to allow share transfers, or this will not be possible. + +A depositor can transfer vault shares to another account by making a [payment](../../references/protocol/transactions/types/payment) transaction. Nothing changes in the way the payment transaction is submitted for transferring vault shares. However, there are new failure scenarios to watch out for if the transaction fails: + +- The trust line or MPT is frozen between the payer and the issuer. +- There is a global freeze or lock. +- The vault pseudo-account is frozen. +- The underlying asset is an MPT and is locked for the payer, destination, or vault pseudo-account. +- The underlying asset is a Fungible Token and the trust line is frozen between the issuer and the payer, destination, or vault pseudo-account. + +If the transfer succeeds and the payee already holds vault shares, their balance increases. Otherwise, a new MPT entry is created for their account. + +## Frozen Assets + +When the asset of a vault is frozen, its corresponding shares also cannot be transferred. + +The issuer of a vault asset can enact a freeze either through a [global freeze](../../tutorials/how-tos/use-tokens/enact-global-freeze#enact-global-freeze) for fungible tokens or by [locking MPTs](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0033-multi-purpose-tokens#21122-flags). When a vault asset is frozen: + +1. Withdrawals can only be made to the asset’s issuer. +2. Frozen assets cannot be deposited into the vault. +3. Its corresponding shares also cannot be transferred. + +## Why Use a Single Asset Vault? + +With a single asset vault you don't have to manage liquidity at the protocol level. Instead, you can use the vault to handle deposits, redemptions, and asset tracking separately. + +Vaults handle asset-to-share conversion, ensure accurate pricing, and eliminate the need to add custom logic to calculate exchange rates or account for unrealized losses. + +Depending on the connected on-chain protocol, vaults can be applied to various use cases, such as: + +- Lending markets +- Aggregators +- Yield-bearing tokens +- Asset management + +The only supported use cases right now are _asset management_ and _lending markets_, with lending currently in development through the [XLS-66d: Lending Protocol](https://github.com/XRPLF/XRPL-Standards/discussions/190). + +{% raw-partial file="/docs/_snippets/common-links.md" /%} + +## See Also + +- **Concepts:** + - [Pseudo-Accounts](../accounts/pseudo-accounts.md) - Special accounts that hold assets on behalf of on-chain protocols. + - [Permissioned Domains](../tokens/decentralized-exchange/permissioned-domains.md) - Manage access control for private vaults. + +- **References:** + - [Vault ledger entry](https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/vault) - Data structure on the ledger that records vault information. diff --git a/docs/img/single-asset-vault-img.svg b/docs/img/single-asset-vault-img.svg new file mode 100644 index 00000000000..79e49b7d832 --- /dev/null +++ b/docs/img/single-asset-vault-img.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/references/http-websocket-apis/public-api-methods/index.md b/docs/references/http-websocket-apis/public-api-methods/index.md index b9e58c35637..a13f0bee2fe 100644 --- a/docs/references/http-websocket-apis/public-api-methods/index.md +++ b/docs/references/http-websocket-apis/public-api-methods/index.md @@ -113,6 +113,11 @@ Use these methods to perform convenient tasks, such as ping and random number ge * **[`ping`](utility-methods/ping.md)** - Confirm connectivity with the server. * **[`random`](utility-methods/random.md)** - Generate a random number. +## [Vault Methods](vault-methods/index.md) + +Use these methods to retrieve vault information. + +* **[`vault_info`](vault-methods/vault_info.md)** - Get information about a specific vault. ## Deprecated Methods diff --git a/docs/references/http-websocket-apis/public-api-methods/vault-methods/index.md b/docs/references/http-websocket-apis/public-api-methods/vault-methods/index.md new file mode 100644 index 00000000000..d4127dd78c7 --- /dev/null +++ b/docs/references/http-websocket-apis/public-api-methods/vault-methods/index.md @@ -0,0 +1,9 @@ +--- +metadata: + indexPage: true +--- +# Vault Methods + +A vault object in the XRP Ledger represents defines the state of a tokenized vault. Use these methods to work with vault info. + +{% child-pages /%} diff --git a/docs/references/http-websocket-apis/public-api-methods/vault-methods/vault_info.md b/docs/references/http-websocket-apis/public-api-methods/vault-methods/vault_info.md new file mode 100644 index 00000000000..384b8bd79c0 --- /dev/null +++ b/docs/references/http-websocket-apis/public-api-methods/vault-methods/vault_info.md @@ -0,0 +1,283 @@ +--- +seo: + description: Retrieve information about a specific vault in the XRP Ledger. +labels: + - Single Asset Vault +--- + +# vault_info + +[[Source]](https://github.com/XRPLF/rippled/blob/develop/src/xrpld/rpc/handlers/VaultInfo.cpp "Source")
+ +The `vault_info` command retrieves information about a vault, its owner, available assets, and details on issued shares. All information retrieved is relative to a particular version of the ledger. + + + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%})_ + +## Request Format + +An example of the request format: + +{% tabs %} + +{% tab label="WebSocket" %} +```json +{ + "command": "vault_info", + "vault_id": "C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52" +} +``` +{% /tab %} + +{% tab label="JSON-RPC" %} +```json +{ + "method": "vault_info", + "params": [ + { + "vault_id": "C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52" + } + ] +} +``` +{% /tab %} + +{% tab label="Commandline" %} +```sh +#Syntax: vault_info [] +rippled vault_info C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52 +``` +{% /tab %} + +{% /tabs %} + + + + +The request includes the following parameters: + +| `Field` | Type | Description | +| :--------- | :----- | :----------------------------------------- | +| `vault_id` | String | The object ID of the Vault to be returned. | +| `owner` | String | The account address of the Vault Owner. | +| `seq` | Number | The transaction sequence number that created the vault. | + +You can provide either the `vault_id`, or both `owner` and `seq` values in the request. + +## Response Format + +An example of a successful response: + +{% tabs %} + +{% tab label="WebSocket" %} +```json +{ + "result": { + "ledger_hash": "31E9E3738E9A07219E49BC7B71E2CD9490AC3CDFB6CB2FD4F173FB8AE1619B34", + "ledger_index": 11, + "validated": true, + "vault": { + "Account": "rhXGX3ecZ8Gqxj9cCZBnJHzcoHfzMJijtV", + "Asset": { + "mpt_issuance_id": "000000065E7AE0F677CFC3478DD710CD900EE92B99AB5B7A" + }, + "AssetsAvailable": "0", + "AssetsTotal": "0", + "Flags": 0, + "LedgerEntryType": "Vault", + "LossUnrealized": "0", + "Owner": "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu", + "OwnerNode": "0", + "PreviousTxnID": "B1F81724FA751966AC1B6A257815D8135F608A74A75C6ED3E29C3E9F5D8DB2D7", + "PreviousTxnLgrSeq": 10, + "Sequence": 4, + "ShareMPTID": "0000000126A1CFADAB543B2A1D81D2ACC22FBEC14231F81D", + "WithdrawalPolicy": 1, + "index": "C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52", + "shares": { + "DomainID": "3B61A239626565A3FBEFC32863AFBF1AD3325BD1669C2C9BC92954197842B564", + "Flags": 56, + "Issuer": "rhXGX3ecZ8Gqxj9cCZBnJHzcoHfzMJijtV", + "LedgerEntryType": "MPTokenIssuance", + "OutstandingAmount": "0", + "OwnerNode": "0", + "PreviousTxnID": "B1F81724FA751966AC1B6A257815D8135F608A74A75C6ED3E29C3E9F5D8DB2D7", + "PreviousTxnLgrSeq": 10, + "Sequence": 1, + "index": "5D316FC6A8C5D2344F5A85E256DCBF06A9596C79B2F450ED7BF4E7E8442F8668", + "mpt_issuance_id": "0000000126A1CFADAB543B2A1D81D2ACC22FBEC14231F81D" + } + } + }, + "status": "success", + "type": "response" +} +``` +{% /tab %} + +{% tab label="JSON-RPC" %} +```json +200 OK + +{ + "result": { + "ledger_hash": "31E9E3738E9A07219E49BC7B71E2CD9490AC3CDFB6CB2FD4F173FB8AE1619B34", + "ledger_index": 11, + "validated": true, + "vault": { + "Account": "rhXGX3ecZ8Gqxj9cCZBnJHzcoHfzMJijtV", + "Asset": { + "mpt_issuance_id": "000000065E7AE0F677CFC3478DD710CD900EE92B99AB5B7A" + }, + "AssetsAvailable": "0", + "AssetsTotal": "0", + "Flags": 0, + "LedgerEntryType": "Vault", + "LossUnrealized": "0", + "Owner": "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu", + "OwnerNode": "0", + "PreviousTxnID": "B1F81724FA751966AC1B6A257815D8135F608A74A75C6ED3E29C3E9F5D8DB2D7", + "PreviousTxnLgrSeq": 10, + "Sequence": 4, + "ShareMPTID": "0000000126A1CFADAB543B2A1D81D2ACC22FBEC14231F81D", + "WithdrawalPolicy": 1, + "index": "C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52", + "shares": { + "DomainID": "3B61A239626565A3FBEFC32863AFBF1AD3325BD1669C2C9BC92954197842B564", + "Flags": 56, + "Issuer": "rhXGX3ecZ8Gqxj9cCZBnJHzcoHfzMJijtV", + "LedgerEntryType": "MPTokenIssuance", + "OutstandingAmount": "0", + "OwnerNode": "0", + "PreviousTxnID": "B1F81724FA751966AC1B6A257815D8135F608A74A75C6ED3E29C3E9F5D8DB2D7", + "PreviousTxnLgrSeq": 10, + "Sequence": 1, + "index": "5D316FC6A8C5D2344F5A85E256DCBF06A9596C79B2F450ED7BF4E7E8442F8668", + "mpt_issuance_id": "0000000126A1CFADAB543B2A1D81D2ACC22FBEC14231F81D" + } + } + }, + "status": "success" +} +``` +{% /tab %} + +{% tab label="Commandline" %} +```json +Loading: "/etc/rippled.cfg" +Connecting to 127.0.0.1:5005 + +{ + "result": { + "ledger_hash": "31E9E3738E9A07219E49BC7B71E2CD9490AC3CDFB6CB2FD4F173FB8AE1619B34", + "ledger_index": 11, + "validated": true, + "vault": { + "Account": "rhXGX3ecZ8Gqxj9cCZBnJHzcoHfzMJijtV", + "Asset": { + "mpt_issuance_id": "000000065E7AE0F677CFC3478DD710CD900EE92B99AB5B7A" + }, + "AssetsAvailable": "0", + "AssetsTotal": "0", + "Flags": 0, + "LedgerEntryType": "Vault", + "LossUnrealized": "0", + "Owner": "rwhaYGnJMexktjhxAKzRwoCcQ2g6hvBDWu", + "OwnerNode": "0", + "PreviousTxnID": "B1F81724FA751966AC1B6A257815D8135F608A74A75C6ED3E29C3E9F5D8DB2D7", + "PreviousTxnLgrSeq": 10, + "Sequence": 4, + "ShareMPTID": "0000000126A1CFADAB543B2A1D81D2ACC22FBEC14231F81D", + "WithdrawalPolicy": 1, + "index": "C043BB1B350FFC5FED21E40535609D3D95BC0E3CE252E2F69F85BE0157020A52", + "shares": { + "DomainID": "3B61A239626565A3FBEFC32863AFBF1AD3325BD1669C2C9BC92954197842B564", + "Flags": 56, + "Issuer": "rhXGX3ecZ8Gqxj9cCZBnJHzcoHfzMJijtV", + "LedgerEntryType": "MPTokenIssuance", + "OutstandingAmount": "0", + "OwnerNode": "0", + "PreviousTxnID": "B1F81724FA751966AC1B6A257815D8135F608A74A75C6ED3E29C3E9F5D8DB2D7", + "PreviousTxnLgrSeq": 10, + "Sequence": 1, + "index": "5D316FC6A8C5D2344F5A85E256DCBF06A9596C79B2F450ED7BF4E7E8442F8668", + "mpt_issuance_id": "0000000126A1CFADAB543B2A1D81D2ACC22FBEC14231F81D" + } + } + }, + "status": "success" +} +``` +{% /tab %} + +{% /tabs %} + +The response follows the [standard format][], with a successful result containing following fields: + +| `Field` | Type | Description | +| :--------------------- | :--------------- | :---------- | +| `ledger_hash` | [Hash][] | _(Omitted if `ledger_current_index` is provided instead)_ The identifying hash of the ledger version that was used when retrieving this data. | +| `ledger_current_index` | [Ledger Index][] | _(Omitted if `ledger_index` is provided instead)_ The [ledger index][] of the current in-progress ledger, which was used when retrieving this information. | +| `ledger_index` | [Ledger Index][] | _(Omitted if `ledger_current_index` is provided instead)_ The [ledger index][] of the ledger version used when retrieving this information. | +| `validated` | Boolean | True if this data is from a validated ledger version; if omitted or set to false, this data is not final. | +| `vault` | Object | The [**Vault Description Object**](#vault-description-object) that represents the current status of the vault. | + +### Vault Description Object + +The `vault` field is an object describing the current status of a Vault entry in the ledger, and contains the following fields: + +| `Field` | Type | Description | +| :--------------------- | :------------------- | :---------- | +| `Account` | String - [Address][] | The address of the vault's pseudo-account. | +| `Asset` | Object | The [Asset](#asset-object) of the vault. An asset can be XRP, a Fungible Token, or an MPT. | +| `AssetsAvailable` | Number | The asset amount that is available in the vault. | +| `AssetsMaximum` | Number | The maximum asset amount that can be held in the vault. If set to 0, this indicates there is no cap. | +| `AssetsTotal` | Number | The total value of the vault. | +| `Flags` | String | Set of bit-flags for this ledger object. | +| `LossUnrealized` | Number | The potential loss amount that is not yet realized, expressed as the vault's asset. | +| `ShareMPTID` | String | The identifier of the share `MPTokenIssuance` object. | +| `WithdrawalPolicy` | String | Indicates the withdrawal strategy used by the vault. | +| `index` | String | The unique index of the vault ledger entry. | +| `shares` | Object | A [**Shares Object**](#shares-object) containing details about the vault's issued shares. | + +### Asset Object + +The `asset` object contains the following nested fields: + +| `Field` | Type | Description | +| :--------------------- | :------------------- | :---------- | +| `currency` | String | _(Omitted if the asset is an MPT)_ The currency code of the asset stored in the vault. | +| `issuer` | String - [Address][] | _(Omitted if the asset is XRP or an MPT)_ The address of the asset issuer. | +| `mpt_issuance_id` | String | _(Omitted if the asset is XRP or a Fungible Token)_ The identifier of the asset's `MPTokenIssuance` object. | + +### Shares Object + +The `shares` object contains the following nested fields: + +| `Field` | Type | Description | +| :--------------------- | :--------------- | :---------- | +| `DomainID` | String | _(Omitted if the vault is public)_ The permissioned domain associated with the vault's shares. | +| `Flags` | Number | Set of bit-flags for this ledger object. | +| `Issuer` | String | The address issuing the shares. This is always the vault's pseudo-account. | +| `LedgerEntryType` | String | The ledger object type (i.e., `MPTokenIssuance`). | +| `OutstandingAmount` | String | The total outstanding shares issued. | +| `OwnerNode` | String | Identifies the page where this item is referenced in the owner's directory. | +| `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 shares. | +| `index` | String | The unique index of the shares ledger entry. | +| `mpt_issuance_id` | String | The identifier of the `MPTokenIssuance` object. This is always equal to the vault's `ShareMPTID`. | + +## Possible Errors + +- Any of the [universal error types][]. +- `invalidParams` - One or more fields are specified incorrectly, or one or more required fields are missing. + +## See Also + +- [Vault entry][] + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/ledger-data/ledger-entry-types/vault.md b/docs/references/protocol/ledger-data/ledger-entry-types/vault.md new file mode 100644 index 00000000000..ab8abe92a9d --- /dev/null +++ b/docs/references/protocol/ledger-data/ledger-entry-types/vault.md @@ -0,0 +1,100 @@ +--- +seo: + description: A Vault object defines the state of a tokenized vault. +labels: + - Vault + - Single Asset Vault +--- + +# Vault + +[[Source]](https://github.com/XRPLF/rippled/blob/develop/include/xrpl/protocol/detail/ledger_entries.macro#L484-L504 "Source" ) + +A {% code-page-name /%} object defines the state of a tokenized vault. It contains key details such as available assets, shares, total value, and other relevant information. You can create a {% code-page-name /%} object with the [VaultCreate](./transactions/vaultcreate.md) transaction. + +The {% code-page-name /%} object is tracked in an [Owner Directory](https://xrpl.org/directorynode.html) owned by the Vault Owner account. +Additionally, to facilitate `Vault` object lookup, the object is tracked in the owner directory of the vault's [pseudo-account](../concepts/pseudo-account.md). + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%})_ + +## Example Vault JSON + +```json +{ + "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", + }, + "AssetsTotal": 1000000, + "AssetsAvailable": 800000, + "LossUnrealized": 200000, + "AssetsMaximum": 0, + "WithdrawalPolicy": "1" +} +``` + +## {% $frontmatter.seo.title %} Fields + +In addition to the [common ledger entry fields](https://xrpl.org/docs/references/protocol/ledger-data/common-fields), {% code-page-name /%} entries have the following fields: + +| Name | JSON Type | Internal Type | Required? | Description | +| :------------------ | :------------ | :------------ | :-------- | -----------------| +| `LedgerEntryType` | String | UInt16 | Yes | Ledger object type. The default value is `0x0081`. | +| `LedgerIndex` | String | UInt16 | Yes | The unique identifier of the ledger object. | +| `Flags` | String | UInt32 | Yes | Set of bit-flags for this ledger object. | +| `PreviousTxnID` | String | Hash256 | Yes | Identifies the transaction ID that most recently modified this object. | +| `PreviousTxnLgrSeq` | Number | UInt32 | Yes | The sequence of the ledger that contains the transaction that most recently modified this object. | +| `Sequence` | Number | UInt32 | Yes | The transaction sequence number that created the vault. | +| `OwnerNode` | Number | UInt64 | Yes | Identifies the page where this item is referenced in the owner's directory. | +| `Owner` | String | AccountID | Yes | The account address of the Vault Owner. | +| `Account` | String | AccountID | Yes | The address of the vault's pseudo-account. | +| `Data` | String | Blob | No | Arbitrary metadata about the vault. Limited to 256 bytes. | +| `Asset` | Object | Issue | Yes | The asset of the vault. The vault supports XRP, Fungible Tokens, and MPTs. | +| `AssetsTotal` | Number | Number | Yes | The total value of the vault. | +| `AssetsAvailable` | Number | Number | Yes | The asset amount that is available in the vault. | +| `AssetsMaximum` | Number | Number | No | The maximum asset amount that can be held in the vault. If set to 0, this indicates there is no cap. | +| `LossUnrealized` | Number | Number | Yes | The potential loss amount that is not yet realized, expressed as the vault's asset. Only a protocol connected to the vault can modify this attribute. | +| `MPTokenIssuanceID` | String | UInt192 | Yes | The identifier of the share `MPTokenIssuance` object. | +| `WithdrawalPolicy` | String | UInt8 | Yes | Indicates the withdrawal strategy used by the vault. | + + +## {% $frontmatter.seo.title %} Flags + +{% code-page-name /%} entries can have the following flags: + +| Flag Name | Flag Value | Description | +| :---------------- | :----------- | :---------------------------| +| `lsfVaultPrivate` | `0x00010000` | If set, indicates that the vault is private. This flag can only be set when _creating_ the vault. | + +## Vault ID Format + +The ID of a {% code-page-name /%} entry is the [`SHA512-Half`](https://xrpl.org/docs/references/protocol/data-types/basic-data-types#hashes) of the following values, concatenated in order: + +- The {% code-page-name /%} space key `0x0056` (capital V). +- The [AccountID](https://xrpl.org/docs/references/protocol/binary-format/#accountid-fields) of the account submitting the `VaultSet` transaction (i.e., `VaultOwner`). +- The transaction `Sequence` number. If the transaction used a [Ticket](https://xrpl.org/docs/concepts/accounts/tickets), use the `TicketSequence` value. + +## See Also + +**API Methods**: + - [vault_info method][] + +**Transactions**: + - [VaultCreate transaction][] + - [VaultDelete transaction][] + - [VaultDeposit transaction][] + - [VaultSet transaction][] + - [VaultWithdraw transaction][] + - [VaultClawback transaction][] + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/transactions/types/vaultclawback.md b/docs/references/protocol/transactions/types/vaultclawback.md new file mode 100644 index 00000000000..c2179988fa1 --- /dev/null +++ b/docs/references/protocol/transactions/types/vaultclawback.md @@ -0,0 +1,66 @@ +--- +seo: + description: Allows the issuer of a Fungible Token or MPT to claw back funds from the vault. +labels: + - Transactions + - Single Asset Vault +--- + +# VaultClawback + +[[Source]](https://github.com/Bronek/rippled/blob/vault/src/xrpld/app/tx/detail/VaultClawback.cpp "Source") + +Performs a [Clawback](https://xrpl.org/docs/use-cases/tokenization/stablecoin-issuer#clawback) from the vault, exchanging the shares of an account for assets. + +Under the hood, the transaction performs a [VaultWithdraw](./vaultwithdraw.md) on behalf of the account from which assets are clawed back, converting its shares into assets and transferring the funds to the asset’s issuing account. Because of this, {% code-page-name /%} must respect any applicable fees or penalties (e.g., unrealized loss). + +{% admonition type="warning" name="Warning" %} +Clawbacks cannot be performed on native XRP. +{% /admonition %} + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%})_ + +## Example {% $frontmatter.seo.title %} JSON + +```json +{ + "TransactionType": "VaultClawback", + "Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", + "Fee": "12", + "Flags": 0, + "LastLedgerSequence": 7108682, + "Sequence": 8, + "VaultID": "77D6234D074E505024D39C04C3F262997B773719AB29ACFA83119E4210328776", + "Holder": "ruazs5h1qEsqpke88pcqnaseXdm6od2xc", + "Amount" : "10000" +} +``` + +## {% $frontmatter.seo.title %} Fields + +| Field Name | JSON Type | Internal Type | Required? | Description | +| :--------- | :-------- | :------------ | :-------- | :---------- | +| `VaultID` | String | Hash256 | Yes | The unique identifier of the vault from which assets are withdrawn. | +| `Holder` | String | AccountID | Yes | The unique identifier of the account from which to claw back the assets. | +| `Amount` | Number | Number | No | The asset amount to claw back. When this field is set to 0, the transaction claws back all funds, up to the total shares the `Holder` owns. | + +If the requested amount exceeds the vault’s available assets, the transaction claws back only up to the vault's `AssetsAvailable` balance. Otherwise, it retrieves the exact asset amount specified in the transaction. + +## {% $frontmatter.seo.title %} Flags + +There are no flags defined for {% code-page-name /%} transactions. + +## Error Cases + +Besides errors that can occur for all transactions, {% code-page-name /%} transactions can result in the following [transaction result codes](https://xrpl.org/docs/references/protocol/transactions/transaction-results): + +| Error Code | Description | +| :---------------------- | :---------- | +| `tecNO_ENTRY` | The `Vault` object with the specified `VaultID` does not exist on the ledger. | +| `tecNO_PERMISSION` | The transaction attempts to claw back XRP, or the asset is a Fungible Token or MPT and the transaction isn't submitted by the issuing account. | +| `tecWRONG_ASSET` | The asset in the transaction does not match the vault's asset type. | +| `tecINSUFFICIENT_FUNDS` | The `MPToken` object for the vault share of the `Holder` account does not exist, or the `MPToken.MPTAmount` is 0. | +| `temDISABLED` | The Single Asset Vault amendment is not enabled. | +| `temMALFORMED` | The transaction was not validly formatted. For example, if the `VaultID` is not provided. | + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/transactions/types/vaultcreate.md b/docs/references/protocol/transactions/types/vaultcreate.md new file mode 100644 index 00000000000..4a142ace2eb --- /dev/null +++ b/docs/references/protocol/transactions/types/vaultcreate.md @@ -0,0 +1,99 @@ +--- +seo: + description: Creates a new vault object in the ledger. +labels: + - Transactions + - Single Asset Vault +--- + +# VaultCreate + +[[Source]](https://github.com/XRPLF/rippled/blob/develop/src/xrpld/app/tx/detail/VaultCreate.cpp "Source" ) + +Creates a new `Vault` ledger entry, an `MPTokenIssuance` ledger entry for the vault’s shares, and an `AccountRoot` for the vault’s [pseudo-account](../../concepts/pseudo-account.md). + +Only the Vault Owner can initiate this transaction. + +{% admonition type="info" name="Note" %} +Currently, the same account that creates the vault must also create other protocols, though this may change in the future. +{% /admonition %} + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%})_ + +## Example {% $frontmatter.seo.title %} JSON + +```json +{ + "TransactionType": "VaultCreate", + "Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", + "Fee": "12", + "Flags": 0, + "LastLedgerSequence": 7108682, + "Sequence": 8, + "Data": "5468697320697320617262697472617279206D657461646174612061626F757420746865207661756C742E", + "Asset": { + "currency": "USD", + "issuer": "rIssuer1234567890abcdef1234567890abcdef", + }, + "AssetsMaximum": 0, + "MPTokenMetadata": "5468697320697320617262697472617279206d657461646174612061626f757420746865204d50542073686172652e", + "WithdrawalPolicy": "1", + "DomainID": "77D6234D074E505024D39C04C3F262997B773719AB29ACFA83119E4210328776" +} +``` + +## {% $frontmatter.seo.title %} Fields + +In addition to the [common fields](https://xrpl.org/docs/references/protocol/transactions/common-fields#transaction-common-fields), {% code-page-name /%} transactions use the following fields: + +| Field Name | JSON Type | [Internal Type][] | Required? |Description | +|:-------------------|:--------------|:------------------|:----------|:------------------| +| `Data` | String | Blob | No | Arbitrary vault metadata, in hex format, limited to 256 bytes. | +| `Asset` | Object | Issue | Yes | The asset to be held in the vault. This can be XRP, a Fungible Token, or an MPT. If the asset is a Fungible Token, the transaction creates a [trust line](https://xrpl.org/docs/concepts/tokens/fungible-tokens#trust-lines) between the vault's pseudo-account and the issuer of the asset. If the asset is an MPT, the transaction creates an `MPToken` object for the vault's pseudo-account. | +| `AssetsMaximum` | Number | UInt64 | No | The maximum asset amount that can be held in a vault. | +| `MPTokenMetadata` | String | Blob | No | Arbitrary metadata about the share `MPToken`, in hex format, limited to 1024 bytes. Use this field if the vault's asset is an MPT. | +| `WithdrawalPolicy` | Number | UInt8 | No | Indicates the withdrawal strategy used by the vault. The default value is `0x0001`, mapped to the string `vaultStrategyFirstComeFirstServe`. See [WithdrawalPolicy](#withdrawalpolicy). | +| `DomainID` | String | Hash256 | No | The [PermissionedDomain](https://github.com/XRPLF/XRPL-Standards/blob/master/XLS-0080-permissioned-domains/) object ID associated with the shares of this vault. If provided, the transaction creates a private vault, which restricts access to accounts with [credentials](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0070-credentials) in the specified Permissioned Domain. | + +## {% $frontmatter.seo.title %} Flags + +{% code-page-name /%} transactions support additional values in the `Flags` field, as follows: + +| Flag Name | Value | Description | +| :---------------------------- | :------------| -------------------------| +| `tfVaultPrivate` | `0x00010000` | Indicates that the vault is private. This flag can only be set when _creating_ the vault. | +| `tfVaultShareNonTransferable` | `0x00020000` | Indicates the vault share is non-transferable. This flag can only be set when _creating_ the vault. | + +## WithdrawalPolicy + +A `WithdrawalPolicy` defines the strategy for processing withdrawal requests from a vault. This policy governs how liquidity is removed. Currently, only one strategy is supported: + +| Policy Name | Value | Description | +| :--------------------------------- | :------- | -------------------------| +| `vaultStrategyFirstComeFirstServe` | `0x0001` | Requests are processed on a first-come, first-served basis. With this strategy, a depositor can redeem any amount of assets, provided they hold a sufficient number of shares. | + +## Transaction Cost + +Since the {% code-page-name /%} transaction creates a new `AccountRoot` object for a vault’s pseudo-account, it incurs a higher than usual [transaction cost](https://xrpl.org/docs/concepts/transactions/transaction-cost) to deter ledger spam. Instead of the standard minimum of 0.00001 XRP, {% code-page-name /%} must destroy an [incremental owner reserve](https://xrpl.org/docs/concepts/accounts/reserves#base-reserve-and-owner-reserve), currently 0.2 XRP. + +## Error Cases + +Besides errors that can occur for all transactions, {% code-page-name /%} transactions can result in the following [transaction result codes](https://xrpl.org/docs/references/protocol/transactions/transaction-results): + +| Error Code | Description | +| :------------------------ | :----------------------------------| +| `tecNO_AUTH` | The asset is an MPT and the `lsfMPTCanTransfer` flag is not set in the `MPTokenIssuance` object, meaning the vault cannot be created with a non-transferable MPT. | +| `tecLOCKED` | The asset is an MPT and the `lsfMPTLocked` flag is set in the `MPTokenIssuance` object, meaning the asset is locked. | +| `tecFROZEN` | The issuer has frozen the asset to be held in the vault. | +| `tecOBJECT_NOT_FOUND` | A ledger entry specified in the transaction does not exist. For example, the provided `DomainID` does not exist. | +| `temMALFORMED` | The transaction was not validly formatted. For example, the `Data` field is larger than 256 bytes. | +| `tecINSUFFICIENT_RESERVE` | There is insufficient `AccountRoot.Balance` for the Owner Reserve. | +| `terNO_RIPPLE` | The issuer of the asset has not enabled the [Default Ripple flag](https://xrpl.org/docs/concepts/tokens/fungible-tokens/stablecoins/configuration#default-ripple). | +| `terNO_ACCOUNT` | The issuer account of the vault's asset does not exist. | +| `temDISABLED` | Either the Single Asset Vault amendment is not enabled, a `DomainID` is provided and the Permissioned Domains amendment is not enabled, or the MPTokensV1 amendment is not enabled. | + +## See Also + +- [Vault entry][] + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/transactions/types/vaultdelete.md b/docs/references/protocol/transactions/types/vaultdelete.md new file mode 100644 index 00000000000..d436a521437 --- /dev/null +++ b/docs/references/protocol/transactions/types/vaultdelete.md @@ -0,0 +1,59 @@ +--- +seo: + description: Deletes an existing Vault object from the ledger. +labels: + - Transactions + - Single Asset Vault +--- + +# VaultDelete + +[[Source]](https://github.com/XRPLF/rippled/blob/develop/src/xrpld/app/tx/detail/VaultDelete.cpp "Source") + +Permanently deletes an existing `Vault` object from the ledger, removes all associated ledger entries, and returns the owner reserve to the Vault Owner. + +Only the Vault Owner can initiate this transaction, and the vault must be completely empty before deletion. + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%})_ + +## Example {% $frontmatter.seo.title %} JSON + +```json +{ + "TransactionType": "VaultDelete", + "Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", + "Fee": "12", + "Flags": 0, + "LastLedgerSequence": 7108682, + "Sequence": 8, + "VaultID": "77D6234D074E505024D39C04C3F262997B773719AB29ACFA83119E4210328776" +} +``` + +## {% $frontmatter.seo.title %} Fields + +In addition to the [common fields](https://xrpl.org/docs/references/protocol/transactions/common-fields#transaction-common-fields), {% code-page-name /%} transactions use the following fields: + +| Field Name | JSON Type | Internal Type | Required? | Description | +| :----------------- | :-------- | :------------ | :-------- | :------------| +| `VaultID` | String | Hash256 | Yes | The unique identifier of the vault that needs to be deleted. | + +## {% $frontmatter.seo.title %} Flags + +There are no flags defined for {% code-page-name /%} transactions. + +## Error Cases + +Besides errors that can occur for all transactions, VaultCreate transactions can result in the following [transaction result codes](https://xrpl.org/docs/references/protocol/transactions/transaction-results): + +| Error Code | Description | +| :------------------------ | :----------------------------------| +| `tecNO_ENTRY` | The `Vault` object with the provided `VaultID` does not exist on the ledger. | +| `tecNO_PERMISSION` | The account submitting the transaction is not the `Owner` of the vault. | +| `tecHAS_OBLIGATIONS` | The vault to be deleted is connected to objects that cannot be deleted in the ledger. For example, the owner directory of the vault's pseudo-account contains references to any objects other than the vault, shares, or assets. | + +## See Also + +- [Vault entry][] + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/transactions/types/vaultdeposit.md b/docs/references/protocol/transactions/types/vaultdeposit.md new file mode 100644 index 00000000000..e145944eba6 --- /dev/null +++ b/docs/references/protocol/transactions/types/vaultdeposit.md @@ -0,0 +1,95 @@ +--- +seo: + description: Deposits a specified number of assets into a vault in exchange for shares. +labels: + - Transactions + - Single Asset Vault +--- + +# VaultDeposit + +[[Source]](https://github.com/XRPLF/rippled/blob/develop/src/xrpld/app/tx/detail/VaultDeposit.cpp "Source") + +Deposits a specified number of assets into a vault in exchange for shares. + +For private vaults, the depositor must be authorized to interact with the vault’s shares and have [credentials](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0070-credentials) in the [Permissioned Domain](https://github.com/XRPLF/XRPL-Standards/blob/master/XLS-0080-permissioned-domains/) of the share. + +Public vaults require no authorization, and anyone can deposit as long as they meet the asset type requirement and have sufficient funds. + +{% admonition type="warning" name="Warning" %} +A depositor cannot deposit assets into the vault if: + +- The asset is frozen for the depositor. +- The trust line or the `MPToken` between the pseudo-account and the issuer of the vault asset is frozen or locked. +- The vault is private and the depositor's credentials have expired. +{% /admonition %} + +If successful, the transaction moves the assets from the depositor's account to the vault's pseudo-account, issues the corresponding vault shares, and updates the vault’s balance. + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%})_ + +## Example {% $frontmatter.seo.title %} JSON + +```json +{ + "TransactionType": "VaultDeposit", + "Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", + "Fee": "12", + "Flags": 0, + "LastLedgerSequence": 7108682, + "Sequence": 8, + "VaultID": "77D6234D074E505024D39C04C3F262997B773719AB29ACFA83119E4210328776", + "Amount" : { + "currency" : "TST", + "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd", + "value" : "2.5" + } +} +``` + +## {% $frontmatter.seo.title %} Fields + +In addition to the [common fields](https://xrpl.org/docs/references/protocol/transactions/common-fields#transaction-common-fields), {% code-page-name /%} transactions use the following fields: + +| Field Name | JSON Type | Internal Type | Required? | Description | +| :-----------------------| :------------ | :------------ | :-------- | :-------------------| +| `VaultID` | String | Hash256 | Yes | The unique identifier of the vault to which the asset is deposited. | +| `Amount` | Object | Amount | Yes | The asset and quantity to be deposited into the vault.| + +The deposited asset must match the vault’s designated asset for the transaction to succeed. Depending on the asset type, the following changes occur: + +- **XRP**: The vault’s pseudo-account balance increases, and the depositor’s balance decreases. +- **Fungible Token**: The [trust line](https://xrpl.org/docs/concepts/tokens/fungible-tokens#trust-lines) balance between the vault's pseudo-account and the asset issuer is adjusted. +- **MPT**: The `MPToken.MPTAmount` of both the depositor and the vault's pseudo-account is updated. + +## {% $frontmatter.seo.title %} Flags + +There are no flags defined for {% code-page-name /%} transactions. + +## Transfer Fees + +A single asset vault does not apply the [transfer fee](https://xrpl.org/docs/concepts/tokens/transfer-fees) to {% code-page-name /%} transactions. Additionally, whenever a protocol moves assets from or to a vault, the transfer fee isn't charged. + +## Error Cases + +Besides errors that can occur for all transactions, {% code-page-name /%} transactions can result in the following [transaction result codes](https://xrpl.org/docs/references/protocol/transactions/transaction-results): + +| Error Code | Description | +| :---------------------- | :----------------------------------| +| `tecNO_ENTRY` | The `Vault` object with the provided `VaultID` does not exist on the ledger. | +| `tecOBJECT_NOT_FOUND` | A ledger entry specified in the transaction does not exist. | +| `tecWRONG_ASSET` | The asset of the vault does not match the asset being deposited. | +| `tecINSUFFICIENT_FUNDS` | The depositor does not have sufficient funds to make a deposit. | +| `tecLIMIT_EXCEEDED` | Adding the provided `Amount` to the `AssetsTotal` exceeds the `AssetsMaximum` value. | +| `tecNO_AUTH` | Either the vault is private and the depositing account does not have credentials in the share's Permissioned Domain, or the asset is a non-transferable MPT. | +| `tecFROZEN` | Either the trust line between the issuer and the depositor is frozen, or the asset is globally frozen. | +| `tecLOCKED` | Either the MPT asset is locked for the depositor, or if the asset is globally locked. | +| `temMALFORMED` | The transaction was not validly formatted. For example, if the `VaultID` is not provided. | +| `temDISABLED` | The Single Asset Vault amendment is not enabled. | +| `temBAD_AMOUNT` | The `Amount` field of the transaction is invalid. | + +## See Also + +- [Vault entry][] + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/transactions/types/vaultset.md b/docs/references/protocol/transactions/types/vaultset.md new file mode 100644 index 00000000000..6b9b49fef23 --- /dev/null +++ b/docs/references/protocol/transactions/types/vaultset.md @@ -0,0 +1,71 @@ +--- +seo: + description: Modifies a single asset vault that you own. +labels: + - Transactions + - Single Asset Vault +--- + +# VaultSet + +[[Source]](https://github.com/XRPLF/rippled/blob/develop/src/xrpld/app/tx/detail/VaultSet.cpp "Source") + +Modifies a single asset vault that you own. +This transaction allows the Vault Owner to update certain mutable fields, including vault metadata and the maximum asset amount. + +{% admonition type="warning" name="Warning" %} +Once a vault is created, its public or private status is permanent and cannot be changed. The [tfVaultPrivate](../vault.md#vault-flags) flag determines this status, and once set, it cannot be updated. +{% /admonition %} + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%})_ + +## Example {% $frontmatter.seo.title %} JSON + +```json +{ + "TransactionType": "VaultSet", + "Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", + "Fee": "12", + "Flags": 0, + "LastLedgerSequence": 7108682, + "Sequence": 8, + "VaultID": "77D6234D074E505024D39C04C3F262997B773719AB29ACFA83119E4210328776", + "Data": "5468697320697320617262697472617279206D657461646174612061626F757420746865207661756C742E", + "AssetsMaximum": 5, + "DomainID": "77D6234D074E505024D39C04C3F262997B773719AB29ACFA83119E4210328776" +} +``` + +## {% $frontmatter.seo.title %} Fields + +In addition to the [common fields](https://xrpl.org/docs/references/protocol/transactions/common-fields#transaction-common-fields), {% code-page-name /%} transactions use the following fields: + +| Field Name | JSON Type | Internal Type | Required? | Description | +| :---------------- | :-------- | :------------ | :-------- | :-------------------| +| `VaultID` | String | Hash256 | Yes | The unique identifier of the vault that needs to be updated. | +| `Data` | String | Blob | No | Arbitrary vault metadata, limited to 256 bytes. | +| `AssetsMaximum` | Number | UInt64 | No | 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` | String | Hash256 | No | The [PermissionedDomain](https://github.com/XRPLF/XRPL-Standards/blob/master/XLS-0080-permissioned-domains/) object ID associated with the shares of this vault. The `DomainID` is only required when updating a private vault. | + +## {% $frontmatter.seo.title %} Flags + +There are no flags defined for {% code-page-name /%} transactions. + +## Error Cases + +Besides errors that can occur for all transactions, {% code-page-name /%} transactions can result in the following [transaction result codes](https://xrpl.org/docs/references/protocol/transactions/transaction-results): + +| Error Code | Description | +| :-------------------- | :-------------------------------------| +| `tecNO_ENTRY` | The transaction attempted to modify a vault that does not exist. Check the `VaultID` field of the transaction. | +| `tecOBJECT_NOT_FOUND` | The `PermissionedDomain` object with the provided `DomainID` does not exist. | +| `tecNO_PERMISSION` | The account submitting the transaction is not the `Owner` of the vault, or is trying to set a `DomainID` for a public vault. | +| `temMALFORMED` | The transaction was not validly formatted. For example, the `Data` field is larger than 256 bytes. | +| `tecLIMIT_EXCEEDED` | The _new_ `AssetsMaximum` value is **lower** than the vault's _current_ `AssetsTotal`. | +| `temDISABLED` | Either the Single Asset Vault amendment is not enabled, or a `DomainID` is provided and the Permissioned Domains amendment is not enabled. | + +## See Also + +- [Vault entry][] + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/references/protocol/transactions/types/vaultwithdraw.md b/docs/references/protocol/transactions/types/vaultwithdraw.md new file mode 100644 index 00000000000..5f4a450a5b2 --- /dev/null +++ b/docs/references/protocol/transactions/types/vaultwithdraw.md @@ -0,0 +1,81 @@ +--- +seo: + description: Redeem vault shares for assets. +labels: + - Transactions + - Single Asset Vault +--- + +# VaultWithdraw + +[[Source]](https://github.com/Bronek/rippled/blob/vault/src/xrpld/app/tx/detail/VaultWithdraw.cpp "Source") + +Redeem vault shares for assets. The amount of assets received depends on the [exchange rate](../../concepts/single-asset-vault.md#exchange-algorithm), which adjusts based on the vault’s total assets and any [unrealized losses](../../concepts/single-asset-vault.md#paper-loss-unrealized-loss). + +{% admonition type="info" name="Note" %} +The `VaultWithdraw` transaction does not respect the Permissioned Domain rules. In other words, any account that holds the shares of the vault can redeem them. This is 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 losing access to their funds. +{% /admonition %} + +A depositor cannot redeem liquidity if the trust line or the `MPToken` between the pseudo-account and the issuer of the vault asset is frozen or locked. + +_(Requires the [SingleAssetVault amendment][] {% not-enabled /%})_ + +## Example {% $frontmatter.seo.title %} JSON + +```json +{ + "TransactionType": "VaultWithdraw", + "Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", + "Fee": "12", + "Flags": 0, + "LastLedgerSequence": 7108682, + "Sequence": 8, + "VaultID": "77D6234D074E505024D39C04C3F262997B773719AB29ACFA83119E4210328776", + "Amount" : "10000", + "Destination": "ruazs5h1qEsqpke88pcqnaseXdm6od2xc" +} +``` + +## {% $frontmatter.seo.title %} Fields + +In addition to the [common fields](https://xrpl.org/docs/references/protocol/transactions/common-fields#transaction-common-fields), {% code-page-name /%} transactions use the following fields: + +| Field Name | JSON Type | Internal Type | Required? | Description | +| :-----------------------| :------------ | :------------ | :-------- | :-------------------| +| `VaultID` | String | Hash256 | Yes | The unique identifier of the vault to which the assets are deposited. | +| `Amount` | Number | Amount | Yes | The exact amount of vault asset to withdraw or vault share to redeem. | +| `Destination` | String | AccountID | No | An account to receive the assets. This account must be able to receive the vault asset or the transaction fails. | + +There are two ways to specify the transaction `Amount` field: + +| Specify Assets | Specify Shares | +|:-------------- |:---------------| +| | | + +## {% $frontmatter.seo.title %} Flags + +There are no flags defined for {% code-page-name /%} transactions. + +## Transfer Fees + +A single asset vault does not apply the [transfer fee](https://xrpl.org/docs/concepts/tokens/transfer-fees) to {% code-page-name /%} transactions. Additionally, whenever a protocol moves assets from or to a vault, the Transfer Fee must not be charged. + +## Error Cases + +Besides errors that can occur for all transactions, {% code-page-name /%} transactions can result in the following [transaction result codes](https://xrpl.org/docs/references/protocol/transactions/transaction-results): + +| Error Code | Description | +| :---------------------- | :----------------------------------| +| `tecNO_ENTRY` | The `Vault` object with the provided `VaultID` does not exist on the ledger. | +| `tecOBJECT_NOT_FOUND` | A ledger entry specified in the transaction does not exist. | +| `tecNO_PERMISSION` | The destination account specified does not have permission to receive the asset. | +| `tecWRONG_ASSET` | The unit of `Amount` is neither a share or asset of the vault. | +| `tecINSUFFICIENT_FUNDS` | There is insufficient liquidity in the vault to fill the request. | +| `tecFROZEN` | Either the trust line between the issuer and the destination account is frozen, or the asset is globally frozen. | +| `tecLOCKED` | The MPT asset is locked for the depositor, destination account, or if the asset is globally locked. | +| `temMALFORMED` | The transaction is not validly formatted. For example, the `VaultID` is not provided. | +| `temDISABLED` | The Single Asset Vault amendment is not enabled. | +| `temBAD_AMOUNT` | The `Amount` field of the transaction is invalid. For example, the provided amount is set to 0. | +| `tecNO_AUTH` | The asset is a non-transferable MPT. | + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/resources/known-amendments.md b/resources/known-amendments.md index d63401b37d0..56baaab0a23 100644 --- a/resources/known-amendments.md +++ b/resources/known-amendments.md @@ -1678,8 +1678,7 @@ When this amendment is activated, the XRP Ledger will undergo a brief scheduled Creates a structure for aggregating assets from multiple depositors. This is intended to be used with the proposed on-chain Lending Protocol. -Specification: [XLS-65](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0065d-single-asset-vault). - +Specification: [XLS-65](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0065-single-asset-vault). ### SortedDirectories [SortedDirectories]: #sorteddirectories @@ -1835,4 +1834,4 @@ Without this amendment, the format of the transaction and ledger entry are the s -{% raw-partial file="/docs/_snippets/common-links.md" /%} \ No newline at end of file +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/sidebars.yaml b/sidebars.yaml index 961a6729140..1ac4efafbd3 100644 --- a/sidebars.yaml +++ b/sidebars.yaml @@ -151,6 +151,7 @@ - page: docs/concepts/tokens/decentralized-exchange/automated-market-makers.md - page: docs/concepts/tokens/decentralized-exchange/permissioned-domains.md - page: docs/concepts/tokens/decentralized-exchange/permissioned-dexes.md + - page: docs/concepts/tokens/single-asset-vault.md - page: docs/concepts/accounts/index.md expanded: false items: @@ -164,6 +165,7 @@ - page: docs/concepts/accounts/depositauth.md - page: docs/concepts/accounts/tickets.md - page: docs/concepts/accounts/permission-delegation.md + - page: docs/concepts/accounts/pseudo-accounts.md - page: docs/concepts/xrpl-sidechains/index.md expanded: false items: @@ -370,6 +372,7 @@ - page: docs/references/protocol/ledger-data/ledger-entry-types/ripplestate.md - page: docs/references/protocol/ledger-data/ledger-entry-types/signerlist.md - page: docs/references/protocol/ledger-data/ledger-entry-types/ticket.md + - page: docs/references/protocol/ledger-data/ledger-entry-types/vault.md - page: docs/references/protocol/ledger-data/ledger-entry-types/xchainownedclaimid.md - page: docs/references/protocol/ledger-data/ledger-entry-types/xchainownedcreateaccountclaimid.md - page: docs/references/protocol/transactions/index.md @@ -428,6 +431,11 @@ - page: docs/references/protocol/transactions/types/signerlistset.md - page: docs/references/protocol/transactions/types/ticketcreate.md - page: docs/references/protocol/transactions/types/trustset.md + - page: docs/references/protocol/transactions/types/vaultcreate.md + - page: docs/references/protocol/transactions/types/vaultdelete.md + - page: docs/references/protocol/transactions/types/vaultdeposit.md + - page: docs/references/protocol/transactions/types/vaultset.md + - page: docs/references/protocol/transactions/types/vaultwithdraw.md - page: docs/references/protocol/transactions/types/xchainaccountcreatecommit.md - page: docs/references/protocol/transactions/types/xchainaddaccountcreateattestation.md - page: docs/references/protocol/transactions/types/xchainaddclaimattestation.md @@ -569,6 +577,12 @@ - page: docs/references/http-websocket-apis/public-api-methods/utility-methods/json.md - page: docs/references/http-websocket-apis/public-api-methods/utility-methods/ping.md - page: docs/references/http-websocket-apis/public-api-methods/utility-methods/random.md + + - page: docs/references/http-websocket-apis/public-api-methods/vault-methods/index.md + expanded: false + items: + - page: docs/references/http-websocket-apis/public-api-methods/vault-methods/vault_info.md + - page: docs/references/http-websocket-apis/admin-api-methods/index.md expanded: false items: