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

本課將展示如何操作:
- 設定帳戶的約定資金轉入第三方帳戶功能。
- 設定轉帳交易的貨幣別。
- 在備用帳戶和營運帳戶之間建立信託專線。
- 在帳戶間轉帳預設的貨幣別。
- 顯示帳戶內所有貨幣別的餘額。
實作編碼:create-trustline-send-currency.js
下面的互動式程式示例可用於任何一種XRPL網路。 目前,有測試網跟開發網支援NFTokens的實作。 在自行開發時,可以根據你選擇的XRPL網路修改程式。 我們建議您在新視窗中點擊「在Codepen上編輯」(右上角的連結)。
開啟代幣測試框架獲取帳戶:
- 使用上面的沙盒在帳戶間傳送貨幣。 我們建議您在新視窗中點擊「在Codepen上編輯」(右上角的連結)。
- 獲取測試帳戶。
- 如果您已有帳戶種子
- 將帳戶種子貼上到種子欄位。
- 點選從種子連結配對的帳戶。
- 如果您沒有帳戶種子:
- 點選獲取新的備用帳戶。
- 點擊獲取新營運帳戶。
- 如果您已有帳戶種子
建立信任線
帳戶間設定信任線:
- 在「貨幣」欄位中輸入貨幣代碼(範例中為美元)。
- 在「金額」欄位中輸入轉賬上限金額(如9999)。
- 在目的地欄位中輸入目標帳戶值。
- 點擊「建立信任線」。
傳送已在鏈上發行的貨幣代幣
您建立了信任線之後,就可以移轉已在鏈上發行的貨幣代幣:
- 輸入金額欄位數量。
- 輸入目的地的帳號。
- 輸入貨幣別的代碼。
- 點擊傳送貨幣執行轉帳功能。
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>