diff --git a/docs/_snippets/common-links.md b/docs/_snippets/common-links.md index 65c873e6..782c4351 100644 --- a/docs/_snippets/common-links.md +++ b/docs/_snippets/common-links.md @@ -12,6 +12,7 @@ [ConfidentialMPTSend transaction]: /docs/xls-96-confidential-transfers/references/transactions/confidentialmptsend.md [ConfidentialTransfers amendment]: https://xls.xrpl.org/xls/XLS-0096-confidential-mpt.html [credentials]: https://xrpl.org/docs/concepts/decentralized-storage/credentials +[DynamicMPT amendment]: https://xls.xrpl.org/xls/XLS-0094-dynamic-MPT.html [EscrowFinish]: https://xrpl.org/docs/references/protocol/transactions/types/escrowfinish [`flags` field]: https://xrpl.org/docs/references/protocol/transactions/common-fields#flags-field [Hash]: https://xrpl.org/docs/references/protocol/data-types/basic-data-types#hashes diff --git a/docs/xls-94-dynamic-mpts/dynamic-mpts.md b/docs/xls-94-dynamic-mpts/dynamic-mpts.md index bc6671a0..1007fa3f 100644 --- a/docs/xls-94-dynamic-mpts/dynamic-mpts.md +++ b/docs/xls-94-dynamic-mpts/dynamic-mpts.md @@ -7,18 +7,32 @@ labels: # Dynamic Multi-Purpose Tokens -Multi-Purpose Tokens (MPT) become immutable after issuance, but some use cases may require the capability to update an MPT's properties after its initial issuance. +Multi-Purpose Tokens (MPT) become immutable after issuance, but some use cases may require the capability to update an MPT's properties after its initial issuance. The Dynamic MPT amendment extends Multi-Purpose Tokens by allowing issuers to set specific properties as mutable when creating an MPT issuance. This enables some properties to be updated later as business needs evolve. For example, an issuer might need to adjust transfer fees based on market conditions, or update token metadata. Issuers can achieve this by explicitly declaring which specific fields and flags can be modified when they issue the MPT. Fields not marked as mutable during initial issuance remain immutable. +_(Requires the [DynamicMPT amendment][] {% not-enabled /%})_ + ## Creating a Dynamic MPT -When you issue an MPT, you can make it dynamic by declaring some properties as mutable in the `MutableFlags` field in the `MPTokenIssuanceCreate` transaction. This gives you flexibility to adapt your token's properties as your business needs evolve. You must carefully consider which properties should be mutable, as this cannot be changed later. +When you issue an MPT, you can declare selected fields and MPT issuance flags as mutable in the `MutableFlags` field of the `MPTokenIssuanceCreate` transaction. Field mutability supports operational updates such as _metadata_ changes and _transfer fee_ adjustments without requiring a new issuance. All other fields and flags must remain immutable. ## Modifying a Dynamic MPT -After creating an MPT with mutable properties, you can update those specific fields or flags using the `MPTokenIssuanceSet` transaction. When you use this transaction, you provide new values for the mutable fields, or use a separate set of flags to set or clear the mutable flags. Only the properties you designated as mutable during creation can be modified. +After creating an MPT with mutable properties, you can update those specific fields or enable mutable MPT issuance flags using the `MPTokenIssuanceSet` transaction. You provide new values for mutable fields, or use a separate set of flags to enable mutable MPT issuance flags. + +Mutable MPT issuance flags are intentionally **one-way**: if the corresponding mutability flag was set during creation, the issuer may later enable the MPT issuance flag through `MPTokenIssuanceSet`, but once enabled, that flag cannot be disabled. + +## Security Considerations + +Mutability is opt-in and strictly bounded by the issuer's original declaration: + +- A field or MPT issuance flag can only be changed if it was explicitly declared mutable during `MPTokenIssuanceCreate`. +- Only the issuer of the `MPTokenIssuance` can use `MPTokenIssuanceSet` to modify mutable fields or enable mutable MPT issuance flags. +- Mutable MPT issuance flags are one-way and cannot be disabled through `MPTokenIssuanceSet` after they are enabled. This prevents an issuer from weakening issuance behavior after participants may have relied on the enabled flag. ## See Also - [Dynamic MPT Reference Documentation](./reference.md) + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/xls-94-dynamic-mpts/reference.md b/docs/xls-94-dynamic-mpts/reference.md index d26aca5f..7524768d 100644 --- a/docs/xls-94-dynamic-mpts/reference.md +++ b/docs/xls-94-dynamic-mpts/reference.md @@ -10,10 +10,12 @@ The Dynamic MPT amendment does not create any new data types, but it modifies se - **Transactions:** - [MPTokenIssuanceCreate](#mptokenissuancecreate-transaction-changes) - The new `MutableFlags` field specifies which fields or flags are mutable after issuance. - - [MPTokenIssuanceSet](#mptokenissuanceset-transaction-changes) - Several new fields let you update mutable metadata, transfer fees, and flags. + - [MPTokenIssuanceSet](#mptokenissuanceset-transaction-changes) - Several new fields let you update mutable metadata and transfer fees, and enable MPT issuance flags that were declared mutable. - **Ledger Entries:** - [MPTokenIssuance](#mptokenissuance-entry-changes) - The new `MutableFlags` field stores mutability settings. +_(Requires the [DynamicMPT amendment][] {% not-enabled /%})_ + ## MPTokenIssuanceCreate Transaction Changes To allow future changes to specific fields or flags of a token, issuers must clearly specify which ones should be mutable when creating the `MPTokenIssuance` object. @@ -29,7 +31,6 @@ This example creates an MPT issuance with mutable metadata: "AssetScale": 4, "TransferFee": 0, "MaximumAmount": "50000000", - "Flags": 83659, "MutableFlags": 65536, // tmfMPTCanMutateMetadata "MPTokenMetadata": "464F4F", "Fee": "12", @@ -44,7 +45,7 @@ MPTokenIssuanceCreate transactions can include the following new field: | Field | JSON Type | [Internal Type][] | Required? | Description | |:-----------------|:--------------------|:------------------|:----------|-------------| -| `MutableFlags` | Number | UInt32 | No | Indicates specific fields or flags that are mutable after issuance. This is a bitwise combination of flags that determine mutability. See [MPTokenIssuanceCreate Mutable Flags](#mptokenissuancecreate-mutable-flags) | +| `MutableFlags` | Number | UInt32 | No | A bitwise combination of flags indicating which fields may be modified after issuance, and which MPT issuance flags may be enabled after issuance. See [MPTokenIssuanceCreate Mutable Flags](#mptokenissuancecreate-mutable-flags). | {% admonition type="warning" name="Warning" %} Only the specified fields and flags may be declared mutable; all other fields remain immutable. @@ -52,18 +53,18 @@ Only the specified fields and flags may be declared mutable; all other fields re ### MPTokenIssuanceCreate Mutable Flags -The following flags are stored in the `MutableFlags` field, which is separate from the `Flags` field of the `MPTokenIssuanceCreate` transaction: +The following flags are stored in the `MutableFlags` field, which is separate from the `Flags` field of the `MPTokenIssuanceCreate` transaction. MPT issuance flags that are declared mutable are one-way: they can be enabled after issuance via `MPTokenIssuanceSet`, but once enabled they cannot be disabled. Mutable fields (`MPTokenMetadata` and `TransferFee`) can always be modified. | Flag Name | Hex Value | Decimal Value | Description | |:----------------------------- |:-------------|:--------------|:------------| -| `tmfMPTCanMutateCanLock` | `0x00000002` | 2 | If enabled, the MPT's **Can Lock** flag, which gives the issuer the power to lock/unlock holders' balances, can change. | -| `tmfMPTCanMutateRequireAuth` | `0x00000004` | 4 | If enabled, the MPT's **Require Auth** flag, which indicates that individual holders must be authorized, can change. | -| `tmfMPTCanMutateCanEscrow` | `0x00000008` | 8 | If enabled, the MPT's **Can Escrow** flag, which indicates that the token can be placed in escrow, can change. | -| `tmfMPTCanMutateCanTrade` | `0x00000010` | 16 | If enabled, the MPT's **Can Trade** flag, which indicates that individual holders can trade their balances using the XRP Ledger DEX or AMM, can change. | -| `tmfMPTCanMutateCanTransfer` | `0x00000020` | 32 | If enabled, the MPT's **Can Transfer** flag, which indicates that tokens held by non-issuers can be transferred to other accounts, can change. | -| `tmfMPTCanMutateCanClawback` | `0x00000040` | 64 | If enabled, the MPT's **Can Clawback** flag, which indicates that the issuer can claw back value from individual holders, can change. | -| `tmfMPTCanMutateMetadata` | `0x00010000` | 65536 | If enabled, the `MPTokenMetadata` field, which stores additional information about the token, can change. | -| `tmfMPTCanMutateTransferFee` | `0x00020000` | 131072 | If enabled, the `TransferFee` field, which determines the fee percentage charged on transfers between users, can change. | +| `tmfMPTCanEnableCanLock` | `0x00000002` | 2 | If enabled, the MPT's **Can Lock** flag, which gives the issuer the power to lock/unlock holders' balances, can be enabled after issuance. | +| `tmfMPTCanEnableRequireAuth` | `0x00000004` | 4 | If enabled, the MPT's **Require Auth** flag, which indicates that individual holders must be authorized, can be enabled after issuance. | +| `tmfMPTCanEnableCanEscrow` | `0x00000008` | 8 | If enabled, the MPT's **Can Escrow** flag, which indicates that the token can be placed in escrow, can be enabled after issuance. | +| `tmfMPTCanEnableCanTrade` | `0x00000010` | 16 | If enabled, the MPT's **Can Trade** flag, which indicates that individual holders can trade their balances using the XRP Ledger DEX or AMM, can be enabled after issuance. | +| `tmfMPTCanEnableCanTransfer` | `0x00000020` | 32 | If enabled, the MPT's **Can Transfer** flag, which indicates that tokens held by non-issuers can be transferred to other accounts, can be enabled after issuance. | +| `tmfMPTCanEnableCanClawback` | `0x00000040` | 64 | If enabled, the MPT's **Can Clawback** flag, which indicates that the issuer can claw back value from individual holders, can be enabled after issuance. | +| `tmfMPTCanMutateMetadata` | `0x00010000` | 65536 | If enabled, the `MPTokenMetadata` field, which stores additional information about the token, can be modified. | +| `tmfMPTCanMutateTransferFee` | `0x00020000` | 131072 | If enabled, the `TransferFee` field, which determines the fee percentage charged on transfers between users, can be modified. | ### Error Cases @@ -76,11 +77,11 @@ The following failure conditions have been added to the `MPTokenIssuanceCreate` ## MPTokenIssuanceSet Transaction Changes -When updating mutable flags, issuers can enable or disable any flag that was marked as mutable during the creation of the `MPTokenIssuance` object. +When updating mutable fields, issuers can change the field value to any allowed value. When enabling MPT issuance flags that were declared mutable, issuers can only enable them; mutable flags are one-way and cannot be disabled by `MPTokenIssuanceSet` once enabled. ### Example JSON -This example udpates the MPT metadata: +This example updates the MPT metadata: ```json { @@ -102,36 +103,30 @@ MPTokenIssuanceSet transactions can include the following new fields: |:-----------------|:--------------------|:------------------|:----------|-------------| | `MPTokenMetadata`| String | Blob | No | New metadata to replace the existing value. Setting an empty value removes the field. Only valid if `lsmfMPTCanMutateMetadata` was set when creating the `MPTokenIssuance` object. | | `TransferFee` | Number | UInt16 | No | The new transfer fee value. Setting this to zero removes the field. Only valid if `lsmfMPTCanMutateTransferFee` was enabled when creating the `MPTokenIssuance` object. See [Transfer Fee Rules](#transfer-fee-rules). | -| `MutableFlags` | Number | UInt32 | No | Set or clear flags that were marked as mutable when creating the `MPTokenIssuance` object. See [MPTokenIssuanceSet Mutable Flags](#mptokenissuanceset-mutable-flags). | +| `MutableFlags` | Number | UInt32 | No | Enable MPT issuance flags that were declared mutable when creating the `MPTokenIssuance` object. See [MPTokenIssuanceSet Mutable Flags](#mptokenissuanceset-mutable-flags). | ### MPTokenIssuanceSet Mutable Flags -The following flags are stored in the `MutableFlags` field, which is separate from the `Flags` field of the `MPTokenIssuanceSet` transaction: +The following flags are stored in the `MutableFlags` field, which is separate from the `Flags` field of the `MPTokenIssuanceSet` transaction. All of these flags are one-way: each one only enables an MPT issuance flag that was declared mutable at creation. Once enabled, the underlying MPT issuance flag cannot be disabled by `MPTokenIssuanceSet`. | Flag Name | Hex Value | Decimal Value | Description | |:-------------------------- |:-------------|:--------------|:------------| -| `tmfMPTSetCanLock` | `0x00000001` | 1 | Enables the MPT's **Can Lock** flag, which allows the token to be locked both individually and globally. | -| `tmfMPTClearCanLock` | `0x00000002` | 2 | Disables the MPT's **Can Lock** flag, which prevents both individual and global locking of the token. | -| `tmfMPTSetRequireAuth` | `0x00000004` | 4 | Enables the MPT's **RequireAuth** flag, which requires individual holders to be authorized to hold the token. | -| `tmfMPTClearRequireAuth` | `0x00000008` | 8 | Disables the MPT's **RequireAuth** flag, which means holders don't need to be authorized to hold the token. | -| `tmfMPTSetCanEscrow` | `0x00000010` | 16 | Enables the MPT's **Can Escrow** flag, which allows holders to place balances into escrow. | -| `tmfMPTClearCanEscrow` | `0x00000020` | 32 | Disables the MPT's **Can Escrow** flag, which means holders can't place balances into escrow. | -| `tmfMPTSetCanTrade` | `0x00000040` | 64 | Enables the MPT's **Can Trade** flag, which allows holders to trade balances on the XRPL DEX. | -| `tmfMPTClearCanTrade` | `0x00000080` | 128 | Disables the MPT's **CanTrade** flag, which stops holders from trading balances on the XRPL DEX. | -| `tmfMPTSetCanTransfer` | `0x00000100` | 256 | Enables the MPT's **CanTransfer** flag, which allows tokens to be transferred to non-issuer accounts. | -| `tmfMPTClearCanTransfer` | `0x00000200` | 512 | Disables the MPT's **CanTransfer** flag, which means transfers to non-issuer accounts are not allowed. Note that when `CanTransfer` is disabled, the `TransferFee` field is automatically removed. | -| `tmfMPTSetCanClawback` | `0x00000400` | 1024 | Enables the MPT's **Can Clawback** flag, which allows the issuer to claw back tokens. | -| `tmfMPTClearCanClawback` | `0x00000800` | 2048 | Disables the MPT's **Can Clawback** flag, which means the token cannot be clawed back. | - -{% admonition type="info" name="Note" %} -You cannot enable and disable the same setting in one transaction. For example, using both the `tmfMPTSetCanLock` flag and the `tmfMPTClearCanLock` flag is invalid. +| `tmfMPTSetCanLock` | `0x00000001` | 1 | Enables the MPT's **Can Lock** flag, which allows the token to be locked both individually and globally. Once enabled, this flag cannot be disabled. | +| `tmfMPTSetRequireAuth` | `0x00000002` | 2 | Enables the MPT's **RequireAuth** flag, which requires individual holders to be authorized to hold the token. Once enabled, this flag cannot be disabled. | +| `tmfMPTSetCanEscrow` | `0x00000004` | 4 | Enables the MPT's **Can Escrow** flag, which allows holders to place balances into escrow. Once enabled, this flag cannot be disabled. | +| `tmfMPTSetCanTrade` | `0x00000008` | 8 | Enables the MPT's **Can Trade** flag, which allows holders to trade balances on the XRPL DEX. Once enabled, this flag cannot be disabled. | +| `tmfMPTSetCanTransfer` | `0x00000010` | 16 | Enables the MPT's **Can Transfer** flag, which allows tokens to be transferred to non-issuer accounts. Once enabled, this flag cannot be disabled. | +| `tmfMPTSetCanClawback` | `0x00000020` | 32 | Enables the MPT's **Can Clawback** flag, which allows the issuer to claw back tokens. Once enabled, this flag cannot be disabled. | + +{% admonition type="success" name="Tip" %} +Re-setting an MPT issuance flag that is already enabled is valid and has no additional effect. {% /admonition %} ### Transfer Fee Rules The ability to modify the `TransferFee` depends on two flags: -- `lsfMPTCanTransfer`: must already be enabled to allow any non-zero `TransferFee`. Note that this flag can be modified through `tmfMPTSetCanTransfer` or `tmfMPTClearCanTransfer` if `lsmfMPTCanMutateCanTransfer` is set. +- `lsfMPTCanTransfer`: must already be enabled to allow any non-zero `TransferFee`. Note that this flag can be enabled through `tmfMPTSetCanTransfer` if `lsmfMPTCanEnableCanTransfer` is set. Once enabled, it cannot be disabled. - `lsmfMPTCanMutateTransferFee`: must be enabled at creation of the MPT issuance to allow any modification of the `TransferFee` field. {% admonition type="info" name="Note" %} @@ -159,8 +154,8 @@ The following failure conditions have been added to the `MPTokenIssuanceSet` tra | `tecNO_PERMISSION` | The sender does not have permission to modify the specified field or flag. For example: | | `temDISABLED` | The `MutableFlags`, `MPTokenMetadata`, or `TransferFee` is present but the DynamicMPT amendment is not enabled. | | `temBAD_TRANSFER_FEE` | The `TransferFee` exceeds the maximum allowed value of 50,000. | -| `temINVALID_FLAG` | The `MutableFlags` field contains an invalid value, including `0`. You may also receive this error if both set and clear flags are specified for the same property (for example, both `tmfMPTSetCanLock` and `tmfMPTClearCanLock`). | -| `temMALFORMED` | The transaction is malformed. For example: | +| `temINVALID_FLAG` | The `MutableFlags` field contains an invalid value, including `0`. | +| `temMALFORMED` | The transaction is malformed. For example: | ## MPTokenIssuance Entry Changes @@ -168,7 +163,7 @@ MPTokenIssuance ledger entries can include the following new field: | Field | JSON Type | [Internal Type][] | Required? | Description | |:-----------------|:--------------------|:------------------|:----------|-------------| -| `MutableFlags` | Number | UInt32 | No | Indicates which fields or flags of this token issuance can be modified after creation. See [MPTokenIssuance Mutable Flags](#mptokenissuance-mutable-flags). | +| `MutableFlags` | Number | UInt32 | No | Indicates which fields of this token issuance can be modified after creation, and which MPT issuance flags can be enabled after creation. See [MPTokenIssuance Mutable Flags](#mptokenissuance-mutable-flags). | ### MPTokenIssuance Mutable Flags @@ -176,12 +171,12 @@ The following flags are stored in the `MutableFlags` field, which is separate fr | Flag Name | Hex Value | Decimal Value | Description | |:--------------------------------- |:-------------|:--------------|:------------| -| `lsmfMPTCanMutateCanLock` | `0x00000002` | 2 | Indicates the **Can Lock** flag can be changed. | -| `lsmfMPTCanMutateRequireAuth` | `0x00000004` | 4 | Indicates the **Require Auth** flag can be changed. | -| `lsmfMPTCanMutateCanEscrow` | `0x00000008` | 8 | Indicates the **Can Escrow** flag can be changed. | -| `lsmfMPTCanMutateCanTrade` | `0x00000010` | 16 | Indicates the **Can Trade** flag can be changed. | -| `lsmfMPTCanMutateCanTransfer` | `0x00000020` | 32 | Indicates the **Can Transfer** flag can be changed. | -| `lsmfMPTCanMutateCanClawback` | `0x00000040` | 64 | Indicates the **Can Clawback** flag can be changed. | +| `lsmfMPTCanEnableCanLock` | `0x00000002` | 2 | Allows the **Can Lock** flag to be enabled after issuance. | +| `lsmfMPTCanEnableRequireAuth` | `0x00000004` | 4 | Allows the **Require Auth** flag to be enabled after issuance. | +| `lsmfMPTCanEnableCanEscrow` | `0x00000008` | 8 | Allows the **Can Escrow** flag to be enabled after issuance. | +| `lsmfMPTCanEnableCanTrade` | `0x00000010` | 16 | Allows the **Can Trade** flag to be enabled after issuance. | +| `lsmfMPTCanEnableCanTransfer` | `0x00000020` | 32 | Allows the **Can Transfer** flag to be enabled after issuance. | +| `lsmfMPTCanEnableCanClawback` | `0x00000040` | 64 | Allows the **Can Clawback** flag to be enabled after issuance. | | `lsmfMPTCanMutateMetadata` | `0x00010000` | 65536 | Allows the `MPTokenMetadata` field to be modified. | | `lsmfMPTCanMutateTransferFee` | `0x00020000` | 131072 | Allows the `TransferFee` field to be modified. |