{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition","amendment-disclaimer","badge","repo-link"]},"redocly_category":"Documentation","type":"markdown"},"seo":{"title":"Migrating from Trust Line Tokens to MPTs","siteUrl":"https://xrpl.org","llmstxt":{"hide":false,"title":"XRPL Developer Portal & Documentation","description":"Explore XRP Ledger documentation, blogs, and other blockchain developer resources needed to start building and integrating with the ledger.","details":{"content":"XRP Ledger concepts, use cases, tutorials, references, and other blockchain developer resources. Also, stay up to date with release announcements and more through the XRPL Blog."},"sections":[{"title":"Introduction","description":"A high-level introduction to the XRP Ledger.","includeFiles":["docs/introduction/**/*.*","about/faq.md"],"excludeFiles":["docs/introduction/index.md"]},{"title":"Use Cases","description":"Real-world applications and business scenarios for the XRP Ledger.","includeFiles":["docs/use-cases/**/*.*"],"excludeFiles":["docs/use-cases/index.md","docs/use-cases/defi/index.md"]},{"title":"Agentic Transactions","description":"XRPL AI Starter Kit to help autonomous agents discover, set up, and execute agentic transactions on the XRP Ledger.","includeFiles":["docs/agents/**/*.*"]},{"title":"Concepts","description":"Core concepts including accounts, tokens, transactions, consensus, and more.","includeFiles":["docs/concepts/**/*.*"],"excludeFiles":["docs/concepts/index.md","docs/concepts/decentralized-storage/index.md","docs/concepts/payment-types/index.md"]},{"title":"Tutorials","description":"Step-by-step guides for building on the XRP Ledger in JavaScript, Python, Go, and more.","includeFiles":["docs/tutorials/**/*.*"]},{"title":"References","description":"Protocol specification, transaction types, ledger entries, and API methods.","includeFiles":["docs/references/**/*.*"],"excludeFiles":["docs/references/xrp-api.md","docs/references/data-api.md","docs/references/protocol/index.md","docs/references/protocol/ledger-data/ledger-entry-types/index.md","docs/references/protocol/transactions/index.md","docs/references/protocol/transactions/types/index.md","docs/references/http-websocket-apis/api-conventions/index.md","docs/references/http-websocket-apis/public-api-methods/*/index.md","docs/references/http-websocket-apis/admin-api-methods/*/index.md"]},{"title":"Infrastructure","description":"Install, configure, and troubleshoot xrpld and Clio servers.","includeFiles":["docs/infrastructure/**/*.*"],"excludeFiles":["docs/infrastructure/index.md","docs/infrastructure/*/index.md","docs/infrastructure/installation/build-run-xrpld-in-reporting-mode.md","docs/infrastructure/configuration/data-retention/index.md","docs/infrastructure/configuration/server-modes/index.md"]},{"title":"Blog (2023+)","description":"Recent XRPL Blog posts (showing 2023 and newer).","includeFiles":["blog/2023/**/*.*","blog/2024/**/*.*","blog/2025/**/*.*","blog/2026/**/*.*"]},{"title":"Resources","description":"Developer resources and contribution guidelines.","includeFiles":["resources/**/*.*"]}]},"description":"A migration guide for issuers and integrators moving from trust line tokens to Multi-Purpose Tokens (MPTs) on the XRP Ledger."},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"migrating-from-trust-line-tokens-to-mpts","__idx":0},"children":["Migrating from Trust Line Tokens to MPTs"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This page is a planning and decision reference for migrating an existing ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/trust-line-tokens"},"children":["Trust Line Token"]}," to a ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/multi-purpose-tokens"},"children":["Multi-Purpose Token (MPT)"]}," on the XRP Ledger. It's aimed at ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["issuers"]}," planning a migration and ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["integrators"]}," (wallets, explorers, exchanges) supporting both token types during the transition."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Trust line tokens and MPTs are distinct fungible token standards that coexist. MPTs are newer, but trust line tokens are fully supported and not deprecated. This guide contrasts the two and links to the references and tutorials you'll need to migrate."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Note"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This is not an exhaustive guide. Refer to the linked references, concepts, and tutorials for full details."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"token-standard-comparison","__idx":1},"children":["Token Standard Comparison"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following table compares features for the two token standards at a high level:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Capability"},"children":["Capability"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Trust Line Token"},"children":["Trust Line Token"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Multi-Purpose Token (MPT)"},"children":["Multi-Purpose Token (MPT)"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Issuing & direct payments"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Escrow"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Requires ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Allow Trust Line Locking"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Requires ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Escrow"]},". Escrowing to a non-issuer also requires ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Transfer"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["On-chain Metadata"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["❌ Not supported. ",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Only the currency code is stored on-ledger. Descriptive fields live off-chain, typically in a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["xrp-ledger.toml"]}," file."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MPTokenMetadata"]}," field stores up to 1024 bytes of  on-chain JSON metadata such as ticker, name and icon."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Mutable properties"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["⚠️ Limited.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Account-wide. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Require Auth"]}," and ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Allow Trust Line Clawback"]}," can only be enabled before trust lines exist, and Clawback and ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["No Freeze"]}," can never be disabled once set. Other flags toggle freely."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported: ",{"$$mdtype":"Tag","name":"AmendmentDisclaimer","attributes":{"name":"DynamicMPT","compact":true,"statusOnly":false,"mode":""},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Per-issuance. Metadata and transfer fee are mutable by default. Flags can only be enabled, never disabled, unless made permanently immutable."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Freeze"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Block one trust line with ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Freeze"]},", or all of them with ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Global Freeze"]},". Add ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Deep Freeze"]}," to also block receiving."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Requires ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Lock"]},". You can lock an MPT globally, or target a single holder."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Clawback"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Requires ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Allow Trust Line Clawback"]},", set before issuing and irreversible."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Requires ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Clawback"]},", set at creation or enabled later."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Confidential balances"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["❌ Not supported."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported: ",{"$$mdtype":"Tag","name":"AmendmentDisclaimer","attributes":{"name":"ConfidentialTransfer","compact":true,"statusOnly":false,"mode":""},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Individual balances and transfer amounts are encrypted, but total supply stays public. Issuers and optional auditors can decrypt individual balances via registered keys."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["DEX, AMM, cross-currency payments & Checks"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["🚧 Pending amendment: ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/resources/known-amendments#mptokensv2"},"children":["MPTokensV2"]}," ",{"$$mdtype":"Tag","name":"Badge","attributes":{"color":""},"children":["In Development: TBD"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Rippling"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["✅ Supported.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Controlled by ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Default Ripple"]},"/",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["No Ripple"]},". See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/rippling"},"children":["Rippling"]}," to learn more."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["❌ Not supported by design."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"why-migrate-to-mpts","__idx":2},"children":["Why Migrate to MPTs?"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Migrating is a feature decision rather than a forced upgrade. Consider migrating to MPTs when a token requires:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Per-token controls"]},": Freeze, clawback, transfer fees, and allow-listing scoped to one token, instead of to every token the account issues."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["On-chain metadata"]},": The ticker and other descriptive fields can live on the ledger in a recommended schema."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Protocol-level capped supply"]},": ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MaximumAmount"]}," enforces a ceiling that trust line tokens can't."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Confidential balances"]},": Holders can keep their balances and transfer amounts private using EC-ElGamal encryption and Zero-Knowledge Proofs (ZKPs)."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Migration may not be appropriate when:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Your flows depend on rippling"]},": MPTs do not support ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/rippling"},"children":["rippling"]}," by design, and transfer directly between holders once you enable the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Transfer"]}," flag. If anything in your flows relies on rippling, migrating changes that behavior."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Your token needs DEX or AMM liquidity"]},": Until the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/resources/known-amendments#mptokensv2"},"children":["MPTokensV2 amendment"]}," is enabled, MPTs cannot be traded on the DEX or added to an AMM."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"migration-steps","__idx":3},"children":["Migration Steps"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following sections outline the steps to migrate from trust line tokens to MPTs. Migration is per-asset: if your account issues multiple trust line tokens, run these steps separately for each asset you migrate."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-create-the-mpt-issuance","__idx":4},"children":["1. Create the MPT Issuance"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Performed by:"]}," Issuer"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Resources:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tutorial:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/tokens/mpts/issue-a-multi-purpose-token"},"children":["Issue a Multi-Purpose Token"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Transactions:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/mptokenissuancecreate"},"children":["MPTokenIssuanceCreate"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/mptokenissuanceset"},"children":["MPTokenIssuanceSet"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Concepts:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/multi-purpose-tokens"},"children":["Multi-Purpose Tokens"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/mutable-mpts"},"children":["Mutable MPTs"]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["MPTs require explicit creation of the token issuance, so you must submit an MPTokenIssuanceCreate transaction, where you can define the token's configuration (for example, the token's precision, supply cap, and transfer fee)."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The create transaction returns the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mpt_issuance_id"]},", which uniquely identifies that issuance."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"amounts-and-fees","__idx":5},"children":["Amounts and fees"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["These three fields control how token amounts are represented and capped, and what fee is charged on transfers:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AssetScale"]}]}," sets how many decimal places the token divides into. Trust line balances carry up to 15 significant digits, so pick a scale that keeps the precision of the existing balances. For example, a balance of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["1.005"]}," needs an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AssetScale"]}," of at least 3, and stores on-ledger as the integer ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["1005"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MaximumAmount"]}]}," sets a permanent cap on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["OutstandingAmount"]},", the field that tracks how many units non-issuers currently hold. Trust line tokens have no such cap, so set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MaximumAmount"]}," high enough to cover your expected circulating supply."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransferFee"]}]}," replaces the account-wide ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransferRate"]},". A non-zero ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransferFee"]}," requires the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Transfer"]}," flag. The fee truncates down to a whole unit, so a small ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AssetScale"]}," can round the fee on small payments down to zero. Like ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransferRate"]},", a non-zero ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransferFee"]}," means a Payment between two holders must include ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SendMax"]}," covering the fee, or it fails with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tecPATH_PARTIAL"]},"."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AssetScale"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MaximumAmount"]}," can't be changed after creation, so think carefully about what you set them to. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransferFee"]}," can be adjusted later if necessary."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/ledger-data/ledger-entry-types/mptokenissuance#mptokenissuance-fields"},"children":["MPTokenIssuance fields"]}," to learn more."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"flags","__idx":6},"children":["Flags"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["With trust lines, capability settings apply to every token you issue. MPTs move that control to the token itself. Each issuance has its own flags, which you enable when creating the token or later with MPTokenIssuanceSet."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To match your existing token's behavior, map the relevant account flags to the MPT flags:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"MPT flag"},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/mptokenissuancecreate#mptokenissuancecreate-flags"},"children":["MPT flag"]}]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Account flag"},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/accountset#accountset-flags"},"children":["Account flag"]}]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Clawback"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTCanClawback"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Allow Trust Line Clawback"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["asfAllowTrustLineClawback"]},")"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Escrow"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTCanEscrow"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Allow Trust Line Locking"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["asfAllowTrustLineLocking"]},")"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Hold Confidential Balance"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTCanHoldConfidentialBalance"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Not supported for trust line tokens."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Lock"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTCanLock"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line freezing is enabled by default."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Trade"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTCanTrade"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line tokens trade on the DEX by default."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Transfer"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTCanTransfer"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line tokens are transferable by default."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Require Auth"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfMPTRequireAuth"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Require Auth"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["asfRequireAuth"]},")"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You don't have to configure every flag at creation. You can enable these later as your needs change. See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/mutable-mpts"},"children":["Mutable MPTs"]}," to learn more."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"metadata","__idx":7},"children":["Metadata"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For a trust line token, the only on-ledger identifier is the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["(currency, issuer)"]}," pair. The currency code doubles as the ticker, but the ledger holds no name, icon, or other descriptive fields. That information lives off-chain in the issuer's ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/xrp-ledger-toml"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["xrp-ledger.toml"]}]}," file."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An MPT carries this metadata on-chain instead. The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MPTokenMetadata"]}," field stores up to 1024 bytes of arbitrary data as hex. By convention it decodes to JSON following a recommended schema, which defines fields like ticker, name, and icon."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/multi-purpose-tokens#on-chain-metadata"},"children":["On-Chain Metadata"]}," to learn more."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-authorize-the-mpt","__idx":8},"children":["2. Authorize the MPT"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Performed by:"]}," Holder, and Issuer if ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Require Auth"]}," is enabled."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Resources:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tutorial:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/payments/send-an-mpt#3-authorize-the-receiving-account"},"children":["Send an MPT"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Transactions:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/mptokenauthorize"},"children":["MPTokenAuthorize"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Concepts:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/multi-purpose-tokens"},"children":["Multi-Purpose Tokens"]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before a holder can receive or send an MPT, they must submit an MPTokenAuthorize transaction with the relevant ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mpt_issuance_id"]}," to opt in to holding that token. Trust lines have no equivalent step; the holder creates a trust line with a ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/trustset"},"children":["TrustSet transaction"]},", or gets a trust line implicitly, such as when buying the token on the DEX."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Each MPT holder signs their own opt-in, so you can't opt in for them or remove the requirement."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If the issuance enables ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/authorized-trust-lines#authorized-trust-lines"},"children":["allow-listing"]}," (",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Require Auth"]}," flag), the opt-in is two-sided. The holder authorizes the MPT first, and then you authorize the holder with your own MPTokenAuthorize transaction. You cannot pre-approve a holder before they have opted in."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-migrate-the-balances","__idx":9},"children":["3. Migrate the balances"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The XRP Ledger doesn't provide a transaction that converts a trust line token into an MPT. To migrate existing balances, you can use the following mechanisms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#dex-or-amm-swap"},"children":["DEX or AMM swap"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#clawback-and-check-swap"},"children":["Clawback and Check swap"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#batch-swap"},"children":["Batch swap"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You don't have to pick just one mechanism. For example, you might seed a one-to-one AMM pool for retail holders, run batch swaps with accounts you can coordinate with, and use clawback and checks only for eligible balances that still haven't swapped by your deadline."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"dex-or-amm-swap","__idx":10},"children":["DEX or AMM swap"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Performed by:"]}," Issuer and Holder"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Resources:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tutorials:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/defi/dex/trade-in-the-decentralized-exchange"},"children":["Trade in the Decentralized Exchange"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/defi/dex/create-an-automated-market-maker"},"children":["Create an Automated Market Maker"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Transactions:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/offercreate"},"children":["OfferCreate"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/ammcreate"},"children":["AMMCreate"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Concepts:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/decentralized-exchange"},"children":["Decentralized Exchange"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/decentralized-exchange/offers"},"children":["Offers"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/decentralized-exchange/automated-market-makers"},"children":["Automated Market Makers"]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"em","attributes":{},"children":["(Requires the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/resources/known-amendments#mptokensv2"},"children":["MPTokensV2 amendment"]}," ",{"$$mdtype":"Tag","name":"Badge","attributes":{"color":""},"children":["In Development: TBD"]},")"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This approach is best for active holders who can migrate themselves. You publish liquidity that trades the old token for the MPT at a one-to-one rate, and holders swap when they're ready."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Trading or pooling the MPT this way requires both ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Trade"]}," and ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Can Transfer"]}," enabled on the issuance."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An issuing account can't hold its own tokens, so fund a separate migration account with the old token and the MPT first. Then provide liquidity in one of two ways:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Standing offers on the DEX."]}," Submit OfferCreate transactions from the migration account that sell the MPT and buy the old token at a one-to-one rate. Holders take those offers with their own OfferCreate transaction. Refill the offers as they're consumed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["A one-to-one AMM pool."]}," Use AMMCreate from the migration account to fund a pool with equal amounts of the old token and the MPT, with a trading fee of zero so holders aren't charged for migrating. Holders swap against the pool at any time, and the pool keeps working without you managing individual offers."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Convert the old token's decimal balance to the MPT's base units when you set the offer or pool amounts, and check that any ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransferFee"]}," on the MPT or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransferRate"]}," on the old token doesn't push the effective rate away from one-to-one."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can track the migration progress by comparing the old token's outstanding supply from the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/http-websocket-apis/public-api-methods/account-methods/gateway_balances"},"children":["gateway_balances"]}," method against the MPT's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["OutstandingAmount"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"clawback-and-check-swap","__idx":11},"children":["Clawback and Check swap"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Performed by:"]}," Issuer and Holder"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Resources:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tutorials:"]}," ",{"$$mdtype":"Tag","name":"RepoLink","attributes":{"path":"_code-samples/clawback/","github_fork":"https://github.com/XRPLF/xrpl-dev-portal","github_branch":"master"},"children":["Clawback code sample"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/payments/send-a-check"},"children":["Send a Check"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/payments/cash-a-check-for-an-exact-amount"},"children":["Cash a Check for an Exact Amount"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Transactions:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/clawback"},"children":["Clawback"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/checkcreate"},"children":["CheckCreate"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/checkcash"},"children":["CheckCash"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Concepts:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/clawing-back-tokens"},"children":["Clawing Back Tokens"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/payment-types/checks"},"children":["Checks"]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This path is best for recovering balances from holders who don't initiate the migration, because you start the swap instead of waiting for them."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For each holder, you submit two transactions:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Clawback"]}," transaction that recovers the holder's old trust line balance and returns it to you."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["CheckCreate"]}," transaction that offers the holder a check for the same value in MPT."," ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["(Requires the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/resources/known-amendments#mptokensv2"},"children":["MPTokensV2 amendment"]}," ",{"$$mdtype":"Tag","name":"Badge","attributes":{"color":""},"children":["In Development: TBD"]},")"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The holder finishes the swap with a CheckCash transaction. A check doesn't move funds until it's cashed, so you keep the MPT until the holder claims it, and you can set an expiration to control how long the offer stays open."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Two preconditions decide whether this path is even available to you:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The old token's issuing account must have ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Allow Trust Line Clawback"]}," enabled, and you can only turn that setting on before the account owns any trust lines or other ledger entries. If you issued the old token without it, you can't claw back those balances."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If the issuance requires allow-listing (",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Require Auth"]}," flag), you must authorize MPT holders before they can cash the check, so run ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#2-authorize-the-mpt"},"children":["Step 2"]}," first."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This swap isn't atomic end to end. Once the clawback succeeds, the holder can end up with neither token if the check expires before they cash it, so watch for expired checks and reissue them."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"batch-swap","__idx":12},"children":["Batch swap"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Performed by:"]}," Issuer and Holder"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Resources:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tutorial:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/best-practices/transaction-sending/send-a-multi-account-batch-transaction"},"children":["Send a Multi-Account Batch Transaction"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Transaction:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/batch"},"children":["Batch"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Concepts:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/transactions/batch-transactions"},"children":["Batch Transactions"]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"AmendmentDisclaimer","attributes":{"name":"BatchV1_1","compact":false,"statusOnly":false,"mode":""},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This path is best for coordinated holder-by-holder swaps, such as institutional accounts you can reach directly. It's the only mechanism that swaps both sides atomically, so no holder is ever left holding neither token."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For each holder, you build a Batch transaction in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ALLORNOTHING"]}," mode with two inner transactions:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Payment"]}," from the holder that returns the old token to you."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Payment"]}," from you that delivers the MPT to the holder."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Because this swap involves two accounts, both of you must sign the whole batch. The inner transactions are unsigned. Each participant signs the outer transaction's account, sequence, and flags, plus the hashes of both inner transactions, and one of you submits the result. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ALLORNOTHING"]}," mode means the holder can't receive the MPT without returning the old token, and vice versa."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A batch holds up to eight inner transactions, so you can combine several holders into one transaction as long as every account involved signs it."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-retire-the-old-token","__idx":13},"children":["4. Retire the old token"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Performed by:"]}," Issuer and Holder"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Resources:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tutorials:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/tokens/fungible-tokens/enact-global-freeze"},"children":["Enact Global Freeze"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/tokens/fungible-tokens/freeze-a-trust-line"},"children":["Freeze a Trust Line"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Transactions:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/accountset"},"children":["AccountSet"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/protocol/transactions/types/trustset"},"children":["TrustSet"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Concepts:"]}," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/trust-line-tokens"},"children":["Trust Line Tokens"]},", ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/freezes"},"children":["Freezes"]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can't delete holders' trust lines, so retiring the old token is a wind-down rather than a deletion:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Announce a migration deadline, and keep at least one of the swap mechanisms open until it passes, so holders who wait until the last minute can still swap voluntarily."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Engage exchanges and custodians before the deadline. They control their customers' balances, so migration happens on their timeline, not the end user's."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Withdraw the liquidity you provided, such as open DEX offers and AMM positions, so no new balances accumulate on the old token."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enact a ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Global Freeze"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["asfGlobalFreeze"]}," on AccountSet) at the deadline, so the remaining balances can't circulate. A Global Freeze is account-wide, freezing every token issued, not just the one you're retiring. If you issue other live tokens from the same account, freeze the old token's trust lines individually instead. Then, clear each freeze (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfClearFreeze"]},") so holders can delete their line and reclaim their reserve.",{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"danger","name":"Warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you enabled ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["No Freeze"]},", a Global Freeze becomes irreversible. You can't lift it to reactivate the old token later."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Encourage holders to offload their old token balance and reset their trust line to the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/trust-line-tokens#trust-line-settings"},"children":["default settings"]},", which deletes it. Until then, each holder carries two owner reserve increments: one for the new ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MPToken"]}," and one for the old trust line."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Offloading the balance and resetting the trust line's limit isn't always enough to delete it. Deletion also requires the holder's ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["No Ripple"]}," flag to be in its default state, which depends on their ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Default Ripple"]}," setting. A plain TrustSet transaction doesn't set this flag, so have holders include ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tfSetNoRipple"]}," in the TrustSet that resets their limit to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["0"]},". See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/tokens/fungible-tokens/trust-line-tokens#reserves-and-deletion"},"children":["Reserves and Deletion"]}," to learn more."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-changes-for-integrators","__idx":14},"children":["What Changes for Integrators"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Wallets, exchanges, explorers, and custody systems that already support MPTs still need to reconcile any token that migrates. The old trust line and the new MPT are two separate ledger entries representing one asset, so balance totals, deposit detection, and displayed tickers must resolve them as the same thing."]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Topic"},"children":["Topic"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"What changes"},"children":["What changes"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"What to look out for"},"children":["What to look out for"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Token identity"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line tokens use a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["(currency, issuer)"]}," pair. MPTs use an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mpt_issuance_id"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Treat both identifiers as two ledger representations of the same display asset during the migration."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Amount format"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line token values are decimals with up to 15 significant digits. MPT values are integers in base units governed by ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AssetScale"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["A holder's balance can be split across both formats during the transition. Convert both to a common precision before combining them into one displayed total."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Balance queries"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line balances live in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["RippleState"]}," entries and are returned by ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/http-websocket-apis/public-api-methods/account-methods/account_lines"},"children":["account_lines"]},". MPT balances live in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MPToken"]}," entries and can be queried with ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/http-websocket-apis/public-api-methods/account-methods/account_objects"},"children":["account_objects"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Deposit detection needs to handle both ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["RippleState"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MPToken"]}," entries during the transition."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Deposit detection"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["A trust line deposit's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["meta.delivered_amount"]}," is shaped ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{currency, issuer, value}"]},". An MPT deposit's is shaped ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{mpt_issuance_id, value}"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Key deposit detection off ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["meta.delivered_amount"]}," and branch on its shape to classify a deposit as a trust line token or an MPT."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Holding the token"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line holders create trust lines. MPT holders opt in to a specific issuance."]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Existing holders who already have a trust line still need to submit a new opt-in before they can receive the same asset as an MPT."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Pathfinding and cross-currency payments"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line tokens support these flows today. MPT support requires the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/resources/known-amendments#mptokensv2"},"children":["MPTokensV2 amendment"]}," ",{"$$mdtype":"Tag","name":"Badge","attributes":{"color":""},"children":["In Development: TBD"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["If your integration depends on pathfinding, DEX, AMM, cross-currency payments, or Checks, wait for MPTokensV2 before migrating that flow."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Display metadata"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line token display data usually comes from the issuer's ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/references/xrp-ledger-toml"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["xrp-ledger.toml"]}]}," file. MPT display data can come from on-chain metadata."]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Resolve both sides to the same ticker, icon, and asset record so users don't see two unrelated assets."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Issuer controls"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Trust line controls are account-wide. MPT controls are per issuance."]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Don't assume a migrated MPT inherits the trust line's freeze, clawback, or other settings. Check the new issuance's own flags instead."]}]}]}]}]}]},"headings":[{"value":"Migrating from Trust Line Tokens to MPTs","id":"migrating-from-trust-line-tokens-to-mpts","depth":1},{"value":"Token Standard Comparison","id":"token-standard-comparison","depth":2},{"value":"Why Migrate to MPTs?","id":"why-migrate-to-mpts","depth":2},{"value":"Migration Steps","id":"migration-steps","depth":2},{"value":"1. Create the MPT Issuance","id":"1-create-the-mpt-issuance","depth":3},{"value":"Amounts and fees","id":"amounts-and-fees","depth":4},{"value":"Flags","id":"flags","depth":4},{"value":"Metadata","id":"metadata","depth":4},{"value":"2. Authorize the MPT","id":"2-authorize-the-mpt","depth":3},{"value":"3. Migrate the balances","id":"3-migrate-the-balances","depth":3},{"value":"DEX or AMM swap","id":"dex-or-amm-swap","depth":4},{"value":"Clawback and Check swap","id":"clawback-and-check-swap","depth":4},{"value":"Batch swap","id":"batch-swap","depth":4},{"value":"4. Retire the old token","id":"4-retire-the-old-token","depth":3},{"value":"What Changes for Integrators","id":"what-changes-for-integrators","depth":2}],"frontmatter":{"seo":{"description":"A migration guide for issuers and integrators moving from trust line tokens to Multi-Purpose Tokens (MPTs) on the XRP Ledger.","title":"Migrating from Trust Line Tokens to MPTs"},"labels":["Tokens","MPTs, Multi-Purpose Tokens","Migration"]},"editPage":{"to":"https://github.com/XRPLF/xrpl-dev-portal/tree/master/docs/use-cases/tokenization/migrating-from-trust-lines-to-mpts.md"},"lastModified":"2026-09-24T08:39:22.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/use-cases/tokenization/migrating-from-trust-lines-to-mpts","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}