XRP Ledger Standards

XLS-0082
Draft
  xls: 82
  title: MPT Integration into DEX
  description: Adds Multi-Purpose Token (MPT) support for XRPL DEX
  author: Gregory Tsipenyuk 
  proposal-from: https://github.com/XRPLF/XRPL-Standards/discussions/231
  status: Draft
  category: Amendment
  requires: XLS-33, XLS-30
  created: 2024-09-19
  updated: 2026-02-10

MPT Integration into DEX

Abstract

This proposal introduces a new amendment MPTVersion2 as an extension to XLS-33 Multi-Purpose Tokens. MPTVersion2 amendment enables Multi-purpose token (MPT) support on the XRPL DEX, including offers, cross-currency payments, checks, and AMM.

1. Overview

The integration of Multi-Purpose Tokens (MPT) into the XRP Ledger Decentralized Exchange (DEX) focuses on extending the functional reach of existing trading mechanisms without introducing new on-ledger objects or modifying core state structures. By leveraging the existing ledger primitives, this update enables standard DEX transactions to natively support MPTs as a valid asset class. This specification outlines the necessary schema updates for transaction requests and provides comprehensive JSON examples to illustrate the interoperability between MPTs, XRP, and standard IOUs. Furthermore, this document details the expanded set of failure scenarios and transaction result codes specific to MPT trading, ensuring robust error handling for cross-asset liquidity paths and order-matching logic. For a comprehensive description of all transactions refer to XRPL documentation

Current transactions, which interact with XRPL DEX are:

  • AMMCreate: Create a new Automated Market Maker (AMM) instance for trading a pair of assets (fungible tokens or XRP).
  • AMMDeposit: Deposit funds into an AMM instance and receive the AMM's liquidity provider tokens (LP Tokens) in exchange.
  • AMMWithdraw: Withdraw assets from an AMM instance by returning the AMM's liquidity provider tokens (LP Tokens).
  • AMMClawback: Enable token issuers to claw back tokens from wallets that have deposited into AMM pools.
  • AMMDelete: Delete an empty AMM instance that could not be fully deleted automatically.
  • CheckCreate: Create a Check object in the ledger, which is a deferred payment that can be cashed by its intended destination.
  • CheckCash: Attempts to redeem a Check object in the ledger to receive up to the amount authorized by the corresponding CheckCreate transaction.
  • OfferCreate: An OfferCreate transaction places an Offer in the decentralized exchange.
  • Payment: A Payment transaction represents a transfer of value from one account to another.

MPT supports all of the above transactions. MPT can be combined with IOU and XRP tokens in the transactions. For instance, a Payment could be a cross-token payment from MPT token to IOU token; AMM can be created for XRP and MPT token-pair; an order book offer can be created to buy some MPT token and to sell another MPT token. MPT doesn't modify the transactions fields, flags, and functionality. However, the JSON of the MPT amount field differs from the JSON of the IOU amount field. Instead of currency and issuer, MPT is identified by mpt_issuance_id. MPT amount value is INT or UINT, which must be less or equal to $63^2 - 1$. Below are the examples of JSON MPT amount and JSON MPT asset:

{
  "Amount": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308",
    "value": "110"
  },
  "Asset": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308"
  }
}

Any transaction with MPT Amount or Asset have to use JSON format as described above. For any transaction, which uses MPT token, the token has to be created first by an issuer with MPTokenIssuanceCreate transaction and in most cases, except for AMMCreate, AMMWithdraw, AMMClawback, CheckCash, and OfferCreate, the token has to be authorized by the holder account with MPTokenAuthorize transaction as described in XLS-33d. MPTokenAuthorize creates MPToken object, owned by a holder account. In addition, MPTokenIssuanceCreate must have the following flags set:

  • lsfMPTCanTrade, in order for individual holders to trade their balances using the XRP Ledger DEX or AMM.
  • lsfMPTCanTransfer, in order for the tokens held by non-issuers to be transferred to other accounts.

2. Transaction: AMMCreate

Any token or both tokens in AMMCreate transaction can be MPT. I.e., in addition to the current combination of XRP/IOU and IOU/IOU token pair, AMMCreate can have XRP/MPT, IOU/MPT, and MPT/MPT token pair. Each MPT in the pair is identified by mpt_issuance_id. If both tokens are MPT then each token must have a unique mpt_issuance_id. In case of AMMCreate the token pair is identified by Amount and Amount2.

