Estimated reading time:

25分鐘

Difficulty:

Intermediate

Key takeaway:

瞭解如何在XRPL鏈上鑄造和銷毀NFT,使用課程中的程式沙盒來體驗XRPL.js函式庫。

Lesson 1

鑄造和銷燬NFTs

在XRPL鏈上鑄造和銷燬NFT。

本課將展示如何操作:

  1. 鑄造全新非同質性代幣(NFT)。
  2. 產生帳戶上現有NFTs藏品列表。
  3. 刪除(燃燒)一顆NFT。

程式實作:mint-and-burn-nfts.js

下面的互動式程式範例可以用於任何一種XRPL網路使用:測試網、開發網或主網。 在自行開發時,可以根據選擇的XRPL網路更新程式。

 

獲取帳戶

  1. 開啟上面的程式沙盒。 我們建議您在新視窗中點擊「在Codepen上編輯」(右上角的連結
  2. 獲取測試帳戶。
    1. 如果您已有NFT-Devnet帳戶種子:
      1. 將帳戶種子貼上到種子欄位中。
      2. 點擊「從種子中獲取帳戶」。
    2. 如果您沒有NFT-Devnet帳戶:
      1. 點按「獲取新的備用帳戶」。
      2. 點按「獲取新營運帳戶

鑄造一顆NFT代幣

鑄造一顆非同質性代幣物件:

  1. .設定「標誌」欄位。 基於測試目的,建議將數值設定為8。 設定tsTransferableflag,代表NFToken物件可以轉移到另一個帳戶。 否則,NFToken物件預設只能轉回NFT發行帳戶。 有關鑄造NFTokens的所有可用標誌的資訊,請參閱NFToken Mint。
  2. 輸入代幣網址。 這是一個URI,指向與NFToken物件關聯的資料或元數據。 如果您沒有自己的URI,您可以使用範例提供的URI。
  3. 輸入轉讓費,即未來銷售NFToken收益的百分比,該收益將歸還給原始NFTs建立者。 這是包含0-50000的區間值,允許0.000%到50.000%之間的轉移率,以0.001%為增量。 如果您沒有在「標誌」欄位設定允許NFToken的可轉讓性,需將此欄位設定為0。
  4. 點擊鑄造代幣

獲取代幣

單擊「獲取代幣」以獲取帳戶內的NFToken藏品列表。

銷燬一顆代幣

NFToken的目前持有者可以銷燬(或燒燬)NFToken物件。

永久銷燬NFToken:

  1. 輸入代幣編號Token ID
  2. 點擊燒毀代幣 Burn Token

JavaScript程式演練:ripplex3-mint-nfts.js

mintToken()

連接到帳本並獲取帳戶錢包。
定義交易。
使用 convertStringToHex 工具將十六進位 URI 轉換成字串。
如果您希望 NFToken 可以轉讓給第三方,請將 Flags 欄位設為 8。
轉讓費用是一個介於0到50000之間的數值,用於設定版稅,範圍從0.000%到50.000%,以0.001為增量。

這句英文翻成繁體中文是:

TokenTaxon 是必填欄位。它是由發行者自行定義的任意值。如果您沒有使用此欄位的需求,可以將其設為 0。

發送交易並等待回應。
請求該帳戶所擁有的 NFT 清單。
報告結果。
從分類帳中斷連線。
// *******************************************************
// ********************** Mint Token *********************
// *******************************************************
      
async function mintToken() {
  results = 'Connecting to ' + getNet() + '....'
  standbyResultField.value = results
  let net = getNet()
  const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
  const client = new xrpl.Client(net)
  await client.connect()
  results += 'nConnected. Minting NFToken.'
  standbyResultField.value = results
      
  // Note that you must convert the token URL to a hexadecimal 
  // value for this transaction.
  // ------------------------------------------------------------------------
  const transactionBlob = {
    "TransactionType": "NFTokenMint",
    "Account": standby_wallet.classicAddress,
    "URI": xrpl.convertStringToHex(standbyTokenUrlField.value),

    "Flags": parseInt(standbyFlagsField.value),

    "TransferFee": parseInt(standbyTransferFeeField.value),

    "NFTokenTaxon": 0 //Required, but if you have no use for it, set to zero.
  }

  // ----------------------------------------------------- Submit signed blob 
  const tx = await client.submitAndWait(transactionBlob, { wallet: standby_wallet} )
  const nfts = await client.request({
    method: "account_nfts",
    account: standby_wallet.classicAddress  
  })
        
  // ------------------------------------------------------- Report results
  results += 'nnTransaction result: '+ tx.result.meta.TransactionResult
  results += 'nnnfts: ' + JSON.stringify(nfts, null, 2)
  standbyBalanceField.value = 
    (await client.getXrpBalance(standby_wallet.address))
  standbyResultField.value = results    
  client.disconnect()
} //End of mintToken()

getTokens()

連接分類帳並取得帳戶錢包。
請求帳戶所擁有的 NFT 清單。
報告結果。
從分類帳中斷連線。
// *******************************************************
// ******************* Get Tokens ************************
// *******************************************************
      
async function getTokens() {
  const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
  let net = getNet()
  const client = new xrpl.Client(net)
  results = 'Connecting to ' + net + '...'
  standbyResultField.value = results
  await client.connect()
  results += 'nConnected. Getting NFTokens...'
  standbyResultField.value = results
  const nfts = await client.request({
    method: "account_nfts",
    account: standby_wallet.classicAddress  
  })
  results += 'nNFTs:n ' + JSON.stringify(nfts,null,2)
  standbyResultField.value = results
  client.disconnect()
} //End of getTokens()

burnToken()

連接到分類帳並取得帳戶錢包。
定義該交易。
提交交易並等待結果。
請求一份客戶所擁有的 NFTokens 清單。
報告結果。
從分類帳斷開連接。
// *******************************************************
// ********************* Burn Token **********************
// *******************************************************
      
async function burnToken() {
  const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
  let net = getNet()
  const client = new xrpl.Client(net)
  results = 'Connecting to ' + net + '...'
  standbyResultField.value = results
  await client.connect()
  results += 'nConnected. Burning NFToken...'
  standbyResultField.value = results

  // ------------------------------------------------------- Prepare transaction
  const transactionBlob = {
    "TransactionType": "NFTokenBurn",
    "Account": standby_wallet.classicAddress,
    "NFTokenID": standbyTokenIdField.value
  }

  //---------------------------------- Submit transaction and wait for the results
  const tx = await client.submitAndWait(transactionBlob,{wallet: standby_wallet})
  const nfts = await client.request({
    method: "account_nfts",
    account: standby_wallet.classicAddress  
  })
  results += 'nTransaction result: '+ tx.result.meta.TransactionResult
  results += 'nBalance changes: ' +
  JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
  standbyResultField.value = results
  standbyBalanceField.value = 
    (await client.getXrpBalance(standby_wallet.address))
  results += 'nNFTs: n' + JSON.stringify(nfts,null,2)
  standbyResultField.value = results
  client.disconnect()
}// End of burnToken()

設定帳戶間交易費 oPmintToken(), oPgetTokens() and oPburnToken()

// **********************************************************************
// ****** Reciprocal Transactions ***************************************
// **********************************************************************
   
// *******************************************************
// ************** Operational Mint Token *****************
// *******************************************************
      
async function oPmintToken() {
  results = 'Connecting to ' + getNet() + '....'
  operationalResultField.value = results
  let net = getNet()
  const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
  const client = new xrpl.Client(net)
  await client.connect()
  results += 'nConnected. Minting NFToken.'
  operationalResultField.value = results

  // Note that you must convert the token URL to a hexadecimal 
  // value for this transaction.
  // ------------------------------------------------------------------------
  const transactionBlob = {
    "TransactionType": 'NFTokenMint',
    "Account": operational_wallet.classicAddress,
    "URI": xrpl.convertStringToHex(operationalTokenUrlField.value),
    "Flags": parseInt(operationalFlagsField.value),
    "TransferFee": parseInt(operationalTransferFeeField.value),
    "NFTokenTaxon": 0 //Required, but if you have no use for it, set to zero.
  }
      
  // ----------------------------------------------------- Submit signed blob 
  const tx = await client.submitAndWait(transactionBlob, { wallet: operational_wallet} )
  const nfts = await client.request({
    method: "account_nfts",
    account: operational_wallet.classicAddress  
  })
        
  // ------------------------------------------------------- Report results
  results += 'nnTransaction result: '+ tx.result.meta.TransactionResult
  results += 'nnnfts: ' + JSON.stringify(nfts, null, 2)
  operationalBalanceField.value = 
    (await client.getXrpBalance(operational_wallet.address))
  operationalResultField.value = results    

  client.disconnect()
} //End of oPmintToken
      
// *******************************************************
// ************** Operational Get Tokens *****************
// *******************************************************

async function oPgetTokens() {
  const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
  let net = getNet()
  const client = new xrpl.Client(net)
  results = 'Connecting to ' + getNet() + '...'
 operationalResultField.value = results
 await client.connect()
  results += 'nConnected. Getting NFTokens...'
  operationalResultField.value = results
  const nfts = await client.request({
    method: "account_nfts",
    account: operational_wallet.classicAddress  
  })
  results += 'nNFTs:n ' + JSON.stringify(nfts,null,2)
  operationalResultField.value = results
  client.disconnect()
} //End of oPgetTokens
      
// *******************************************************
// ************* Operational Burn Token ******************
// *******************************************************
      
async function oPburnToken() {
  const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
  let net = getNet()
  const client = new xrpl.Client(net)
  results = 'Connecting to ' + getNet() + '...'
  operationalResultField.value = results
  await client.connect()
  results += 'nConnected. Burning NFToken...'
  operationalResultField.value = results
      
  // ------------------------------------------------------- Prepare transaction
  const transactionBlob = {
    "TransactionType": "NFTokenBurn",
    "Account": operational_wallet.classicAddress,
    "NFTokenID": operationalTokenIdField.value
  }
      
  //-------------------------------------------------------- Submit signed blob
  const tx = await client.submitAndWait(transactionBlob,{wallet: operational_wallet})
  const nfts = await client.request({
    method: "account_nfts",
    account: operational_wallet.classicAddress  
  })
  results += 'nTransaction result: '+ tx.result.meta.TransactionResult
  results += 'nBalance changes: ' +
    JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
  operationalResultField.value = results
  operationalBalanceField.value = 
    (await client.getXrpBalance(operational_wallet.address))
  operationalBalanceField.value = 
    (await client.getXrpBalance(operational_wallet.address))
  results += 'nNFTs: n' + JSON.stringify(nfts,null,2)
  operationalResultField.value = results
  client.disconnect()
}
// End of oPburnToken()

網頁表單預覽: 3.mint-nfts.html

下方粗體字代表支援新功能的表單改變。

<html>
  <head>
    <title>Token Test Harness</title>
    <link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
    <style>
       body{font-family: "Work Sans", sans-serif;padding: 20px;background: #fafafa;}
       h1{font-weight: bold;}
       input, button {padding: 6px;margin-bottom: 8px;}
       button{font-weight: bold;font-family: "Work Sans", sans-serif;}
       td{vertical-align: top;padding-right:10px;}
    </style>
    <script src='https://unpkg.com/xrpl@2.2.3'></script>
    <script>
      if (typeof module !== "undefined") {
        const xrpl = require('xrpl')
      }
    </script>
  </head>
  
<!-- ************************************************************** -->
<!-- ********************** The Form ****************************** -->
<!-- ************************************************************** -->

  <body>
    <h1>Token Test Harness</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>
            <button type="button" onClick="getAccount('standby')">Get New Standby Account</button>
            <table>
              <tr valign="top">
                <td align="left">
                  Standby Account<br/> <input type="text" id="standbyAccountField" size="30" />
                </td>
                <td></td>
              </tr>
              <tr>
                <td align="left">
                  Public Key<br/>
                  <input type="text" id="standbyPubKeyField" size="30"></input>                                                 </td>
                <td align="left">
                  Private Key<br/>
                  <input type="text" id="standbyPrivKeyField" size="30"></input>
                </td>
              </tr>
              <tr>
                <td align="left">
                  Seed <br/>
                  <input type="text" id="standbySeedField" size="30"></input>
                  <br>
                </td>
                <td align="left">
                  XRP Balance <br/>
                  <input type="text" id="standbyBalanceField" size="30"></input>
                </td>
            </tr>
            <tr>
                <td align="left">
                  Amount<br/>
                  <input type="text" id="standbyAmountField" size="30"></input>
                </td>
                <td align="left">
                  Destination Account <br/>
                <input type="text" id="standbyDestinationField" size="30"></input>
                </td>
              </tr>
              <tr valign="top">
                <td><button type="button" onClick="configureAccount('standby',document.querySelector('#standbyDefault').checked)">Configure Account</button><br/>
                  <input type="checkbox" id="standbyDefault" checked="true"/>
                  <label for="standbyDefault">Allow Rippling</label>
                </td>

                <td>
                  Currency<br/>
                  <input type="text" id="standbyCurrencyField" size="30" value="USD"></input>
                </td>
              </tr>
              <tr>
                <td colspan=2>NFToken URL<br/>
                  <input type="text" id="standbyTokenUrlField"
                  value = "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf4dfuylqabf3oclgtqy55fbzdi" size="70"/>
                </td>
              </tr>
              <tr>
                <td colspan=2>Flags<br/>
                  <input type="text" id="standbyFlagsField" value="1" size="10"/></td>
              </tr>
              <tr>
                <td colspan=2>NFToken ID<br/>
                  <input type="text" id="standbyTokenIdField" value="" size="70"/></td>
              </tr>
              <tr>
                <td colspan=2>Transfer Fee<br/>
                  <input type="text" id="standbyTransferFeeField" value="" size="70"/></td>
              </tr>
              <tr>
                <td colspan=2>
                  <p align="right">
                    <button type="button" onClick="sendXRP()">Send XRP ↓</button>
                    <button type="button" onClick="createTrustline()">Create TrustLine</button>
                    <button type="button" onClick="sendCurrency()">Send Currency</button>
                    <button type="button" onClick="getBalances()">Get Balances</button>
                    <br/>
                    <button type="button" onClick="mintToken()">Mint NFToken</button>
                    <button type="button" onClick="getTokens()">Get NFTokens</button>
                    <button type="button" onClick="burnToken()">Burn NFToken</button>
                  </p>
                </td>
              </tr>
            </table>
          </td>
          <td valign="top">
            <textarea id="standbyResultField" cols="60" rows="20" ></textarea>
          </td>
        </tr>
      </table>
      <br/><br/>
      <table>
        <tr valign="top">
          <td>
            <button type="button" onClick="getAccount('operational')">Get New Operational Account</button>
            <table>
              <tr valign="top">
                <td align="left">
                  Operational Account<br/> <input type="text" id="operationalAccountField" size="30" />
                </td>
                <td></td>
              </tr>
              <tr>
                <td align="left">Public Key<br/>
                  <input type="text" id="operationalPubKeyField" size="30" />                                                 </td>
                <td align="left">
                  Private Key<br/>
                  <input type="text" id="operationalPrivKeyField" size="30"></input>
                </td>
              </tr>
              <tr>
                <td align="left">
                  Seed <br/>
                  <input type="text" id="operationalSeedField" size="30"></input>
                  <br>
                </td>
                <td align="left">
                  XRP Balance <br/>
                  <input type="text" id="operationalBalanceField" size="30" />
                </td>
            </tr>
            <tr>
                <td align="left">
                  Amount<br/>
                  <input type="text" id="operationalAmountField" size="30" />
                </td>
                <td align="left">
                  Destination Account <br/>
                <input type="text" id="operationalDestinationField" size="30" />
                </td>
              </tr>
              <tr valign="top">
                <td><button type="button" onClick="configureAccount('operational',document.querySelector('#operationalDefault').checked)">Configure Account</button><br/>
                  <input type="checkbox" id="operatoinalDefault" checked="true"/>
                  <label for="operationalDefault">Allow Rippling</label>
                </td>

                <td>
                  Currency<br/>
                  <input type="text" id="operationalCurrencyField" size="30" value="USD"></input>
                </td>
              </tr>
                            <tr>
                <td colspan=2>NFToken URL<br/>
                  <input type="text" id="operationalTokenUrlField"
                  value = "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf4dfuylqabf3oclgtqy55fbzdi" size="70"/>
                </td>
              </tr>
              <tr>
                <td colspan=2>Flags<br/>
                  <input type="text" id="operationalFlagsField" value="1" size="10"/></td>
              </tr>
              <tr>
                <td colspan=2>NFToken ID<br/>
                  <input type="text" id="operationalTokenIdField" value="" size="70"/></td>
              </tr>
              <tr>
                <td colspan=2>Transfer Fee<br/>
                  <input type="text" id="operationalTransferFeeField" value="" size="70"/></td>
              </tr>
              <tr>
                <td colspan=2>
                  <p align="right">
                    <button type="button" onClick="oPsendXRP()">Send XRP ↑</button>
                    <button type="button" onClick="oPcreateTrustline()">Create TrustLine</button>
                    <button type="button" onClick="oPsendCurrency()">Send Currency</button>
                    <button type="button" onClick="getBalances()">Get Balances</button>
                    <br/>
                    <button type="button" onClick="oPmintToken()">Mint NFToken</button>
                    <button type="button" onClick="oPgetTokens()">Get NFTokens</button>
                    <button type="button" onClick="oPburnToken()">Burn NFToken</button>
                  </p>
                </td>
              </tr>
            </table>
          </td>
          <td>
            <textarea id="operationalResultField" cols="60" rows="20" ></textarea>
          </td>
        </tr>
      </table>
    </form>
  </body>
  <script src='ripplex1-send-xrp.js' async></script>
  <script src='ripplex2-send-currency.js' async></script>
  <script src='ripplex3-mint-nfts.js' async></script>
</html>

其他資源

END OF LESSON

現在您已經瞭解了一些關於在 XRP 分類帳上鑄造和銷毀 NFT 的知識,請通過測驗來測試您的理解

Welcome to your Mint and burn NFTs (CH)

NFTokenTaxon ID 是做什麼用的?