예상 독서 시간

25분

난이도

중급

주요 요점

XRP Ledger에서 NFT를 발행하고 소각하는 방법을 알아보세요. XRPL.js 라이브러리 코드를 실험하려면 강의의 코드 샌드박스를 사용하세요.

레슨1

NFT를 발행하고 소각하기

XRP Ledger에서 NFT를 발행하고 소각하세요.

이 강의에서는 다음을 배웁니다.

  1. 대체 불가능한 토큰 (NFT)를 발행합니다 .
  2. 계정에 있는 기존 NFT 목록을 가져옵니다.
  3. NFT를 삭제(burn) 합니다.

코드를 편집해 보세요: mint-and-burn-nfts.js

아래의 대화형 코드 예제는 모든 XRP Ledger 네트워크( 테스트넷 , 개발넷 또는 메인넷) 와 함께 사용할 수 있습니다. 빌드할 때, 다른 XRP Ledger 네트워크나 추가 XRP Ledger 네트워크를 선택할 수 있도록 코드를 수정할 수 있습니다.

 

계정 받기

  1. 코드 샌드박스를 엽니다. 새 창에서 “Edit on Codepen”을 클릭하는 것을 권장합니다.
  2. 테스트 계정을 받습니다.
    1. 기존 NFT-Devnet 계정 시드가 있는 경우:
      1. Seed 필드에 계정 시드를 붙여 넣습니다.
      2. “Get Accounts from Seeds”를 클릭합니다.
    2. 기존 NFT-Devnet 계정이 없는 경우:
      1. “Get New Standby Account”를 클릭합니다.
      2. “Get New Operational Account”를 클릭합니다.

NFToken 발행

대체 불가능 토큰을 발행하기 위해:

  1. “Flag” 필드를 설정합니다. 테스트 목적으로 값을 8로 설정하는 것을 추천합니다. 이렇게 하면 tsTransferable 플래그가 설정되어 NFToken 객체를 다른 계정으로 전송할 수 있습니다. 그렇지 않으면 NFToken 객체를 발급 계정으로만 다시 전송할 수 있습니다. NFToken을 발행하는 데 사용할 수 있는 모든 플래그에 대한 정보는 NFToken Mint를 참조하세요.
  2. “Token URL”을 입력합니다. 이는 NFToken 개체와 관련된 데이터 또는 메타데이터를 가리키는 URI입니다. 고유한 샘플 URI가 없는 경우 제공된 샘플 URI를 사용할 수 있습니다.
  3. “Transfer Fee” 입력합니다. 이는 NFToken의 미래 판매 수익의 백분율로, 원래 제작자에게 반환됩니다. 이는 0-50000을 포함하는 값으로, 0.001% 단위로 0.000%에서 50.000% 사이의 전송률을 허용합니다. NFToken을 전송할 수 있도록 “Flags” 필드를 설정하지 않은 경우 이 필드를 0으로 설정합니다.
  4. “Mint Token”을 클릭합니다.

토큰 얻기

“Get Tokens”를 클릭하면 해당 계정이 소유한 NFT 토큰 목록을 가져옵니다.

토큰 소각

NFToken의 현재 소유자는 언제든지 NFToken 객체를 파기(burn) 할 수 있습니다.

NFToken을 영구적으로 파기하기 위해:

  1. “Token ID” 를 입력합니다.
  2. “Burn Token” 을 클릭합니다.

JavaScript 코드 연습: ripplex3-mint-nfts.js

mintToken()

XRPL에 연결하고 계정 지갑을 가져옵니다.
트랜잭션을 정의합니다.
hex URI를 convertStringToHex 유틸리티를 사용하여 문자열로 변환합니다.
NFToken을 제3자에게 양도 가능하게 하려면 Flags 필드를 8로 설정합니다.
Transfer Fee는 0에서 50000까지의 값으로, 0.000%에서 50.000%까지의 로열티를 0.001 단위로 설정하는 데 사용됩니다.
TokenTaxon은 필수 값입니다. 발행자가 정의한 임의의 값입니다. 필드에 사용할 용도가 없으면 0으로 설정할 수 있습니다.
트랜잭션을 전송하고 응답을 기다립니다.
계정이 소유한 NFT 목록을 요청합니다.
결과를 보고합니다.
XRPL과 연결을 끊습니다.
// *******************************************************
// ********************** 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()

XRPL에 연결하고 계정 지갑을 가져옵니다.
계정이 소유한 NFT 목록을 요청합니다.
결과를 보고합니다.
XRPL과 연결을 끊습니다.
// *******************************************************
// ******************* 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()

XRPL에 연결하고 계정 지갑을 가져옵니다.
트랜잭션을 정의합니다.
트랜잭션을 제출하고 결과를 기다립니다.
클라이언트가 소유한 NFTokens 목록을 요청합니다.
결과를 보고합니다.
XRPL과 연결을 끊습니다.
// *******************************************************
// ********************* 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()

HTML 폼 미리보기: 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>

Additional resources

수업 종료

지금까지 배운 내용을 테스트할 시간입니다!

1. NFTokenTaxon ID는 무엇에 사용되나요?
2. 5000의 TransferFee는 어떤 수수료를 뜻하나요?
3. NFToken의 URI는 어떤 정보를 저장하기 위한 것인가요?