2.1. Fields

We do not introduce new fields.

2.2. Failure Conditions

We extend the AMMCreate with the following failure conditions, where MPTokenIssuance refers to the ledger object defining the specific MPT type identified in the transaction's Amount or Amount2 fields; MPToken refers to the ledger object representing the specific MPT balance of the account executing the transaction (if that account is not the issuer); and flags refer to those set on the MPTokenIssuance object unless explicitly stated as being set on the individual MPToken object:

  1. Amount or Amount2 hold MPT and featureMPTokensV2 amendment is not enabled, fail with temDISABLED.
  2. MPTokenIssuance object doesn't exist, fail with tecOBJECT_NOT_FOUND.
  3. MPToken object doesn't exist and AMM creator is not the issuer of MPT, fail with tecNO_AUTH.
  4. MPTLock flag is set on MPTokenIssuance, fail for issuer and holder with tecFROZEN.
  5. MPTLock flag is set on MPToken, fail for holder with tecFROZEN.
  6. MPTRequireAuth flag is set and AMM creator is not authorized, fail with tecNO_AUTH.
  7. MPTCanTransfer flag is not set and AMM creator is not the issuer of MPT, with tecNO_PERMISSION.
  8. MPTCanTrade flag is not set, fail with tecNO_PERMISSION.

2.3. State Changes

On success AMMCreate creates and authorizes an MPToken object for each MPT token for the AMM pseudo-account.

2.4. MPToken Ledger Object

MPToken object is created for each asset representing MPToken as follows:

Field Name JSON Type Internal Type Description
Account String ACCOUNTID (Required) AMM Pseudo-account.
MPTAmount String UINT64 (Required) AMM pool amount.
Flags String UINT32 (Required) lsfMPTAMM(0x00000004). If MPTokenIssuance requires explicit authorization then also lsfMPTAuthorized(0x00000002).

2.5. Example JSON

{
  "Account": "rffMEZLzDQPNU6VYbWNkgQBtMz6gCYnMAG",
  "Amount": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308",
    "value": "1000"
  },
  "Amount2": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308",
    "value": "1000"
  },
  "Fee": "2000000",
  "Flags": 0,
  "TradingFee": "0",
  "TransactionType": "AMMCreate"
}

3. Transaction: AMMDeposit

AMMDeposit is identified by Asset and Asset2 with the token type corresponding to Amount and Amount2 of AMMCreate. Asset and Asset2 are STIssue type, which represents a token by currency and issuer. If STIssue type represents MPT then mpt_issuance_id must be used instead. AMMDeposit has optional fields Amount and Amount2, which if present must match the type of Asset and Asset2 respectively.

3.1. Fields

We do not introduce new fields.

3.2. Failure Conditions

We extend the AMMDeposit with the following failure conditions, where MPTokenIssuance refers to the ledger object defining the specific MPT type identified in the transaction's Amount or Amount2 fields; MPToken refers to the ledger object representing the specific MPT balance of the account executing the transaction (if that account is not the issuer); and flags refer to those set on the MPTokenIssuance object unless explicitly stated as being set on the individual MPToken object:

  1. Asset, Asset2, Amount, or Amount2 hold MPT and featureMPTokensV2 amendment is not enabled, fail with temDISABLED.
  2. MPTokenIssuance object doesn't exist, fail with terNO_AMM.
  3. MPToken object doesn't exist and the account is not the issuer of MPT, fail with tecNO_AUTH.
  4. MPTLock flag is set on MPTokenIssuance, fail for issuer and holder with tecFROZEN.
  5. MPTLock flag is set on MPToken, fail for holder with tecFROZEN.
  6. MPTRequireAuth flag is set and the account is not authorized, fail with tecNO_AUTH.
  7. MPTCanTransfer flag is not set and the account is not the issuer of MPT, fail with tecNO_PERMISSION.
  8. MPTCanTrade flag is not set, fail with tecNO_PERMISSION.

3.3. State Changes

We do not introduce new state changes.

3.4. Example JSON

