diff --git a/XLS-0065-single-asset-vault/README.md b/XLS-0065-single-asset-vault/README.md index bd54fce4..8617bc25 100644 --- a/XLS-0065-single-asset-vault/README.md +++ b/XLS-0065-single-asset-vault/README.md @@ -110,9 +110,11 @@ A vault has the following fields: The `Vault` object supports the following flags: -| Flag Name | Flag Value | Modifiable? | Description | -| ----------------- | :----------: | :---------: | :------------------------------------------: | -| `lsfVaultPrivate` | `0x00010000` | No | If set, indicates that the vault is private. | +| Flag Name | Flag Value | Modifiable? | Description | +| ------------------------------ | :----------: | :---------: | :---------------------------------------------------------: | +| `lsfVaultPrivate` | `0x00010000` | `No` | If set, indicates that the vault is private. | +| `lsfVaultDepositBlocked` | `0x00020000` | `No` | If set, indicates that deposits to a vault are blocked. | +| `lsfVaultOwnerCanBlockDeposit` | `0x00040000` | `No` | If set, indicates that the Vault Owner can block a deposit. | #### 3.1.3 Vault `_pseudo-account_` @@ -389,6 +391,7 @@ The `VaultCreate` transaction creates a new `Vault` object. | ----------------------------- | :----------: | :--------------------------------------------------------------------------------------- | | `tfVaultPrivate` | `0x00010000` | Indicates that the vault is private. It can only be set during Vault creation. | | `tfVaultShareNonTransferable` | `0x00020000` | Indicates the vault share is non-transferable. It can only be set during Vault creation. | +| `tfVaultOwnerCanBlockDeposit` | `0x00040000` | Indicates the vault owner can block deposits. It can only be set during Vault creation. | ##### 3.2.3 WithdrawalPolicy @@ -472,29 +475,51 @@ The `VaultSet` updates an existing `Vault` ledger object. | ----------------- | :------: | :-------: | :-----------: | :-----------: | :-------------------------------------------------------------------------------------------------------------------------------------- | | `TransactionType` | Yes | `string` | `Uint16` | `59` | The transaction type. | | `VaultID` | Yes | `string` | `Hash256` | `N/A` | The ID of the Vault to be modified. Must be included when updating the Vault. | +| `Flags` | No | `number` | `UINT32` | 0 | Specifies the flags for the Vault. | | `Data` | No | `string` | `Blob` | | Arbitrary Vault metadata, limited to 256 bytes. | | `AssetsMaximum` | No | `number` | `Number` | | The maximum asset amount that can be held in a vault. The value cannot be lower than the current `AssetsTotal` unless the value is `0`. | | `DomainID` | No | `string` | `Hash256` | | The `PermissionedDomain` object ID associated with the shares of this Vault. | -#### 3.3.2 Failure Conditions +#### 3.3.2 Flags -1. `Vault` object with the specified `VaultID` does not exist on the ledger. -2. The submitting account is not the `Owner` of the vault. -3. The `Data` field is larger than 256 bytes. -4. If `Vault.AssetsMaximum` > `0` AND `AssetsMaximum` > 0 AND: - 1. The `AssetsMaximum` < `Vault.AssetsTotal` (new `AssetsMaximum` cannot be lower than the current `AssetsTotal`). -5. The `sfVaultPrivate` flag is not set and the `DomainID` is provided (Vault Owner is attempting to set a PermissionedDomain to a public Vault). -6. The `PermissionedDomain` object does not exist with the provided `DomainID`. -7. The transaction is attempting to modify an immutable field. -8. The transaction does not specify any of the modifiable fields. +| Flag Name | Flag Value | Description | +| ----------------------- | :----------: | :------------------------------- | +| `tfVaultDepositBlock` | `0x00010000` | Block deposits into the vault. | +| `tfVaultDepositUnblock` | `0x00020000` | Unblock deposits into the vault. | + +### 3.3.3 Failure Conditions + +#### 3.3.3.1 Data Verification + +1. `VaultID` is empty. (`temMALFORMED`) +2. The `Data` field is larger than 256 bytes (`temMALFORMED`) +3. `AssetsMaximum` is negative integer (`temMALFORMED`) +4. The transaction does not specify any of the modifiable fields. (`temMALFORMED`) +5. Both `tfVaultDepositBlock` and `tfVaultDepositUnblock` are set. (`temMALFORMED`) + +#### 3.3.3.2 Protocol-Level Failures -#### 3.3.3 State Changes +1. `Vault` object with the specified `VaultID` does not exist on the ledger. (`tecNO_ENTRY`) +2. The submitting account is not the `Owner` of the vault. (`tecNO_PERMISSION`) +3. The `sfVaultPrivate` flag is not set and the `DomainID` is provided. (`tecNO_PERMISSION`) +4. The `PermissionedDomain` object does not exist with the provided `DomainID`. (`tecNO_OBJECT_NOT_FOUND`) +5. If `Vault.AssetsMaximum` > `0` AND `AssetsMaximum` > 0 AND: + 1. The `AssetsMaximum` < `Vault.AssetsTotal` (new `AssetsMaximum` cannot be lower than the current `AssetsTotal`). (`tecLIMIT_EXCEEDED`) +6. `Vault.lsfVaultDepositBlocked` is set and `tfVaultDepositBlock` is set (cannot block an already blocked vault). (`tecNO_PERMISSION`) +7. `Vault.lsfVaultDepositBlocked` is **not** set and `tfVaultDepositUnblock` is set (cannot unblock an already unblocked vault). (`tecNO_PERMISSION`) +8. `Vault.lsfVaultOwnerCanBlockDeposit` is **not** set, and `tfVaultDepositBlock` or `tfVaultDepositUnblock` are set. (`tecNO_PERMISSION`) + +#### 3.3.4 State Changes 1. Update mutable fields in the `Vault` ledger object. 2. If `DomainID` is provided: 1. Set `MPTokenIssuance(Vault.ShareMPTID).DomainID = DomainID` (Set the Permissioned Domain). +3. If `tfVaultDepositBlock` is provided: + 1. Set `Vault.Flags |= lsfVaultDepositBlocked` flag (Block Deposits). +4. If `tfVaultDepositUnblock` is provided: + 1. Set `Vault.Flags &= ~lsfVaultDepositBlocked` flag (Unblock Deposits). -#### 3.3.4 Invariants +#### 3.3.5 Invariants - The _pseudo-account_ asset balance must not change. - `.AssetsTotal == '.AssetsTotal` (assets total must not change). @@ -502,7 +527,7 @@ The `VaultSet` updates an existing `Vault` ledger object. - `IF '.AssetsMaximum > 0 THEN '.AssetsTotal <= '.AssetsMaximum`. - `MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount` must not change. -#### 3.3.5 Example JSON +#### 3.3.6 Example JSON ```json { @@ -573,43 +598,72 @@ The `VaultDeposit` transaction adds Liqudity in exchange for vault shares. | `TransactionType` | Yes | `string` | `UINT16` | `61` | Transaction type. | | `VaultID` | Yes | `string` | `HASH256` | `N/A` | The ID of the vault to which the assets are deposited. | | `Amount` | Yes | `string` or `object` | `STAmount` | `N/A` | Asset amount to deposit. | +| `Flags` | No | `number` | `UINT32` | 0 | Specifies additional flags for the transaction. | + +### 6.1 Flags + +| Flag Name | Flag Value | Description | +| --------------- | :----------: | :------------------------------- | +| `tfVaultDonate` | `0x00010000` | Donate the funds into the vault. | #### 3.5.2 Failure Conditions -1. `Vault` object with the `VaultID` does not exist on the ledger. -2. The asset type of the vault does not match the asset type the depositor is depositing. -3. The depositor does not have sufficient funds to make a deposit. -4. Adding the `Amount` to the `AssetsTotal` of the vault would exceed the `AssetsMaximum`. -5. The `Vault` `lsfVaultPrivate` flag is set and the `Account` depositing the assets does not have credentials in the permissioned domain of the share. +#### 6.2.1. Data Verification -6. The `Vault.Asset` is `MPT`: - 1. `MPTokenIssuance.lsfMPTCanTransfer` is not set (the asset is not transferable). - 2. `MPTokenIssuance.lsfMPTLocked` flag is set (the asset is globally locked). - 3. `MPToken(MPTokenIssuanceID, AccountID).lsfMPTLocked` flag is set (the asset is locked for the depositor). - 4. `MPToken(MPTokenIssuanceID, AccountID).MPTAmount` < `Amount` (insufficient balance). +1. `VaultID` is has a zero value. (`temMALFORMED`) +2. `Amount` is less or equal to zero. (`temBAD_AMOUNT`) -7. The `Asset` is an `IOU`: - 1. The `lsfGlobalFreeze` flag is set on the issuing account (the asset is frozen). - 2. The `lsfHighFreeze` or `lsfLowFreeze` flag is set on the `RippleState` object between the Asset `Issuer` and the depositor. - 3. The `RippleState` object `Balance` < `Amount` (insufficient balance). +#### 6.2.2. Protocol-Level Failures + +1. `Vault` object with the `VaultID` does not exist on the ledger. (`tecNO_ENTRY`) +2. `Amount.Asset` does not match the asset type of the vault. (`tecWRONG_ASSET`) +3. The depositor does not have sufficient funds to make a deposit. (`tecINSUFFICIENT_FUNDS`) +4. Adding the `Amount` to the `AssetsTotal` of the vault would exceed the `AssetsMaximum` (`tecLIMIT_EXCEEDED`) + +5. `tfVaultDonate` flag is set and: + 1. `Account` submitting the transaction is not the vault owner. (`tecNO_PERMISSION`) + 2. `MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount == 0`, the Vault is empty. (`tecNO_PERMISSION`) + +6. The `Vault` `lsfVaultPrivate` flag is set and the `Account` is not `Vault.Owner`: + 1. If `Account` credentials are expired. (`tecEXPIRED`) + 2. If `Account` does not have valid credentials. (`tecNO_AUTH`) + +7. If vault is insolvent, `Vault.AssetsTotal = 0` and `MPTokenIssuance(Vault.ShareMPTID).OutstandingAmount > 0`. (`tecLOCKED`) + +8. The `Vault.Asset` is `MPT`: + 1. `MPTokenIssuance.lsfMPTCanTransfer` is not set (the asset is not transferable). (`tecNO_AUTH`) + 2. `MPTokenIssuance.lsfMPTLocked` flag is set (the asset is globally locked) (`tecLOCKED`) + 3. `MPToken(MPTokenIssuanceID, AccountID).lsfMPTLocked` flag is set (the asset is locked for the depositor). (`tecLOCKED`) + 4. `MPToken(MPTokenIssuanceID, AccountID).MPTAmount` < `Amount` (insufficient balance). (`tecINSUFFICIENT_FUNDS`) + +9. The `Asset` is an `IOU`: + 1. `lsfDefaultRipple` flag is not set on either the issuer or the depositor. (`terNO_RIPPLE`) + 2. The `lsfGlobalFreeze` flag is set on the issuing account (the asset is frozen). (`tecFROZEN`) + 3. The `lsfHighFreeze` or `lsfLowFreeze` flag is set on the `RippleState` object between the Asset `Issuer` and the depositor. (`tecFROZEN`) + 4. The `RippleState` object `Balance` < `Amount` (insufficient balance). (`tecINSUFFICIENT_FUNDS`) + +10. `Vault.lsfVaultDepositBlocked` flag is set (deposits are not permitted). (`tecNO_PERMISSION`) +11. `Vault.AssetsTotal + Amount > Vault.AssetsMaximum`, deposit would exceed the maximum allowed amount. (`tecLIMIT_EXCEEDED`) #### 3.5.3 State Changes 1. If no `MPToken` object exists for the depositor, create one. For object details, see [2.1.6.2 `MPToken`](#2162-mptoken). -2. Increase the `MPTAmount` field of the share `MPToken` object of the `Account` by $\Delta_{share}$. -3. Increase the `OutstandingAmount` field of the share `MPTokenIssuance` object by $\Delta_{share}$. -4. Increase the `AssetsTotal` and `AssetsAvailable` of the `Vault` by `Amount`. +2. If `tfVaultDonate` flag is **not** set: + 1. Increase the `MPTAmount` field of the share `MPToken` object of the `Account` by $\Delta_{share}$. + 2. Increase the `OutstandingAmount` field of the share `MPTokenIssuance` object by $\Delta_{share}$. + +3. Increase the `AssetsTotal` and `AssetsAvailable` of the `Vault` by `Amount`. -5. If the `Vault.Asset` is `XRP`: +4. If the `Vault.Asset` is `XRP`: 1. Increase the `Balance` field of _pseudo-account_ `AccountRoot` by `Amount`. 2. Decrease the `Balance` field of the depositor `AccountRoot` by `Amount`. -6. If the `Vault.Asset` is an `IOU`: +5. If the `Vault.Asset` is an `IOU`: 1. Increase the `RippleState` balance between the _pseudo-account_ `AccountRoot` and the `Issuer` `AccountRoot` by `Amount`. 2. Decrease the `RippleState` balance between the depositor `AccountRoot` and the `Issuer` `AccountRoot` by `Amount`. -7. If the `Vault.Asset` is an `MPT`: +6. If the `Vault.Asset` is an `MPT`: 1. Increase the `MPToken.MPTAmount` by `Amount` of the _pseudo-account_ `MPToken` object for the `Vault.Asset`. 2. Decrease the `MPToken.MPTAmount` by `Amount` of the depositor `MPToken` object for the `Vault.Asset`.