Incorporate MPT Use Case 2 with Use Case 1
103
_code-samples/mpt-sender/get-accounts.js
Normal file
@@ -0,0 +1,103 @@
|
||||
// ******************************************************
|
||||
// ************* 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(type) {
|
||||
let net = getNet()
|
||||
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + net + '....'
|
||||
|
||||
// This uses the default faucet for Testnet/Devnet
|
||||
let faucetHost = null
|
||||
|
||||
if (type == 'left') {
|
||||
leftResultField.value = results
|
||||
} else {
|
||||
rightResultField.value = results
|
||||
}
|
||||
await client.connect()
|
||||
|
||||
results += '\nConnected, funding wallet.'
|
||||
if (type == 'left') {
|
||||
leftResultField.value = results
|
||||
} else {
|
||||
rightResultField.value = results
|
||||
}
|
||||
|
||||
// -----------------------------------Create and fund a test account wallet
|
||||
const my_wallet = (await client.fundWallet(null, { faucetHost })).wallet
|
||||
|
||||
results += '\nGot a wallet.'
|
||||
if (type == 'left') {
|
||||
leftResultField.value = results
|
||||
} else {
|
||||
rightResultField.value = results
|
||||
}
|
||||
|
||||
// ------------------------------------------------------Get the current balance.
|
||||
const my_balance = (await client.getXrpBalance(my_wallet.address))
|
||||
|
||||
if (type == 'left') {
|
||||
leftAccountField.value = my_wallet.address
|
||||
leftBalanceField.value = (await client.getXrpBalance(my_wallet.address))
|
||||
leftSeedField.value = my_wallet.seed
|
||||
results += '\nStandby account created.'
|
||||
leftResultField.value = results
|
||||
} else {
|
||||
rightAccountField.value = my_wallet.address
|
||||
rightSeedField.value = my_wallet.seed
|
||||
rightBalanceField.value = (await client.getXrpBalance(my_wallet.address))
|
||||
results += '\nOperational account created.'
|
||||
rightResultField.value = results
|
||||
}
|
||||
// --------------- Capture the seeds for both accounts for ease of reload.
|
||||
seeds.value = leftSeedField.value + '\n' + rightSeedField.value
|
||||
client.disconnect()
|
||||
} // End of getAccount()
|
||||
|
||||
// *******************************************************
|
||||
// ********** Get Accounts from Seeds ********************
|
||||
// *******************************************************
|
||||
|
||||
async function getAccountsFromSeeds() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
leftResultField.value = results
|
||||
await client.connect()
|
||||
results += '\nConnected, finding wallets.\n'
|
||||
leftResultField.value = results
|
||||
|
||||
// -------------------------------------------------Find the test account wallets.
|
||||
var lines = seeds.value.split('\n')
|
||||
const left_wallet = xrpl.Wallet.fromSeed(lines[0])
|
||||
const right_wallet = xrpl.Wallet.fromSeed(lines[1])
|
||||
|
||||
// -------------------------------------------------------Get the current balance.
|
||||
const left_balance = (await client.getXrpBalance(left_wallet.address))
|
||||
const right_balance = (await client.getXrpBalance(right_wallet.address))
|
||||
|
||||
// ----------------------Populate the fields for Standby and Operational accounts.
|
||||
leftAccountField.value = left_wallet.address
|
||||
leftSeedField.value = left_wallet.seed
|
||||
leftBalanceField.value = (await client.getXrpBalance(left_wallet.address))
|
||||
|
||||
rightAccountField.value = right_wallet.address
|
||||
rightSeedField.value = right_wallet.seed
|
||||
rightBalanceField.value = (await client.getXrpBalance(right_wallet.address))
|
||||
|
||||
client.disconnect()
|
||||
|
||||
} // End of getAccountsFromSeeds()
|
||||
139
_code-samples/mpt-sender/mpt-generator.css
Normal file
@@ -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;
|
||||
}
|
||||
BIN
_code-samples/mpt-sender/mpt-sender.zip
Normal file
211
_code-samples/mpt-sender/send-mpt.html
Normal file
@@ -0,0 +1,211 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Send MPT Test Harness</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
|
||||
<link href="mpt-generator.css" rel="stylesheet">
|
||||
<script src='https://unpkg.com/xrpl@4.1.0/build/xrpl-latest.js'></script>
|
||||
<script src='get-accounts.js'></script>
|
||||
<script src='send-mpt.js'></script>
|
||||
<script>
|
||||
if (typeof module !== "undefined") {
|
||||
const xrpl = require('xrpl')
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<!-- ************************************************************** -->
|
||||
<!-- ********************** The Form ****************************** -->
|
||||
<!-- ************************************************************** -->
|
||||
|
||||
<body>
|
||||
<h1>Send MPTs</h1>
|
||||
<form id="theForm">
|
||||
Choose your ledger instance:
|
||||
|
||||
<input type="radio" id="tn" name="server"
|
||||
value="wss://s.altnet.rippletest.net:51233" >
|
||||
<label for="testnet">Testnet</label>
|
||||
|
||||
<input type="radio" id="dn" name="server"
|
||||
value="wss://s.devnet.rippletest.net:51233" checked>
|
||||
<label for="devnet">Devnet</label>
|
||||
<br/><br/>
|
||||
<button type="button" onClick="getAccountsFromSeeds()">Get Accounts From Seeds</button>
|
||||
<br/>
|
||||
<textarea id="seeds" cols="40" rows= "2"></textarea>
|
||||
<br/><br/>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<td>
|
||||
<button type="button" onClick="getAccount('left')">Get New Left Account</button>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td align="right">
|
||||
Left Account
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="leftAccountField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
Seed
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="leftSeedField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
XRP Balance
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="leftBalanceField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
Quantity
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="leftQuantityField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
Destination
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="leftDestinationField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
MPT Issuance ID
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="leftIssuanceIdField" size="40"></input>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p align="left">
|
||||
<textarea id="leftResultField" cols="80" rows="20" ></textarea>
|
||||
</p>
|
||||
</td>
|
||||
</td>
|
||||
<td>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td align="center" valign="top">
|
||||
<button type="button" onClick="MPTAuthorize()">Authorize MPTs</button>
|
||||
<br/>
|
||||
<button type="button" onClick="sendMPT()">Send MPT</button>
|
||||
<br/>
|
||||
<button type="button" onClick="getMPTs()">Get MPTs</button>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" valign="top">
|
||||
<button type="button" onClick="rightMPTAuthorize()">Authorize MPTs</button>
|
||||
<br/>
|
||||
<button type="button" onClick="rightSendMPT()">Send MPT</button>
|
||||
<br/>
|
||||
<button type="button" onClick="rightGetMPTs()">Get MPTs</button>
|
||||
</td>
|
||||
<td valign="top" align="right">
|
||||
<button type="button" onClick="getAccount('right')">Get New Right Account</button>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td align="right">
|
||||
Right Account
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="rightAccountField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
Seed
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="rightSeedField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
XRP Balance
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="rightBalanceField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
Quantity
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="rightQuantityField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
Destination
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="rightDestinationField" size="40"></input>
|
||||
<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
MPT Issuance ID
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="rightIssuanceIdField" size="40"></input>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p align="right">
|
||||
<textarea id="rightResultField" cols="80" rows="20" ></textarea>
|
||||
</p>
|
||||
</td>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
235
_code-samples/mpt-sender/send-mpt.js
Normal file
@@ -0,0 +1,235 @@
|
||||
// *******************************************************
|
||||
// ********************* Send MPT ************************
|
||||
// *******************************************************
|
||||
|
||||
async function sendMPT() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
document.getElementById('leftResultField').value = results
|
||||
|
||||
await client.connect()
|
||||
|
||||
results += '\nConnected.'
|
||||
leftResultField.value = results
|
||||
|
||||
const left_wallet = xrpl.Wallet.fromSeed(leftSeedField.value)
|
||||
const mpt_issuance_id = leftIssuanceIdField.value
|
||||
const mpt_quantity = leftQuantityField.value
|
||||
|
||||
const send_mpt_tx = {
|
||||
"TransactionType": "Payment",
|
||||
"Account": left_wallet.address,
|
||||
"Amount": {
|
||||
"mpt_issuance_id": mpt_issuance_id,
|
||||
"value": mpt_quantity,
|
||||
},
|
||||
"Destination": leftDestinationField.value,
|
||||
}
|
||||
|
||||
const pay_prepared = await client.autofill(send_mpt_tx)
|
||||
const pay_signed = left_wallet.sign(pay_prepared)
|
||||
results += `\n\nSending ${mpt_quantity} ${mpt_issuance_id} to ${leftDestinationField.value} ...`
|
||||
leftResultField.value = results
|
||||
const pay_result = await client.submitAndWait(pay_signed.tx_blob)
|
||||
if (pay_result.result.meta.TransactionResult == "tesSUCCESS") {
|
||||
|
||||
results += 'Transaction succeeded.\n\n'
|
||||
results += JSON.stringify(pay_result.result, null, 2)
|
||||
leftResultField.value = results
|
||||
} else {
|
||||
results += 'Transaction failed: See JavaScript console for details.'
|
||||
results += JSON.stringify(pay_result.result, null, 2)
|
||||
leftResultField.value = results
|
||||
}
|
||||
client.disconnect()
|
||||
} // end of sendMPT()
|
||||
|
||||
// *******************************************************
|
||||
// ******************** Get MPTs *************************
|
||||
// *******************************************************
|
||||
|
||||
async function getMPTs() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
leftResultField.value = results
|
||||
|
||||
await client.connect()
|
||||
const left_wallet = xrpl.Wallet.fromSeed(leftSeedField.value)
|
||||
results += '\nConnected.'
|
||||
leftResultField.value = results
|
||||
const left_mpts = await client.request({
|
||||
command: "account_objects",
|
||||
account: left_wallet.address,
|
||||
ledger_index: "validated",
|
||||
type: "mptoken"
|
||||
})
|
||||
let JSONString = JSON.stringify(left_mpts.result, null, 2)
|
||||
let JSONParse = JSON.parse(JSONString)
|
||||
let numberOfMPTs = JSONParse.account_objects.length
|
||||
console.log("length: " + numberOfMPTs)
|
||||
let x = 0
|
||||
while (x < numberOfMPTs){
|
||||
results += "\n\nMPT Issuance ID: " + JSONParse.account_objects[x].MPTokenIssuanceID
|
||||
+ "\nMPT Amount: " + JSONParse.account_objects[x].MPTAmount
|
||||
x++
|
||||
}
|
||||
results += "\n\n" + JSONString
|
||||
leftResultField.value = results
|
||||
client.disconnect()
|
||||
} // End of getMPTs()
|
||||
|
||||
// **********************************************************************
|
||||
// ****** MPTAuthorize Transaction ***************************************
|
||||
// **********************************************************************
|
||||
|
||||
async function MPTAuthorize() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
document.getElementById('leftResultField').value = results
|
||||
await client.connect()
|
||||
|
||||
const left_wallet = xrpl.Wallet.fromSeed(leftSeedField.value)
|
||||
const mpt_issuance_id = leftIssuanceIdField.value
|
||||
|
||||
const auth_mpt_tx = {
|
||||
"TransactionType": "MPTokenAuthorize",
|
||||
"Account": left_wallet.address,
|
||||
"MPTokenIssuanceID": mpt_issuance_id,
|
||||
}
|
||||
const auth_prepared = await client.autofill(auth_mpt_tx)
|
||||
const auth_signed = left_wallet.sign(auth_prepared)
|
||||
results += `\n\nSending authorization...`
|
||||
leftResultField.value = results
|
||||
const auth_result = await client.submitAndWait(auth_signed.tx_blob)
|
||||
|
||||
if (auth_result.result.meta.TransactionResult == "tesSUCCESS") {
|
||||
results += `Transaction succeeded`
|
||||
leftResultField.value = results
|
||||
} else {
|
||||
results += 'Transaction failed: See JavaScript console for details.'
|
||||
leftResultField.value = results
|
||||
}
|
||||
client.disconnect()
|
||||
} // end of MPTAuthorize()
|
||||
|
||||
// **********************************************************************
|
||||
// ****** Reciprocal Transactions ***************************************
|
||||
// **********************************************************************
|
||||
|
||||
// *******************************************************
|
||||
// ************* Right Send MPT ********
|
||||
// *******************************************************
|
||||
|
||||
async function rightSendMPT() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
rightResultField.value = results
|
||||
|
||||
await client.connect()
|
||||
|
||||
results += '\nConnected.'
|
||||
rightResultField.value = results
|
||||
|
||||
const right_wallet = xrpl.Wallet.fromSeed(rightSeedField.value)
|
||||
const mpt_issuance_id = rightIssuanceIdField.value
|
||||
const mpt_quantity = rightQuantityField.value
|
||||
|
||||
const send_mpt_tx = {
|
||||
"TransactionType": "Payment",
|
||||
"Account": right_wallet.address,
|
||||
"Amount": {
|
||||
"mpt_issuance_id": mpt_issuance_id,
|
||||
"value": mpt_quantity,
|
||||
},
|
||||
"Destination": rightDestinationField.value,
|
||||
}
|
||||
|
||||
const pay_prepared = await client.autofill(send_mpt_tx)
|
||||
const pay_signed = right_wallet.sign(pay_prepared)
|
||||
results += `\n\nSending ${mpt_quantity} ${mpt_issuance_id} to ${rightDestinationField.value} ...`
|
||||
rightResultField.value = results
|
||||
const pay_result = await client.submitAndWait(pay_signed.tx_blob)
|
||||
if (pay_result.result.meta.TransactionResult == "tesSUCCESS") {
|
||||
results += 'Transaction succeeded.\n\n'
|
||||
results += JSON.stringify(pay_result.result, null, 2)
|
||||
rightResultField.value = results
|
||||
} else {
|
||||
results += 'Transaction failed: See JavaScript console for details.'
|
||||
results += JSON.stringify(pay_result.result, null, 2)
|
||||
rightResultField.value = results
|
||||
}
|
||||
client.disconnect()
|
||||
} // end of rightSendMPT()
|
||||
|
||||
// **********************************************************************
|
||||
// ****** MPTAuthorize Transaction ***************************************
|
||||
// **********************************************************************
|
||||
|
||||
async function rightMPTAuthorize() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
document.getElementById('rightResultField').value = results
|
||||
await client.connect()
|
||||
|
||||
const right_wallet = xrpl.Wallet.fromSeed(rightSeedField.value)
|
||||
const mpt_issuance_id = rightIssuanceIdField.value
|
||||
const auth_mpt_tx = {
|
||||
"TransactionType": "MPTokenAuthorize",
|
||||
"Account": right_wallet.address,
|
||||
"MPTokenIssuanceID": mpt_issuance_id,
|
||||
}
|
||||
const auth_prepared = await client.autofill(auth_mpt_tx)
|
||||
const auth_signed = right_wallet.sign(auth_prepared)
|
||||
results += `\n\nSending authorization...`
|
||||
rightResultField.value = results
|
||||
const auth_result = await client.submitAndWait(auth_signed.tx_blob)
|
||||
console.log(JSON.stringify(auth_result.result, null, 2))
|
||||
|
||||
if (auth_result.result.meta.TransactionResult == "tesSUCCESS") {
|
||||
results += `Transaction succeeded`
|
||||
rightResultField.value = results
|
||||
} else {
|
||||
results += 'Transaction failed: See JavaScript console for details.'
|
||||
rightResultField.value = results
|
||||
}
|
||||
client.disconnect()
|
||||
} // end of rightMPTAuthorize()
|
||||
|
||||
// **********************************************************************
|
||||
// ****** Right Get MPTs ***************************************
|
||||
// **********************************************************************
|
||||
|
||||
async function rightGetMPTs() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
rightResultField.value = results
|
||||
|
||||
await client.connect()
|
||||
const right_wallet = xrpl.Wallet.fromSeed(rightSeedField.value)
|
||||
results += '\nConnected.'
|
||||
rightResultField.value = results
|
||||
const right_mpts = await client.request({
|
||||
command: "account_objects",
|
||||
account: right_wallet.address,
|
||||
ledger_index: "validated",
|
||||
type: "mptoken"
|
||||
})
|
||||
let JSONString = JSON.stringify(right_mpts.result, null, 2)
|
||||
let JSONParse = JSON.parse(JSONString)
|
||||
let numberOfMPTs = JSONParse.account_objects.length
|
||||
let x = 0
|
||||
while (x < numberOfMPTs){
|
||||
results += "\n\nMPT Issuance ID: " + JSONParse.account_objects[x].MPTokenIssuanceID
|
||||
+ "\nMPT Amount: " + JSONParse.account_objects[x].MPTAmount
|
||||
x++
|
||||
}
|
||||
results += "\n\n" + JSONString
|
||||
rightResultField.value = results
|
||||
client.disconnect()
|
||||
} // End of rightGetMPTs()
|
||||
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 253 KiB |
|
Before Width: | Height: | Size: 528 KiB After Width: | Height: | Size: 456 KiB |
|
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 224 KiB |
|
Before Width: | Height: | Size: 523 KiB After Width: | Height: | Size: 440 KiB |
|
Before Width: | Height: | Size: 324 KiB After Width: | Height: | Size: 278 KiB |
BIN
docs/img/uc-mpt2-mpt-sender-empty-form.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
@@ -138,6 +138,7 @@ const transactionJson = {
|
||||
} else {
|
||||
successURLfield.value = "https://devnet.xrpl.org/ledgers/" + tx.result.ledger_index
|
||||
}
|
||||
mptIssuanceIdField.value = JSON.stringify(tx.result.meta.mpt_issuance_id)
|
||||
} //End of sendTransaction()
|
||||
|
||||
</script>
|
||||
@@ -340,6 +341,11 @@ const transactionJson = {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p><b>MPT Issuance ID</b><br/>
|
||||
<input type="text" id="mptIssuanceIdField" size="40"></input>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -374,6 +380,8 @@ The form sets the standard flags for an Issuer account and displays additional c
|
||||
| **Signer Weights** | _int_ | The weight of each signer's signature, relative to other signers. |
|
||||
| **Signer Quorum** | _int_ | The required minimum value of signer weights to approve a transaction. |
|
||||
|
||||
{% admonition type="info" name="Note" %}In practice, configuring signers for your issuing account is a best practice. To reduce complexity, this example does not use signer configuration.{% /admonition %}
|
||||
|
||||
#### Issuer Account Flag Settings
|
||||
|
||||
Use the sliders to configure the standard suggested flag settings. Overall, you want holders of your T-bill to be able to trade with other holders, so rippling is an essential function. You want to be careful about what other accounts are able to send to your account, so you should disallow most types of transfers. One exception is trust lines, which you do want other accounts to be able to create to your issuing account.
|
||||
@@ -429,7 +437,7 @@ The metadata you provide is what distinguishes your token from other MPTs. The f
|
||||
"ExternalUrl": "https://example.com/t-bill-token-metadata.json"
|
||||
}
|
||||
```
|
||||
Once you've set your preferred values, click **Generate Code** to see the transaction syntax for your settings. The `Flags` field displays the sum of the flags you've selected, and the `MPTokenMetadata` is converted to a hexidecimal string.
|
||||
Once you've set your preferred values, click **Generate Transaction** to see the transaction syntax for your settings. The `Flags` field displays the sum of the flags you've selected, and the `MPTokenMetadata` is converted to a hexidecimal string.
|
||||
|
||||

|
||||
|
||||
@@ -437,6 +445,8 @@ To create your T-bill MPT, click **Send Transaction**. When your transaction suc
|
||||
|
||||

|
||||
|
||||
Follow the link and scroll down to find the `MPTokenIssuanceCreate` transaction for your new T-bill in the Explorer.
|
||||
Be sure to copy and save the **Seed** field and the **MPT Issuance ID** so that you can try transferring the MPT to another account as shown in [Sending an MPT](./send-an-mpt.md).
|
||||
|
||||
Follow the link appended to the result field and scroll down to find the `MPTokenIssuanceCreate` transaction for your new T-bill in the Explorer.
|
||||
|
||||

|
||||
@@ -20,6 +20,10 @@ const useCases = [
|
||||
description: "NFT Marketplace",
|
||||
link: "/docs/use-cases/tokenization/nftoken-marketplace/",
|
||||
},
|
||||
{
|
||||
description: "MPT Overview",
|
||||
link: "/docs/use-cases/tokenization/mpt-overview/"
|
||||
},
|
||||
{
|
||||
description: "Authorized Minter",
|
||||
link: "/docs/use-cases/tokenization/authorized-minter/",
|
||||
|
||||
26
docs/use-cases/tokenization/mpt-overview.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
seo:
|
||||
description: Overview of Multi-purpose Token use cases.
|
||||
labels:
|
||||
- Tokenization
|
||||
- MPT
|
||||
- Multi-purpose Token
|
||||
---
|
||||
|
||||
# Multi-purpose Tokens Overview
|
||||
|
||||
Multi-purpose Tokens (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.
|
||||
|
||||
- [Creating an Asset-based Multi-purpose Token](./creating-an-asset-backed-multi-purpose-token.md)
|
||||
- [Sending an MPT](./send-an-mpt.md)
|
||||
@@ -1,6 +1,4 @@
|
||||
---
|
||||
html: nft-mkt-overview.html
|
||||
parent: tokenization.html
|
||||
seo:
|
||||
description: Overview of NFT Marketplace use cases.
|
||||
labels:
|
||||
|
||||
368
docs/use-cases/tokenization/send-an-mpt.md
Normal file
@@ -0,0 +1,368 @@
|
||||
---
|
||||
seo:
|
||||
description: Issue an asset-backed token such as a US Treasury bill using multi-purpose tokens.
|
||||
labels:
|
||||
- Tokens
|
||||
- MPT
|
||||
---
|
||||
# Sending an MPT
|
||||
|
||||
_As an XRPL holder, I want to send multi-purpose tokens to another account in order to complete an offline transaction._
|
||||
|
||||
To send an MPT to another account, the receiving account must first authorize the receipt of the MPT, based on its MPToken Issuance ID. This is to prevent malicious users from spamming accounts with unwanted tokens that could negatively impact storage and XRP reserves.
|
||||
|
||||
## Send MPT Utility
|
||||
|
||||
The Send MPT utility embedded on the page below lets you create an account to receive an MPT, authorize it to receive a specific MPT issuance, then send an MPT from an issuer or holder account. (You can issue an MPT using the [MPT Generator](./creating-an-asset-backed-multi-purpose-token.md) utility.)
|
||||
|
||||

|
||||
|
||||
You can download a [standalone version of the MPT Sender](../../../_code-samples/mpt-sender/mpt-sender.zip) as sample code, or use the embedded form that follows.
|
||||
|
||||
<div>
|
||||
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
|
||||
<script src='https://unpkg.com/xrpl@4.1.0/build/xrpl-latest.js'></script>
|
||||
<script>
|
||||
if (typeof module !== "undefined") {
|
||||
const xrpl = require("xrpl")
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
getHolderAccountFromSeedButton.addEventListener("click", getHolderFromSeed)
|
||||
getReceiverAccountButton.addEventListener("click", getAccount)
|
||||
getReceiverFromSeedButton.addEventListener("click", getReceiverFromSeed)
|
||||
authorizeMPTButton.addEventListener("click", authorizeMPT)
|
||||
sendMPTButton.addEventListener("click", sendMPT)
|
||||
getMPTsButton.addEventListener("click", getMPTs)
|
||||
})
|
||||
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)
|
||||
receiverAccountField.value = "Getting a new account..."
|
||||
results = 'Connecting to ' + net + '....'
|
||||
//-------------------------------This uses the default faucet for Testnet/Devnet.
|
||||
let faucetHost = null
|
||||
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.
|
||||
receiverAccountField.value = my_wallet.address
|
||||
receiverSeedField.value = my_wallet.seed
|
||||
results += '\nAccount created.'
|
||||
console.log(results)
|
||||
client.disconnect()
|
||||
} // End of getAccount()
|
||||
// **********************************************************
|
||||
// *********** Get Holder from Seed *************************
|
||||
// **********************************************************
|
||||
async function getHolderFromSeed() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
holderAccountField.value = "Getting holder account from seed..."
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
await client.connect()
|
||||
results += '\nConnected, finding wallets.\n'
|
||||
console.log(results)
|
||||
// --------------------------------------------------Find the test account wallet.
|
||||
const my_wallet = xrpl.Wallet.fromSeed(holderSeedField.value)
|
||||
// -------------------------------------------------------Get the current balance.
|
||||
holderAccountField.value = my_wallet.address
|
||||
holderSeedField.value = my_wallet.seed
|
||||
client.disconnect()
|
||||
} // End of getHolderFromSeed()
|
||||
// **********************************************************
|
||||
// *********** Get Receiver from Seed *************************
|
||||
// **********************************************************
|
||||
async function getReceiverFromSeed() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
receiverAccountField.value = "Getting receiver account from seed..."
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
await client.connect()
|
||||
results += '\nConnected, finding wallets.\n'
|
||||
resultsArea.value = results
|
||||
// --------------------------------------------------Find the test account wallet.
|
||||
const my_wallet = xrpl.Wallet.fromSeed(receiverSeedField.value)
|
||||
// -------------------------------------------------------Get the current balance.
|
||||
receiverAccountField.value = my_wallet.address
|
||||
receiverSeedField.value = my_wallet.seed
|
||||
resultsArea.value = results
|
||||
client.disconnect()
|
||||
} // End of getReceiverFromSeed()
|
||||
// *******************************************************
|
||||
// *************** Send MPT **********************
|
||||
// *******************************************************
|
||||
async function sendMPT() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
resultsArea.value = results
|
||||
await client.connect()
|
||||
results += '\nConnected.'
|
||||
resultsArea.value = results
|
||||
const holder_wallet = xrpl.Wallet.fromSeed(holderSeedField.value)
|
||||
const mpt_issuance_id = mptIssuanceIDField.value
|
||||
const mpt_quantity = quantityField.value
|
||||
const send_mpt_tx = {
|
||||
"TransactionType": "Payment",
|
||||
"Account": holder_wallet.address,
|
||||
"Amount": {
|
||||
"mpt_issuance_id": mpt_issuance_id,
|
||||
"value": mpt_quantity,
|
||||
},
|
||||
"Destination": receiverAccountField.value,
|
||||
}
|
||||
const pay_prepared = await client.autofill(send_mpt_tx)
|
||||
const pay_signed = holder_wallet.sign(pay_prepared)
|
||||
results += `\n\nSending ${mpt_quantity} ${mpt_issuance_id} to ${receiverAccountField.value} ...`
|
||||
resultsArea.value = results
|
||||
const pay_result = await client.submitAndWait(pay_signed.tx_blob)
|
||||
if (pay_result.result.meta.TransactionResult == "tesSUCCESS") {
|
||||
results += 'Transaction succeeded.\n\n'
|
||||
results += JSON.stringify(pay_result.result, null, 2)
|
||||
resultsArea.value = results
|
||||
} else {
|
||||
results += 'Transaction failed: See JavaScript console for details.'
|
||||
results += JSON.stringify(pay_result.result, null, 2)
|
||||
resultsArea.value = results
|
||||
}
|
||||
client.disconnect()
|
||||
} // end of sendMPT()
|
||||
// *******************************************************
|
||||
// ******************** Get MPTs *************************
|
||||
// *******************************************************
|
||||
async function getMPTs() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
resultsArea.value = results
|
||||
await client.connect()
|
||||
const receiver_wallet = xrpl.Wallet.fromSeed(receiverSeedField.value)
|
||||
results += '\nConnected.'
|
||||
resultsArea.value = results
|
||||
const mpts = await client.request({
|
||||
command: "account_objects",
|
||||
account: receiver_wallet.address,
|
||||
ledger_index: "validated",
|
||||
type: "mptoken"
|
||||
})
|
||||
let JSONString = JSON.stringify(mpts.result, null, 2)
|
||||
let JSONParse = JSON.parse(JSONString)
|
||||
let numberOfMPTs = JSONParse.account_objects.length
|
||||
let x = 0
|
||||
while (x < numberOfMPTs){
|
||||
results += "\n\nMPT Issuance ID: " + JSONParse.account_objects[x].MPTokenIssuanceID
|
||||
+ "\nMPT Amount: " + JSONParse.account_objects[x].MPTAmount
|
||||
x++
|
||||
}
|
||||
results += "\n\n" + JSONString
|
||||
resultsArea.value = results
|
||||
client.disconnect()
|
||||
} // End of getMPTs()
|
||||
// **********************************************************************
|
||||
// ****** MPTAuthorize Transaction ***************************************
|
||||
// **********************************************************************
|
||||
async function authorizeMPT() {
|
||||
let net = getNet()
|
||||
const client = new xrpl.Client(net)
|
||||
results = 'Connecting to ' + getNet() + '....'
|
||||
resultsArea.value = results
|
||||
await client.connect()
|
||||
const receiver_wallet = xrpl.Wallet.fromSeed(receiverSeedField.value)
|
||||
const mpt_issuance_id = mptIssuanceIDField.value
|
||||
const auth_mpt_tx = {
|
||||
"TransactionType": "MPTokenAuthorize",
|
||||
"Account": receiver_wallet.address,
|
||||
"MPTokenIssuanceID": mpt_issuance_id,
|
||||
}
|
||||
const auth_prepared = await client.autofill(auth_mpt_tx)
|
||||
const auth_signed = receiver_wallet.sign(auth_prepared)
|
||||
results += `\n\nSending authorization...`
|
||||
resultsArea.value = results
|
||||
const auth_result = await client.submitAndWait(auth_signed.tx_blob)
|
||||
console.log(JSON.stringify(auth_result.result, null, 2))
|
||||
if (auth_result.result.meta.TransactionResult == "tesSUCCESS") {
|
||||
results += `Transaction succeeded`
|
||||
resultsArea.value = results
|
||||
} else {
|
||||
results += 'Transaction failed: See JavaScript console for details.'
|
||||
resultsArea.value = results
|
||||
}
|
||||
client.disconnect()
|
||||
} // end of MPTAuthorize()
|
||||
</script>
|
||||
<div>
|
||||
<form>
|
||||
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
|
||||
<script src='https://unpkg.com/xrpl@4.1.0/build/xrpl-latest.js'></script>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<h4>MPT Sender</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<b>1. Choose your preferred network.</b>
|
||||
</div>
|
||||
<div class="col align-self-center">
|
||||
<input type="radio" id="tn" name="server"
|
||||
value="wss://s.altnet.rippletest.net:51233">
|
||||
<label for="tn">Testnet</label>
|
||||
<br/>
|
||||
<input type="radio" id="dn" name="server"
|
||||
value="wss://s.devnet.rippletest.net:51233" checked>
|
||||
<label for="dn">Devnet</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<b>2. Get the holder (or issuer) account from its seed.<br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<label for="holderSeedField">Holder Seed</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<input type="text" id="holderSeedField" size="40"></input>
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<label for="holderAccountField">Holder Account</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<input type="text" id="holderAccountField" size="40"></input>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<button type="button" id="getHolderAccountFromSeedButton" class="btn btn-primary">Get Holder Account From Seed</button>
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<b>3. Get a new receiver account or retrieve one from its seed.</b>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<label for="receiverSeedField">Receiver Seed</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<input type="text" id="receiverSeedField" size="40"></input>
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<label for="receiverAccountField">Receiver Account</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<input type="text" id="receiverAccountField" size="40"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<button type="button" id="getReceiverAccountButton" class="btn btn-primary">Get New Receiver Account</button>
|
||||
</div>
|
||||
<div class="col align-self-start">
|
||||
<button type="button" id="getReceiverFromSeedButton" class="btn btn-primary">Get Receiver Account From Seed</button>
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<b>4. Enter the <i>MPT Issuance ID</i>.</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<label for="mptIssuanceIDField">MPT Issuance ID</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<input type="text" id="mptIssuanceIDField" size="40"></input>
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<b>5. Click <i>Authorize MPT</i> to authorize the MPT for the receiver.</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<button type="button" id="authorizeMPTButton" class="btn btn-primary">Authorize MPT</button>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<b>5. Enter the <i>Quantity</i> of MPTs to send.</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<label for="quantity">Quantity</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col align-self-start">
|
||||
<input type="text" id="quantityField" size="40"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-align-items-left">
|
||||
<br/>
|
||||
<p><b>6. Click Send MPTs</b><br/>
|
||||
<button type="button" id="sendMPTButton" class="btn btn-primary">Send MPTs</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-align-self-start">
|
||||
<p><b>Results</b></p>
|
||||
<textarea class="form-control" id="resultsArea" rows="18" cols="40"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-align-self-start">
|
||||
<br/>
|
||||
<p><b>7. Click Get MPTs</b><br/>
|
||||
<button type = "button" id="getMPTsButton" class="btn btn-primary">Get MPTs</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<hr/>
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
expanded: false
|
||||
items:
|
||||
- page: docs/use-cases/tokenization/stablecoin-issuer.md
|
||||
- page: docs/use-cases/tokenization/creating-an-asset-backed-multi-purpose-token.md
|
||||
- page: docs/use-cases/tokenization/nft-mkt-overview.md
|
||||
expanded: false
|
||||
items:
|
||||
@@ -34,6 +33,11 @@
|
||||
- page: docs/use-cases/tokenization/authorized-minter.md
|
||||
- page: docs/use-cases/tokenization/digital-artist.md
|
||||
- page: docs/use-cases/tokenization/real-world-assets.page.tsx
|
||||
- page: docs/use-cases/tokenization/mpt-overview.md
|
||||
expanded: false
|
||||
items:
|
||||
- page: docs/use-cases/tokenization/creating-an-asset-backed-multi-purpose-token.md
|
||||
- page: docs/use-cases/tokenization/send-an-mpt.md
|
||||
- page: docs/use-cases/defi/index.md
|
||||
expanded: false
|
||||
items:
|
||||
|
||||