完了目安時間:

25分

難易度:

Intermediate

重要なポイント:

XRP Ledgerでトラストラインを作成し、通貨を送信する方法を学びます。レッスン内のコードサンドボックスを使用して、XRPL.jsライブラリのコードを試してみてください。

Lesson 1

トラストラインの作成と通貨の送信

XRPL Testnet上の2つのアカウント間にトラストラインを作成し、通貨を転送します。

このレッスンでは、以下の方法を説明します。

  1. 第三者のアカウントへの資金移動を許可するようにアカウントを設定
  2. トランザクションの通貨タイプを設定
  3. スタンバイアカウントとオペレーションアカウントの間にトラストラインを作成
  4. アカウント間で発行された通貨を送信
  5. アカウントのすべての通貨の残高を表示

コードを編集してみる:create-trustline-send-currency.js

以下のインタラクティブなコード例は、どのXRP Ledgerネットワークでも使用できます。現在、TestnetとDevnetがあり、実験的なNFT-DevnetサーバーはNFTokenをサポートしています。ご自身で構築する際には、コードを更新して、別の、または追加のXRP Ledgerネットワークを選択できます。新しいウィンドウで「Edit on Codepen」(右上のリンク)をクリックすることをお勧めします。

Token Test Harnessを開き、アカウントを取得する:

  1. 上記のサンドボックスを使用して、アカウント間で通貨を送金してください。新しいウィンドウで「Edit on Codepen」をクリックすることをお勧めします(右上にリンクがあります)。
  2. テストアカウントの取得
    1. If you have existing account seeds
      1. 既存のアカウントシードがある場合
      2. シードフィールドにアカウントのシードを貼り付ける
    2. アカウントのシードがない場合
      1. 新規スタンバイアカウントを取得をクリック
      2. 新規オペレーションアカウントを取得をクリック

トラストラインの作成

アカウント間でトラストラインを作成するには:

  1. 通貨フィールドに通貨コードを入力(ここではUSDを使用)。
  2. 金額フィールドに、最大の送金制限額(9999など)を入力
  3. 宛先フィールドに、宛先アカウントの値を入力します。
  4. トラストラインを作成をクリック

発行済みの通貨トークンの送信

発行された通貨トークンを転送するには、まずトラストラインを作成する必要があります。

  1. 金額の入力
  2. 宛先の入力
  3. 通貨の入力
  4. 通貨を送信をクリック

JavaScriptコードのウォークスルー:create-trustline-send-currency.js

configureAccount()

法定通貨の送金では、XRPのように資金の実際の移動が同時には行われません。異なる通貨のために第三者に通貨が送金される場合、元の口座に影響を与える通貨の切り下げが発生する可能性があります。この通貨の上下の評価(ripplingと呼ばれます)を避けるため、デフォルトでは許可されていません。あるアカウントから送金された通貨は、同じアカウントにしか送金できません。第三者への通貨送金を有効にするには、defaultRIppletの値をtrueに設定する必要があります。Token Test Harnessには、ripplingを有効または無効にするためのチェックボックスがあります。

