diff --git a/_code-samples/mpt-generator/mpt-generator.css b/_code-samples/mpt-generator/mpt-generator.css new file mode 100644 index 0000000000..5132fb3507 --- /dev/null +++ b/_code-samples/mpt-generator/mpt-generator.css @@ -0,0 +1,139 @@ +body { + font-family: "Inter", sans-serif; + padding: 20px; + background: #abe2ff; +} + +h1 { + font-weight: bold; +} + +td { + padding-left: 25px; + vertical-align: top; +} + +input, +button { + padding: 6px; + margin-bottom: 8px; + border: none +} + +button { + font-weight: bold; + font-family: "Work Sans", sans-serif; + background-color: #006aff; + -webkit-text-fill-color: white; +} + +td { + vertical-align: middle; +} + +/* The switch - the box around the slider */ +.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +/* Hide default HTML checkbox */ +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +/* The slider */ +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; +} + +input:checked+.slider { + background-color: #2196F3; +} + +input:focus+.slider { + box-shadow: 0 0 1px #2196F3; +} + +input:checked+.slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 34px; +} + +.slider.round:before { + border-radius: 50%; +} +.tooltip { + position: relative; + border-bottom: 1px dotted black; +} + +.tooltip:before { + content: attr(tooltip-data); + position: absolute; + width: 250px; + background-color: #006aff; + color: #fff; + text-align: center; + padding: 15px; + line-height: 1.1; + border-radius: 5px; + z-index: 1; + opacity: 0; + transition: opacity .5s; + bottom: 125%; + left: 50%; + margin-left: -60px; + font-size: 0.70em; + visibility: hidden; +} + +.tooltip:after { + content: ""; + position: absolute; + bottom: 75%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + opacity: 0; + transition: opacity .5s; + border-color: #000 transparent transparent transparent; + visibility: hidden; +} + +.tooltip:hover:before, +.tooltip:hover:after { + opacity: 1; + visibility: visible; +} \ No newline at end of file diff --git a/_code-samples/mpt-generator/mpt-generator.htm b/_code-samples/mpt-generator/mpt-generator.htm new file mode 100644 index 0000000000..f49093acc5 --- /dev/null +++ b/_code-samples/mpt-generator/mpt-generator.htm @@ -0,0 +1,219 @@ + + + + MPT Generator + + + + + + + + + + +

MPT Generator

+
+ + +
+ + + + + +
+ + + + + + + + + + + + + + + +
+ + Choose your ledger instance: + +    + + +    + +
+ +
+
+ Account + +
+
+ + + + +
+ Seed + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Asset Scale + + + +
+ + Maximum Tokens + + + +
+ + Transfer Fee + + + +
+ + Clawback + + + +
+ + Lock + + + +
+ + Require Authorization + + + +
+ + Can Transfer + + + +
+ + Can Trade + + + +
+ + Can Escrow + + + +
+ Token Metadata +
+ +
+
+

MPToken Create Transaction

+

+   

+ + Link to Explorer entry for MPT Issuance. + +

+ +
+ + + + \ No newline at end of file diff --git a/_code-samples/mpt-generator/mpt-generator.js b/_code-samples/mpt-generator/mpt-generator.js new file mode 100644 index 0000000000..0aeda3a8f2 --- /dev/null +++ b/_code-samples/mpt-generator/mpt-generator.js @@ -0,0 +1,112 @@ +function generateCode() { + let v_flags = 0 + if (clawbackSlider.checked) {v_flags+=64} + if (lockSlider.checked) {v_flags+=2} + if (authTokensSlider.checked) {v_flags +=4} + if (txrSlider.checked) {v_flags += 32} + if (tradeSlider.checked) {v_flags += 16} + if (escrowSlider.checked) {v_flags+=8} + const mptHexString = xrpl.convertStringToHex(metadataTextArea.value) + let v_codeBlock = "{\n \"TransactionType\": \"MPTokenIssuanceCreate\",\n \"Account\": \"" + accountField.value + + "\",\n \"AssetScale\": 2, \n \"MaximumAmount\": \"" + maximumAmountField.value + + "\",\n \"TransferFee\": " + transferFeeField.value + + ",\n \"Flags\": " + v_flags + ",\n \"MPTokenMetadata\": \"" + mptHexString + "\"\n}" + + codeTextArea.value = v_codeBlock +} +// ****************************************************** +// ************* Get the Preferred Network ************** +// ****************************************************** + +function getNet() { + let net + if (document.getElementById("tn").checked) net = "wss://s.altnet.rippletest.net:51233" + if (document.getElementById("dn").checked) net = "wss://s.devnet.rippletest.net:51233" + return net + } // End of getNet() + + // ******************************************************* + // ************* Get Account ***************************** + // ******************************************************* + + async function getAccount() { + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + net + '....' + + //-------------------------------This uses the default faucet for Testnet/Devnet. + let faucetHost = null + codeTextArea.value = results + await client.connect() + results += '\nConnected, funding wallet.' + // ----------------------------------------Create and fund a test account wallet. + const my_wallet = (await client.fundWallet(null, { faucetHost })).wallet + results += '\nGot a wallet.' + + // ------------------------------------------------------Get the current balance. + const my_balance = (await client.getXrpBalance(my_wallet.address)) + accountField.value = my_wallet.address + seedField.value = my_wallet.seed + results += '\nAccount created.' + codeTextArea.value = results + client.disconnect() + } // End of getAccount() + + // ******************************************************* + // ************ Get Account from Seed ******************** + // ******************************************************* + + async function getAccountFromSeed() { + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '....' + await client.connect() + results += '\nConnected, finding wallets.\n' + codeTextArea.value = results + // --------------------------------------------------Find the test account wallet. + const my_wallet = xrpl.Wallet.fromSeed(seedField.value) + + // -------------------------------------------------------Get the current balance. + accountField.value = my_wallet.address + seedField.value = my_wallet.seed + client.disconnect() + } // End of getAccountFromSeed() + + // ******************************************************* + // *************** Send Transaction ********************** + // ******************************************************* + +async function sendTransaction() { + let v_flags = 0 + if (clawbackSlider.checked) {v_flags+=64} + if (lockSlider.checked) {v_flags+=2} + if (authTokensSlider.checked) {v_flags +=4} + if (txrSlider.checked) {v_flags += 32} + if (tradeSlider.checked) {v_flags += 16} + if (escrowSlider.checked) {v_flags+=8} + results = 'Connecting to ' + getNet() + '....' + console.log(results) + let net = getNet() + const my_wallet = xrpl.Wallet.fromSeed(seedField.value) + const client = new xrpl.Client(net) + await client.connect() + +const metadataHexString = xrpl.convertStringToHex(metadataTextArea.value) + +const transactionJson = { + "TransactionType": "MPTokenIssuanceCreate", + "Account": accountField.value, + "AssetScale": parseInt(assetScaleField.value), + "MaximumAmount": maximumAmountField.value, + "TransferFee": parseInt(transferFeeField.value), + "Flags": v_flags, + "MPTokenMetadata": metadataHexString +} + const tx = await client.submitAndWait(transactionJson, { wallet: my_wallet} ) + if (document.getElementById("tn").checked) { + codeTextArea.value += "\n Success! Ledger Index: " + tx.result.ledger_index + "\nSee https://testnet.xrpl.org/ledgers/" + tx.result.ledger_index + } else { + codeTextArea.value += "\n Success! Ledger Index: " + tx.result.ledger_index + "\nSee https://devnet.xrpl.org/ledgers/" + tx.result.ledger_index + } + urlField.value = "https://devnet.xrpl.org/ledgers/" + tx.result.ledger_index +} diff --git a/_code-samples/mpt-generator/mpt-generator.zip b/_code-samples/mpt-generator/mpt-generator.zip new file mode 100644 index 0000000000..e1565e80f7 Binary files /dev/null and b/_code-samples/mpt-generator/mpt-generator.zip differ diff --git a/docs/img/uc-mpt1-mpt-generator-empty-form.png b/docs/img/uc-mpt1-mpt-generator-empty-form.png new file mode 100644 index 0000000000..ad735a62ee Binary files /dev/null and b/docs/img/uc-mpt1-mpt-generator-empty-form.png differ diff --git a/docs/img/uc-mpt1-t-bill-create-success.png b/docs/img/uc-mpt1-t-bill-create-success.png index 5241edcbc6..5b43ef1eff 100644 Binary files a/docs/img/uc-mpt1-t-bill-create-success.png and b/docs/img/uc-mpt1-t-bill-create-success.png differ diff --git a/docs/img/uc-mpt1-t-bill-in-explorer.png b/docs/img/uc-mpt1-t-bill-in-explorer.png index 61854c4b89..5513ea22f6 100644 Binary files a/docs/img/uc-mpt1-t-bill-in-explorer.png and b/docs/img/uc-mpt1-t-bill-in-explorer.png differ diff --git a/docs/img/uc-mpt1-t-bill-mpt-generator-generate-code.png b/docs/img/uc-mpt1-t-bill-mpt-generator-generate-code.png index ca0351a7ad..ec796c9020 100644 Binary files a/docs/img/uc-mpt1-t-bill-mpt-generator-generate-code.png and b/docs/img/uc-mpt1-t-bill-mpt-generator-generate-code.png differ diff --git a/docs/img/uc-mpt1-t-bill-mpt-generator.png b/docs/img/uc-mpt1-t-bill-mpt-generator.png index 4351ebd9b0..569fb743f5 100644 Binary files a/docs/img/uc-mpt1-t-bill-mpt-generator.png and b/docs/img/uc-mpt1-t-bill-mpt-generator.png differ diff --git a/docs/use-cases/tokenization/creating-an-asset-backed-multi-purpose-token.md b/docs/use-cases/tokenization/creating-an-asset-backed-multi-purpose-token.md index 160e5d3ea4..b5bcffe562 100644 --- a/docs/use-cases/tokenization/creating-an-asset-backed-multi-purpose-token.md +++ b/docs/use-cases/tokenization/creating-an-asset-backed-multi-purpose-token.md @@ -23,6 +23,10 @@ To learn more, see [Multi-purpose Tokens](../../concepts/tokens/fungible-tokens/ The MPT Generator utility embedded on the page below lets you experiment with an MPT configuration in a sandbox environment. When you are satisfied with the settings, you can generate the transaction code required to create your MPT on Mainnet. +![MPT Generator Utility](../../img/uc-mpt1-mpt-generator-empty-form.png) + +You can download a [standalone version of the MPT Generator](../../../_code-samples/mpt-generator/mpt-generator.zip) as sample code, or use the embedded form that follows. + In practice, you want to use an Issuer account configuration to issue an MPT, but you can try the form below with a new account and the transaction works fine. See [Creating a US Treasury Bill](#creating-a-us-treasury-bill) for a full description of the issuance process. The form is populated with sample values, but you can change the parameters for your own experiments. A T-bill is just one example of the many types of asset you can create and trade on the XRP Ledger.