{
  "Account": "rffMEZLzDQPNU6VYbWNkgQBtMz6gCYnMAG",
  "Amount": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308",
    "value": "100"
  },
  "Amount2": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308",
    "value": "100"
  },
  "Asset": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308"
  },
  "Asset2": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308"
  },
  "Fee": "10",
  "Flags": 524288,
  "TransactionType": "AMMDeposit"
}

4. Transaction: AMMWithdraw

AMMWithdraw is identified by Asset and Asset2 with the token type corresponding to Amount and Amount2 of AMMCreate. Asset and Asset2 are STIssue type, which represents a token by currency and issuer. If STIssue type represents MPT then mpt_issuance_id must be used instead. AMMWithdraw has optional fields Amount and Amount2, which if present must match the type of Asset and Asset2 respectively.

4.1. Fields

We do not introduce new fields.

4.2. Failure Conditions

We extend the AMMWithdraw with the following failure conditions, where MPTokenIssuance refers to the ledger object defining the specific MPT type identified in the transaction's Amount or Amount2 fields; MPToken refers to the ledger object representing the specific MPT balance of the account executing the transaction (if that account is not the issuer); and flags refer to those set on the MPTokenIssuance object unless explicitly stated as being set on the individual MPToken object:

  1. Asset, Asset2, Amount, or Amount2 hold MPT and featureMPTokensV2 amendment is not enabled, fail with temDISABLED.
  2. MPTokenIssuance object doesn't exist, fail with terNO_AMM.
  3. MPTLock flag is set on MPTokenIssuance, fail for issuer and holder with tecFROZEN. Can withdraw another asset.
  4. MPTLock flag is set on MPToken, fail for holder with tecFROZEN. Can withdraw another asset.
  5. MPTRequireAuth flag is set and the account is not authorized, fail with tecNO_AUTH. Can withdraw another asset.
  6. MPTCanTransfer flag is not set and the account is not the issuer of MPT, fail with tecNO_PERMISSION. Can withdraw another asset.
  7. MPTCanTrade flag is not set, fail with tecNO_PERMISSION.

4.3. State Changes

On success AMMWithdraw creates and authorizes MPToken object if Liquidity Provider doesn't own MPToken object for a withdrawn token.

4.4. MPToken Ledger Object

MPToken object is created as follows:

Field Name JSON Type Internal Type Description
Account String ACCOUNTID (Required) Liquidity Provider account.
MPTAmount String UINT64 (Required) Withdrawn amount.
Flags String UINT32 (Required) 0.

4.5. Example JSON

{
  "Account": "rffMEZLzDQPNU6VYbWNkgQBtMz6gCYnMAG",
  "Amount": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308",
    "value": "100"
  },
  "Amount2": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308",
    "value": "100"
  },
  "Asset": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308"
  },
  "Asset2": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308"
  },
  "Fee": "10",
  "Flags": 1048576,
  "TransactionType": "AMMWithdraw"
}

5. Transaction: AMMDelete

AMMDelete is identified by Asset and Asset2 with the token type corresponding to Amount and Amount2 of AMMCreate. Asset and Asset2 are STIssue type, which represents a token by currency and issuer. If STIssue type represents MPT then mpt_issuance_id must be used instead.

5.1. Fields

We do not introduce new fields.

5.2. Failure Conditions

We extend the AMMDelete transaction with the following failure conditions:

  • Asset or Asset2 hold MPT and featureMPTokensV2 amendment is not enabled, fail with temDISABLED.

5.3. State Changes

We do not introduce new state changes.

5.4. Example JSON

{
  "Account": "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
  "Asset": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308"
  },
  "Asset2": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308"
  },
  "Fee": "10",
  "Flags": 0,
  "Sequence": 9,
  "TransactionType": "AMMDelete"
}

6. Transaction: AMMClawback

AMMClawback is identified by Asset and Asset2 with the token type corresponding to Amount and Amount2 of AMMCreate. Asset and Asset2 are STIssue type, which represents a token by currency and issuer. If STIssue type represents MPT then mpt_issuance_id must be used instead. AMMClawback has optional field Amount, which if present must match the type of Asset.

6.1. Fields

We do not introduce new fields.

6.2. Failure Conditions