レジャーに接続します。
ステータスを results フィールドに更新します。
アカウントのウォレットを取得します。
トランザクションを準備します。rippleDefault 引数が true の場合は asfDefaultRipple フラグを設定し、false の場合はクリアします。
トランザクションのデフォルト値を自動入力します。
トランザクションに署名します。
トランザクションを送信し、結果が出るまで待ちます。
結果を results フィールドに表示します。
レジャーから切断します。
// *******************************************************
// **************** アカウントの設定 ********************
// *******************************************************
      
      async function configureAccount(type, rippleDefault) {
        let net = getNet()
        const client = new xrpl.Client(net)
        results = 'Connecting to ' + getNet() + '....'
        standbyResultField.value = results
        await client.connect()
        results += 'nConnected, finding wallet.'
        standbyResultField.value = results
 
        if (type=='standby') {
          my_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
        } else {
          my_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
        }
        results += 'Ripple Default Setting: ' + rippleDefault
        standbyResultField.value = results
        
        let settings_tx = {}
        if (rippleDefault) {
          settings_tx = {
          "TransactionType": "AccountSet",
          "Account": my_wallet.address,
          "SetFlag": xrpl.AccountSetAsfFlags.asfDefaultRipple
          } 
          results += 'n Set Default Ripple flag.' 
        } else {
          settings_tx = {
          "TransactionType": "AccountSet",
          "Account": my_wallet.address,
          "ClearFlag": xrpl.AccountSetAsfFlags.asfDefaultRipple
          }
          results += 'n Clear Default Ripple flag.' 
        }
          results += 'nSending account setting.'
          standbyResultField.value = results
      
          const cst_prepared = await client.autofill(settings_tx)

          const cst_signed = my_wallet.sign(cst_prepared)
          const cst_result = await client.submitAndWait(cst_signed.tx_blob)
          if (cst_result.result.meta.TransactionResult == "tesSUCCESS") {
          results += 'nAccount setting succeeded.'
          standbyResultField.value = results
          } else {
          throw 'Error sending transaction: ${cst_result}'
          results += 'nAccount setting failed.'
          standbyResultField.value = results
          }
      
        client.disconnect()
      } // configureAccount()の終わり
      
スタンバイ用と運用用のウォレットを取得します。
スタンバイ通貨フィールドから通貨コードを取得します。
トランザクションを定義し、フォームフィールドから通貨コードと(制限)金額を取得します。
トランザクションを準備し、デフォルトパラメータを自動入力します。
トランザクションに署名します。
トランザクションを送信し、結果が出るまで待ちます。
結果を表示します。

createTrustline()

トラストラインを使用すると、2つのアカウントが、設定された上限まで特定の通貨を取引できるようになります。これにより、参加者は、すべての取引が既知のエンティティ間で、合意された最大金額内で行われることを保証されます。

// *******************************************************
// ***************** トラストラインの作成 ********************
// *******************************************************
      
      async function createTrustline() {
        let net = getNet()
        const client = new xrpl.Client(net)
        results = 'Connecting to ' + getNet() + '....'
        standbyResultField.value = results
        
        await client.connect()
        
        results += 'nConnected.'
        standbyResultField.value = results
          
        const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
        const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
        const currency_code = standbyCurrencyField.value

        const trustSet_tx = {
          "TransactionType": "TrustSet",
          "Account": standbyDestinationField.value,
          "LimitAmount": {
            "currency": standbyCurrencyField.value,
            "issuer": standby_wallet.address,
            "value": standbyAmountField.value
          }
        }
        const ts_prepared = await client.autofill(trustSet_tx)

        const ts_signed = operational_wallet.sign(ts_prepared)
        results += 'nCreating trust line from operational account to standby account...'
        standbyResultField.value = results
        const ts_result = await client.submitAndWait(ts_signed.tx_blob)
        if (ts_result.result.meta.TransactionResult == "tesSUCCESS") {
          results += 'nTrustline established between account n' + standbyDestinationField.value + ' n and accountn' + standby_wallet.address + '.'
          standbyResultField.value = results
        } else {
          results += 'nTrustLine failed. See JavaScript console for details.'
          standbyResultField.value = results     
          throw 'Error sending transaction: ${ts_result.result.meta.TransactionResult}'
        }
      } //End of createTrustline()
      
レジャーに接続します。
アカウントのウォレット、通貨コード、金額を取得します。
トランザクション情報を定数に保存します。
トランザクションを準備し、デフォルト値を自動入力します。
トランザクションに署名します。
トランザクションを送信し、結果が出るまで待ちます。
結果を表示します。
レジャーから切断します。

sendCurrency()で発行済みトークンの送信

