|
1 | | -import { stringToHex, hexToString } from '@xrplf/isomorphic/dist/utils/index.js' |
2 | | -import { MPTokenIssuanceCreateFlags, Client } from 'xrpl' |
| 1 | +import { |
| 2 | + MPTokenIssuanceCreateFlags, |
| 3 | + Client, |
| 4 | + encodeMPTokenMetadata, |
| 5 | + decodeMPTokenMetadata, |
| 6 | +} from "xrpl"; |
3 | 7 |
|
4 | 8 | // Connect to network and get a wallet |
5 | | -const client = new Client('wss://s.devnet.rippletest.net:51233') |
6 | | -await client.connect() |
| 9 | +const client = new Client("wss://s.devnet.rippletest.net:51233"); |
| 10 | +await client.connect(); |
7 | 11 |
|
8 | | -console.log('Funding new wallet from faucet...') |
9 | | -const { wallet } = await client.fundWallet() |
| 12 | +console.log("=== Funding new wallet from faucet...==="); |
| 13 | +const { wallet: issuer } = await client.fundWallet(); |
| 14 | +console.log(`Issuer address: ${issuer.address}`); |
10 | 15 |
|
11 | 16 | // Define metadata as JSON |
12 | 17 | const mpt_metadata = { |
13 | | - t: 'TBILL', |
14 | | - n: 'T-Bill Yield Token', |
15 | | - d: 'A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.', |
16 | | - i: 'https://example.org/tbill-icon.png', |
17 | | - ac: 'rwa', |
18 | | - as: 'treasury', |
19 | | - in: 'Example Yield Co.', |
20 | | - us: [ |
| 18 | + ticker: "TBILL", |
| 19 | + name: "T-Bill Yield Token", |
| 20 | + desc: "A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.", |
| 21 | + icon: "https://example.org/tbill-icon.png", |
| 22 | + asset_class: "rwa", |
| 23 | + asset_subclass: "treasury", |
| 24 | + issuer_name: "Example Yield Co.", |
| 25 | + uris: [ |
21 | 26 | { |
22 | | - u: 'https://exampleyield.co/tbill', |
23 | | - c: 'website', |
24 | | - t: 'Product Page' |
| 27 | + uri: "https://exampleyield.co/tbill", |
| 28 | + category: "website", |
| 29 | + title: "Product Page", |
25 | 30 | }, |
26 | 31 | { |
27 | | - u: 'https://exampleyield.co/docs', |
28 | | - c: 'docs', |
29 | | - t: 'Yield Token Docs' |
30 | | - } |
| 32 | + uri: "https://exampleyield.co/docs", |
| 33 | + category: "docs", |
| 34 | + title: "Yield Token Docs", |
| 35 | + }, |
31 | 36 | ], |
32 | | - ai: { |
33 | | - interest_rate: '5.00%', |
34 | | - interest_type: 'variable', |
35 | | - yield_source: 'U.S. Treasury Bills', |
36 | | - maturity_date: '2045-06-30', |
37 | | - cusip: '912796RX0' |
38 | | - } |
39 | | -} |
| 37 | + additional_info: { |
| 38 | + interest_rate: "5.00%", |
| 39 | + interest_type: "variable", |
| 40 | + yield_source: "U.S. Treasury Bills", |
| 41 | + maturity_date: "2045-06-30", |
| 42 | + cusip: "912796RX0", |
| 43 | + }, |
| 44 | +}; |
40 | 45 |
|
41 | | -// Convert JSON to a string (without excess whitespace), then string to hex |
42 | | -const mpt_metadata_hex = stringToHex(JSON.stringify(mpt_metadata)) |
| 46 | +// Encode the metadata. |
| 47 | +// The encodeMPTokenMetadata function converts the JSON metadata object into |
| 48 | +// a compact, hex-encoded string, following the XLS-89 standard. |
| 49 | +// https://xls.xrpl.org/xls/XLS-0089-multi-purpose-token-metadata-schema.html |
| 50 | +console.log("\n=== Encoding metadata...==="); |
| 51 | +const mpt_metadata_hex = encodeMPTokenMetadata(mpt_metadata); |
| 52 | +console.log("Encoded mpt_metadata_hex: ", mpt_metadata_hex); |
43 | 53 |
|
44 | 54 | // Define the transaction, including other MPT parameters |
45 | 55 | const mpt_issuance_create = { |
46 | | - TransactionType: 'MPTokenIssuanceCreate', |
47 | | - Account: wallet.address, |
| 56 | + TransactionType: "MPTokenIssuanceCreate", |
| 57 | + Account: issuer.address, |
48 | 58 | AssetScale: 4, |
49 | | - MaximumAmount: '50000000', |
| 59 | + MaximumAmount: "50000000", |
50 | 60 | TransferFee: 0, |
51 | | - Flags: MPTokenIssuanceCreateFlags.tfMPTCanTransfer | |
52 | | - MPTokenIssuanceCreateFlags.tfMPTCanTrade, |
53 | | - MPTokenMetadata: mpt_metadata_hex |
54 | | -} |
| 61 | + Flags: |
| 62 | + MPTokenIssuanceCreateFlags.tfMPTCanTransfer | |
| 63 | + MPTokenIssuanceCreateFlags.tfMPTCanTrade, |
| 64 | + MPTokenMetadata: mpt_metadata_hex, |
| 65 | +}; |
55 | 66 |
|
56 | | -// Prepare, sign, and submit the transaction |
57 | | -console.log('Sending MPTokenIssuanceCreate transaction...') |
58 | | -const submit_response = await client.submitAndWait(mpt_issuance_create, { wallet, autofill: true }) |
| 67 | +// Sign and submit the transaction |
| 68 | +console.log("\n=== Sending MPTokenIssuanceCreate transaction...==="); |
| 69 | +console.log(JSON.stringify(mpt_issuance_create, null, 2)); |
| 70 | +const submit_response = await client.submitAndWait(mpt_issuance_create, { |
| 71 | + wallet: issuer, |
| 72 | + autofill: true, |
| 73 | +}); |
59 | 74 |
|
60 | | -// Check transaction results and disconnect |
61 | | -console.log(JSON.stringify(submit_response, null, 2)) |
62 | | -if (submit_response.result.meta.TransactionResult !== 'tesSUCCESS') { |
63 | | - const result_code = response.result.meta.TransactionResult |
64 | | - console.warn(`Transaction failed with result code ${result_code}.`) |
65 | | - process.exit(1) |
| 75 | +// Check transaction results |
| 76 | +console.log("\n=== Checking MPTokenIssuanceCreate results... ==="); |
| 77 | +console.log(JSON.stringify(submit_response.result, null, 2)); |
| 78 | +if (submit_response.result.meta.TransactionResult !== "tesSUCCESS") { |
| 79 | + const result_code = submit_response.result.meta.TransactionResult; |
| 80 | + console.warn(`Transaction failed with result code ${result_code}.`); |
| 81 | + await client.disconnect(); |
| 82 | + process.exit(1); |
66 | 83 | } |
67 | 84 |
|
68 | | -const issuance_id = submit_response.result.meta.mpt_issuance_id |
69 | | -console.log(`MPToken created successfully with issuance ID ${issuance_id}.`) |
| 85 | +const issuance_id = submit_response.result.meta.mpt_issuance_id; |
| 86 | +console.log( |
| 87 | + `\n- MPToken created successfully with issuance ID: ${issuance_id}` |
| 88 | +); |
| 89 | +// View the MPT issuance on the XRPL Explorer |
| 90 | +console.log(`- Explorer URL: https://devnet.xrpl.org/mpt/${issuance_id}`); |
70 | 91 |
|
71 | 92 | // Look up MPT Issuance entry in the validated ledger |
72 | | -console.log('Confirming MPT Issuance metadata in the validated ledger.') |
| 93 | +console.log("\n=== Confirming MPT Issuance metadata in the validated ledger... ==="); |
73 | 94 | const ledger_entry_response = await client.request({ |
74 | | - "command": "ledger_entry", |
75 | | - "mpt_issuance": issuance_id, |
76 | | - "ledger_index": "validated" |
77 | | -}) |
78 | | - |
79 | | -// Decode the metadata |
80 | | -const metadata_blob = ledger_entry_response.result.node.MPTokenMetadata |
81 | | -const decoded_metadata = JSON.parse(hexToString(metadata_blob)) |
82 | | -console.log('Decoded metadata:', decoded_metadata) |
| 95 | + command: "ledger_entry", |
| 96 | + mpt_issuance: issuance_id, |
| 97 | + ledger_index: "validated", |
| 98 | +}); |
83 | 99 |
|
| 100 | +// Decode the metadata. |
| 101 | +// The decodeMPTokenMetadata function takes a hex-encoded string representing MPT metadata, |
| 102 | +// decodes it to a JSON object, and expands any compact field names to their full forms. |
| 103 | +const metadata_blob = ledger_entry_response.result.node.MPTokenMetadata; |
| 104 | +const decoded_metadata = decodeMPTokenMetadata(metadata_blob); |
| 105 | +console.log("Decoded MPT metadata:\n", decoded_metadata); |
84 | 106 |
|
85 | | -client.disconnect() |
| 107 | +// Disconnect from the client |
| 108 | +await client.disconnect(); |
0 commit comments