diff --git a/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js b/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js index 18d786de67..23983dc2c9 100644 --- a/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js +++ b/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js @@ -1,35 +1,40 @@ -import { stringToHex, hexToString } from '@xrplf/isomorphic/dist/utils/index.js' -import { MPTokenIssuanceCreateFlags, Client } from 'xrpl' +import { + MPTokenIssuanceCreateFlags, + Client, + encodeMPTokenMetadata, + decodeMPTokenMetadata +} from 'xrpl' // Connect to network and get a wallet const client = new Client('wss://s.devnet.rippletest.net:51233') await client.connect() -console.log('Funding new wallet from faucet...') -const { wallet } = await client.fundWallet() +console.log('=== Funding new wallet from faucet...===') +const { wallet: issuer } = await client.fundWallet() +console.log(`Issuer address: ${issuer.address}`) // Define metadata as JSON const mpt_metadata = { - t: 'TBILL', - n: 'T-Bill Yield Token', - d: 'A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.', - i: 'https://example.org/tbill-icon.png', - ac: 'rwa', - as: 'treasury', - in: 'Example Yield Co.', - us: [ + ticker: 'TBILL', + name: 'T-Bill Yield Token', + desc: 'A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.', + icon: 'https://example.org/tbill-icon.png', + asset_class: 'rwa', + asset_subclass: 'treasury', + issuer_name: 'Example Yield Co.', + uris: [ { - u: 'https://exampleyield.co/tbill', - c: 'website', - t: 'Product Page' + uri: 'https://exampleyield.co/tbill', + category: 'website', + title: 'Product Page' }, { - u: 'https://exampleyield.co/docs', - c: 'docs', - t: 'Yield Token Docs' + uri: 'https://exampleyield.co/docs', + category: 'docs', + title: 'Yield Token Docs' } ], - ai: { + additional_info: { interest_rate: '5.00%', interest_type: 'variable', yield_source: 'U.S. Treasury Bills', @@ -38,8 +43,13 @@ const mpt_metadata = { } } -// Convert JSON to a string (without excess whitespace), then string to hex -const mpt_metadata_hex = stringToHex(JSON.stringify(mpt_metadata)) +// Encode the metadata. +// The encodeMPTokenMetadata function converts the JSON metadata object into +// a compact, hex-encoded string, following the XLS-89 standard. +// https://xls.xrpl.org/xls/XLS-0089-multi-purpose-token-metadata-schema.html +console.log('\n=== Encoding metadata...===') +const mpt_metadata_hex = encodeMPTokenMetadata(mpt_metadata) +console.log("Encoded mpt_metadata_hex:", mpt_metadata_hex) // Define the transaction, including other MPT parameters const mpt_issuance_create = { @@ -54,32 +64,39 @@ const mpt_issuance_create = { } // Prepare, sign, and submit the transaction -console.log('Sending MPTokenIssuanceCreate transaction...') -const submit_response = await client.submitAndWait(mpt_issuance_create, { wallet, autofill: true }) +console.log('\n=== Sending MPTokenIssuanceCreate transaction...===') +const submit_response = await client.submitAndWait(mpt_issuance_create, + { wallet, autofill: true } +) -// Check transaction results and disconnect -console.log(JSON.stringify(submit_response, null, 2)) +// Check transaction results +console.log('\n=== Checking MPTokenIssuanceCreate results...===') if (submit_response.result.meta.TransactionResult !== 'tesSUCCESS') { - const result_code = response.result.meta.TransactionResult + const result_code = submit_response.result.meta.TransactionResult console.warn(`Transaction failed with result code ${result_code}.`) + await client.disconnect() process.exit(1) } const issuance_id = submit_response.result.meta.mpt_issuance_id -console.log(`MPToken created successfully with issuance ID ${issuance_id}.`) +console.log(`- MPToken created successfully with issuance ID: ${issuance_id}`) +// View the MPT issuance on the XRPL Explorer +console.log(`\n- Explorer URL: https://devnet.xrpl.org/mpt/${issuance_id}`) // Look up MPT Issuance entry in the validated ledger -console.log('Confirming MPT Issuance metadata in the validated ledger.') +console.log('\n=== Confirming MPT Issuance metadata in the validated ledger... ===') const ledger_entry_response = await client.request({ "command": "ledger_entry", "mpt_issuance": issuance_id, "ledger_index": "validated" }) -// Decode the metadata +// Decode the metadata. +// The decodeMPTokenMetadata function takes a hex-encoded string representing MPT metadata, +// decodes it to a JSON object, and expands any compact field names to their full forms. const metadata_blob = ledger_entry_response.result.node.MPTokenMetadata -const decoded_metadata = JSON.parse(hexToString(metadata_blob)) -console.log('Decoded metadata:', decoded_metadata) - +const decoded_metadata = decodeMPTokenMetadata(metadata_blob) +console.log('Decoded MPT metadata: ', decoded_metadata) +// Disconnect from the client client.disconnect() diff --git a/_code-samples/issue-mpt-with-metadata/js/package.json b/_code-samples/issue-mpt-with-metadata/js/package.json index 43c89bf1e0..fab7850610 100644 --- a/_code-samples/issue-mpt-with-metadata/js/package.json +++ b/_code-samples/issue-mpt-with-metadata/js/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "xrpl": "^4.4.0" + "xrpl": "^4.4.3" }, "type": "module" } diff --git a/_code-samples/issue-mpt-with-metadata/py/requirements.txt b/_code-samples/issue-mpt-with-metadata/py/requirements.txt index a566e000a8..b3112f4240 100644 --- a/_code-samples/issue-mpt-with-metadata/py/requirements.txt +++ b/_code-samples/issue-mpt-with-metadata/py/requirements.txt @@ -1 +1 @@ -xrpl-py==4.3.0 +xrpl-py==4.4.3 diff --git a/docs/tutorials/how-tos/use-tokens/issue-a-multi-purpose-token.md b/docs/tutorials/how-tos/use-tokens/issue-a-multi-purpose-token.md new file mode 100644 index 0000000000..ec25fb3005 --- /dev/null +++ b/docs/tutorials/how-tos/use-tokens/issue-a-multi-purpose-token.md @@ -0,0 +1,147 @@ +--- +seo: + description: Issue a Multi-Purpose Token (MPT) with arbitrary metadata on the XRP Ledger. +metadata: + indexPage: true +labels: + - Multi-Purpose Token + - MPT + - Token Issuance +--- +# Issue a Multi-Purpose Token (MPT) + +A [Multi-Purpose Token (MPT)](../../../concepts/tokens/fungible-tokens/multi-purpose-tokens.md) lets you to quickly access powerful, built-in tokenization features on the XRP Ledger with minimal code. + +This tutorial shows you how to issue an MPT with on-chain metadata such as the token's ticker, name, or description, encoded according to the MPT [metadata schema](../../../concepts/tokens/fungible-tokens/multi-purpose-tokens.md#metadata-schema) defined in [XLS-89](https://xls.xrpl.org/xls/XLS-0089-multi-purpose-token-metadata-schema.html). + +## Goals + +By the end of this tutorial, you will be able to: + +- Issue a new MPT using the `MPTokenIssuanceCreate` transaction. +- Encode or decode token metadata following MPT standards best practices. + +## Prerequisites + +To complete this tutorial, you should: + +- Have a basic understanding of the XRP Ledger and token issuance. +- Have an XRP Ledger client library set up in your development environment. This page provides examples for the following: + - **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js). See [Get Started Using JavaScript](../../javascript/build-apps/get-started.md) for setup steps. + +## Source Code + +You can find the complete source code for this tutorial's example in the [code samples section of this website's repository](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/issue-mpt-with-metadata). + +## Steps + +### 1. Install dependencies + +{% tabs %} +{% tab label="Javascript" %} +From the code sample folder, use npm to install dependencies: + +```bash +npm install xrpl +``` +{% /tab %} +{% /tabs %} + +### 2. Set up client and fund issuer wallet + +Import the client library, instantiate a client to connect to the XRPL, and fund a new wallet to act as the token issuer. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js" language="js" before="// Define metadata as JSON" /%} +{% /tab %} +{% /tabs %} + +### 3. Define and encode MPT metadata + +Define your token's metadata as a JSON object: + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js" language="js" from="// Define metadata as JSON" before="// Encode the metadata" /%} +{% /tab %} +{% /tabs %} + +The metadata schema supports both long field names (e.g., `ticker`, `name`, `desc`) and compact short keys (e.g., `t`, `n`, `d`). To save space on the ledger, it’s recommended to use short key names. The MPT metadata field has a 1024-byte limit, so using compact keys allows you to include more information. + +The SDK libraries provide utility functions to encode or decode the metadata for you, so you don't have to. If long field names are provided in the metadata JSON, the _encoding_ utility function automatically shortens them to their compact key equivalents before encoding. Similarly, when decoding, the _decoding_ utility function converts the shorthands back to the respective long names. + +{% tabs %} +{% tab label="Javascript" %} +Use the `encodeMPTokenMetadata()` function to encode metadata with `xrpl.js`. +{% code-snippet file="/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js" language="js" from="// Encode the metadata" before="// Define the transaction" /%} +{% /tab %} + +{% /tabs %} + +{% admonition type="warning" name="Warning" %} +While the encoding utility formats the JSON for you correctly and replaces the full key names with shorthands, it does **not** validate the metadata content or size. +{% /admonition %} + +### 4. Prepare the MPTokenIssuanceCreate transaction + +Create the transaction object, specifying the issuer, asset scale, maximum amount, transfer/trade flags, and the encoded metadata. + +| Field | Value | +|:------------------|:---------------------------------------------------------------------| +| `TransactionType` | The type of transaction, in this case `MPTokenIssuanceCreate`. | +| `Account` | The wallet address of the account that is issuing the MPT. | +| `AssetScale` | The number of decimal places for the token. | +| `MaximumAmount` | The maximum supply of the token to be issued. | +| `TransferFee` | The transfer fee (if any) to charge for token transfers. | +| `Flags` | Flags to control transfer/trade permissions. | +| `MPTokenMetadata` | The hex-encoded metadata for the token. | + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js" language="js" from="// Define the transaction" before="// Prepare, sign, and submit the transaction" /%} +{% /tab %} +{% /tabs %} + +### 5. Submit the transaction + +Sign and submit the transaction, then wait for validation. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js" language="js" from="// Prepare, sign, and submit the transaction" before="// Check transaction results" /%} +{% /tab %} +{% /tabs %} + +### 6. Check transaction result + +Verify that the transaction succeeded and retrieve the MPT issuance ID. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js" language="js" from="// Check transaction results" before="// Look up MPT Issuance entry" /%} +{% /tab %} +{% /tabs %} + +A `tesSUCCESS` result indicates that the MPT issuance transaction was processed successfully and the token was created. + +### 7. Confirm MPT issuance and decode metadata + +Look up the MPT issuance entry in the validated ledger and decode the metadata to verify it matches your original input. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/issue-mpt-with-metadata/js/issue-mpt-with-metadata.js" language="js" from="// Look up MPT Issuance entry" /%} +{% /tab %} +{% /tabs %} + +The _decoding_ utility function converts the metadata shorthand key names back to their respective long names. + +## See Also + +- **Concepts**: + - [Multi-Purpose Tokens (MPT)](../../../concepts/tokens/fungible-tokens/multi-purpose-tokens.md) +- **References**: + - [MPTokenIssuanceCreate Transaction](../../../references/protocol/transactions/types/mptokenissuancecreate.md) + +{% raw-partial file="/docs/_snippets/common-links.md" /%}