We extend the AMMClawback transaction with the following failure conditions, where MPTokenIssuance refers to the ledger object defining the specific MPT type identified in the transaction's Amount:

  1. Asset, Asset2, or Amount hold MPT and featureMPTokensV2 amendment is not enabled, fail with temDISABLED.
  2. MPTokenIssuance object doesn't exist, fail with terNO_AMM.
  3. lsfMPTCanClawback flag is not set on MPTokenIssuance, fail with tecNO_PERMISSION.

6.3. State Changes

On success AMMClawback creates and authorizes MPToken object if Liquidity Provider doesn't own MPToken object for a clawbacked token.

6.4. MPToken Ledger Object

MPToken object is created as follows:

Field Name JSON Type Internal Type Description
Account String ACCOUNTID (Required) Liquidity Provider account.
MPTAmount String UINT64 (Required) Clawbacked amount.
Flags String UINT32 (Required) 0.

6.5. Example JSON

{
  "TransactionType": "AMMClawback",
  "Account": "rPdYxU9dNkbzC5Y2h4jLbVJ3rMRrk7WVRL",
  "Holder": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
  "Asset": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308"
  },
  "Asset2": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308"
  },
  "Amount": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308",
    "value": "1000"
  },
  "Flags": 1
}

7. Transaction: CheckCreate

If SendMax field is MPT then it is identified by mpt_issuance_id.

7.1. Fields

We do not introduce new fields.

7.2. Failure Conditions

We extend the CheckCreate with the following failure conditions, where MPTokenIssuance refers to the ledger object defining the specific MPT type identified in the transaction's SendMax; and flags refer to those set on the MPTokenIssuance object unless explicitly stated as being set on the individual MPToken object:

  1. SendMax holds MPT and featureMPTokensV2 amendment is not enabled, fail with temDISABLED.
  2. MPTokenIssuance object doesn't exist, fail with tecOBJECT_NO_FOUND.
  3. MPTLock flag is set on MPTokenIssuance, fail for issuer and holder with tecFROZEN.
  4. MPTLock flag is set on MPToken, fail for holder as source and destination with tecFROZEN.
  5. MPTCanTrade flag is not set, fail with tecNO_PERMISSION.

7.3. State Changes

We do not introduce new state changes.

7.4. Example JSON

{
  "TransactionType": "CheckCreate",
  "Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
  "Destination": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
  "SendMax": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308",
    "value": "100"
  },
  "Expiration": 570113521,
  "InvoiceID": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B",
  "DestinationTag": 1,
  "Fee": "12"
}

8. Transaction: CheckCash

If Amount or DeliverMin fields are MPT then they are identified by mpt_issuance_id. mpt_issuance_id of DeliverMin and Amount must match.

8.1. Fields

We do not introduce new fields.

8.2. Failure Conditions

We extend the CheckCash with the following failure conditions, where MPTokenIssuance refers to the ledger object defining the specific MPT type identified in the transaction's Amount or DeliverMin fields; MPToken refers to the ledger object representing the specific MPT balance of the account executing the transaction (if that account is not the issuer); and flags refer to those set on the MPTokenIssuance object unless explicitly stated as being set on the individual MPToken object:

  1. MPTokenIssuance object doesn't exist, fail with tecNO_ENTRY.
  2. MPToken object doesn't exist and the account is not the issuer of MPT, fail with tecPATH_PARTIAL.
  3. MPTLock flag is set on MPTokenIssuance, fail with tecPATH_PARTIAL if source and destination are holders. Fail with tecFROZEN if source is issuer and destination is holder.
  4. MPTLock flag is set on MPToken, fail for issuer and holder as destination with tecPATH_PARTIAL. Fail for holder as source with tecFROZEN.
  5. MPTRequireAuth flag is set and the account is not authorized, fail with tecNO_AUTH.
  6. MPTCanTransfer flag is not set and the account is not the issuer of MPT, fail with tecPATH_PARTIAL.
  7. MPTCanTrade flag is not set, fail with tecNO_PERMISSION.

8.3. State Changes

On success CheckCash creates and authorizes MPToken object if the account doesn't own MPToken object.

8.4. MPToken Ledger Object

MPToken object is created as follows:

