Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MPTs to xrpl.org docs #2908

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/_snippets/mpts-disclaimer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% admonition type="info" name="Attention" %}
Multi-purpose Token functionality is part of the proposed XLS-33d extension to the XRP Ledger protocol. You can use these functions on test networks for now. Until there is an amendment in a stable release, the details documented on these pages are subject to change.
{% /admonition %}
54 changes: 54 additions & 0 deletions docs/concepts/tokens/fungible-tokens/multi-purpose-tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
blurb: Multi-purpose tokens offer a more compact, flexible token type than trust lines.
labels:
- Tokens
- MPTs
- Multi-purpose Tokens
status: not_enabled
---
# Multi-purpose Tokens

{% partial file="/docs/_snippets/mpts-disclaimer.md" /%}

Multi-purpose tokens (MPTs) are a more compact and flexible type of fungible token.

MPTs let you take advantage of ready-to-use tokenization features with a few lines of code. You can create many token experiences from one token program itself. Notable features include:

- MPTs store their metadata directly on the XRPL blockchain.
- A 1024-byte URI field provides a metadata pointer that allows you to use an off-chain source for metadata in addition to the on-chain source. This lets your application access necessary information directly from the chain, prompting higher interoperability for tokens, without losing the ability to attach additional information.
- MPTs can have a fixed token supply where you set a cap on the maximum number of tokens that can be minted.
- You can define MPTs as non-transferable, tokens that can only be transferred back to the issuer, but not among tokenholders. Useful for cases such as issuing airline credits or loyalty rewards.
- Issuers can set transfer fees to collect on-chain revenue each time the token is traded among tokenholders.
- MPTs also have advanced compliance features:
- The ability to lock tokens held by a tokenholder to support compliance requirements.
- The ability to set a global lock for all MPT balances across all tokenholders.
- The issuer can configure MPTs that can be clawed back from tokenholder wallets, either to revoke them, or to reassign them in the case of lost wallet keys.
- An opt-in feature can allow only wallets authorized by the issuer to hold issued tokens.

## MPTs vs Trust Lines

Unlike trust lines, MPTs do not represent bidirectional debt relationships. Instead, MPTs function more like a unidirectional trust line with only one balance. This reduces the overhead to support common tokenization requirements, including non-monetary use cases such as tracking reputation points in an online game.

MPTs offer a less complicated conceptual model than trust lines.

MPTs require significantly less space than trust lines. They require roughly 52 bytes for each MPT held by a token holder, compared to at least 234 bytes for every new trust line.

They reduce the long-term infrastructure and storage burdens for node operators, increasing network resiliency.

MPTs also improve node perfomance when processing large volumes of transactions.

MPTs are unidirectional. While trust lines use "balance netting," MPTs have only a single balance.

An account can issue a maximum of 32 unique MPT issuances. If an issuer wants to support more than this number of MPTs, they can open additional accounts.

Since token holders will not acquire an MPT without first making an off-ledger trust decision, MPTs have no trust limits. For example, a common use case for an MPT is a fiat-backed stablecoin, where a token holder wouldn't purchase more stablecoins than they would feel comfortable holding.

Unlike some existing capabilities of the ledger, MPTs are not subject to rippling, and do not require configurability settings related to that functionality.

## MPTs versus IOUs

On a technical level, MPTs provide a fundamentally different way to represent fungible tokens on the ledger. While IOUs are represented by trustlines and have bilateral debt relationships, MPTs use a simpler, unilateral relationship captured by an MPToken object. This results in substantial space savings on the ledger. The representation of a fungible token as a token object instead of a trustline makes it easier to enable functionality for real-world financial assets on-chain, such as token-level metadata, fixed supply, and fixed-point balance.

On a usage level, MPTs provide a straightforward conceptual model compared to trustlines and rippling. Developers can more easily build web3 applications around `MPToken` and `MPTokenIssuance` objects, with some similarities to the conceptual model of XLS-20 NFTs. It is also simpler for ordinary users to understand what tokens are available, what tokens they have issued, and what they hold in their wallet. For both issuers and holders of MPTs, there will typically be a smaller XRP reserve compared to the equivalent representations with IOU trustlines.

