Estimated reading time:

25分鐘

Difficulty:

Beginner

Key takeaway:

瞭解如何在XRPL鏈上建立信託專線並發送貨幣,使用課程中的程式沙盒來體驗XRPL.js函式庫。

Lesson 1

建立信託專線並轉帳貨幣

在XRPL測試網的兩個帳戶間建立信任線並轉帳貨幣。

本課將展示如何操作:

  1. 設定帳戶的約定資金轉入第三方帳戶功能。
  2. 設定轉帳交易的貨幣別。
  3. 在備用帳戶和營運帳戶之間建立信託專線。
  4. 在帳戶間轉帳預設的貨幣別。
  5. 顯示帳戶內所有貨幣別的餘額。

實作編碼:create-trustline-send-currency.js

下面的互動式程式示例可用於任何一種XRPL網路。 目前,有測試網跟開發網支援NFTokens的實作。 在自行開發時,可以根據你選擇的XRPL網路修改程式。 我們建議您在新視窗中點擊「在Codepen上編輯」(右上角的連結)。

開啟代幣測試框架獲取帳戶:

  1. 使用上面的沙盒在帳戶間傳送貨幣。 我們建議您在新視窗中點擊「在Codepen上編輯」(右上角的連結)。
  2. 獲取測試帳戶。
    1. 如果您已有帳戶種子
      1. 將帳戶種子貼上到種子欄位。
      2. 點選從種子連結配對的帳戶
    2. 如果您沒有帳戶種子:
      1. 選獲取新的備用帳戶
      2. 點擊獲取新營運帳戶

建立信任線

帳戶間設定信任線:

  1. 在「貨幣」欄位中輸入貨幣代碼(範例中為美元)。
  2. 在「金額」欄位中輸入轉賬上限金額(如9999)。
  3. 目的地欄位中輸入目標帳戶值。
  4. 點擊「建立信任線」。

傳送已在鏈上發行的貨幣代幣

您建立了信任線之後,就可以移轉已在鏈上發行的貨幣代幣:

  1. 輸入金額欄位數量
  2. 輸入目的地的帳號
  3. 輸入貨幣別的代碼
  4. 點擊傳送貨幣執行轉帳功能。

JavaScript程式練習:create-trustline-send-currency.js

設定帳戶()

在轉移法定貨幣時,實際的資金轉移不會像轉帳瑞波幣XRP那樣進行,因為法定法幣有貶值的可能性,如果貨幣是以不同的貨幣別轉讓給第三方帳戶,貨幣貶值可能會影響發起轉帳的帳戶方,為了避免這種情況,這種貨幣價值的上下區間估值,被稱為「波動」,因此,在轉帳預設交易中是不允許的。預設的情況是從一個帳戶轉帳出去的貨幣只能轉回相同帳戶,要向第三方啟用貨幣轉帳功能,需要先將rippleDefault值設定為true,代幣測試框架中提供選項框,用以啟用或停用「波動」值。

連接帳本。
將結果欄位更新為狀態。
取得帳戶錢包。
準備交易。如果 rippleDefault 參數為 true,則設定 asfDefaultRipple 標誌;如果為 false,則清除 asfDefaultRipple 標誌。
自動填入交易的預設值。
簽署交易。
提交交易並等待結果。
將結果回報到結果欄位。
斷開與帳本的連接。
// *******************************************************
// **************** Configure Account ********************
// *******************************************************
      
      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()
      } // End of configureAccount()
      
取得待命錢包和運作中的錢包。
從待命貨幣欄位擷取貨幣代碼。
將交易定義為從表單欄位擷取貨幣代碼和(限額)金額。
準備交易,並自動填寫預設參數。
簽署交易。
提交交易並等待結果。
報告結果。

建立信任線()

一個信任線允許兩個賬戶在設定的限額下交易指定貨幣,這讓參與者確信,任何交換都是在已知實體之間以商定的最高金額進行的。

// *******************************************************
// ***************** Create TrustLine ********************
// *******************************************************
      
      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()傳送已發行貨幣

一旦您建立了從帳戶到自己的帳戶的信任行,您就可以向該帳戶傳送已發行的貨幣代幣,最高限額為既定限額。

// *******************************************************
// *************** Send Issued Currency ******************
// *******************************************************
      
      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 餘額。
斷開與帳本的連接。

獲取餘額()

// *******************************************************
// ****************** 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()請求沒有附帶互惠交易,因為這個指令只是用來顯示兩個帳戶的餘額。

// **********************************************************************
// ****** Reciprocal Transactions ***************************************
// **********************************************************************
      
// *******************************************************
// ************ Create Operational TrustLine *************
// *******************************************************
      
      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}'
        }
      } //End of oPcreateTrustline
      
// *******************************************************
// ************* Operational Send Issued Currency ********
// *******************************************************
      
      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()

網頁表單預覽: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>
END OF LESSON

現在您已經瞭解了一些關於在 XRP分類帳上創建信任線和發送貨幣的知識,請通過測驗來測試您的理解。

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

為什麼使用代幣和貨幣進行交易需要信任線?