xls: 90 title: Permissioned Domains for MPTs description: Allow MPT issuers to authorize holders through credentials accepted by a permissioned domain. implementation: https://github.com/XRPLF/rippled/pull/5509 author: Vito Tumascategory: Amendment status: Draft proposal-from: https://github.com/XRPLF/XRPL-Standards/discussions/267 requires: [XLS-33](./XLS-0033-multi-purpose-tokens.html), [XLS-65](./XLS-0065-single-asset-vault.html), [XLS-80](./XLS-0080-permissioned-domains.html) created: 2025-02-18 updated: 2026-09-07
Permissioned Domains for MPTs¶
1. Abstract¶
An issuer can require explicit authorization for accounts to hold a Multi-Purpose Token (MPT). This proposal additionally lets the issuer associate the issuance with an XLS-80 Permissioned Domain. An account is then authorized if it has credentials accepted by the domain or has explicit authorization from the MPT issuer.
2. Motivation¶
Authorizing every holder individually requires the MPT issuer to submit and maintain one authorization per account. A permissioned domain lets the issuer define accepted credential issuer-and-type pairs once and lets accounts prove eligibility with accepted credentials.
3. Specification¶
The DomainID functionality described by this specification is available only when both the SingleAssetVault and PermissionedDomains amendments are enabled. Before then, a transaction that includes DomainID in MPTokenIssuanceCreate or MPTokenIssuanceSet fails with temDISABLED.
An MPTokenIssuance with a DomainID must also have lsfMPTRequireAuth set. When authorization for such an issuance is checked, an account is authorized if any of the following is true:
- The account is the MPT issuer.
- The account has a valid, accepted credential matching the referenced permissioned domain.
- The account has an
MPTokenobject withlsfMPTAuthorizedset.
Permissioned-domain and explicit issuer authorization therefore form a union. Authorization is evaluated against the current MPTokenIssuance.DomainID; no domain-related flag is added to individual MPToken objects.
3.1. Ledger Entry: MPTokenIssuance¶
3.1.1. Fields¶
This proposal adds the optional DomainID field to the existing MPTokenIssuance ledger entry. Unchanged fields are included below so that the example is self-contained.
| Field Name | Constant | Required | Internal Type | Default Value | Description |
|---|---|---|---|---|---|
LedgerEntryType |
Yes | Yes | UINT16 |
0x007e |
Identifies this as an MPTokenIssuance object. |
Flags |
No | Yes | UINT32 |
0 |
A set of flags controlling the issuance. |
Issuer |
No | Yes | ACCOUNT |
N/A | The account that issued the MPT. |
Sequence |
No | Yes | UINT32 |
N/A | The issuer sequence used to derive the issuance ID. |
OwnerNode |
No | Yes | UINT64 |
N/A | A hint to the issuance's page in the issuer's owner directory. |
OutstandingAmount |
No | Yes | UINT64 |
0 |
The total amount of this MPT currently held by non-issuer accounts. |
PreviousTxnID |
No | Yes | HASH256 |
N/A | The transaction that most recently modified this entry. |
PreviousTxnLgrSeq |
No | Yes | UINT32 |
N/A | The ledger index of the most recent transaction that modified this entry. |
DomainID |
No | No | HASH256 |
N/A | The associated PermissionedDomain object ID. |
3.1.1.1. DomainID¶
If present, DomainID identifies the permissioned domain used to authorize MPT holders. The field is mutable and can be added, replaced, or removed with MPTokenIssuanceSet.
3.1.2. Flags¶
This proposal does not add a ledger-entry flag. An issuance with DomainID uses the existing lsfMPTRequireAuth flag (0x00000004).
3.1.3. Invariants¶
- If
<MPTokenIssuance>.DomainIDis present,<MPTokenIssuance>.Flags & lsfMPTRequireAuth != 0.
3.1.4. Example JSON¶
{
"LedgerEntryType": "MPTokenIssuance",
"Flags": 4,
"Issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Sequence": 42,
"OwnerNode": "0000000000000000",
"OutstandingAmount": "0",
"PreviousTxnID": "C4B1A16F1DF4E2B3D5A8D061C2A30DAB8E84D1B0A7B5F6F4DE2EA1D2E1C113A0",
"PreviousTxnLgrSeq": 1000000,
"DomainID": "3B61A239626565A3FBEFC32863AFBF1AD3325BD1669C2C9BC92954197842B564"
}
3.2. Transaction: MPTokenIssuanceCreate¶
3.2.1. Fields¶
This proposal adds DomainID to the existing transaction. Other fields shown are used by the example.
| Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
|---|---|---|---|---|---|
TransactionType |
Yes | string |
UINT16 |
MPTokenIssuanceCreate |
Identifies the transaction. |
Account |
Yes | string |
ACCOUNT |
N/A | The MPT issuer. |
Flags |
No | number |
UINT32 |
0 |
Must include tfMPTRequireAuth when DomainID is set. |
Fee |
No | string |
AMOUNT |
N/A | The transaction fee in drops. |
DomainID |
No | string |
HASH256 |
N/A | The ID of the permissioned domain used for authorization. |
3.2.2. Failure Conditions¶
3.2.2.1. Data Verification¶
DomainIDis present but eitherSingleAssetVaultorPermissionedDomainsis disabled. (temDISABLED)DomainIDis zero. (temMALFORMED)DomainIDis present buttfMPTRequireAuthis not set. (temMALFORMED)
MPTokenIssuanceCreate does not require the referenced permissioned domain to exist when the issuance is created.
3.2.2.2. Protocol-Level Failures¶
This proposal adds no protocol-level failure conditions to MPTokenIssuanceCreate.
3.2.3. State Changes¶
On Success (tesSUCCESS):
- Create the
MPTokenIssuancewith itsDomainIDset to the transaction'sDomainID, if provided.
3.2.4. Example JSON¶
{
"TransactionType": "MPTokenIssuanceCreate",
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Flags": 4,
"Fee": "10",
"DomainID": "3B61A239626565A3FBEFC32863AFBF1AD3325BD1669C2C9BC92954197842B564"
}
3.3. Transaction: MPTokenIssuanceSet¶
3.3.1. Fields¶
This proposal adds DomainID to the existing transaction. Other fields shown are used by the example.
| Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
|---|---|---|---|---|---|
TransactionType |
Yes | string |
UINT16 |
MPTokenIssuanceSet |
Identifies the transaction. |
Account |
Yes | string |
ACCOUNT |
N/A | The MPT issuer. |
MPTokenIssuanceID |
Yes | string |
UINT192 |
N/A | Identifies the issuance to modify. |
Fee |
No | string |
AMOUNT |
N/A | The transaction fee in drops. |
DomainID |
No | string |
HASH256 |
N/A | A domain ID to set, or all zeroes to remove the current DomainID field. |
3.3.2. Failure Conditions¶
3.3.2.1. Data Verification¶
DomainIDis present but eitherSingleAssetVaultorPermissionedDomainsis disabled. (temDISABLED)- Both
DomainIDandHolderare present. (temMALFORMED)
3.3.2.2. Protocol-Level Failures¶
- The
MPTokenIssuancedoes not exist. (tecOBJECT_NOT_FOUND) Accountis not the issuance'sIssuer. (tecNO_PERMISSION)- The issuance does not have
lsfMPTRequireAuthset. (tecNO_PERMISSION) DomainIDis non-zero and the referencedPermissionedDomaindoes not exist. (tecOBJECT_NOT_FOUND)
3.3.3. State Changes¶
On Success (tesSUCCESS):
- If
DomainIDis non-zero, add or replaceMPTokenIssuance.DomainID. - If
DomainIDis zero, removeMPTokenIssuance.DomainIDif it is present.
3.3.4. Example JSON¶
{
"TransactionType": "MPTokenIssuanceSet",
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"MPTokenIssuanceID": "0000002A9F14C21D846D8D06E7B3C3275A0C288442D6E5C5",
"Fee": "10",
"DomainID": "3B61A239626565A3FBEFC32863AFBF1AD3325BD1669C2C9BC92954197842B564"
}
3.4. Transaction: Payment¶
3.4.1. Fields¶
This proposal adds no fields to Payment. The relevant existing fields are shown for the example.
| Field Name | Required? | JSON Type | Internal Type | Default Value | Description |
|---|---|---|---|---|---|
TransactionType |
Yes | string |
UINT16 |
Payment |
Identifies the transaction. |
Account |
Yes | string |
ACCOUNT |
N/A | The sending account. |
Destination |
Yes | string |
ACCOUNT |
N/A | The receiving account. |
Amount |
Yes | object |
AMOUNT |
N/A | The MPT amount to deliver. |
Fee |
No | string |
AMOUNT |
N/A | The transaction fee in drops. |
3.4.2. Failure Conditions¶
3.4.2.1. Data Verification¶
This proposal adds no data-verification failures to Payment.
3.4.2.2. Protocol-Level Failures¶
For an MPT whose issuance has DomainID, authorization is checked for both Account and Destination, except that the MPT issuer is always authorized.
- An account has neither a valid credential accepted by the domain nor an
MPTokenwithlsfMPTAuthorizedset. (tecNO_AUTH, ortecEXPIREDif its matching credentials are expired) - The referenced
PermissionedDomaindoes not exist and the account does not have anMPTokenwithlsfMPTAuthorizedset. (tecOBJECT_NOT_FOUND)
3.4.3. State Changes¶
This proposal adds no state changes to Payment.
3.4.4. Example JSON¶
{
"TransactionType": "Payment",
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Destination": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
"Amount": {
"mpt_issuance_id": "0000002A9F14C21D846D8D06E7B3C3275A0C288442D6E5C5",
"value": "100"
},
"Fee": "10"
}
4. Rationale¶
A permissioned domain complements explicit per-account authorization: credential policy can be maintained in one domain while the issuer can still authorize exceptional accounts individually. Evaluating the current issuance-level DomainID at authorization time avoids adding a redundant domain flag to every MPToken object and lets the issuer change or remove a domain without rewriting all holder objects.
The alternative is to use only MPTokenAuthorize. That provides finer-grained control but requires an issuer transaction for every account and does not automatically react to credential acceptance, expiration, or deletion.
5. Backwards Compatibility¶
The change is amendment-gated. Before both required amendments are active, the new transaction field is rejected. Existing issuances without DomainID retain their prior authorization behavior.
Changing or removing an issuance's domain can immediately change which accounts may transfer or receive the MPT. Existing balances and MPToken objects are not rewritten.
6. Test Plan¶
Implementation tests cover amendment gating, zero and missing domain identifiers, the lsfMPTRequireAuth requirement, adding, replacing, and removing a domain, issuer authorization, explicit authorization fallback, credential-based payments, and credential deletion.
7. Reference Implementation¶
8. Security Considerations¶
Issuers must treat a DomainID update as an access-control policy change. Replacing or removing it takes effect on subsequent authorization checks and may immediately prevent existing holders from transferring or receiving the MPT.
Credential expiration or deletion removes domain-based authorization. Explicit authorization is independent: an account whose MPToken has lsfMPTAuthorized set remains authorized even if its credential is invalid or the referenced domain has been deleted.
MPTokenIssuanceCreate does not verify that a non-zero DomainID identifies an existing object. An issuer that supplies an incorrect or not-yet-created domain can make domain-based authorization fail until the issuer uses MPTokenIssuanceSet to select an existing domain or remove the field. MPTokenIssuanceSet verifies non-zero domain identifiers before applying them.