Field Name JSON Type Internal Type Description
Account String ACCOUNTID (Required) Destination account.
MPTAmount String UINT64 (Required) Cashed amount.
Flags String UINT32 (Required) 0.

8.5. Example JSON

{
  "Account": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
  "TransactionType": "CheckCash",
  "Amount": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308",
    "value": "100"
  },
  "CheckID": "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334",
  "Fee": "12"
}

9. Transaction: OfferCreate

OfferCreate can have any token combination of TakerGets and TakerPays. I.e., in addition to the current combination of XRP/IOU and IOU/IOU tokens, OfferCreate can have XRP/MPT, IOU/MPT, and MPT/MPT tokens. If TakerPays or TakerGets fields are MPT then they are identified by mpt_issuance_id.

To ensure asset transfer consistency on offer crossing, the following logic is applied to the offer's assets transfer between the accounts.

TakerGets asset is transferred if:

  • MPTCanTransfer is set
  • The offer's owner is the issuer
  • The asset is the delivered asset and the destination account is the issuer

TakerPays is transferred if:

  • MPTCanTransfer is set
  • The offer's owner is the issuer
  • The asset is the source asset and the source account is the issuer
  • The offer's TakerPays and TakerGets are not the source and destination assets

MPT tokens are not adjusted for TickSize in the offers.

9.1. Fields

We do not introduce new fields.

9.2. Failure Conditions

We extend the OfferCreate with the following failure conditions, where MPTokenIssuance refers to the ledger object defining the specific MPT type identified in the transaction's TakerPays or TakerGets fields; MPToken refers to the ledger object representing the specific MPT balance of the account executing the transaction (if that account is not the issuer); and flags refer to those set on the MPTokenIssuance object unless explicitly stated as being set on the individual MPToken object:

  1. MPTokenIssuance object doesn't exist, fail with tecOBJECT_NOT_FOUND for TakerPays and tecUNFUNDED_OFFER for TakerGets.
  2. MPToken object doesn't exist and the account is not the issuer of MPT, fail with tecUNFUNDED_OFFER for TakerGets.
  3. MPTLock flag is set and the account is not the issuer of MPT, fail with tecUNFUNDED_OFFER for TakerGets. Create but not cross the offer for TakerPays.
  4. MPTRequireAuth flag is set and the account is not authorized, fail with tecUNFUNDED_OFFER.
  5. MPTCanTransfer flag is not set and the account is not the issuer of MPT. OfferCreate succeeds but doesn't cross other offers owned by holders. It crosses offers owned by an issuer. If MPTCanTransfer is cleared after an offer is created then this offer is removed from the order book on offer crossing or cross-currency payment.
  6. MPTCanTrade flag is not set, fail with tecNO_PERMISSION. If MPTCanTrade is cleared after an offer is created then this offer is removed from the order book on offer crossing or cross-currency payment.

9.3. State Changes

On success OfferCreate creates and authorizes MPToken object for the offer's owner account if the offer is consumed, the offer's owner is not MPToken issuer, and MPToken object doesn't exist for TakerPays's mpt_issuance_id.

9.4. MPToken Ledger Object

MPToken object is created as follows:

Field Name JSON Type Internal Type Description
Account String ACCOUNTID (Required) Offer's owner account.
MPTAmount String UINT64 (Required) Buy amount.
Flags String UINT32 (Required) 0.

9.5. Example JSON

{
  "Account": "rMTysmc799PzTvK228jNaua6w3b6VgYUjw",
  "Fee": "10",
  "Flags": 0,
  "TakerGets": {
    "mpt_issuance_id": "00000003430427B80BD2D09D36B70B969E12801065F22308",
    "value": "100"
  },
  "TakerPays": {
    "mpt_issuance_id": "00000002430427B80BD2D09D36B70B969E12801065F22308",
    "value": "100"
  },
  "TransactionType": "OfferCreate"
}

10. Transaction: Payment

Payment can have any cross-token payment combination. I.e., in addition to the current combination of XRP/IOU and IOU/IOU cross-token payment, Payment can have XRP/MPT, IOU/MPT, and MPT/MPT cross-token payment. MPT can be used to specify Paths, in which case mpt_issuance_id should be used instead of currency and issuer as shown in the JSON example below. MPT doesn't support payment rippling. mpt_issuance_id identifies a unique MPT. It's impossible to reference the same MPT with different issuer. If Amount, DeliverMax, DeliverMin, or SendMax fields are MPT then they are identified by mpt_issuance_id.