MPTs are intended to be complementary to IOUs. While there might be use cases where either MPTs or IOUs might be suitable, there will likely be a need for both over the long term. There will be use cases such as credit lines for lending and borrowing that might be better represented by IOUs long term. The MPT feature set should evolve in an incremental manner to unlock more common use cases first and deliver additional feature support at a later time. During the MPT development period, some cases might still be better represented by an IOU, then later be better supported with MPTs.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ In addition to the general fields above, you must specify *exactly 1* of the fol
- [Get DepositPreauth Object](#get-depositpreauth-object)
- [Get Ticket Object](#get-ticket-object)
- [Get NFT Page](#get-nft-page)
- [Get MPT Issuance Object](#get-mpt-issuance-object)
- [Get MPToken Object](#get-mptoken-object)
- [Response Format](#response-format)
- [Possible Errors](#possible-errors)

Expand Down Expand Up @@ -921,6 +923,200 @@ An example of a successful response:

{% /tabs %}

### Get MPT Issuance Object

Return an `MPTokenIssuance` object.

| Field | Type | Description |
|:------------------------|:---------------------------|:----------------------|
| `mpt_issuance` | String | The 192-bit `MPTokenIssuanceID` that's associated with the MPTokenIssuance. |

<!-- MULTICODE_BLOCK_START -->

*WebSocket*

```json
{
"id": "example_get_mpt_issuance",
"command": "ledger_entry",
"mpt_issuance": "000004C463C52827307480341125DA0577DEFC38405B0E3E",
"ledger_index": "validated"
}
```

*JSON-RPC*

```json
{
"method": "ledger_entry",
"params": [{
"mpt_issuance": "000004C463C52827307480341125DA0577DEFC38405B0E3E",
"ledger_index": "validated"
}]
}
```
*Commandline*

```sh
rippled json ledger_entry '{ "mpt_issuance": "000004C463C52827307480341125DA0577DEFC38405B0E3E", "ledger_index": "validated" }'
```
### Get MPToken Object

Return an `MPToken` object.

| Field | Type | Description |
|:------------------------|:---------------------------|:----------------------|
| `mptoken` | ️Object or String | If a string, interpret as ledger entry ID of the MPToken to retrieve. If an object, requires the sub-fields account and mpt_issuance_id to unique identify the MPToken. |
| mptoken.mpt_issuance_id | ️String | (Required if the `MPToken` is specified as an object) The 192-bit MPTokenIssuanceID that's associated with the MPTokenIssuance. |
| mptoken.account ️ | String | (Required if the `MPToken` is specified as an object) The account that owns the MPToken. |

<!-- MULTICODE_BLOCK_START -->

*WebSocket*

```json
{
"id": "example_get_mpt_issuance",
"command": "ledger_entry",
"mpt_issuance": "000004C463C52827307480341125DA0577DEFC38405B0E3E",
"ledger_index": "validated"
}
```

*JSON-RPC*

```json
{
"method": "ledger_entry",
"params": [{
"mpt_issuance": "000004C463C52827307480341125DA0577DEFC38405B0E3E",
"ledger_index": "validated"
}]
}
```
*Commandline*

```sh
rippled json ledger_entry '{ "mpt_issuance": "000004C463C52827307480341125DA0577DEFC38405B0E3E", "ledger_index": "validated" }'
DennisDawson marked this conversation as resolved.
Show resolved Hide resolved
```
<!-- MULTICODE_BLOCK_END -->

[Try it! >](https://xrpl.org/resources/dev-tools/websocket-api-tool.html#ledger_entry-mpt_issuance)

## Response Format

The response follows the [standard format](https://xrpl.org/docs/references/http-websocket-apis/api-conventions/response-formatting/), with a successful result containing the following fields:

| Field | Type | Description |
|:---------------|:-----------------|:-----------------------------------------|
| `index` | String | The unique ID of this [ledger entry](https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/). |
| `ledger_index` | Unsigned Integer | The [ledger index](https://xrpl.org/docs/references/protocol/data-types/basic-data-types/#ledger-index) of the ledger that was used when retrieving this data. |
| `node` | Object | _(Omitted if `"binary": true` specified.)_ Object containing the data of this ledger entry, according to the [ledger format](https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/). |
| `node_binary` | String | _(Omitted unless `"binary":true` specified)_ The [binary representation](https://xrpl.org/docs/references/protocol/binary-format/) of the ledger object, as hexadecimal. |

An example of a successful response:

<!-- MULTICODE_BLOCK_START -->

*WebSocket*

```json
{
"id": "example_get_accountroot",
"result": {
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
"ledger_hash": "31850E8E48E76D1064651DF39DF4E9542E8C90A9A9B629F4DE339EB3FA74F726",
"ledger_index": 61966146,
"node": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"AccountTxnID": "4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB",
"Balance": "424021949",
"Domain": "6D64756F31332E636F6D",
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
"Flags": 9568256,
"LedgerEntryType": "AccountRoot",
"MessageKey": "0000000000000000000000070000000300",
"OwnerCount": 12,
"PreviousTxnID": "4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB",
"PreviousTxnLgrSeq": 61965653,
"RegularKey": "rD9iJmieYHn8jTtPjwwkW2Wm9sVDvPXLoJ",
"Sequence": 385,
"TransferRate": 4294967295,
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8"
},
"validated": true
},
"status": "success",
"type": "response"
}
```

*JSON-RPC*

```json
200 OK

{
"result": {
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
"ledger_hash": "395946243EA36C5092AE58AF729D2875F659812409810A63096AC006C73E656E",
"ledger_index": 61966165,
"node": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"AccountTxnID": "4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB",
"Balance": "424021949",
"Domain": "6D64756F31332E636F6D",
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
"Flags": 9568256,
"LedgerEntryType": "AccountRoot",
"MessageKey": "0000000000000000000000070000000300",
"OwnerCount": 12,
"PreviousTxnID": "4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB",
"PreviousTxnLgrSeq": 61965653,
"RegularKey": "rD9iJmieYHn8jTtPjwwkW2Wm9sVDvPXLoJ",
"Sequence": 385,
"TransferRate": 4294967295,
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8"
},
"status": "success",
"validated": true
}
}
```

*Commandline*

```json
{
"result": {
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
"ledger_hash": "395946243EA36C5092AE58AF729D2875F659812409810A63096AC006C73E656E",
"ledger_index": 61966165,
"node": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"AccountTxnID": "4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB",
"Balance": "424021949",
"Domain": "6D64756F31332E636F6D",
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
"Flags": 9568256,
"LedgerEntryType": "AccountRoot",
"MessageKey": "0000000000000000000000070000000300",
"OwnerCount": 12,
"PreviousTxnID": "4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB",
"PreviousTxnLgrSeq": 61965653,
"RegularKey": "rD9iJmieYHn8jTtPjwwkW2Wm9sVDvPXLoJ",
"Sequence": 385,
"TransferRate": 4294967295,
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8"
},
"status": "success",
"validated": true
}
}
```

<!-- MULTICODE_BLOCK_END -->


## Possible Errors

Expand Down
Loading