mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-19 19:25:51 +00:00
Merge pull request #953 from mDuo13/ticketbatch_tutorial
"Use Tickets" tutorial
This commit is contained in:
76
content/_snippets/generate-step.ja.md
Normal file
76
content/_snippets/generate-step.ja.md
Normal file
@@ -0,0 +1,76 @@
|
||||
{% 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で同じアドレスを使用**しない**ことをお勧めします。
|
||||
78
content/_snippets/generate-step.md
Normal file
78
content/_snippets/generate-step.md
Normal file
@@ -0,0 +1,78 @@
|
||||
{% 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.
|
||||
@@ -1,3 +1,12 @@
|
||||
---
|
||||
html: monitor-incoming-payments-with-websocket.html
|
||||
funnel: Build
|
||||
doc_type: Tutorials
|
||||
category: Get Started
|
||||
blurb: WebSocket APIを使用して、新しいXRPペイメントなどを積極的に監視します。
|
||||
filters:
|
||||
- interactive_steps
|
||||
---
|
||||
# WebSocketを使用した着信ペイメントの監視
|
||||
|
||||
このチュートリアルでは、[WebSocket `rippled` API](rippled-api.html)を使用して、着信[ペイメント](payment-types.html)を監視する方法を説明します。すべてのXRP Ledgerトランザクションは公開されているため、誰もが任意のアドレスへの着信ペイメントを監視できます。
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
---
|
||||
html: monitor-incoming-payments-with-websocket.html
|
||||
funnel: Build
|
||||
doc_type: Tutorials
|
||||
category: Get Started
|
||||
blurb: Use the WebSocket API to actively monitor for new XRP payments (and more).
|
||||
filters:
|
||||
- interactive_steps
|
||||
---
|
||||
# Monitor Incoming Payments with WebSocket
|
||||
|
||||
This tutorial shows how to monitor for incoming [payments](payment-types.html) using the [WebSocket `rippled` API](rippled-api.html). Since all XRP Ledger transactions are public, anyone can monitor incoming payments to any address.
|
||||
|
||||
382
content/tutorials/manage-account-settings/use-tickets.md
Normal file
382
content/tutorials/manage-account-settings/use-tickets.md
Normal file
@@ -0,0 +1,382 @@
|
||||
---
|
||||
html: use-tickets.html
|
||||
funnel: Build
|
||||
doc_type: Tutorials
|
||||
category: Manage Account Settings
|
||||
blurb: Use Tickets to send a transaction outside of normal Sequence order.
|
||||
filters:
|
||||
- interactive_steps
|
||||
---
|
||||
# Use Tickets
|
||||
|
||||
_(Requires the [TicketBatch amendment][] :not_enabled:)_
|
||||
|
||||
[Tickets](tickets.html) provide a way to send transactions out of the normal order. This tutorial walks through the steps of creating a Ticket, then using it to send another transaction.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<!-- Interactive example use ripple-lib and its prerequisites -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
|
||||
<script type="application/javascript" src="{{target.ripple_lib_url}}"></script>
|
||||
<!-- 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>
|
||||
|
||||
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.
|
||||
|
||||
Since JavaScript works in the web browser, you can read along and use the interactive steps without any setup.
|
||||
|
||||
Tickets must be enabled. At this time, the [TicketBatch amendment][] :not_enabled: is only available on Devnet.
|
||||
|
||||
|
||||
|
||||
## Steps
|
||||
{% set n = cycler(* range(1,99)) %}
|
||||
|
||||
This tutorial is divided into a few phases:
|
||||
|
||||
- (Steps 1-2) **Setup:** You need an XRP Ledger address and secret. For production, you can use the same address and secret consistently. For this tutorial, you can generate new test credentials as needed. You also need to be connected to the network.
|
||||
- (Steps 3-6) **Create Tickets:** Send a transaction to set aside some Tickets.
|
||||
- (Optional) **Intermission:** After creating Tickets, you can send various other transactions at any time before, during, and after the following steps.
|
||||
- (Steps 7-10) **Use Ticket:** Use one of your set-aside Tickets to send a transaction. You can repeat these steps while skipping the previous parts as long as you have at least one Ticket remaining to use.
|
||||
|
||||
### {{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 -->
|
||||
|
||||
{% set faucet_url = "https://faucet.devnet.rippletest.net/accounts" %}
|
||||
{% include '_snippets/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 Network
|
||||
|
||||
You must be connected to the network to submit transactions to it.
|
||||
|
||||
The following code uses a RippleAPI instance to connect to a public XRP Devnet server:
|
||||
|
||||
```js
|
||||
ripple = require('ripple-lib')
|
||||
|
||||
async function main() {
|
||||
api = new ripple.RippleAPI({server: 'wss://s.devnet.rippletest.net:51233'})
|
||||
await api.connect()
|
||||
|
||||
// Code in the following examples continues here...
|
||||
}
|
||||
|
||||
main()
|
||||
```
|
||||
|
||||
**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.
|
||||
|
||||
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() }}
|
||||
|
||||
|
||||
### {{n.next()}}. Check Sequence Number
|
||||
|
||||
Before you create any Tickets, you should check what [Sequence Number][] your account is at. You want the current Sequence number for the next step, and the Ticket Sequence numbers it sets aside start from this number.
|
||||
|
||||
```js
|
||||
async function get_sequence() {
|
||||
const account_info = await api.request("account_info", {
|
||||
"account": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
})
|
||||
console.log("Current sequence:", account_info.account_data.Sequence)
|
||||
return account_info.account_data.Sequence
|
||||
}
|
||||
|
||||
let current_sequence = 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>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
|
||||
### {{n.next()}}. Prepare and Sign TicketCreate
|
||||
|
||||
Construct a [TicketCreate transaction][] using the sequence number you determined in the previous step. Use the `TicketCount` field to specify how many Tickets to create. For example, to [prepare a transaction](rippleapi-reference.html#preparetransaction) that would make 10 Tickets:
|
||||
|
||||
```js
|
||||
let prepared = await api.prepareTransaction({
|
||||
"TransactionType": "TicketCreate",
|
||||
"Account": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
|
||||
"TicketCount": 10,
|
||||
"Sequence": current_sequence
|
||||
})
|
||||
console.log("Prepared transaction:", prepared.txJSON)
|
||||
let max_ledger = prepared.instructions.maxLedgerVersion
|
||||
|
||||
let signed = api.sign(prepared.txJSON, "s████████████████████████████")
|
||||
console.log("Transaction hash:", signed.id)
|
||||
|
||||
let tx_blob = signed.signedTransaction
|
||||
```
|
||||
|
||||
Record the transaction's hash and `LastLedgerSequence` value so you can [be sure whether or not it got validated](reliable-transaction-submission.html) later.
|
||||
|
||||
|
||||
{{ 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>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
|
||||
### {{n.next()}}. Submit TicketCreate
|
||||
|
||||
Submit the signed transaction blob that you created in the previous step. Record the latest validated ledger index at the time of submission, so you can set a lower bound on what ledger versions the transaction could be validated in. For example:
|
||||
|
||||
```js
|
||||
let prelim_result = await api.request("submit", {"tx_blob": tx_blob})
|
||||
console.log("Preliminary result:", prelim_result)
|
||||
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>
|
||||
{{ 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).)
|
||||
|
||||
You use the `ledger` event type in RippleAPI to trigger your code to run whenever there is a new validated ledger version. For example:
|
||||
|
||||
```js
|
||||
// signed.id is the hash we're waiting for
|
||||
// min_ledger is the validated ledger index at time of first submission
|
||||
// max_ledger is the transaction's LastLedgerSequence value
|
||||
let tx_status = ""
|
||||
api.on('ledger', async (ledger) => {
|
||||
console.log("Ledger version", ledger.ledgerVersion, "was validated.")
|
||||
if (!tx_status) {
|
||||
try {
|
||||
tx_result = await api.request("tx", {
|
||||
"transaction": signed.id,
|
||||
"min_ledger": min_ledger,
|
||||
"max_ledger": max_ledger
|
||||
})
|
||||
|
||||
if (tx_result.validated) {
|
||||
console.log("Got validated result:", tx_result.meta.TransactionResult)
|
||||
tx_status = "validated"
|
||||
} else {
|
||||
// Transaction found, but not yet validated. No change.
|
||||
}
|
||||
} catch(e) {
|
||||
if (e.data.error == "txnNotFound") {
|
||||
if (e.data.searched_all) {
|
||||
console.log(`Tx not found in ledgers ${min_ledger}-${max_ledger}`)
|
||||
tx_status = "rejected"
|
||||
// This result is final if min_ledger and max_ledger are correct
|
||||
} else {
|
||||
if (max_ledger > ledger.ledgerVersion) {
|
||||
// Transaction may yet be confirmed. Keep waiting.
|
||||
} else {
|
||||
console.log("Can't get final result. Check a full history server.")
|
||||
tx_result = "unknown - check full history"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unknown error; pass it back up
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
{{ 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>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
### (Optional) Intermission
|
||||
|
||||
The power of Tickets is that you can carry on with your account's business as usual while you are getting Ticketed transactions ready. When you want to send a transaction using a Ticket, you can do that in parallel with other sending transactions, including ones using different Tickets, and submit a Ticketed transaction at any time. The only constraint is that each Ticket can only be used once.
|
||||
|
||||
**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>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
|
||||
### {{n.next()}}. Check Available Tickets
|
||||
|
||||
When you want to send a Ticketed transaction, you need to know what Ticket Sequence number to use for it. If you've been keeping careful track of your account, you already know which Tickets you have, but if you're not sure, you can use the [account_objects method][] (or [`getAccountObjects()`](rippleapi-reference.html#getaccountobjects)) to look up your available tickets. For example:
|
||||
|
||||
```js
|
||||
let response = await api.request("account_objects", {
|
||||
"account": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
|
||||
"type": "ticket"
|
||||
})
|
||||
|
||||
console.log("Available Tickets:", response.account_objects)
|
||||
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>
|
||||
{{ end_step() }}
|
||||
|
||||
**Tip:** You can repeat the steps from here through the end as long as you have Tickets left to be used!
|
||||
|
||||
### {{n.next()}}. Prepare Ticketed Transaction
|
||||
|
||||
Now that you have a Ticket available, you can prepare a transaction that uses it.
|
||||
|
||||
This can be any [type of transaction](transaction-types.html) you like. The following example uses a no-op [AccountSet transaction][] since that doesn't require any other setup in the ledger. Set the `Sequence` field to `0` and include a `TicketSequence` field with the Ticket Sequence number of one of your available Tickets.
|
||||
|
||||
```js
|
||||
let prepared_t = await api.prepareTransaction({
|
||||
"TransactionType": "AccountSet",
|
||||
"Account": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
|
||||
"TicketSequence": use_ticket,
|
||||
"Sequence": 0
|
||||
}, {
|
||||
// Adjust instructions to allow more time before submitting the transaction
|
||||
maxLedgerVersionOffset: 20
|
||||
//maxLedgerVersion: null // or, let the transaction remain valid indefinitely
|
||||
})
|
||||
console.log("Prepared JSON:", prepared_t.txJSON)
|
||||
|
||||
let signed_t = api.sign(prepared_t.txJSON,
|
||||
"s████████████████████████████")
|
||||
console.log("Transaction hash:", signed_t.id)
|
||||
let tx_blob_t = signed.signedTransaction
|
||||
console.log("Signed transaction blob:", tx_blob_t)
|
||||
```
|
||||
|
||||
**Tip:** If you don't plan to submit the TicketCreate transaction right away, you should explicitly set the [instructions'](rippleapi-reference.html#transaction-instructions) `maxLedgerVersionOffset` to a larger number of ledgers. To create a transaction that could remain valid indefinitely, set the `maxLedgerVersion` to `null`.
|
||||
|
||||
{{ start_step("Prepare Ticketed Tx") }}
|
||||
<div id="ticket-selector">
|
||||
<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>
|
||||
{{ end_step() }}
|
||||
|
||||
|
||||
### {{n.next()}}. Submit Ticketed Transaction
|
||||
|
||||
Submit the signed transaction blob that you created in the previous step. For example:
|
||||
|
||||
```js
|
||||
let prelim_result_t = await api.request("submit", {"tx_blob": tx_blob_t})
|
||||
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>
|
||||
{{ 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>
|
||||
{{ end_step() }}
|
||||
|
||||
## With Multi-Signing
|
||||
|
||||
One of the main use cases for Tickets is to be able to collect signatures for several [multi-signed transactions](multi-signing.html) in parallel. By using a Ticket, you can send a multi-signed transaction as soon as it is fully signed and ready to go, without worrying about which one will be ready first.
|
||||
|
||||
In this scenario, [step 8, "Prepare Ticketed Transaction"](#8-prepare-ticketed-transaction) is slightly different. Instead of preparing and signing all at once, you would follow the steps for [sending any multi-signed transaction](send-a-multi-signed-transaction.html): first prepare the transaction, then circulate it among trusted signers to collect their signatures, and finally combine the signatures into the final multi-signed transaction.
|
||||
|
||||
You could do this in parallel for several different potential transactions as long as each one uses a different Ticket.
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
- **Concepts:**
|
||||
- [Tickets](tickets.html)
|
||||
- [Multi-Signing](multi-signing.html)
|
||||
- **Tutorials:**
|
||||
- [Set Up Multi-Signing](set-up-multi-signing.html)
|
||||
- [Reliable Transaction Submission](reliable-transaction-submission.html)
|
||||
- **References:**
|
||||
- [account_objects method][]
|
||||
- [sign_for method][]
|
||||
- [submit_multisigned method][]
|
||||
- [TicketCreate transaction][]
|
||||
- [Transaction Common Fields](transaction-common-fields.html)
|
||||
|
||||
<!--{# common link defs #}-->
|
||||
{% include '_snippets/rippled-api-links.md' %}
|
||||
{% include '_snippets/tx-type-links.md' %}
|
||||
{% include '_snippets/rippled_versions.md' %}
|
||||
@@ -1,3 +1,13 @@
|
||||
---
|
||||
html: send-xrp.html
|
||||
funnel: Build
|
||||
doc_type: Tutorials
|
||||
category: Get Started
|
||||
blurb: Test Netを使用してXRPの送金をテストします。
|
||||
cta_text: XRPを送金しよう
|
||||
filters:
|
||||
- interactive_steps
|
||||
---
|
||||
# XRPの送金
|
||||
|
||||
このチュートリアルでは、RippleAPI for JavaScriptを使用してシンプルなXRP送金を行う方法について説明します。まずは、XRP Test Netを使用してプロセスを順に進めます。次に、そのプロセスと、本番で同様の処理を行う場合に発生する追加要件とを比較します。
|
||||
@@ -6,88 +16,15 @@
|
||||
|
||||
<!-- Interactive example use ripple-lib and its prerequisites -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
|
||||
<script type="application/javascript" src="assets/js/ripple-lib-1.8.0-min.js"></script>
|
||||
<script type="application/javascript" src="{{target.ripple_lib_url}}"></script>
|
||||
<!-- Helper for interactive tutorial breadcrumbs -->
|
||||
<script type="application/javascript" src="assets/js/interactive-tutorial.js"></script>
|
||||
|
||||
- このページでは、ripple-lib(RippleAPI)ライブラリーバージョン1.1.2を使用するJavaScriptの例を紹介します。[RippleAPI入門ガイド](get-started-with-rippleapi-for-javascript.html)に、RippleAPIを使用してJavaScriptからXRP Ledgerデータにアクセスする方法の説明があります。
|
||||
- このページでは、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を入手できます。
|
||||
|
||||
{{ 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"> 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-0").show()
|
||||
|
||||
$.ajax({
|
||||
url: "https://faucet.altnet.rippletest.net/accounts",
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$("#loader-0").hide()
|
||||
$("#address").hide().html("<strong>Address:</strong> " +
|
||||
'<span id="test-net-faucet-address">' +
|
||||
data.account.address
|
||||
+ "</span>").show()
|
||||
$("#secret").hide().html('<strong>Secret:</strong> ' +
|
||||
'<span id="test-net-faucet-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
|
||||
let generated_addr = ""
|
||||
$("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-0").hide();
|
||||
alert("There was an error with the Ripple Test Net, please try again.");
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const EXAMPLE_ADDR = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const EXAMPLE_SECRET = "s████████████████████████████"
|
||||
$("#populate-creds-button").click( () => {
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
**注意:** RippleはXRP Test Netをテストの目的でのみ運用しており、Test Netの状態とすべての残高を定期的にリセットしています。予防措置として、Test Netと本番で同じアドレスを使用**しない**ことをお勧めします。
|
||||
{% include '_snippets/generate-step.ja.md' %}
|
||||
|
||||
## Test Netでの送金
|
||||
{% set n = cycler(* range(1,99)) %}
|
||||
@@ -196,7 +133,7 @@ txJSON = doPrepare()
|
||||
// Wipe existing results
|
||||
$("#prepare-output").html("")
|
||||
|
||||
const sender = $("#test-net-faucet-address").text() || "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const sender = $("#use-address").text() || "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const preparedTx = await api.prepareTransaction({
|
||||
"TransactionType": "Payment",
|
||||
"Account": sender,
|
||||
@@ -254,7 +191,7 @@ title="Complete all previous steps first" disabled>サンプルトランザク
|
||||
$("#sign-output").html("")
|
||||
|
||||
const preparedTxJSON = $("#prepared-tx-json").text()
|
||||
const secret = $("#test-net-faucet-secret").text()
|
||||
const secret = $("#use-secret").text()
|
||||
|
||||
if (!secret) {
|
||||
alert("Can't sign transaction without a real secret. Generate credentials first.")
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
---
|
||||
html: send-xrp.html
|
||||
funnel: Build
|
||||
doc_type: Tutorials
|
||||
category: Get Started
|
||||
blurb: Learn how to send test payments right from your browser.
|
||||
cta_text: Send XRP
|
||||
filters:
|
||||
- interactive_steps
|
||||
---
|
||||
# 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.
|
||||
@@ -6,88 +16,15 @@ This tutorial explains how to send a simple XRP Payment using RippleAPI for Java
|
||||
|
||||
<!-- Interactive example use ripple-lib and its prerequisites -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
|
||||
<script type="application/javascript" src="assets/js/ripple-lib-1.8.0-min.js"></script>
|
||||
<script type="application/javascript" src="{{target.ripple_lib_url}}"></script>
|
||||
<!-- Helper for interactive tutorial breadcrumbs -->
|
||||
<script type="application/javascript" src="assets/js/interactive-tutorial.js"></script>
|
||||
|
||||
- This page provides JavaScript examples that use the ripple-lib (RippleAPI) library version 1.1.2. 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.
|
||||
- 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 Test Net with a supply of Test Net XRP using the following interface:
|
||||
- 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:
|
||||
|
||||
{{ start_step("Generate") }}
|
||||
<button id="generate-creds-button" class="btn btn-primary">Generate credentials</button>
|
||||
<div id='loader-0' 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-0").show()
|
||||
|
||||
$.ajax({
|
||||
url: "https://faucet.altnet.rippletest.net/accounts",
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$("#loader-0").hide()
|
||||
$("#address").hide().html("<strong>Address:</strong> " +
|
||||
'<span id="test-net-faucet-address">' +
|
||||
data.account.address
|
||||
+ "</span>").show()
|
||||
$("#secret").hide().html('<strong>Secret:</strong> ' +
|
||||
'<span id="test-net-faucet-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
|
||||
let generated_addr = ""
|
||||
$("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-0").hide();
|
||||
alert("There was an error with the Ripple Test Net, please try again.");
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const EXAMPLE_ADDR = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const EXAMPLE_SECRET = "s████████████████████████████"
|
||||
$("#populate-creds-button").click( () => {
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
**Caution:** Ripple provides the XRP Test Net for testing purposes only, and regularly resets the state of the test net along with all balances. As a precaution, Ripple recommends **not** using the same addresses on the test net and production.
|
||||
{% include '_snippets/generate-step.md' %}
|
||||
|
||||
|
||||
## Send a Payment on the Test Net
|
||||
@@ -198,7 +135,7 @@ txJSON = JSON.stringify(doPrepare())
|
||||
// Wipe existing results
|
||||
$("#prepare-output").html("")
|
||||
|
||||
const sender = $("#test-net-faucet-address").text() || "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const sender = $("#use-address").text() || "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
|
||||
const preparedTx = await api.prepareTransaction({
|
||||
"TransactionType": "Payment",
|
||||
"Account": sender,
|
||||
@@ -258,7 +195,7 @@ The signing API also returns the transaction's ID, or identifying hash, which yo
|
||||
$("#sign-output").html("")
|
||||
|
||||
const preparedTxJSON = $("#prepared-tx-json").text()
|
||||
const secret = $("#test-net-faucet-secret").text()
|
||||
const secret = $("#use-secret").text()
|
||||
|
||||
if (!secret) {
|
||||
alert("Can't sign transaction without a real secret. Generate credentials first.")
|
||||
|
||||
Reference in New Issue
Block a user