10.1. Fields

We do not introduce new fields.

10.2. Failure Conditions

We extend the Payment with the following failure conditions, where MPTokenIssuance refers to the ledger object defining the specific MPT type identified in the transaction's Amount or SendMax fields; MPToken refers to the ledger object representing the specific MPT balance of the account executing the transaction (if that account is not the issuer); and flags refer to those set on the MPTokenIssuance object unless explicitly stated as being set on the individual MPToken object:

  1. MPTokenIssuance object doesn't exist, fail with tecOBJECT_NO_FOUND.
  2. MPToken object doesn't exist and the account is not the issuer of MPT, fail with tecNO_AUTH.
  3. MPTLock flag is set on MPTokenIssuance, fail with tecPATH_DRY.
  4. MPTLock flag is set on MPToken, fail with tecPATH_DRY.
  5. MPTRequireAuth flag is set and the account is not authorized. Any transfer between unauthorized accounts fail with tecNO_AUTH.
  6. MPTCanTransfer flag is not set. Any transfer between unauthorized accounts fail with tecPATH_PARTIAL.
  7. MPTCanTrade is not set, fail with tecPATH_DRY.

10.3 State Changes

We do not introduce new state changes.

10.4. Example JSON

{
  "Account": "rJ85Mok8YRNxSo7NnxKGrPuk29uAeZQqwZ",
  "DeliverMax": {
    "mpt_issuance_id": "00000010A407AF5856CCF3C42619DAA925813FC955C72983",
    "value": "100"
  },
  "DeliverMin": {
    "mpt_issuance_id": "00000010A407AF5856CCF3C42619DAA925813FC955C72983",
    "value": "90"
  },
  "Destination": "rHKBGB4vhnnVFmfrj4sUx3F9riz2CiHgCK",
  "Fee": "10",
  "Flags": 131072,
  "Paths": [
    [
      {
        "mpt_issuance_id": "00000004A407AF5856CCF3C42619DAA925813FC955C72983"
      },
      {
        "mpt_issuance_id": "0000000AA407AF5856CCF3C42619DAA925813FC955C72983"
      },
      {
        "mpt_issuance_id": "00000010A407AF5856CCF3C42619DAA925813FC955C72983"
      }
    ]
  ],
  "SendMax": "100000000"
}

11. RPC: path_find

11.1. Request Fields

We do not introduce new fields.

mpt_issuance_id subfield replaces currency and issuer subfields in MPT amount fields.

11.2 Response Fields

We do not introduce new fields.

mpt_issuance_id subfield replaces currency and issuer subfields in MPT amount fields, and currency subfield in paths_computed field.

11.3 Example Request

{
  "command": "path_find",
  "subcommand": "create",
  "destination_account": "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
  "destination_amount": {
    "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
    "value": "-1"
  },
  "send_max": "100000000000000",
  "source_account": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn"
}

11.4 Example Response

{
  "alternatives": [
    {
      "destination_amount": {
        "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
        "value": "100"
      },
      "paths_canonical": [],
      "paths_computed": [
        [
          {
            "issuer": "r9QxhA9RghPZBbUchA9HkrmLKaWvkLXU29",
            "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
            "type": 96
          }
        ]
      ],
      "source_amount": "100000000"
    }
  ],
  "destination_account": "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
  "destination_amount": {
    "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
    "value": "-1"
  },
  "destination_currencies": [
    "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
    "XRP"
  ],
  "full_reply": true,
  "ledger_current_index": 8,
  "source_account": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
  "validated": false
}

11.5. Failure Conditions

There is no new failure conditions.

12. RPC: ripple_path_find

12.1. Request Fields

We do not introduce new fields.

mpt_issuance_id subfield replaces currency and issuer subfields in MPT amount fields.

12.2 Response Fields

We do not introduce new fields.

mpt_issuance_id subfield replaces currency and issuer subfields in MPT amount fields, and currency subfield in paths_computed field.

