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:
mDuo13
2021-03-10 18:33:17 -08:00
parent d98249e984
commit 6d91616a62
37 changed files with 1928 additions and 1031 deletions

View File

@@ -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() }}

View File

@@ -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() }}

View File

@@ -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

View File

@@ -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

View File

@@ -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-libRippleAPIライブラリーバージョン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()}}. 検証の待機
ほとんどのトランザクションは送信後の次のレジャーバージョンに承認されます。つまり、47秒でトランザクションの結果が最終的なものになる可能性があります。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と本番で同じアドレスを使用しないことも推奨します。指定したパラメーターによっては、一方のネットワークに向けて作成したトランザクションが、もう一方のネットワークでも実行可能になるおそれがあるためです。

View File

@@ -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