mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-12-02 09:35:53 +00:00
Improve & refactor interactive tutorial code
Interactive tutorials: more consistent style Interactive tutorials: Use new generics for send-xrp, use-tickets Interactive tutorials: clean up now-unused code Interactive tutorials: progress & debugging of errors Interactive: Require Destination Tags; and related - Validate addresses in Transaction Sender and warn on Mainnet X-address - Option to load destination address from query param in Tx Sender - Some more/updated helpers in interactive tutorial JS Interactive tutorials: fix JA version Interactive tutorials: readme, include code filter (incomplete) Interactive tutorials: improvements for consistency Interactive Tutorials: finish readme Interactive tutorials: fix syntax errors
This commit is contained in:
11
content/_code-samples/require-destination-tags/demo.html
Normal file
11
content/_code-samples/require-destination-tags/demo.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/ripple-lib@1.9.1/build/ripple-latest-min.js"></script>
|
||||
<script type="application/javascript" src="../rippleapi_quickstart/semi-reliable-submit.js"></script>
|
||||
<script type="application/javascript" src="require-destination-tags.js"></script>
|
||||
</head>
|
||||
<body>Open your browser's console (F12) to see the logs.</body>
|
||||
</html>
|
||||
@@ -0,0 +1,85 @@
|
||||
// Connect -------------------------------------------------------------------
|
||||
api = new ripple.RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
|
||||
api.connect()
|
||||
api.on('connected', async () => {
|
||||
|
||||
// Get credentials from the Testnet Faucet -----------------------------------
|
||||
// This doesn't technically need to happen after you call api.connect() but
|
||||
// it's convenient to do here because we can use await on the faucet call and
|
||||
// to wait for the new account to be funded.
|
||||
const faucet_url = "https://faucet.altnet.rippletest.net/accounts"
|
||||
const response = await fetch(faucet_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: '{}'
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw `Faucet returned an error: ${data.error}`
|
||||
}
|
||||
const data = await response.json()
|
||||
const address = data.account.address
|
||||
const secret = data.account.secret
|
||||
|
||||
console.log("Waiting until we have a validated starting sequence number...")
|
||||
// If you go too soon, the funding transaction might slip back a ledger and
|
||||
// then your starting Sequence number will be off. This is mostly relevant
|
||||
// when you want to use a Testnet account right after getting a reply from
|
||||
// the faucet.
|
||||
while (true) {
|
||||
try {
|
||||
await api.request("account_info", {account: address, ledger_index: "validated"})
|
||||
break
|
||||
} catch(e) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send AccountSet transaction -----------------------------------------------
|
||||
const prepared = await api.prepareTransaction({
|
||||
"TransactionType": "AccountSet",
|
||||
"Account": address,
|
||||
"SetFlag": 1 // RequireDest
|
||||
})
|
||||
console.log("Prepared transaction:", prepared.txJSON)
|
||||
const max_ledger = prepared.instructions.maxLedgerVersion
|
||||
|
||||
const signed = api.sign(prepared.txJSON, secret)
|
||||
console.log("Transaction hash:", signed.id)
|
||||
const tx_id = signed.id
|
||||
const tx_blob = signed.signedTransaction
|
||||
|
||||
const prelim_result = await api.request("submit", {"tx_blob": tx_blob})
|
||||
console.log("Preliminary result:", prelim_result)
|
||||
const min_ledger = prelim_result.validated_ledger_index
|
||||
|
||||
// (Semi-)reliable Transaction Submission ------------------------------------
|
||||
console.log(`Begin final outcome lookup.
|
||||
tx_id: ${tx_id}
|
||||
max_ledger: ${max_ledger}
|
||||
min_ledger: ${min_ledger}`)
|
||||
let tx_status
|
||||
try {
|
||||
tx_status = await lookup_tx_final(tx_id, max_ledger, min_ledger)
|
||||
} catch(err) {
|
||||
tx_status = err
|
||||
}
|
||||
console.log("Final transaction status:", tx_status)
|
||||
|
||||
// Confirm Account Settings --------------------------------------------------
|
||||
let account_info = await api.request("account_info", {
|
||||
"account": address,
|
||||
"ledger_index": "validated"
|
||||
})
|
||||
const flags = api.parseAccountFlags(account_info.account_data.Flags)
|
||||
console.log(JSON.stringify(flags, null, 2))
|
||||
if (flags.requireDestinationTag) {
|
||||
console.log("Require Destination Tag is enabled.")
|
||||
} else {
|
||||
console.log("Require Destination Tag is DISABLED.")
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,85 @@
|
||||
function lookup_tx_final(tx_id, max_ledger, min_ledger) {
|
||||
if (typeof min_ledger == "undefined") {
|
||||
min_ledger = -1
|
||||
}
|
||||
if (typeof max_ledger == "undefined") {
|
||||
max_ledger = -1
|
||||
}
|
||||
if (min_ledger > max_ledger) {
|
||||
// Assume the args were just passed backwards & swap them
|
||||
[min_ledger, max_ledger] = [max_ledger, min_ledger]
|
||||
}
|
||||
|
||||
// Helper to determine if we (should) know the transaction's final result yet.
|
||||
// If the server has validated all ledgers the tx could possibly appear in,
|
||||
// then we should know its final result.
|
||||
async function server_has_ledger_range(min_ledger, max_ledger) {
|
||||
const si = await api.request("server_info")
|
||||
if (si.info.complete_ledgers == "empty") {
|
||||
console.warn("Connected server is not synced.")
|
||||
return false
|
||||
}
|
||||
// In case of a discontiguous set, use only the last set, since we need
|
||||
// continuous history from submission to expiration to know that a
|
||||
// transaction failed to achieve consensus.
|
||||
const ledger_ranges = si.info.complete_ledgers.split(',')
|
||||
// Note: last_range can be in the form 'x-y' or just 'y'
|
||||
const last_range = ledger_ranges[ledger_ranges.length -1].split('-')
|
||||
const lr_min = parseInt(last_range[0])
|
||||
const lr_max = parseInt(last_range[last_range.length - 1])
|
||||
const max_validated = Math.min(lr_max, lr_max)
|
||||
if (lr_min <= min_ledger && max_validated >= max_ledger) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
api.on('ledger', async (ledger) => {
|
||||
try {
|
||||
tx_result = await api.request("tx", {
|
||||
"transaction": tx_id,
|
||||
"min_ledger": min_ledger,
|
||||
"max_ledger": max_ledger
|
||||
})
|
||||
|
||||
if (tx_result.validated) {
|
||||
resolve(tx_result.meta.TransactionResult)
|
||||
} else if (max_ledger > ledger.ledgerVersion) {
|
||||
// Transaction found, not validated, but we should have a final result
|
||||
// by now.
|
||||
// Work around https://github.com/ripple/rippled/issues/3727
|
||||
if (server_has_ledger_range(min_ledger, max_ledger)) {
|
||||
// Transaction should have been validated by now.
|
||||
reject(`Transaction not found in ledgers ${min_ledger}-${max_ledger}. This result is final if this ledger is correct.`)
|
||||
} else {
|
||||
reject("Can't get final result. Check a full history server.")
|
||||
}
|
||||
} else {
|
||||
// Transaction may still be validated later. Keep waiting.
|
||||
}
|
||||
} catch(e) {
|
||||
if (e.data.error == "txnNotFound") {
|
||||
if (e.data.searched_all) {
|
||||
reject(`Transaction not found in ledgers ${min_ledger}-${max_ledger}. This result is final if this range is correct.`)
|
||||
} else {
|
||||
if (max_ledger > ledger.ledgerVersion) {
|
||||
// Transaction may yet be confirmed. This would not be a bad time
|
||||
// to resubmit the transaction just in case.
|
||||
} else {
|
||||
// Work around https://github.com/ripple/rippled/issues/3750
|
||||
if (server_has_ledger_range(min_ledger, max_ledger)) {
|
||||
reject(`Transaction not found in ledgers ${min_ledger}-${max_ledger}. This result is final if this range is correct.`)
|
||||
} else {
|
||||
reject("Can't get final result. Check a full history server.")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unknown error; pass it back up
|
||||
reject(`Unknown Error: ${e}`)
|
||||
}
|
||||
}
|
||||
}) // end ledger event handler
|
||||
}) // end promise def
|
||||
}
|
||||
12
content/_code-samples/send-xrp/demo.html
Normal file
12
content/_code-samples/send-xrp/demo.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Code Sample - Send XRP</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/ripple-lib@1.9.1/build/ripple-latest-min.js"></script>
|
||||
<script type="application/javascript" src="../rippleapi_quickstart/semi-reliable-submit.js"></script>
|
||||
<script type="application/javascript" src="send-xrp.js"></script>
|
||||
</head>
|
||||
<body>Open your browser's console (F12) to see the logs.</body>
|
||||
</html>
|
||||
107
content/_code-samples/send-xrp/send-xrp.js
Normal file
107
content/_code-samples/send-xrp/send-xrp.js
Normal file
@@ -0,0 +1,107 @@
|
||||
// Example credentials
|
||||
let address = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
let secret = "s████████████████████████████"
|
||||
|
||||
// Connect -------------------------------------------------------------------
|
||||
// ripple = require('ripple-lib') // For Node.js. In browsers, use <script>.
|
||||
api = new ripple.RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
|
||||
api.connect()
|
||||
api.on('connected', async () => {
|
||||
|
||||
// Get credentials from the Testnet Faucet -----------------------------------
|
||||
// This doesn't technically need to happen after you call api.connect() but
|
||||
// it's convenient to do here because we can use await on the faucet call and
|
||||
// to wait for the new account to be funded.
|
||||
const faucet_url = "https://faucet.altnet.rippletest.net/accounts"
|
||||
const response = await fetch(faucet_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: '{}'
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw `Faucet returned an error: ${data.error}`
|
||||
}
|
||||
const data = await response.json()
|
||||
address = data.account.address
|
||||
secret = data.account.secret
|
||||
|
||||
console.log("Waiting until we have a validated starting sequence number...")
|
||||
// If you go too soon, the funding transaction might slip back a ledger and
|
||||
// then your starting Sequence number will be off. This is mostly relevant
|
||||
// when you want to use a Testnet account right after getting a reply from
|
||||
// the faucet.
|
||||
while (true) {
|
||||
try {
|
||||
await api.request("account_info", {account: address, ledger_index: "validated"})
|
||||
break
|
||||
} catch(e) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare transaction -------------------------------------------------------
|
||||
const preparedTx = await api.prepareTransaction({
|
||||
"TransactionType": "Payment",
|
||||
"Account": address,
|
||||
"Amount": api.xrpToDrops("22"), // Same as "Amount": "22000000"
|
||||
"Destination": "rUCzEr6jrEyMpjhs4wSdQdz4g8Y382NxfM"
|
||||
}, {
|
||||
// Expire this transaction if it doesn't execute within ~5 minutes:
|
||||
"maxLedgerVersionOffset": 75
|
||||
})
|
||||
const maxLedgerVersion = preparedTx.instructions.maxLedgerVersion
|
||||
console.log("Prepared transaction instructions:", preparedTx.txJSON)
|
||||
console.log("Transaction cost:", preparedTx.instructions.fee, "XRP")
|
||||
console.log("Transaction expires after ledger:", maxLedgerVersion)
|
||||
|
||||
// Sign prepared instructions ------------------------------------------------
|
||||
const signed = api.sign(preparedTx.txJSON, secret)
|
||||
const txID = signed.id
|
||||
const tx_blob = signed.signedTransaction
|
||||
console.log("Identifying hash:", txID)
|
||||
console.log("Signed blob:", tx_blob)
|
||||
|
||||
// Submit signed blob --------------------------------------------------------
|
||||
// The earliest ledger a transaction could appear in is the first ledger
|
||||
// after the one that's already validated at the time it's *first* submitted.
|
||||
const earliestLedgerVersion = (await api.getLedgerVersion()) + 1
|
||||
const result = await api.submit(tx_blob)
|
||||
console.log("Tentative result code:", result.resultCode)
|
||||
console.log("Tentative result message:", result.resultMessage)
|
||||
|
||||
// Wait for validation -------------------------------------------------------
|
||||
let has_final_status = false
|
||||
api.request("subscribe", {accounts: [address]})
|
||||
api.connection.on("transaction", (event) => {
|
||||
if (event.transaction.hash == txID) {
|
||||
console.log("Transaction has executed!", event)
|
||||
has_final_status = true
|
||||
}
|
||||
})
|
||||
api.on('ledger', ledger => {
|
||||
if (ledger.ledgerVersion > maxLedgerVersion && !has_final_status) {
|
||||
console.log("Ledger version", ledger.ledgerVersion, "was validated.")
|
||||
console.log("If the transaction hasn't succeeded by now, it's expired")
|
||||
has_final_status = true
|
||||
}
|
||||
})
|
||||
|
||||
// There are other ways to do this, but they're more complicated.
|
||||
// See https://xrpl.org/reliable-transaction-submission.html for details.
|
||||
while (!has_final_status) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
|
||||
// Check transaction results -------------------------------------------------
|
||||
try {
|
||||
tx = await api.getTransaction(txID, {
|
||||
minLedgerVersion: earliestLedgerVersion})
|
||||
console.log("Transaction result:", tx.outcome.result)
|
||||
console.log("Balance changes:", JSON.stringify(tx.outcome.balanceChanges))
|
||||
} catch(error) {
|
||||
console.log("Couldn't get transaction outcome:", error)
|
||||
}
|
||||
|
||||
}) // End of api.on.('connected')
|
||||
@@ -1,76 +0,0 @@
|
||||
{% if faucet_url is undefined %}
|
||||
{% set faucet_url = "https://faucet.altnet.rippletest.net/accounts" %}
|
||||
{% endif %}
|
||||
|
||||
{{ start_step("Generate") }}
|
||||
<button id="generate-creds-button" class="btn btn-primary">暗号鍵を作成する</button>
|
||||
<div id='loader-0' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png">暗号鍵を作成しています…</div>
|
||||
<div id='address'></div>
|
||||
<div id='secret'></div>
|
||||
<div id='balance'></div>
|
||||
<div id="populate-creds-status"></div>
|
||||
{{ end_step() }}
|
||||
<script type="application/javascript">
|
||||
$(document).ready( () => {
|
||||
|
||||
$("#generate-creds-button").click( () => {
|
||||
// Wipe existing results
|
||||
$("#address").html("")
|
||||
$("#secret").html("")
|
||||
$("#balance").html("")
|
||||
$("#populate-creds-status").html("")
|
||||
|
||||
$("#loader-generate").show()
|
||||
|
||||
$.ajax({
|
||||
url: "{{faucet_url}}",
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$("#loader-generate").hide()
|
||||
$("#address").hide().html("<strong>アドレス:</strong> " +
|
||||
'<span id="use-address">' +
|
||||
data.account.address
|
||||
+ "</span>").show()
|
||||
$("#secret").hide().html('<strong>シード:</strong> ' +
|
||||
'<span id="use-secret">' +
|
||||
data.account.secret +
|
||||
"</span>").show()
|
||||
$("#balance").hide().html('<strong>残高:</strong> ' +
|
||||
Number(data.balance).toLocaleString('en') +
|
||||
' XRP').show()
|
||||
|
||||
// Automatically populate examples with these credentials...
|
||||
// Set sender address
|
||||
$("code span:contains('"+EXAMPLE_ADDR+"')").each( function() {
|
||||
let eltext = $(this).text()
|
||||
$(this).text( eltext.replace(EXAMPLE_ADDR, data.account.address) )
|
||||
})
|
||||
|
||||
// Set sender secret
|
||||
$("code span:contains('"+EXAMPLE_SECRET+"')").each( function() {
|
||||
let eltext = $(this).text()
|
||||
$(this).text( eltext.replace(EXAMPLE_SECRET, data.account.secret) )
|
||||
})
|
||||
|
||||
$("#populate-creds-status").text("このページの例にこのアドレスとシードを入力しました。")
|
||||
|
||||
complete_step("Generate")
|
||||
|
||||
},
|
||||
error: function() {
|
||||
$("#loader-generate").hide();
|
||||
$("#populate-creds-status").html(
|
||||
`<p class="devportal-callout warning"><strong>エラー:</strong>
|
||||
テストネットワークFaucetにエラーが発生しました。もう一度試してください。`);
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const EXAMPLE_ADDR = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const EXAMPLE_SECRET = "s████████████████████████████"
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
**注意:** Rippleは[TestnetとDevnet](parallel-networks.html)をテストの目的でのみ運用しており、その状態とすべての残高を定期的にリセットしています。予防措置として、Testnet、DevnetとMainnetで同じアドレスを使用**しない**ことをお勧めします。
|
||||
@@ -1,78 +0,0 @@
|
||||
{% if faucet_url is undefined %}
|
||||
{% set faucet_url = "https://faucet.altnet.rippletest.net/accounts" %}
|
||||
{% endif %}
|
||||
|
||||
{{ start_step("Generate") }}
|
||||
<button id="generate-creds-button" class="btn btn-primary">Generate credentials</button>
|
||||
<div id='loader-generate' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"> Generating Keys...</div>
|
||||
<div id='address'></div>
|
||||
<div id='secret'></div>
|
||||
<div id='balance'></div>
|
||||
<div id="populate-creds-status"></div>
|
||||
{{ end_step() }}
|
||||
<script type="application/javascript">
|
||||
$(document).ready( () => {
|
||||
|
||||
$("#generate-creds-button").click( () => {
|
||||
// Wipe existing results
|
||||
$("#address").html("")
|
||||
$("#secret").html("")
|
||||
$("#balance").html("")
|
||||
$("#populate-creds-status").html("")
|
||||
|
||||
$("#loader-generate").show()
|
||||
|
||||
$.ajax({
|
||||
url: "{{faucet_url}}",
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$("#loader-generate").hide()
|
||||
$("#address").hide().html("<strong>Address:</strong> " +
|
||||
'<span id="use-address">' +
|
||||
data.account.address
|
||||
+ "</span>").show()
|
||||
$("#secret").hide().html('<strong>Secret:</strong> ' +
|
||||
'<span id="use-secret">' +
|
||||
data.account.secret +
|
||||
"</span>").show()
|
||||
$("#balance").hide().html('<strong>Balance:</strong> ' +
|
||||
Number(data.balance).toLocaleString('en') +
|
||||
' XRP').show()
|
||||
|
||||
// Automatically populate examples with these credentials...
|
||||
// Set sender address
|
||||
$("code span:contains('"+EXAMPLE_ADDR+"')").each( function() {
|
||||
let eltext = $(this).text()
|
||||
$(this).text( eltext.replace(EXAMPLE_ADDR, data.account.address) )
|
||||
})
|
||||
|
||||
// Set sender secret
|
||||
$("code span:contains('"+EXAMPLE_SECRET+"')").each( function() {
|
||||
let eltext = $(this).text()
|
||||
$(this).text( eltext.replace(EXAMPLE_SECRET, data.account.secret) )
|
||||
})
|
||||
|
||||
$("#populate-creds-status").text("Populated this page's examples with these credentials.")
|
||||
|
||||
complete_step("Generate")
|
||||
|
||||
},
|
||||
error: function() {
|
||||
$("#loader-generate").hide();
|
||||
$("#populate-creds-status").html(
|
||||
`<p class="devportal-callout warning"><strong>Error:</strong>
|
||||
There was an error connecting to the test network Faucet. Please
|
||||
try again.</p>`)
|
||||
return;
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const EXAMPLE_ADDR = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const EXAMPLE_SECRET = "s████████████████████████████"
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
**Caution:** Ripple provides the [Testnet and Devnet](parallel-networks.html) for testing purposes only, and sometimes resets the state of these test networks along with all balances. As a precaution, Ripple recommends **not** using the same addresses on Testnet/Devnet and Mainnet.
|
||||
17
content/_snippets/interactive-tutorials/connect-step.ja.md
Normal file
17
content/_snippets/interactive-tutorials/connect-step.ja.md
Normal file
@@ -0,0 +1,17 @@
|
||||
{% if use_network is undefined or use_network == "Testnet" %}
|
||||
{% set ws_url = "wss://s.altnet.rippletest.net:51233" %}
|
||||
{% set use_network = "Testnet" %}
|
||||
{% elif use_network == "Devnet" %}
|
||||
{% set ws_url = "wss://s.devnet.rippletest.net:51233" %}
|
||||
{% elif use_network == "Mainnet" %}
|
||||
{% set ws_url = "wss://xrplcluster.com" %}
|
||||
{% endif %}
|
||||
|
||||
{{ start_step("Connect") }}
|
||||
<button id="connect-button" class="btn btn-primary" data-wsurl="{{ws_url}}">{{use_network}}に接続する</button>
|
||||
<div>
|
||||
<strong>接続ステータス:</strong>
|
||||
<span id="connection-status">接続されていません</span>
|
||||
<div class="loader collapse" id="loader-connect"><img class="throbber" src="assets/img/xrp-loader-96.png"></div>
|
||||
</div>
|
||||
{{ end_step() }}
|
||||
17
content/_snippets/interactive-tutorials/connect-step.md
Normal file
17
content/_snippets/interactive-tutorials/connect-step.md
Normal file
@@ -0,0 +1,17 @@
|
||||
{% if use_network is undefined or use_network == "Testnet" %}
|
||||
{% set ws_url = "wss://s.altnet.rippletest.net:51233" %}
|
||||
{% set use_network = "Testnet" %}
|
||||
{% elif use_network == "Devnet" %}
|
||||
{% set ws_url = "wss://s.devnet.rippletest.net:51233" %}
|
||||
{% elif use_network == "Mainnet" %}
|
||||
{% set ws_url = "wss://xrplcluster.com" %}
|
||||
{% endif %}
|
||||
|
||||
{{ start_step("Connect") }}
|
||||
<button id="connect-button" class="btn btn-primary" data-wsurl="{{ws_url}}">Connect to {{use_network}}</button>
|
||||
<div>
|
||||
<strong>Connection status:</strong>
|
||||
<span id="connection-status">Not connected</span>
|
||||
<div class="loader collapse" id="loader-connect"><img class="throbber" src="assets/img/xrp-loader-96.png"></div>
|
||||
</div>
|
||||
{{ end_step() }}
|
||||
15
content/_snippets/interactive-tutorials/generate-step.ja.md
Normal file
15
content/_snippets/interactive-tutorials/generate-step.ja.md
Normal file
@@ -0,0 +1,15 @@
|
||||
{% if use_network is undefined or use_network == "Testnet" %}
|
||||
{% set use_network = "Testnet" %}
|
||||
{% set faucet_url = "https://faucet.altnet.rippletest.net/accounts" %}
|
||||
{% elif use_network == "Devnet" %}
|
||||
{% set faucet_url = "https://faucet.devnet.rippletest.net/accounts" %}
|
||||
{# No faucet for Mainnet! #}
|
||||
{% endif %}
|
||||
|
||||
{{ start_step("Generate") }}
|
||||
<button id="generate-creds-button" class="btn btn-primary" data-fauceturl="{{faucet_url}}">{{use_network}}の暗号鍵を作成する</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">暗号鍵を作成しています…</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
**注意:** Rippleは[TestnetとDevnet](parallel-networks.html)をテストの目的でのみ運用しており、その状態とすべての残高を定期的にリセットしています。予防措置として、Testnet、DevnetとMainnetで同じアドレスを使用**しない**ことをお勧めします。
|
||||
15
content/_snippets/interactive-tutorials/generate-step.md
Normal file
15
content/_snippets/interactive-tutorials/generate-step.md
Normal file
@@ -0,0 +1,15 @@
|
||||
{% if use_network is undefined or use_network == "Testnet" %}
|
||||
{% set use_network = "Testnet" %}
|
||||
{% set faucet_url = "https://faucet.altnet.rippletest.net/accounts" %}
|
||||
{% elif use_network == "Devnet" %}
|
||||
{% set faucet_url = "https://faucet.devnet.rippletest.net/accounts" %}
|
||||
{# No faucet for Mainnet! #}
|
||||
{% endif %}
|
||||
|
||||
{{ start_step("Generate") }}
|
||||
<button id="generate-creds-button" class="btn btn-primary" data-fauceturl="{{faucet_url}}">Get {{use_network}} credentials</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Generating Keys...</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
**Caution:** Ripple provides the [Testnet and Devnet](parallel-networks.html) for testing purposes only, and sometimes resets the state of these test networks along with all balances. As a precaution, Ripple recommends **not** using the same addresses on Testnet/Devnet and Mainnet.
|
||||
27
content/_snippets/interactive-tutorials/wait-step.ja.md
Normal file
27
content/_snippets/interactive-tutorials/wait-step.ja.md
Normal file
@@ -0,0 +1,27 @@
|
||||
{% if use_network is undefined or use_network == "Testnet" %}
|
||||
{% set explorer_url = "https://testnet.xrpl.org" %}
|
||||
{% elif use_network == "Devnet" %}
|
||||
{% set explorer_url = "https://devnet.xrpl.org" %}
|
||||
{% elif use_network == "Mainnet" %}
|
||||
{% set explorer_url = "https://livenet.xrpl.org" %}
|
||||
{% endif %}
|
||||
|
||||
<table class="wait-step" data-explorerurl="{{explorer_url}}">
|
||||
<tr>
|
||||
<th>トランザクションのID:</th>
|
||||
<td class="waiting-for-tx">(無)</td>
|
||||
<tr>
|
||||
<th>最新の検証レジャーインデックス:</th>
|
||||
<td class="validated-ledger-version">接続されていません</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>送信時のレジャーインデックス:</th>
|
||||
<td class="earliest-ledger-version">(まだ送信されません)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>トランザクションの<code>LastLedgerSequence</code>:</th>
|
||||
<td class="lastledgersequence">(準備されません)</td>
|
||||
</tr>
|
||||
<tr class="tx-validation-status">
|
||||
</tr>
|
||||
</table>
|
||||
27
content/_snippets/interactive-tutorials/wait-step.md
Normal file
27
content/_snippets/interactive-tutorials/wait-step.md
Normal file
@@ -0,0 +1,27 @@
|
||||
{% if use_network is undefined or use_network == "Testnet" %}
|
||||
{% set explorer_url = "https://testnet.xrpl.org" %}
|
||||
{% elif use_network == "Devnet" %}
|
||||
{% set explorer_url = "https://devnet.xrpl.org" %}
|
||||
{% elif use_network == "Mainnet" %}
|
||||
{% set explorer_url = "https://livenet.xrpl.org" %}
|
||||
{% endif %}
|
||||
|
||||
<table class="wait-step" data-explorerurl="{{explorer_url}}">
|
||||
<tr>
|
||||
<th>Transaction ID:</th>
|
||||
<td class="waiting-for-tx">(None)</td>
|
||||
<tr>
|
||||
<th>Latest Validated Ledger Index:</th>
|
||||
<td class="validated-ledger-version">(Not connected)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Ledger Index at Time of Submission:</th>
|
||||
<td class="earliest-ledger-version">(Not submitted)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Transaction <code>LastLedgerSequence</code>:</th>
|
||||
<td class="lastledgersequence">(Not prepared)</td>
|
||||
</tr>
|
||||
<tr class="tx-validation-status">
|
||||
</tr>
|
||||
</table>
|
||||
@@ -8,6 +8,8 @@ Source tags indicate the originator or source of a payment. Most commonly, a Sou
|
||||
|
||||
The practice of giving customers the ability to send and receive transactions from your XRP Ledger address using another interface is called providing _hosted accounts_. Hosted accounts typically use source and destination tags for each customer.
|
||||
|
||||
**Tip:** An [X-address](https://xrpaddress.info/) combines a classic address with a tag into a single address that encodes both. If you are showing a deposit address to customers, it may be easier for your customers to use an X-address rather than making them keep track of two pieces of information. (The tag in an X-address acts as a source tag when sending and a destination tag when receiving.)
|
||||
|
||||
## Rationale
|
||||
|
||||
In other distributed ledgers, it is common to use different deposit addresses for each customer. In the XRP Ledger, an address must be a funded, permanent [account](accounts.html) to receive payments. Using this approach in the XRP Ledger wastefully consumes resources of all servers in the network, and is costly because the [reserve](reserves.html) amount must be set aside indefinitely for each address.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 取引の結果
|
||||
# トランザクションの結果
|
||||
|
||||
[[ソース]<br>](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/TER.h "ソース")
|
||||
[[ソース]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/TER.h "Source")
|
||||
|
||||
`rippled`サーバーは、取引結果の要約を結果コードで示し、結果コードは`engine_result`や`meta.TransactionResult`などのフィールドに記述されます。これらのコードは、それぞれ異なるプレフィクスを付加した複数のカテゴリーに分類されます。
|
||||
`rippled`サーバーは、トランザクション結果の要約を結果コードで示し、結果コードは`engine_result`や`meta.TransactionResult`などのフィールドに記述されます。これらのコードは、それぞれ異なるプレフィクスを付加した複数のカテゴリーに分類されます。
|
||||
|
||||
| カテゴリー | プレフィクス | 説明 |
|
||||
|:----------------------|:------------------------|:---------------------------|
|
||||
@@ -45,4 +45,4 @@
|
||||
<!--{# common link defs #}-->
|
||||
{% include '_snippets/rippled-api-links.md' %}
|
||||
{% include '_snippets/tx-type-links.md' %}
|
||||
{% include '_snippets/rippled_versions.md' %}
|
||||
{% include '_snippets/rippled_versions.md' %}
|
||||
|
||||
@@ -79,7 +79,6 @@ const socket = new WebSocket('ws://localhost:6006')
|
||||
<button id="connect-button" class="btn btn-primary">Connect</button>
|
||||
<strong>Connection status:</strong>
|
||||
<span id="connection-status">Not connected</span>
|
||||
<div id='loader-{{n.current}}' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"></div>
|
||||
<h5>Console:</h5>
|
||||
<div class="ws-console" id="monitor-console-connect"><span class="placeholder">(Log is empty)</span></div>
|
||||
{{ end_step() }}
|
||||
|
||||
@@ -79,7 +79,6 @@ Example:
|
||||
<button id="connect-button" class="btn btn-primary">Connect</button>
|
||||
<strong>Connection status:</strong>
|
||||
<span id="connection-status">Not connected</span>
|
||||
<div id='loader-{{n.current}}' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"></div>
|
||||
<h5>Console:</h5>
|
||||
<div class="ws-console" id="monitor-console-connect"><span class="placeholder">(Log is empty)</span></div>
|
||||
{{ end_step() }}
|
||||
|
||||
@@ -1,74 +1,140 @@
|
||||
---
|
||||
html: require-destination-tags.html
|
||||
funnel: Build
|
||||
doc_type: Tutorials
|
||||
category: Manage Account Settings
|
||||
blurb: Require users to specify a destination tag when sending to your address.
|
||||
embed_ripple_lib: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
---
|
||||
# Require Destination Tags
|
||||
|
||||
The `RequireDest` setting (`requireDestinationTag` in RippleAPI) is designed to prevent customers from sending [payments](payment-types.html) to your address if they forgot the [destination tag](source-and-destination-tags.html) that identifies whom to credit for the payment. When enabled, the XRP Ledger rejects any payment to your address if it does not specify a destination tag.
|
||||
The Require Destination Tag setting is designed for addresses that host balances for multiple people or purposes, to prevent people from sending money and forgetting to use a [destination tag](source-and-destination-tags.html) to identify whom to credit. When this setting is enabled on your address, the XRP Ledger rejects [any payment](payment-types.html) to your address if it does not specify a destination tag.
|
||||
|
||||
The following is an example of using a locally-hosted `rippled`'s [submit method][] to send an [AccountSet transaction][] to enable the `RequireDest` flag:
|
||||
This tutorial demonstrates how to enable the Require Destination Tag flag on your account.
|
||||
|
||||
Request:
|
||||
**Note:** The meanings of specific destination tags are entirely up to the logic built on top of the XRP Ledger. The ledger has no way of knowing whether any specific tag is valid in your system, so you must still be ready to receive transactions with the wrong destination tag. Typically, this involves providing a customer support experience that can track down payments made incorrectly and credit customers accordingly, and possibly also bouncing unwanted payments.
|
||||
|
||||
<!-- MULTICODE_BLOCK_START -->
|
||||
## Prerequisites
|
||||
|
||||
*JSON-RPC*
|
||||
- You need a funded XRP Ledger account, with an address, secret key, and some XRP. For production, you can use the same address and secret consistently. For this tutorial, you can generate new test credentials as needed.
|
||||
- You need a connection to the XRP Ledger network.
|
||||
|
||||
```json
|
||||
POST http://localhost:5005/
|
||||
Content-Type: application/json
|
||||
This page provides examples that use [ripple-lib for JavaScript](get-started-with-rippleapi-for-javascript.html). Since JavaScript works in the web browser, you can read along and use the interactive steps without any setup.
|
||||
|
||||
{
|
||||
"method": "submit",
|
||||
"params": [
|
||||
{
|
||||
"secret": "sn3nxiW7v8KXzPzAqzyHXbSSKNuN9",
|
||||
"tx_json": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "15000",
|
||||
"Flags": 0,
|
||||
"SetFlag": 1,
|
||||
"TransactionType": "AccountSet"
|
||||
}
|
||||
}
|
||||
]
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="assets/js/tutorials/require-destination-tags.js"></script>
|
||||
|
||||
|
||||
## Steps
|
||||
{% set n = cycler(* range(1,99)) %}
|
||||
|
||||
### {{n.next()}}. Get Credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address and secret key, and some XRP. For development purposes, you can get these using the following interface:
|
||||
|
||||
{% include '_snippets/interactive-tutorials/generate-step.md' %}
|
||||
|
||||
When you're [building actual production-ready software](production-readiness.html), you'll instead use an existing account, and manage your keys using a [secure signing configuration](set-up-secure-signing.html).
|
||||
|
||||
### {{n.next()}}. Connect to the Network
|
||||
|
||||
You must be connected to the network to submit transactions to it.
|
||||
|
||||
The following code uses a [ripple-lib for JavaScript](rippleapi-reference.html) instance to connect to a public XRP Testnet server:
|
||||
|
||||
```js
|
||||
ripple = require('ripple-lib') // Node.js only. Use a <script> tag in browsers.
|
||||
|
||||
async function main() {
|
||||
api = new ripple.RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
|
||||
await api.connect()
|
||||
|
||||
// Code in the following examples continues here...
|
||||
}
|
||||
|
||||
main()
|
||||
```
|
||||
|
||||
{% include '_snippets/secret-key-warning.md' %}
|
||||
<!--{#_ #}-->
|
||||
**Note:** The code samples in this tutorial use JavaScript's [`async`/`await` pattern](https://javascript.info/async-await). Since `await` needs to be used from within an `async` function, the remaining code samples are written to continue inside the `main()` function started here. You can also use Promise methods `.then()` and `.catch()` instead of `async`/`await` if you prefer.
|
||||
|
||||
<!-- MULTICODE_BLOCK_END -->
|
||||
For this tutorial, you can connect directly from your browser by pressing the following button:
|
||||
|
||||
Response:
|
||||
{% include '_snippets/interactive-tutorials/connect-step.md' %}
|
||||
|
||||
<!-- MULTICODE_BLOCK_START -->
|
||||
### {{n.next()}}. Send AccountSet Transaction
|
||||
|
||||
*JSON-RPC*
|
||||
To enable the `RequireDest` flag, set the [`asfRequireDest` value (`1`)](accountset.html#accountset-flags) in the `SetFlag` field of an [AccountSet transaction][]. To send the transaction, you first _prepare_ it to fill out all the necessary fields, then _sign_ it with your account's secret key, and finally _submit_ it to the network.
|
||||
|
||||
```json
|
||||
200 OK
|
||||
For example:
|
||||
|
||||
{
|
||||
"result" : {
|
||||
"deprecated" : "Signing support in the 'submit' command has been deprecated and will be removed in a future version of the server. Please migrate to a standalone signing tool.",
|
||||
"engine_result" : "tesSUCCESS",
|
||||
"engine_result_code" : 0,
|
||||
"engine_result_message" : "The transaction was applied. Only final in a validated ledger.",
|
||||
"status" : "success",
|
||||
"tx_blob" : "12000322000000002400000179202100000001684000000000003A98732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402201C430B4C29D0A0AB94286AE55FB9981B00F84C7985AF4BD44570782C5E0C5E290220363B68B81580231B32176F8C477B822ECB9EC673B84237BEF15BE6F59108B97D81144B4E9C06F24296074F7BC48F92A97916C6DC5EA9",
|
||||
"tx_json" : {
|
||||
"Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee" : "15000",
|
||||
"Flags" : 0,
|
||||
"Sequence" : 377,
|
||||
"SetFlag" : 1,
|
||||
"SigningPubKey" : "03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB",
|
||||
"TransactionType" : "AccountSet",
|
||||
"TxnSignature" : "304402201C430B4C29D0A0AB94286AE55FB9981B00F84C7985AF4BD44570782C5E0C5E290220363B68B81580231B32176F8C477B822ECB9EC673B84237BEF15BE6F59108B97D",
|
||||
"hash" : "3F2B233907BE9EC51AE1C822EC0B6BB0965EFD2400B218BE988DDA9529F53CA4"
|
||||
}
|
||||
}
|
||||
}
|
||||
```js
|
||||
const prepared = await api.prepareTransaction({
|
||||
"TransactionType": "AccountSet",
|
||||
"Account": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
|
||||
"SetFlag": 1 // RequireDest
|
||||
})
|
||||
console.log("Prepared transaction:", prepared.txJSON)
|
||||
const max_ledger = prepared.instructions.maxLedgerVersion
|
||||
|
||||
const signed = api.sign(prepared.txJSON, "s████████████████████████████")
|
||||
console.log("Transaction hash:", signed.id)
|
||||
const tx_id = signed.id
|
||||
const tx_blob = signed.signedTransaction
|
||||
|
||||
const prelim_result = await api.request("submit", {"tx_blob": tx_blob})
|
||||
console.log("Preliminary result:", prelim_result)
|
||||
const min_ledger = prelim_result.validated_ledger_index
|
||||
|
||||
// min_ledger, max_ledger, and tx_id are useful for looking up the transaction's
|
||||
// status later.
|
||||
```
|
||||
|
||||
<!-- MULTICODE_BLOCK_END -->
|
||||
{{ start_step("Send AccountSet") }}
|
||||
<button id="send-accountset" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait">Send AccountSet</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Sending...</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
### {{n.next()}}. Wait for Validation
|
||||
|
||||
Most transactions are accepted into the next ledger version after they're submitted, which means it may take 4-7 seconds for a transaction's outcome to be final. If the XRP Ledger is busy or poor network connectivity delays a transaction from being relayed throughout the network, a transaction may take longer to be confirmed. (For information on how to set an expiration for transactions, see [Reliable Transaction Submission](reliable-transaction-submission.html).)
|
||||
|
||||
{{ start_step("Wait") }}
|
||||
{% include '_snippets/interactive-tutorials/wait-step.md' %}
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
### {{n.next()}}. Confirm Account Settings
|
||||
|
||||
After the transaction is validated, you can check your account's settings to confirm that the Require Destination Tag flag is enabled.
|
||||
|
||||
```js
|
||||
let account_info = await api.request("account_info", {
|
||||
"account": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
|
||||
"ledger_index": "validated"
|
||||
})
|
||||
const flags = api.parseAccountFlags(account_info.account_data.Flags)
|
||||
console.log(JSON.stringify(flags, null, 2))
|
||||
// Look for "requireDestinationTag": true
|
||||
```
|
||||
|
||||
{{ start_step("Confirm Settings") }}
|
||||
<button id="confirm-settings" class="btn btn-primary previous-steps-required" data-wait-step-name="Wait">Confirm Settings</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Sending...</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
For further confirmation, you can send test transactions (from a different address) to confirm that the setting is working as you expect it to. If you a payment with a destination tag, it should succeed, and if you send one _without_ a destination tag, it should fail with the error code [`tecDST_TAG_NEEDED`](tec-codes.html).
|
||||
|
||||
{{ start_step("Test Payments") }}
|
||||
<button class="test-payment btn btn-primary" data-dt="10">Send XRP (with Destination Tag)</button>
|
||||
<button class="test-payment btn btn-primary" data-dt="">Send XRP (without Destination Tag)</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Sending...</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
@@ -4,6 +4,7 @@ funnel: Build
|
||||
doc_type: Tutorials
|
||||
category: Manage Account Settings
|
||||
blurb: Use Tickets to send a transaction outside of normal Sequence order.
|
||||
embed_ripple_lib: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
---
|
||||
@@ -15,13 +16,9 @@ _(Requires the [TicketBatch amendment][] :not_enabled:)_
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<!-- ripple-lib & prerequisites -->
|
||||
{{currentpage.lodash_tag}}
|
||||
{{currentpage.ripple_lib_tag}}
|
||||
<!-- Helper for interactive tutorial breadcrumbs -->
|
||||
<script type="application/javascript" src="assets/js/interactive-tutorial.js"></script>
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="assets/js/tutorials/use-tickets.js"></script>
|
||||
{% set use_network = "Devnet" %}<!--TODO: change to Testnet eventually -->
|
||||
|
||||
This page provides JavaScript examples that use the ripple-lib (RippleAPI) library. The [RippleAPI Beginners Guide](get-started-with-rippleapi-for-javascript.html) describes how to get started using RippleAPI to access XRP Ledger data from JavaScript.
|
||||
|
||||
@@ -43,10 +40,9 @@ This tutorial is divided into a few phases:
|
||||
|
||||
### {{n.next()}}. Get Credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address and secret key, and some XRP. For development purposes, you can get these on the [Devnet](parallel-networks.html) using the following interface: <!--TODO: change to Testnet eventually -->
|
||||
To transact on the XRP Ledger, you need an address and secret key, and some XRP. For development purposes, you can get these on the [{{use_network}}](parallel-networks.html) using the following interface:
|
||||
|
||||
{% set faucet_url = "https://faucet.devnet.rippletest.net/accounts" %}
|
||||
{% include '_snippets/generate-step.md' %}
|
||||
{% include '_snippets/interactive-tutorials/generate-step.md' %}
|
||||
|
||||
When you're [building actual production-ready software](production-readiness.html), you'll instead use an existing account, and manage your keys using a [secure signing configuration](set-up-secure-signing.html).
|
||||
|
||||
@@ -74,14 +70,7 @@ main()
|
||||
|
||||
For this tutorial, you can connect directly from your browser by pressing the following button:
|
||||
|
||||
{{ start_step("Connect") }}
|
||||
<button id="connect-button" class="btn btn-primary">Connect to Devnet</button> <!-- TODO: Testnet -->
|
||||
<div>
|
||||
<strong>Connection status:</strong>
|
||||
<span id="connection-status">Not connected</span>
|
||||
<div id='loader-connect' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"></div>
|
||||
</div>
|
||||
{{ end_step() }}
|
||||
{% include '_snippets/interactive-tutorials/connect-step.md' %}
|
||||
|
||||
|
||||
### {{n.next()}}. Check Sequence Number
|
||||
@@ -101,9 +90,9 @@ let current_sequence = await get_sequence()
|
||||
```
|
||||
|
||||
{{ start_step("Check Sequence") }}
|
||||
<button id="check-sequence" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>Check Sequence Number</button>
|
||||
<div id="check-sequence-output"></div>
|
||||
<button id="check-sequence" class="btn btn-primary previous-steps-required">Check Sequence Number</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Querying...</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
@@ -132,9 +121,8 @@ Record the transaction's hash and `LastLedgerSequence` value so you can [be sure
|
||||
|
||||
|
||||
{{ start_step("Prepare & Sign") }}
|
||||
<button id="prepare-and-sign" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>Prepare & Sign</button>
|
||||
<div id="prepare-and-sign-output"></div>
|
||||
<button id="prepare-and-sign" class="btn btn-primary previous-steps-required">Prepare & Sign</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
@@ -152,9 +140,9 @@ const min_ledger = prelim_result.validated_ledger_index
|
||||
**Warning:** Be sure that you **DO NOT UPDATE** the `min_ledger` value. It is safe to submit a signed transaction blob multiple times (the transaction can only execute at most once), but when you look up the status of the transaction you should use the earliest possible ledger index that the transaction could be in, _not_ the validated ledger index at the time of the most recent submission. Using the wrong minimum ledger value could cause you to incorrectly conclude that the transaction did not execute. For best practices, see [Reliable Transaction Submission](reliable-transaction-submission.html).
|
||||
|
||||
{{ start_step("Submit") }}
|
||||
<button id="ticketcreate-submit" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>Submit</button>
|
||||
<div id="ticketcreate-submit-output"></div>
|
||||
<button id="ticketcreate-submit" class="btn btn-primary previous-steps-required" data-tx-blob-from="#tx_blob" data-wait-step-name="Wait">Submit</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png">Sending...</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
@@ -209,26 +197,7 @@ api.on('ledger', async (ledger) => {
|
||||
```
|
||||
|
||||
{{ start_step("Wait") }}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Transaction Hash:</th>
|
||||
<td id="waiting-for-tx"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Latest Validated Ledger Version:</th>
|
||||
<td id="current-ledger-version">(Not connected)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Ledger Version at Time of Submission:</th>
|
||||
<td id="earliest-ledger-version">(Not submitted)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><code>LastLedgerSequence</code>:</th>
|
||||
<td id="lastledgersequence">(Not prepared)</td>
|
||||
</tr>
|
||||
<tr id="tx-validation-status">
|
||||
</tr>
|
||||
</table>
|
||||
{% include '_snippets/interactive-tutorials/wait-step.md' %}
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
@@ -239,13 +208,10 @@ The power of Tickets is that you can carry on with your account's business as us
|
||||
**Tip:** You can come back here to send Sequenced transactions between or during any of the following steps, without interfering with the success of your Ticketed transaction.
|
||||
|
||||
{{ start_step("Intermission") }}
|
||||
<button id="intermission-payment" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>Payment</button>
|
||||
<button id="intermission-escrowcreate" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>EscrowCreate</button>
|
||||
<button id="intermission-accountset" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>AccountSet</button>
|
||||
<div id="intermission-output"></div>
|
||||
<button id="intermission-payment" class="btn btn-primary previous-steps-required">Payment</button>
|
||||
<button id="intermission-escrowcreate" class="btn btn-primary previous-steps-required">EscrowCreate</button>
|
||||
<button id="intermission-accountset" class="btn btn-primary previous-steps-required">AccountSet</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
@@ -266,9 +232,8 @@ let use_ticket = response.account_objects[0].TicketSequence
|
||||
|
||||
|
||||
{{ start_step("Check Tickets") }}
|
||||
<button id="check-tickets" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>Submit</button>
|
||||
<div id="check-tickets-output"></div>
|
||||
<button id="check-tickets" class="btn btn-primary previous-steps-required">Check Tickets</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
**Tip:** You can repeat the steps from here through the end as long as you have Tickets left to be used!
|
||||
@@ -306,9 +271,8 @@ console.log("Signed transaction blob:", tx_blob_t)
|
||||
<h4>Select a Ticket:</h4>
|
||||
<div class="form-area"></div>
|
||||
</div>
|
||||
<button id="prepare-ticketed-tx" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>Prepare Ticketed Transaction</button>
|
||||
<div id="prepare-ticketed-tx-output"></div>
|
||||
<button id="prepare-ticketed-tx" class="btn btn-primary previous-steps-required">Prepare Ticketed Transaction</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
@@ -322,34 +286,17 @@ console.log("Preliminary result:", prelim_result_t)
|
||||
```
|
||||
|
||||
{{ start_step("Submit Ticketed Tx") }}
|
||||
<button id="ticketedtx-submit" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>Submit</button>
|
||||
<div id="ticketedtx-submit-output"></div>
|
||||
<button id="ticketedtx-submit" class="btn btn-primary previous-steps-required" data-tx-blob-from="#tx_blob_t" data-wait-step-name="Wait Again">Submit</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
|
||||
### {{n.next()}}. Wait for Validation
|
||||
|
||||
Ticketed transactions go through the consensus process the same way that Sequenced transactions do.
|
||||
|
||||
{{ start_step("Wait Again") }}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Latest Validated Ledger Version:</th>
|
||||
<td id="current-ledger-version_t">(Not connected)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Ledger Version at Time of Submission:</th>
|
||||
<td id="earliest-ledger-version_t">(Not submitted)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Ticketed Transaction <code>LastLedgerSequence</code>:</th>
|
||||
<td id="lastledgersequence_t">(Not prepared)</td>
|
||||
</tr>
|
||||
<tr id="tx-validation-status_t">
|
||||
</tr>
|
||||
</table>
|
||||
{% include '_snippets/interactive-tutorials/wait-step.md' %}
|
||||
{{ end_step() }}
|
||||
|
||||
## With Multi-Signing
|
||||
|
||||
@@ -5,6 +5,7 @@ doc_type: Tutorials
|
||||
category: Get Started
|
||||
blurb: Test Netを使用してXRPの送金をテストします。
|
||||
cta_text: XRPを送金しよう
|
||||
embed_ripple_lib: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
---
|
||||
@@ -14,17 +15,15 @@ filters:
|
||||
|
||||
## 前提条件
|
||||
|
||||
<!-- ripple-lib & prerequisites -->
|
||||
{{currentpage.lodash_tag}}
|
||||
{{currentpage.ripple_lib_tag}}
|
||||
<!-- Helper for interactive tutorial breadcrumbs -->
|
||||
<script type="application/javascript" src="assets/js/interactive-tutorial.js"></script>
|
||||
<!-- このチュートリアルのインタラクティブ部分のソースコード: -->
|
||||
<script type="application/javascript" src="assets/js/tutorials/send-xrp.js"></script>
|
||||
{% set use_network = "Testnet" %}
|
||||
|
||||
- このページでは、ripple-lib(RippleAPI)ライブラリーバージョン1.8.2を使用するJavaScriptの例を紹介します。[RippleAPI入門ガイド](get-started-with-rippleapi-for-javascript.html)に、RippleAPIを使用してJavaScriptからXRP Ledgerデータにアクセスする方法の説明があります。
|
||||
|
||||
- XRP Ledgerでトランザクションを送信するには、まずアドレスと秘密鍵、そしていくらかのXRPが必要となります。次のインターフェイスを使用して、XRP Test NetにあるアドレスとTest Net XRPを入手できます。
|
||||
|
||||
{% include '_snippets/generate-step.ja.md' %}
|
||||
{% include '_snippets/interactive-tutorials/generate-step.ja.md' %}
|
||||
|
||||
## Test Netでの送金
|
||||
{% set n = cycler(* range(1,99)) %}
|
||||
@@ -43,39 +42,7 @@ api.connect()
|
||||
|
||||
このチュートリアルでは、以下のボタンをクリックすることでブラウザーから直接接続できます。
|
||||
|
||||
{{ start_step("Connect") }}
|
||||
<button id="connect-button" class="btn btn-primary">TestNetに接続する</button>
|
||||
<div>
|
||||
<strong>Connection status:</strong>
|
||||
<span id="connection-status">Not connected</span>
|
||||
<div id='loader-{{n.current}}' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"></div>
|
||||
</div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
api = new ripple.RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
|
||||
api.on('connected', () => {
|
||||
$("#connection-status").text("Connected")
|
||||
$("#connect-button").prop("disabled", true)
|
||||
$("#loader-{{n.current}}").hide()
|
||||
|
||||
// Update breadcrumbs & active next step
|
||||
complete_step("Connect")
|
||||
$("#interactive-prepare button").prop("disabled", false)
|
||||
$("#interactive-prepare button").prop("title", "")
|
||||
})
|
||||
api.on('disconnected', (code) => {
|
||||
$("#connection-status").text( "Disconnected ("+code+")" )
|
||||
$("#connect-button").prop("disabled", false)
|
||||
$(".connection-required").prop("disabled", true)
|
||||
$(".connection-required").prop("title", "Connection to Test Net required")
|
||||
})
|
||||
$("#connect-button").click(() => {
|
||||
$("#connection-status").text( "Connecting..." )
|
||||
$("#loader-{{n.current}}").show()
|
||||
api.connect()
|
||||
})
|
||||
</script>
|
||||
{% include '_snippets/interactive-tutorials/connect-step.ja.md' %}
|
||||
|
||||
|
||||
### {{n.next()}}. トランザクションの準備
|
||||
@@ -114,54 +81,30 @@ async function doPrepare() {
|
||||
"maxLedgerVersionOffset": 75
|
||||
})
|
||||
const maxLedgerVersion = preparedTx.instructions.maxLedgerVersion
|
||||
console.log("Prepared transaction instructions:", preparedTx.txJSON)
|
||||
console.log("Transaction cost:", preparedTx.instructions.fee, "XRP")
|
||||
console.log("Transaction expires after ledger:", maxLedgerVersion)
|
||||
console.log("準備されたトランザクション指示:", preparedTx.txJSON)
|
||||
console.log("トランザクションコスト:", preparedTx.instructions.fee, "XRP")
|
||||
console.log("トランザクションの有効期限はこのレジャー後:", maxLedgerVersion)
|
||||
return preparedTx.txJSON
|
||||
}
|
||||
txJSON = doPrepare()
|
||||
```
|
||||
|
||||
{{ start_step("Prepare") }}
|
||||
<button id="prepare-button" class="btn btn-primary connection-required"
|
||||
title="Connect to Test Net first" disabled>サンプルトランザクションを準備する</button>
|
||||
<div id="prepare-output"></div>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">送金する額:</span>
|
||||
</div>
|
||||
<input type="number" class="form-control" value="22" id="xrp-amount"
|
||||
aria-label="XRPの額(小数)" aria-describedby="xrp-amount-label"
|
||||
min=".000001" max="100000000000" step="any">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="xrp-amount-label"> XRP</span>
|
||||
</div>
|
||||
</div>
|
||||
<button id="prepare-button" class="btn btn-primary previous-steps-required">サンプルトランザクションを準備する</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
$("#prepare-button").click( async function() {
|
||||
// Wipe existing results
|
||||
$("#prepare-output").html("")
|
||||
|
||||
const sender = $("#use-address").text() || "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const preparedTx = await api.prepareTransaction({
|
||||
"TransactionType": "Payment",
|
||||
"Account": sender,
|
||||
"Amount": api.xrpToDrops("22"), // Same as "Amount": "22000000"
|
||||
"Destination": "rUCzEr6jrEyMpjhs4wSdQdz4g8Y382NxfM"
|
||||
}, {
|
||||
// Expire this transaction if it doesn't execute within ~5 minutes:
|
||||
"maxLedgerVersionOffset": 75
|
||||
})
|
||||
const maxLedgerVersion = preparedTx.instructions.maxLedgerVersion
|
||||
$("#tx-lls").text(maxLedgerVersion) //for the table in the later step
|
||||
|
||||
$("#prepare-output").html(
|
||||
"<div><strong>Prepared transaction instructions:</strong> <pre><code id='prepared-tx-json'>" +
|
||||
JSON.stringify(JSON.parse(preparedTx.txJSON), null, 2) + "</code></pre></div>" +
|
||||
"<div><strong>Transaction cost:</strong> " +
|
||||
preparedTx.instructions.fee + " XRP</div>" +
|
||||
"<div><strong>Transaction expires after ledger:</strong> " +
|
||||
maxLedgerVersion + "</div>"
|
||||
)
|
||||
|
||||
// Update breadcrumbs & active next step
|
||||
complete_step("Prepare")
|
||||
$("#interactive-sign button").prop("disabled", false)
|
||||
$("#interactive-sign button").prop("title", "")
|
||||
})
|
||||
</script>
|
||||
|
||||
### {{n.next()}}. トランザクションの指示への署名
|
||||
|
||||
RippleAPIの[sign()メソッド](rippleapi-reference.html#sign)を使用して、トランザクションに署名します。最初の引数は、署名するJSONトランザクションの文字列バージョンです。
|
||||
@@ -180,39 +123,10 @@ console.log("Signed blob:", txBlob)
|
||||
署名APIは、トランザクションのID、つまり識別用ハッシュを返します。この識別用ハッシュは、後でトランザクションを検索する際に使用します。識別用ハッシュは、このトランザクションに固有の64文字の16進文字列です。
|
||||
|
||||
{{ start_step("Sign") }}
|
||||
<button id="sign-button" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>サンプルトランザクションに署名する</button>
|
||||
<div id="sign-output"></div>
|
||||
<button id="sign-button" class="btn btn-primary previous-steps-required">サンプルトランザクションに署名する</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
$("#sign-button").click( function() {
|
||||
// Wipe previous output
|
||||
$("#sign-output").html("")
|
||||
|
||||
const preparedTxJSON = $("#prepared-tx-json").text()
|
||||
const secret = $("#use-secret").text()
|
||||
|
||||
if (!secret) {
|
||||
alert("Can't sign transaction without a real secret. Generate credentials first.")
|
||||
return
|
||||
}
|
||||
|
||||
signResponse = api.sign(preparedTxJSON, secret)
|
||||
|
||||
$("#sign-output").html(
|
||||
"<div><strong>Signed Transaction blob:</strong> <code id='signed-tx-blob' style='overflow-wrap: anywhere; word-wrap: anywhere'>" +
|
||||
signResponse.signedTransaction + "</code></div>" +
|
||||
"<div><strong>Identifying hash:</strong> <span id='signed-tx-hash'>" +
|
||||
signResponse.id + "</span></div>"
|
||||
)
|
||||
|
||||
// Update all breadcrumbs & activate next step
|
||||
complete_step("Sign")
|
||||
$("#interactive-submit button").prop("disabled", false)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
### {{n.next()}}. 署名済みブロブの送信
|
||||
|
||||
@@ -227,8 +141,8 @@ async function doSubmit(txBlob) {
|
||||
|
||||
const result = await api.submit(txBlob)
|
||||
|
||||
console.log("Tentative result code:", result.resultCode)
|
||||
console.log("Tentative result message:", result.resultMessage)
|
||||
console.log("予備結果コード:", result.resultCode)
|
||||
console.log("予備結果メッセージ", result.resultMessage)
|
||||
|
||||
// Return the earliest ledger index this transaction could appear in
|
||||
// as a result of this submission, which is the first one after the
|
||||
@@ -250,42 +164,11 @@ const earliestLedgerVersion = doSubmit(txBlob)
|
||||
他の可能性については、[トランザクション結果](transaction-results.html)の完全なリストを参照してください。
|
||||
|
||||
{{ start_step("Submit") }}
|
||||
<button id="submit-button" class="btn btn-primary connection-required"
|
||||
title="Connection to Test Net required" disabled>サンプルトランザクションを送信する</button>
|
||||
<div id='loader-{{n.current}}' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"></div>
|
||||
<div id="submit-output"></div>
|
||||
<button id="submit-button" class="btn btn-primary previous-steps-required" data-tx-blob-from="#signed-tx-blob" data-wait-step-name="Wait">サンプルトランザクションを送信する</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png"> 送信中...</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
$("#submit-button").click( async function() {
|
||||
$("#submit-output").html("") // Wipe previous output
|
||||
$("#loader-{{n.current}}").show()
|
||||
|
||||
const txBlob = $("#signed-tx-blob").text()
|
||||
const earliestLedgerVersion = await api.getLedgerVersion()
|
||||
$("#earliest-ledger-version").text(earliestLedgerVersion)
|
||||
|
||||
try {
|
||||
const result = await api.submit(txBlob)
|
||||
$("#loader-{{n.current}}").hide()
|
||||
$("#submit-output").html(
|
||||
"<div><strong>Tentative result:</strong> " +
|
||||
result.resultCode + " - " +
|
||||
result.resultMessage +
|
||||
"</div>"
|
||||
)
|
||||
|
||||
// Update breadcrumbs & active next step
|
||||
complete_step("Submit")
|
||||
}
|
||||
catch(error) {
|
||||
$("#loader-{{n.current}}").hide()
|
||||
$("#submit-output").text("Error: "+error)
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
### {{n.next()}}. 検証の待機
|
||||
|
||||
ほとんどのトランザクションは送信後の次のレジャーバージョンに承認されます。つまり、4~7秒でトランザクションの結果が最終的なものになる可能性があります。XRP Ledgerがビジーになっているか、ネットワーク接続の品質が悪いためにトランザクションをネットワーク内で中継する処理が遅延した場合は、トランザクション確定までにもう少し時間がかかることがあります。(トランザクションの有効期限を設定する方法については、[信頼できるトランザクションの送信](reliable-transaction-submission.html)を参照してください。)
|
||||
@@ -294,42 +177,17 @@ RippleAPIの`ledger`イベントタイプを使用して、新しい検証済み
|
||||
|
||||
```js
|
||||
api.on('ledger', ledger => {
|
||||
console.log("Ledger version", ledger.ledgerVersion, "was validated.")
|
||||
console.log("レジャーインデックス", ledger.ledgerVersion, "は検証されました。")
|
||||
if (ledger.ledgerVersion > maxLedgerVersion) {
|
||||
console.log("If the transaction hasn't succeeded by now, it's expired")
|
||||
console.log("トランザクションはまだ検証されていませんなら、有効期限が切れています。")
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
{{ start_step("Wait") }}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Latest Validated Ledger Version:</th>
|
||||
<td id="current-ledger-version">(Not connected)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Ledger Version at Time of Submission:</th>
|
||||
<td id="earliest-ledger-version">(Not submitted)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Transaction LastLedgerSequence:</th>
|
||||
<td id="tx-lls"></td>
|
||||
</tr>
|
||||
</table>
|
||||
{% include '_snippets/interactive-tutorials/wait-step.ja.md' %}
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
api.on('ledger', ledger => {
|
||||
$("#current-ledger-version").text(ledger.ledgerVersion)
|
||||
|
||||
if ( $(".breadcrumb-item.bc-wait").hasClass("active") ) {
|
||||
// Advance to "Check" as soon as we see a ledger close
|
||||
complete_step("Wait")
|
||||
$("#get-tx-button").prop("disabled", false)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
### {{n.next()}}. トランザクションステータスの確認
|
||||
|
||||
@@ -341,10 +199,10 @@ api.on('ledger', ledger => {
|
||||
// txID was noted when the transaction was signed.
|
||||
try {
|
||||
tx = await api.getTransaction(txID, {minLedgerVersion: earliestLedgerVersion})
|
||||
console.log("Transaction result:", tx.outcome.result)
|
||||
console.log("Balance changes:", JSON.stringify(tx.outcome.balanceChanges))
|
||||
console.log("トランザクションの結果:", tx.outcome.result)
|
||||
console.log("残高変化:", JSON.stringify(tx.outcome.balanceChanges))
|
||||
} catch(error) {
|
||||
console.log("Couldn't get transaction outcome:", error)
|
||||
console.log("トランザクションの結果を取得出来ませんでした。エラー:", error)
|
||||
}
|
||||
|
||||
```
|
||||
@@ -354,37 +212,10 @@ RippleAPIの`getTransaction()`メソッドは、トランザクションが検
|
||||
**注意:** 他のAPIは、まだ検証されていないレジャーバージョンからの暫定的な結果を返す場合があります。例えば、`rippled` APIの[txメソッド][]を使用した場合は、応答内の`"validated": true`を探して、データが検証済みレジャーバージョンからのものであることを確認してください。検証済みレジャーバージョンからのものではないトランザクション結果は、変わる可能性があります。詳細は、[結果のファイナリティー](finality-of-results.html)を参照してください。
|
||||
|
||||
{{ start_step("Check") }}
|
||||
<button id="get-tx-button" class="btn btn-primary connection-required"
|
||||
title="Connection to Test Net required" disabled>トランザクションステータスを確認する</button>
|
||||
<div id="get-tx-output"></div>
|
||||
<button id="get-tx-button" class="btn btn-primary previous-steps-required">トランザクションステータスを確認する</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
$("#get-tx-button").click( async function() {
|
||||
// Wipe previous output
|
||||
$("#get-tx-output").html("")
|
||||
|
||||
const txID = $("#signed-tx-hash").text()
|
||||
const earliestLedgerVersion = parseInt($("#earliest-ledger-version").text(), 10)
|
||||
|
||||
try {
|
||||
const tx = await api.getTransaction(txID, {minLedgerVersion: earliestLedgerVersion})
|
||||
|
||||
$("#get-tx-output").html(
|
||||
"<div><strong>Transaction result:</strong> " +
|
||||
tx.outcome.result + "</div>" +
|
||||
"<div><strong>Balance changes:</strong> <pre><code>" +
|
||||
JSON.stringify(tx.outcome.balanceChanges, null, 2) +
|
||||
"</pre></code></div>"
|
||||
)
|
||||
|
||||
complete_step("Check")
|
||||
} catch(error) {
|
||||
$("#get-tx-output").text("Couldn't get transaction outcome:" + error)
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
## 本番環境の場合の相違点
|
||||
|
||||
@@ -399,8 +230,8 @@ RippleAPIの`getTransaction()`メソッドは、トランザクションが検
|
||||
|
||||
```js
|
||||
const generated = api.generateAddress()
|
||||
console.log(generated.address) // Example: rGCkuB7PBr5tNy68tPEABEtcdno4hE6Y7f
|
||||
console.log(generated.secret) // Example: sp6JS7f14BuwFY8Mw6bTtLKWauoUs
|
||||
console.log(generated.address) // 例: rGCkuB7PBr5tNy68tPEABEtcdno4hE6Y7f
|
||||
console.log(generated.secret) // 例: sp6JS7f14BuwFY8Mw6bTtLKWauoUs
|
||||
```
|
||||
|
||||
**警告:** ローカルマシンで安全な方法で生成したアドレスとシークレットのみを使用してください。別のコンピューターでアドレスとシークレットを生成して、ネットワーク経由でそれらを自分に送信した場合は、ネットワーク上の他の人がその情報を見ることができる可能性があります。その情報見ることができる人は、あなたと同じようにあなたのXRPを操作できます。また、Test Netと本番で同じアドレスを使用しないことも推奨します。指定したパラメーターによっては、一方のネットワークに向けて作成したトランザクションが、もう一方のネットワークでも実行可能になるおそれがあるためです。
|
||||
|
||||
@@ -5,78 +5,53 @@ doc_type: Tutorials
|
||||
category: Get Started
|
||||
blurb: Learn how to send test payments right from your browser.
|
||||
cta_text: Send XRP
|
||||
embed_ripple_lib: true
|
||||
filters:
|
||||
- interactive_steps
|
||||
- include_code
|
||||
---
|
||||
# Send XRP
|
||||
|
||||
This tutorial explains how to send a simple XRP Payment using RippleAPI for JavaScript. First, we step through the process with the XRP Test Net. Then, we compare that to the additional requirements for doing the equivalent in production.
|
||||
|
||||
**Tip:** Check out the [Code Samples](https://github.com/ripple/xrpl-dev-portal/tree/master/content/_code-samples) for a complete version of the code used in this tutorial.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<!-- ripple-lib & prerequisites -->
|
||||
{{currentpage.lodash_tag}}
|
||||
{{currentpage.ripple_lib_tag}}
|
||||
<!-- Helper for interactive tutorial breadcrumbs -->
|
||||
<script type="application/javascript" src="assets/js/interactive-tutorial.js"></script>
|
||||
<!-- Source for this specific tutorial's interactive bits: -->
|
||||
<script type="application/javascript" src="assets/js/tutorials/send-xrp.js"></script>
|
||||
{% set use_network = "Testnet" %}
|
||||
|
||||
- This page provides JavaScript examples that use the ripple-lib (RippleAPI) library. The [RippleAPI Beginners Guide](get-started-with-rippleapi-for-javascript.html) describes how to get started using RippleAPI to access XRP Ledger data from JavaScript.
|
||||
|
||||
- To send transactions in the XRP Ledger, you first need an address and secret key, and some XRP. You can get an address in the XRP Testnet with a supply of Test Net XRP using the following interface:
|
||||
|
||||
{% include '_snippets/generate-step.md' %}
|
||||
|
||||
|
||||
## Send a Payment on the Test Net
|
||||
{% set n = cycler(* range(1,99)) %}
|
||||
|
||||
### {{n.next()}}. Connect to a Test Net Server
|
||||
### {{n.next()}}. Get Credentials
|
||||
|
||||
To transact on the XRP Ledger, you need an address and secret key, and some XRP. The address and secret key look like this:
|
||||
|
||||
{{ include_code("_code-samples/send-xrp/send-xrp.js", end_before="// Connect", language="js") }}
|
||||
|
||||
For development purposes, you can get these using the following interface:
|
||||
|
||||
{% include '_snippets/interactive-tutorials/generate-step.md' %}
|
||||
|
||||
When you're [building actual production-ready software](production-readiness.html), you'll instead use an existing account, and manage your keys using a [secure signing configuration](set-up-secure-signing.html).
|
||||
|
||||
|
||||
### {{n.next()}}. Connect to a Testnet Server
|
||||
|
||||
To provide the necessary auto-fillable fields, ripple-lib must be connected to a server where it can get the current status of your account and the shared ledger itself. (For more security, you should sign transactions while being offline, but you must provide the auto-fillable fields manually if you do so.) You must be connected to the network to submit transactions to it.
|
||||
|
||||
The following code sample instantiates a new RippleAPI instance and connects to one of the public XRP Test Net servers that Ripple runs:
|
||||
The following code sample creates a new RippleAPI instance and connects to one of the public Testnet servers that Ripple runs:
|
||||
|
||||
```js
|
||||
ripple = require('ripple-lib')
|
||||
api = new ripple.RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
|
||||
api.connect()
|
||||
```
|
||||
{{ include_code("_code-samples/send-xrp/send-xrp.js", start_with="// Connect", end_before="// Get credentials", language="js") }}
|
||||
|
||||
For this tutorial, you can connect directly from your browser by pressing the following button:
|
||||
|
||||
{{ start_step("Connect") }}
|
||||
<button id="connect-button" class="btn btn-primary">Connect to TestNet</button>
|
||||
<div>
|
||||
<strong>Connection status:</strong>
|
||||
<span id="connection-status">Not connected</span>
|
||||
<div id='loader-{{n.current}}' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"></div>
|
||||
</div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
api = new ripple.RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
|
||||
api.on('connected', () => {
|
||||
$("#connection-status").text("Connected")
|
||||
$("#connect-button").prop("disabled", true)
|
||||
$("#loader-{{n.current}}").hide()
|
||||
|
||||
// Update breadcrumbs & active next step
|
||||
complete_step("Connect")
|
||||
$("#interactive-prepare button").prop("disabled", false)
|
||||
$("#interactive-prepare button").prop("title", "")
|
||||
})
|
||||
api.on('disconnected', (code) => {
|
||||
$("#connection-status").text( "Disconnected ("+code+")" )
|
||||
$("#connect-button").prop("disabled", false)
|
||||
$(".connection-required").prop("disabled", true)
|
||||
$(".connection-required").prop("title", "Connection to Test Net required")
|
||||
})
|
||||
$("#connect-button").click(() => {
|
||||
$("#connection-status").text( "Connecting..." )
|
||||
$("#loader-{{n.current}}").show()
|
||||
api.connect()
|
||||
})
|
||||
</script>
|
||||
{% include '_snippets/interactive-tutorials/connect-step.md' %}
|
||||
|
||||
|
||||
### {{n.next()}}. Prepare Transaction
|
||||
@@ -101,122 +76,43 @@ The bare minimum set of instructions you must provide for an XRP Payment is:
|
||||
|
||||
Technically, a viable transaction must contain some additional fields, and certain optional fields such as `LastLedgerSequence` are strongly recommended. The [`prepareTransaction()` method](rippleapi-reference.html#preparetransaction) automatically fills in good defaults for the remaining fields of a transaction. Here's an example of preparing the above payment:
|
||||
|
||||
```js
|
||||
// Continuing after connecting to the API
|
||||
async function doPrepare() {
|
||||
const sender = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const preparedTx = await api.prepareTransaction({
|
||||
"TransactionType": "Payment",
|
||||
"Account": sender,
|
||||
"Amount": api.xrpToDrops("22"), // Same as "Amount": "22000000"
|
||||
"Destination": "rUCzEr6jrEyMpjhs4wSdQdz4g8Y382NxfM"
|
||||
}, {
|
||||
// Expire this transaction if it doesn't execute within ~5 minutes:
|
||||
"maxLedgerVersionOffset": 75
|
||||
})
|
||||
const maxLedgerVersion = preparedTx.instructions.maxLedgerVersion
|
||||
console.log("Prepared transaction instructions:", preparedTx.txJSON)
|
||||
console.log("Transaction cost:", preparedTx.instructions.fee, "XRP")
|
||||
console.log("Transaction expires after ledger:", maxLedgerVersion)
|
||||
return preparedTx.txJSON
|
||||
}
|
||||
txJSON = JSON.stringify(doPrepare())
|
||||
```
|
||||
{{ include_code("_code-samples/send-xrp/send-xrp.js", start_with="// Prepare", end_before="// Sign", language="js" ) }}
|
||||
|
||||
{{ start_step("Prepare") }}
|
||||
<button id="prepare-button" class="btn btn-primary connection-required"
|
||||
title="Connect to Test Net first" disabled>Prepare
|
||||
example transaction</button>
|
||||
<div id="prepare-output"></div>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Send: </span>
|
||||
</div>
|
||||
<input type="number" class="form-control" value="22" id="xrp-amount"
|
||||
aria-label="Amount of XRP, as a decimal" aria-describedby="xrp-amount-label"
|
||||
min=".000001" max="100000000000" step="any">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="xrp-amount-label"> XRP</span>
|
||||
</div>
|
||||
</div>
|
||||
<button id="prepare-button" class="btn btn-primary previous-steps-required">Prepare
|
||||
example transaction</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
$("#prepare-button").click( async function() {
|
||||
// Wipe existing results
|
||||
$("#prepare-output").html("")
|
||||
|
||||
const sender = $("#use-address").text() || "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const preparedTx = await api.prepareTransaction({
|
||||
"TransactionType": "Payment",
|
||||
"Account": sender,
|
||||
"Amount": api.xrpToDrops("22"), // Same as "Amount": "22000000"
|
||||
"Destination": "rUCzEr6jrEyMpjhs4wSdQdz4g8Y382NxfM"
|
||||
}, {
|
||||
// Expire this transaction if it doesn't execute within ~5 minutes:
|
||||
"maxLedgerVersionOffset": 75
|
||||
})
|
||||
const maxLedgerVersion = preparedTx.instructions.maxLedgerVersion
|
||||
$("#tx-lls").text(maxLedgerVersion) //for the table in the later step
|
||||
|
||||
$("#prepare-output").html(
|
||||
"<div><strong>Prepared transaction instructions:</strong> <pre><code id='prepared-tx-json'>" +
|
||||
JSON.stringify(JSON.parse(preparedTx.txJSON), null, 2) + "</code></pre></div>" +
|
||||
"<div><strong>Transaction cost:</strong> " +
|
||||
preparedTx.instructions.fee + " XRP</div>" +
|
||||
"<div><strong>Transaction expires after ledger:</strong> " +
|
||||
maxLedgerVersion + "</div>"
|
||||
)
|
||||
|
||||
// Update breadcrumbs & active next step
|
||||
complete_step("Prepare")
|
||||
$("#interactive-sign button").prop("disabled", false)
|
||||
$("#interactive-sign button").prop("title", "")
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
### {{n.next()}}. Sign the Transaction Instructions
|
||||
|
||||
Use the [sign() method](rippleapi-reference.html#sign) to sign the transaction with RippleAPI. The first argument is a string version of the JSON transaction to sign.
|
||||
|
||||
```js
|
||||
// Continuing from the previous step...
|
||||
const response = api.sign(txJSON, "s████████████████████████████")
|
||||
const txID = response.id
|
||||
console.log("Identifying hash:", txID)
|
||||
const txBlob = response.signedTransaction
|
||||
console.log("Signed blob:", txBlob)
|
||||
```
|
||||
{{ include_code("_code-samples/send-xrp/send-xrp.js",
|
||||
start_with="// Sign", end_before="// Submit", language="js" ) }}
|
||||
|
||||
The result of the signing operation is a transaction object containing a signature. Typically, XRP Ledger APIs expect a signed transaction to be the hexadecimal representation of the transaction's canonical [binary format](serialization.html), called a "blob".
|
||||
|
||||
The signing API also returns the transaction's ID, or identifying hash, which you can use to look up the transaction later. This is a 64-character hexadecimal string that is unique to this transaction.
|
||||
|
||||
{{ start_step("Sign") }}
|
||||
<button id="sign-button" class="btn btn-primary connection-required"
|
||||
title="Complete all previous steps first" disabled>Sign
|
||||
<button id="sign-button" class="btn btn-primary previous-steps-required">Sign
|
||||
example transaction</button>
|
||||
<div id="sign-output"></div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
$("#sign-button").click( function() {
|
||||
// Wipe previous output
|
||||
$("#sign-output").html("")
|
||||
|
||||
const preparedTxJSON = $("#prepared-tx-json").text()
|
||||
const secret = $("#use-secret").text()
|
||||
|
||||
if (!secret) {
|
||||
alert("Can't sign transaction without a real secret. Generate credentials first.")
|
||||
return
|
||||
}
|
||||
|
||||
signResponse = api.sign(preparedTxJSON, secret)
|
||||
|
||||
$("#sign-output").html(
|
||||
"<div><strong>Signed Transaction blob:</strong> <code id='signed-tx-blob' style='overflow-wrap: anywhere; word-wrap: anywhere'>" +
|
||||
signResponse.signedTransaction + "</code></div>" +
|
||||
"<div><strong>Identifying hash:</strong> <span id='signed-tx-hash'>" +
|
||||
signResponse.id + "</span></div>"
|
||||
)
|
||||
|
||||
// Update all breadcrumbs & activate next step
|
||||
complete_step("Sign")
|
||||
$("#interactive-submit button").prop("disabled", false)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
### {{n.next()}}. Submit the Signed Blob
|
||||
|
||||
@@ -224,23 +120,7 @@ Use the [submit() method](rippleapi-reference.html#submit) to submit a transacti
|
||||
|
||||
Of course, if the same transaction was previously submitted, it could already be in a previous ledger. (It can't succeed a second time, but you may not realize it succeeded if you aren't looking in the right ledger versions.)
|
||||
|
||||
```js
|
||||
// use txBlob from the previous example
|
||||
async function doSubmit(txBlob) {
|
||||
const latestLedgerVersion = await api.getLedgerVersion()
|
||||
|
||||
const result = await api.submit(txBlob)
|
||||
|
||||
console.log("Tentative result code:", result.resultCode)
|
||||
console.log("Tentative result message:", result.resultMessage)
|
||||
|
||||
// Return the earliest ledger index this transaction could appear in
|
||||
// as a result of this submission, which is the first one after the
|
||||
// validated ledger at time of submission.
|
||||
return latestLedgerVersion + 1
|
||||
}
|
||||
const earliestLedgerVersion = doSubmit(txBlob)
|
||||
```
|
||||
{{ include_code("_code-samples/send-xrp/send-xrp.js", start_with="// Submit", end_before="// Wait", language="js" ) }}
|
||||
|
||||
This method returns the **tentative** result of trying to apply the transaction locally. This result _can_ change when the transaction is included in a validated ledger: transactions that succeed initially might ultimately fail, and transactions that fail initially might ultimately succeed. Still, the tentative result often matches the final result, so it's OK to get excited if you see `tesSUCCESS` here. 😁
|
||||
|
||||
@@ -255,142 +135,41 @@ See the full list of [transaction results](transaction-results.html) for more po
|
||||
|
||||
|
||||
{{ start_step("Submit") }}
|
||||
<button id="submit-button" class="btn btn-primary connection-required"
|
||||
title="Connection to Test Net required" disabled>Submit
|
||||
example transaction</button>
|
||||
<div id='loader-{{n.current}}' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"></div>
|
||||
<div id="submit-output"></div>
|
||||
<button id="submit-button" class="btn btn-primary previous-steps-required" data-tx-blob-from="#signed-tx-blob" data-wait-step-name="Wait">Submit
|
||||
example transaction</button>
|
||||
<div class="loader collapse"><img class="throbber" src="assets/img/xrp-loader-96.png"> Sending...</div>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
$("#submit-button").click( async function() {
|
||||
$("#submit-output").html("") // Wipe previous output
|
||||
$("#loader-{{n.current}}").show()
|
||||
|
||||
const txBlob = $("#signed-tx-blob").text()
|
||||
const earliestLedgerVersion = await api.getLedgerVersion()
|
||||
$("#earliest-ledger-version").text(earliestLedgerVersion)
|
||||
|
||||
try {
|
||||
const result = await api.submit(txBlob)
|
||||
$("#loader-{{n.current}}").hide()
|
||||
$("#submit-output").html(
|
||||
"<div><strong>Tentative result:</strong> " +
|
||||
result.resultCode + " - " +
|
||||
result.resultMessage +
|
||||
"</div>"
|
||||
)
|
||||
|
||||
// Update breadcrumbs & active next step
|
||||
complete_step("Submit")
|
||||
}
|
||||
catch(error) {
|
||||
$("#loader-{{n.current}}").hide()
|
||||
$("#submit-output").text("Error: "+error)
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
### {{n.next()}}. Wait for Validation
|
||||
|
||||
Most transactions are accepted into the next ledger version after they're submitted, which means it may take 4-7 seconds for a transaction's outcome to be final. If the XRP Ledger is busy or poor network connectivity delays a transaction from being relayed throughout the network, a transaction may take longer to be confirmed. (For information on how to set an expiration for transactions, see [Reliable Transaction Submission](reliable-transaction-submission.html).)
|
||||
|
||||
You use the `ledger` event type in RippleAPI to trigger your code to run whenever there is a new validated ledger version. For example:
|
||||
Use an account [subscription](rippleapi-reference.html#listening-to-streams) to listen for an event when the transaction is confirmed. Use the `ledger` event type to trigger your code to run whenever there is a new validated ledger version so that you can know if the transaction can no longer be confirmed. For example:
|
||||
|
||||
```js
|
||||
api.on('ledger', ledger => {
|
||||
console.log("Ledger version", ledger.ledgerVersion, "was validated.")
|
||||
if (ledger.ledgerVersion > maxLedgerVersion) {
|
||||
console.log("If the transaction hasn't succeeded by now, it's expired")
|
||||
}
|
||||
})
|
||||
```
|
||||
{{ include_code("_code-samples/send-xrp/send-xrp.js", start_with="// Wait", end_before="// There are other", language="js" ) }}
|
||||
|
||||
{{ start_step("Wait") }}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Latest Validated Ledger Version:</th>
|
||||
<td id="current-ledger-version">(Not connected)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Ledger Version at Time of Submission:</th>
|
||||
<td id="earliest-ledger-version">(Not submitted)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Transaction <code>LastLedgerSequence</code>:</th>
|
||||
<td id="tx-lls"></td>
|
||||
</tr>
|
||||
</table>
|
||||
{% include '_snippets/interactive-tutorials/wait-step.md' %}
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
api.on('ledger', ledger => {
|
||||
$("#current-ledger-version").text(ledger.ledgerVersion)
|
||||
|
||||
if ( $(".breadcrumb-item.bc-wait").hasClass("active") ) {
|
||||
// Advance to "Check" as soon as we see a ledger close
|
||||
complete_step("Wait")
|
||||
$("#get-tx-button").prop("disabled", false)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
### {{n.next()}}. Check Transaction Status
|
||||
|
||||
To know for sure what a transaction did, you must look up the outcome of the transaction when it appears in a validated ledger version. For example, you can use the [`getTransaction()` method](rippleapi-reference.html#gettransaction) to check the status of a transaction:
|
||||
|
||||
```js
|
||||
// Continues from previous examples.
|
||||
// earliestLedgerVersion was noted when the transaction was submitted.
|
||||
// txID was noted when the transaction was signed.
|
||||
try {
|
||||
tx = await api.getTransaction(txID, {minLedgerVersion: earliestLedgerVersion})
|
||||
console.log("Transaction result:", tx.outcome.result)
|
||||
console.log("Balance changes:", JSON.stringify(tx.outcome.balanceChanges))
|
||||
} catch(error) {
|
||||
console.log("Couldn't get transaction outcome:", error)
|
||||
}
|
||||
|
||||
```
|
||||
{{ include_code("_code-samples/send-xrp/send-xrp.js",
|
||||
start_with="// Check", language="js" ) }}
|
||||
|
||||
The RippleAPI `getTransaction()` method only returns success if the transaction is in a validated ledger version. Otherwise, the `await` expression raises an exception.
|
||||
|
||||
**Caution:** Other APIs may return tentative results from ledger versions that have not yet been validated. For example, if you use the `rippled` APIs' [tx method][], be sure to look for `"validated": true` in the response to confirm that the data comes from a validated ledger version. Transaction results that are not from a validated ledger version are subject to change. For more information, see [Finality of Results](finality-of-results.html).
|
||||
|
||||
{{ start_step("Check") }}
|
||||
<button id="get-tx-button" class="btn btn-primary connection-required"
|
||||
title="Connection to Test Net required" disabled>Check transaction status</button>
|
||||
<div id="get-tx-output"></div>
|
||||
<button id="get-tx-button" class="btn btn-primary previous-steps-required">Check transaction status</button>
|
||||
<div class="output-area"></div>
|
||||
{{ end_step() }}
|
||||
|
||||
<script type="application/javascript">
|
||||
$("#get-tx-button").click( async function() {
|
||||
// Wipe previous output
|
||||
$("#get-tx-output").html("")
|
||||
|
||||
const txID = $("#signed-tx-hash").text()
|
||||
const earliestLedgerVersion = parseInt($("#earliest-ledger-version").text(), 10)
|
||||
|
||||
try {
|
||||
const tx = await api.getTransaction(txID, {minLedgerVersion: earliestLedgerVersion})
|
||||
|
||||
$("#get-tx-output").html(
|
||||
"<div><strong>Transaction result:</strong> " +
|
||||
tx.outcome.result + "</div>" +
|
||||
"<div><strong>Balance changes:</strong> <pre><code>" +
|
||||
JSON.stringify(tx.outcome.balanceChanges, null, 2) +
|
||||
"</pre></code></div>"
|
||||
)
|
||||
|
||||
complete_step("Check")
|
||||
} catch(error) {
|
||||
$("#get-tx-output").text("Couldn't get transaction outcome:" + error)
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
## Differences for Production
|
||||
|
||||
@@ -409,9 +188,9 @@ console.log(generated.address) // Example: rGCkuB7PBr5tNy68tPEABEtcdno4hE6Y7f
|
||||
console.log(generated.secret) // Example: sp6JS7f14BuwFY8Mw6bTtLKWauoUs
|
||||
```
|
||||
|
||||
**Warning:** You should only use an address and secret that you generated securely, on your local machine. If another computer generated the address and secret and sent it to you over a network, it's possible that someone else on the network may see that information. If they do, they'll have as much control over your XRP as you do. It's also recommended not to use the same address for the test net and for production, because transactions that you created for use on one network could potentially also be viable on the other network, depending on the parameters you provided.
|
||||
**Warning:** You should only use an address and secret that you generated securely, on your local machine. If another computer generated the address and secret and sent it to you over a network, it's possible that someone else on the network may see that information. If they do, they'll have as much control over your XRP as you do. It's also recommended not to use the same address for the Testnet and Mainnet, because transactions that you created for use on one network could potentially also be viable on the other network, depending on the parameters you provided.
|
||||
|
||||
Generating an address and secret doesn't get you XRP directly; it's only choosing a random number. You must also receive XRP at that address to [fund the account](accounts.html#creating-accounts). A common way to acquire XRP is to buy it from an exchange, then withdraw it to your own address. For more information, see Ripple's [XRP Buying Guide](https://ripple.com/xrp/buy-xrp/).
|
||||
Generating an address and secret doesn't get you XRP directly; you're only choosing a random number. You must also receive XRP at that address to [fund the account](accounts.html#creating-accounts). A common way to acquire XRP is to buy it from an [exchange](exchanges.html), then withdraw it to your own address.
|
||||
|
||||
### Connecting to the Production XRP Ledger
|
||||
|
||||
|
||||
Reference in New Issue
Block a user