12.3 Example Request

{
  "command": "ripple_path_find",
  "destination_account": "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
  "destination_amount": {
    "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
    "value": "-1"
  },
  "send_max": "100000000000000",
  "source_account": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn"
}

12.4 Example Response

{
  "alternatives": [
    {
      "destination_amount": {
        "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
        "value": "100"
      },
      "paths_canonical": [],
      "paths_computed": [
        [
          {
            "issuer": "r9QxhA9RghPZBbUchA9HkrmLKaWvkLXU29",
            "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
            "type": 96
          }
        ]
      ],
      "source_amount": "100000000"
    }
  ],
  "destination_account": "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
  "destination_amount": {
    "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
    "value": "-1"
  },
  "destination_currencies": [
    "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
    "XRP"
  ],
  "full_reply": true,
  "ledger_current_index": 8,
  "source_account": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
  "validated": false
}

12.5. Failure Conditions

There is no new failure conditions.

13. RPC: amm_info

13.1. Request Fields

We do not introduce new fields.

mpt_issuance_id subfield replaces currency and issuer subfields in asset fields.

13.2 Response Fields

We do not introduce new fields.

mpt_issuance_id subfield replaces currency and issuer subfields in MPT amount fields.

13.3 Example Request

{
  "command": "amm_info",
  "asset": {
    "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83"
  },
  "asset2": {
    "mpt_issuance_id": "000000055C488AAC5813270850685FFD89F4A4A8F4CD4C83"
  }
}

13.4 Example Response

{
  "result": {
    "amm": {
      "account": "rKM4AJ3JkgmdhKkJLpBcRUSZo7Prq13BYS",
      "amount": {
        "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
        "value": "100"
      },
      "amount2": {
        "mpt_issuance_id": "000000055C488AAC5813270850685FFD89F4A4A8F4CD4C83",
        "value": "100"
      },
      "asset2_frozen": false,
      "asset_frozen": false,
      "auction_slot": {
        "account": "r9QxhA9RghPZBbUchA9HkrmLKaWvkLXU29",
        "discounted_fee": 0,
        "expiration": "2000-01-02T00:00:40+0000",
        "price": {
          "currency": "033EE62589A944E08A96DC309D6ADBD2FBCFBD11",
          "issuer": "rKM4AJ3JkgmdhKkJLpBcRUSZo7Prq13BYS",
          "value": "0"
        },
        "time_interval": 0
      },
      "lp_token": {
        "currency": "033EE62589A944E08A96DC309D6ADBD2FBCFBD11",
        "issuer": "rKM4AJ3JkgmdhKkJLpBcRUSZo7Prq13BYS",
        "value": "100"
      },
      "trading_fee": 0,
      "vote_slots": [
        {
          "account": "r9QxhA9RghPZBbUchA9HkrmLKaWvkLXU29",
          "trading_fee": 0,
          "vote_weight": 100000
        }
      ]
    },
    "ledger_current_index": 8,
    "status": "success",
    "validated": false
  }
}

13.5. Failure Conditions

There is no new failure conditions.

14. RPC: book_offers

14.1. Request Fields

We do not introduce new fields.

mpt_issuance_id subfield replaces currency and issuer subfields in taker_gets and taker_pays fields.

14.2 Response Fields

We do not introduce new fields.

mpt_issuance_id subfield replaces currency and issuer subfields in TakerGets and TakerPays fields.

14.3 Example Request

{
  "command": "book_offers",
  "ledger_index": "current",
  "taker": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
  "taker_gets": {
    "mpt_issuance_id": "000000065C488AAC5813270850685FFD89F4A4A8F4CD4C83"
  },
  "taker_pays": {
    "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83"
  }
}

14.4 Example Response