アカウントから自身のアカウントへのトラストラインを作成したら、設定された制限まで、発行された通貨トークンをそのアカウントに送信できます。

// *******************************************************
// *************** 発行済みトークンの送信 ******************
// *******************************************************
      
      async function sendCurrency() {
        let net = getNet()
        const client = new xrpl.Client(net)
        results = 'Connecting to ' + getNet() + '....'
        standbyResultField.value = results
        
        await client.connect()
        
        results += 'nConnected.'
        standbyResultField.value = results
          
        const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
        const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
        const currency_code = standbyCurrencyField.value
        const issue_quantity = standbyAmountField.value
        
        const send_token_tx = {
          "TransactionType": "Payment",
          "Account": standby_wallet.address,
          "Amount": {
            "currency": standbyCurrencyField.value,
            "value": standbyAmountField.value,
            "issuer": standby_wallet.address
          },
          "Destination": standbyDestinationField.value
        }
      
        const pay_prepared = await client.autofill(send_token_tx)

        const pay_signed = standby_wallet.sign(pay_prepared)
        results += 'Sending ' + standbyAmountField.value + standbyCurrencyField.value + 'to ' + standbyDestinationField.value + '...'
        standbyResultField.value = results
        const pay_result = await client.submitAndWait(pay_signed.tx_blob)
        if (pay_result.result.meta.TransactionResult == "tesSUCCESS") {
          results += 'Transaction succeeded: https://testnet.xrpl.org/transactions/${pay_signed.hash}'
          standbyResultField.value = results
        } else {
          results += 'Transaction failed: See JavaScript console for details.'
          standbyResultField.value = results
          throw 'Error sending transaction: ${pay_result.result.meta.TransactionResult}'
        }
        standbyBalanceField.value = 
              (await client.getXrpBalance(standby_wallet.address))
        operationalBalanceField.value = 
              (await client.getXrpBalance(operational_wallet.address))
        getBalances()
        client.disconnect()
      
      } // end of sendIOU()
      
レジャーに接続します。
アカウントのウォレットを取得します。
スタンバイアカウント用のリクエストを定義して送信し、結果が出るまで待ちます。
結果を表示します。
運用アカウント用のリクエストを定義して送信し、結果が出るまで待ちます。
結果を表示します。
フォームを現在の XRP 残高で更新します。
レジャーから切断します。

getBalances()

// *******************************************************
// ****************** Get Balances ***********************
// *******************************************************

      async function getBalances() {
        let net = getNet()
        const client = new xrpl.Client(net)
        results = 'Connecting to ' + getNet() + '....'
        standbyResultField.value = results
        
        await client.connect()
        
        results += 'nConnected.'
        standbyResultField.value = results
       
        const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
        const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
      
        results= "nGetting standby account balances...n"
        const standby_balances = await client.request({
          command: "gateway_balances",
          account: standby_wallet.address,
          ledger_index: "validated",
          hotwallet: [operational_wallet.address]
        })
        results += JSON.stringify(standby_balances.result, null, 2)
        standbyResultField.value = results
      
        results= "nGetting operational account balances...n"
        const operational_balances = await client.request({
          command: "account_lines",
          account: operational_wallet.address,
          ledger_index: "validated"
        })
        results += JSON.stringify(operational_balances.result, null, 2)
        operationalResultField.value = results
      
        operationalBalanceField.value = 
          (await client.getXrpBalance(operational_wallet.address))
        standbyBalanceField.value = 
          (await client.getXrpBalance(standby_wallet.address))
          
        client.disconnect()
       
      } // End of getBalances()

反対のトランザクション oPcreateTrustline() とoPsendCurrency()

それぞれのトランザクションには、運用アカウントに対応する相互トランザクションが、oPという接頭辞を付けて存在します。コードの解説については、スタンバイアカウントに対応する関数を参照してください。getBalances()リクエストは、両方のアカウントの残高を報告するため、相互トランザクションはありません。