{
  "result": {
    "ledger_current_index": 12,
    "offers": [
      {
        "Account": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
        "BookDirectory": "55795BD0628C360A24D3163A2A1EDD66AA9F715E94E9C1D954232CE5E5C6B16D",
        "BookNode": "0",
        "Flags": 0,
        "LedgerEntryType": "Offer",
        "OwnerNode": "0",
        "PreviousTxnID": "1177EC0BC778D39306481F6D2E33C267DB783800A58EE2F90C91AE38F1B023AD",
        "PreviousTxnLgrSeq": 11,
        "Sequence": 6,
        "TakerGets": {
          "mpt_issuance_id": "000000065C488AAC5813270850685FFD89F4A4A8F4CD4C83",
          "value": "101"
        },
        "TakerPays": {
          "mpt_issuance_id": "000000045C488AAC5813270850685FFD89F4A4A8F4CD4C83",
          "value": "100"
        },
        "index": "F4715C7C5957FE81246F259315494C671AF12C8B180BB32398DE5148B82ADD93",
        "owner_funds": "1000",
        "quality": "0.9900990099009901"
      }
    ],
    "status": "success",
    "validated": false
  }
}

14.5. Failure Conditions

There is no new failure conditions.

15. Rationale

The primary motivation for integrating Multi-Purpose Tokens (MPTs) into the XRPL’s Decentralized Exchange (DEX) is to ensure that the ledger’s next-generation token standard is not siloed from its existing liquidity ecosystem. While MPTs were designed to offer a more compact, scalable, and compliant alternative to traditional Trust Line-based tokens (IOUs), their utility is fundamentally capped if they cannot interact with Automated Market Makers (AMMs) or order books. By enabling MPTs as native trading assets, the ledger provides institutional issuers with a high-performance "Version 2" fungible token that retains the XRPL's core value proposition: atomic, cross-currency settlement. Unlike other blockchains that rely on smart contract standards like ERC-20, where DEX integration requires a wrapper or a complex external contract audit, the XRPL MPT/DEX integration is embedded at the protocol level. This ensures that compliance features—such as individual locks, global freezes, and clawbacks—are automatically enforced during trading without adding the latency or security risks associated with application-layer logic.

A cornerstone of this design is the high degree of transparency and parity between MPT and traditional IOU interactions within the DEX. Rather than introducing a disparate trading engine, the specification extends existing transaction types—such as OfferCreate, AMMCreate, and Payment—to support MPTs natively. This decision was driven by the need for ease of integration; by mirroring the behavior of the "Version 1" token standard, developers can leverage familiar design patterns and existing codebases. For the end user, the experience is intended to be virtually indistinguishable: an MPT functions as a first-class trading asset that can be paired with XRP or any other issued currency. This "plug-and-play" compatibility ensures that the transition to MPTs does not require a steep learning curve for the community or a costly overhaul of the ecosystem’s middleware.

Furthermore, the design prioritizes a unified liquidity model where the ledger's pathfinding logic treats MPTs and IOUs as functionally equivalent nodes. While MPTs use a unique mpt_issuance_id for technical precision, the underlying economic logic—such as cross-currency payments and order book mechanics—remains consistent. This prevents a fragmented developer experience where two different "flavors" of trading would need to be maintained. By choosing to wrap the new functionality within the ledger’s battle-tested DEX primitives, the XLS provides a robust and secure migration path, allowing institutions to adopt the more efficient MPT standard without losing access to the global liquidity and mature tooling that the XRP Ledger has cultivated over the past decade.

16. Security

While Multipurpose Tokens (MPT) inherit the core security model of the XRPL (including issuer-controlled freezes and authorization), this integration acknowledges the architectural shift from RippleState to MPT objects. Security is maintained by performing real-time verification of MPT-specific flags and ensuring that DEX quality calculations account for MPT-specific decimal scaling to prevent rounding exploits. Furthermore, the DEX engine treats MPT-specific freezes as immediate execution barriers, mirroring the existing IOU freeze behavior.

Appendix

A: STIssue serialization

STIssue type is extended to support MPT as follows:

  • Break down mpt_issuance_id into its sequence number and account.
  • The account is serialized in the first 160 bits, followed by a dedicated black hole account in the next 160 bits.
  • Finally, the sequence number (32 bits) is serialized last.
  • Deserialization method reads 320-bit currency and account. If account is the black hole account then additional 32 bits have to be read and deserialized into a sequence number.
  • This method maintains backward compatibility, doesn’t require a separate amendment, but adds 32 extra bits compared to the current format, or adds 160 bits compared to 192 bits required for serializing mpt_issuance_id.
160 bits MPT issuer account 160 bits black-hole account 32 bits sequence