// **********************************************************************
// ****** 反対のトランザクション ***************************************
// **********************************************************************
      
// *******************************************************
// ************ 運用アカウントのトラストラインを作成 *************
// *******************************************************
      
      async function oPcreateTrustline() {
        let net = getNet()
        const client = new xrpl.Client(net)
        results = 'Connecting to ' + getNet() + '....'
        operationalResultField.value = results
        
        await client.connect()
        
        results += 'nConnected.'
        operationalResultField.value = results
          
        const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
        const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
        const trustSet_tx = {
          "TransactionType": "TrustSet",
          "Account": operationalDestinationField.value,
          "LimitAmount": {
            "currency": operationalCurrencyField.value,
            "issuer": operational_wallet.address,
            "value": operationalAmountField.value
          }
        }
        const ts_prepared = await client.autofill(trustSet_tx)
        const ts_signed = standby_wallet.sign(ts_prepared)
        results += 'nCreating trust line from operational account to ' + operationalDestinationField.value + ' account...'
        operationalResultField.value = results
        const ts_result = await client.submitAndWait(ts_signed.tx_blob)
        if (ts_result.result.meta.TransactionResult == "tesSUCCESS") {
          results += 'nTrustline established between account n' + standby_wallet.address + ' n and accountn' + operationalDestinationField.value + '.'
          operationalResultField.value = results
        } else {
          results += 'nTrustLine failed. See JavaScript console for details.'
          operationalResultField.value = results     
          throw 'Error sending transaction: ${ts_result.result.meta.TransactionResult}'
        }
      } //oPcreateTrustline()の終わり
      
// *******************************************************
// ************* 運用アカウントから発行済みトークンの送信 ********
// *******************************************************
      
      async function oPsendCurrency() {
        let net = getNet()
        const client = new xrpl.Client(net)
        results = 'Connecting to ' + getNet() + '....'
        operationalResultField.value = results
        
        await client.connect()
        
        results += 'nConnected.'
        operationalResultField.value = results
          
        const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
        const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
        const currency_code = operationalCurrencyField.value
        const issue_quantity = operationalAmountField.value
        
        const send_token_tx = {
          "TransactionType": "Payment",
          "Account": operational_wallet.address,
          "Amount": {
            "currency": currency_code,
            "value": issue_quantity,
            "issuer": operational_wallet.address
          },
          "Destination": operationalDestinationField.value
        }
      
        const pay_prepared = await client.autofill(send_token_tx)
        const pay_signed = operational_wallet.sign(pay_prepared)
        results += 'Sending' + operationalAmountField.value + operationalCurrencyField.value + ' to ' + operationalDestinationField.value + '...'
        operationalResultField.value = results
        const pay_result = await client.submitAndWait(pay_signed.tx_blob)
        if (pay_result.result.meta.TransactionResult == "tesSUCCESS") {
          results += 'Transaction succeeded: https://testnet.xrpl.org/transactions/${pay_signed.hash}'
          operationalResultField.value = results
        } else {
          results += 'Transaction failed: See JavaScript console for details.'
          operationalResultField.value = results
          throw 'Error sending transaction: ${pay_result.result.meta.TransactionResult}'
        }
        standbyBalanceField.value = 
              (await client.getXrpBalance(standby_wallet.address))
        operationalBalanceField.value = 
              (await client.getXrpBalance(operational_wallet.address))
        getBalances()
        client.disconnect()

      } // end of oPsendCurrency()

HTMLフォームのプレビュー:2.create-trustline-send-currency.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>
                  <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>
                  </p>
                </td>
              </tr>
            </table>
          </td>
          <td>
            <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>
                  <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>
                  </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>
</html>
レッスン終了

XRP Ledgerでトラストラインを作成し、通貨を送信する方法を学んだので、クイズで知識を試してみましょう。

Welcome to your Create trust line and send currency (JP)

トークンと通貨のトランザクションにトラストラインが必要なのはなぜですか?