xrpl.js updates for interactive tutorials

This commit is contained in:
mDuo13
2021-10-01 13:08:38 -07:00
parent d4b10f4dfe
commit 0d0a671ee1
4 changed files with 97 additions and 115 deletions

View File

@@ -63,17 +63,7 @@ function setup_2x_generate_step() {
}) })
} }
function get_address_2(event, which_one) { function get_wallet_2(event, which_one) {
// which_one should be either "cold" or "hot" (case-sensitive)
const address = $(`#${which_one}-use-address`).text()
if (!address) {
const block = $(event.target).closest(".interactive-block")
if (!block.length) {return}
show_error(block, tl("Couldn't get a valid address/secret value. Check that the previous steps were completed successfully."))
}
return address
}
function get_secret_2(event, which_one) {
// which_one should be either "cold" or "hot" (case-sensitive) // which_one should be either "cold" or "hot" (case-sensitive)
const secret = $(`#${which_one}-use-secret`).text() const secret = $(`#${which_one}-use-secret`).text()
if (!secret) { if (!secret) {
@@ -81,13 +71,7 @@ function get_secret_2(event, which_one) {
if (!block.length) {return} if (!block.length) {return}
show_error(block, tl("Couldn't get a valid address/secret value. Check that the previous steps were completed successfully.")) show_error(block, tl("Couldn't get a valid address/secret value. Check that the previous steps were completed successfully."))
} }
// TODO: check for *both* example secrets return xrpl.Wallet.fromSeed(secret)
// if (secret == EXAMPLE_SECRET) {
// const block = $(event.target).closest(".interactive-block")
// if (!block.length) {return}
// show_error(block, tl("Can't use the example secret here. Check that the previous steps were completed successfully."))
// }
return secret
} }
// Get the hexadecimal ASCII representation of a domain name string. // Get the hexadecimal ASCII representation of a domain name string.
@@ -140,15 +124,14 @@ $(document).ready(() => {
$("#config-issuer-button").click( async (event) => { $("#config-issuer-button").click( async (event) => {
const block = $(event.target).closest(".interactive-block") const block = $(event.target).closest(".interactive-block")
block.find(".output-area").empty() block.find(".output-area").empty()
const cold_address = get_address_2(event, "cold") const cold_wallet = get_wallet_2(event, "cold")
const cold_secret = get_secret_2(event, "cold")
let flags = 0 let flags = 0
if ($("#cold-require-dest").prop("checked")) { if ($("#cold-require-dest").prop("checked")) {
flags |= api.txFlags.AccountSet.RequireDestTag flags |= xrpl.AccountSetTransactionFlags.tfRequireDestTag
} }
if ($("#cold-disallow-xrp").prop("checked")) { if ($("#cold-disallow-xrp").prop("checked")) {
flags |= api.txFlags.AccountSet.DisallowXRP flags |= xrpl.AccountSetTransactionFlags.tfDisallowXRP
} }
const tick_size = parseInt($("#cold-tick-size").val(), 10) const tick_size = parseInt($("#cold-tick-size").val(), 10)
@@ -170,15 +153,15 @@ $(document).ready(() => {
try { try {
const cold_settings_tx = { const cold_settings_tx = {
"TransactionType": "AccountSet", "TransactionType": "AccountSet",
"Account": cold_address, "Account": cold_wallet.classicAddress,
"TransferRate": transfer_rate, "TransferRate": transfer_rate,
"TickSize": tick_size, "TickSize": tick_size,
"SetFlag": 8, // enable Default Ripple "SetFlag": xrpl.AccountSetFlags.asfDefaultRipple,
"Domain": domain, "Domain": domain,
"Flags": flags "Flags": flags
} }
await generic_full_send(event, cold_settings_tx, cold_secret) await generic_full_send(event, cold_settings_tx, cold_wallet)
complete_step("Configure Issuer") complete_step("Configure Issuer")
} catch(err) { } catch(err) {
@@ -192,15 +175,14 @@ $(document).ready(() => {
$("#config-hot-address-button").click( async (event) => { $("#config-hot-address-button").click( async (event) => {
const block = $(event.target).closest(".interactive-block") const block = $(event.target).closest(".interactive-block")
block.find(".output-area").empty() block.find(".output-area").empty()
const hot_address = get_address_2(event, "hot") const hot_wallet = get_wallet_2(event, "hot")
const hot_secret = get_secret_2(event, "hot")
let flags = 0 let flags = 0
if ($("#hot-require-dest").prop("checked")) { if ($("#hot-require-dest").prop("checked")) {
flags |= api.txFlags.AccountSet.RequireDestTag flags |= xrpl.AccountSetTransactionFlags.tfRequireDestTag
} }
if ($("#hot-disallow-xrp").prop("checked")) { if ($("#hot-disallow-xrp").prop("checked")) {
flags |= api.txFlags.AccountSet.DisallowXRP flags |= xrpl.AccountSetTransactionFlags.tfDisallowXRP
} }
const domain = $("#hot-domain-hex").text().trim() const domain = $("#hot-domain-hex").text().trim()
@@ -209,14 +191,14 @@ $(document).ready(() => {
try { try {
const hot_settings_tx = { const hot_settings_tx = {
"TransactionType": "AccountSet", "TransactionType": "AccountSet",
"Account": hot_address, "Account": hot_wallet.classicAddress,
"SetFlag": 2, // enable Require Auth so we can't accidentally issue from // Require Auth so we can't accidentally issue from the hot address
// the hot address "SetFlag": xrpl.AccountSetFlags.asfRequireAuth,
"Domain": domain, "Domain": domain,
"Flags": flags "Flags": flags
} }
await generic_full_send(event, hot_settings_tx, hot_secret) await generic_full_send(event, hot_settings_tx, hot_wallet)
complete_step("Configure Hot Address") complete_step("Configure Hot Address")
} catch(err) { } catch(err) {
@@ -229,9 +211,8 @@ $(document).ready(() => {
$("#create-trust-line-button").click( async (event) => { $("#create-trust-line-button").click( async (event) => {
const block = $(event.target).closest(".interactive-block") const block = $(event.target).closest(".interactive-block")
block.find(".output-area").empty() block.find(".output-area").empty()
const hot_address = get_address_2(event, "hot") const cold_address = get_wallet_2(event, "cold").classicAddress
const cold_address = get_address_2(event, "cold") const hot_wallet = get_wallet_2(event, "hot")
const hot_secret = get_secret_2(event, "hot")
let currency_code let currency_code
if ($("#use-std-code").prop("checked")) { if ($("#use-std-code").prop("checked")) {
@@ -253,14 +234,14 @@ $(document).ready(() => {
try { try {
const trust_set_tx = { const trust_set_tx = {
"TransactionType": "TrustSet", "TransactionType": "TrustSet",
"Account": hot_address, "Account": hot_wallet.classicAddress,
"LimitAmount": { "LimitAmount": {
"currency": currency_code, "currency": currency_code,
"issuer": cold_address, "issuer": cold_address,
"value": limit "value": limit
} }
} }
await generic_full_send(event, trust_set_tx, hot_secret) await generic_full_send(event, trust_set_tx, hot_wallet)
complete_step("Make Trust Line") complete_step("Make Trust Line")
} catch(err) { } catch(err) {
@@ -273,9 +254,8 @@ $(document).ready(() => {
$("#send-token-button").click( async (event) => { $("#send-token-button").click( async (event) => {
const block = $(event.target).closest(".interactive-block") const block = $(event.target).closest(".interactive-block")
block.find(".output-area").empty() block.find(".output-area").empty()
const hot_address = get_address_2(event, "hot") const hot_address = get_wallet_2(event, "hot").classicAddress
const cold_address = get_address_2(event, "cold") const cold_wallet = get_wallet_2(event, "cold")
const cold_secret = get_secret_2(event, "cold")
const currency_code = $("#send-currency-code").text().trim() const currency_code = $("#send-currency-code").text().trim()
const issue_quantity = $("#send-amount").val().trim() const issue_quantity = $("#send-amount").val().trim()
@@ -294,18 +274,18 @@ $(document).ready(() => {
try { try {
const send_token_tx = { const send_token_tx = {
"TransactionType": "Payment", "TransactionType": "Payment",
"Account": cold_address, "Account": cold_wallet.classicAddress,
"Amount": { "Amount": {
"currency": currency_code, "currency": currency_code,
"value": issue_quantity, "value": issue_quantity,
"issuer": cold_address "issuer": cold_wallet.classicAddress
}, },
"Destination": hot_address "Destination": hot_address
} }
if (use_dest_tag) { if (use_dest_tag) {
send_token_tx["DestinationTag"] = dest_tag send_token_tx["DestinationTag"] = dest_tag
} }
await generic_full_send(event, send_token_tx, cold_secret) await generic_full_send(event, send_token_tx, cold_wallet)
complete_step("Send Token") complete_step("Send Token")
} catch(err) { } catch(err) {
@@ -319,28 +299,30 @@ $(document).ready(() => {
$("#confirm-balances-button").click( async (event) => { $("#confirm-balances-button").click( async (event) => {
const block = $(event.target).closest(".interactive-block") const block = $(event.target).closest(".interactive-block")
block.find(".output-area").empty() block.find(".output-area").empty()
const hot_address = get_address_2(event, "hot") const hot_address = get_wallet_2(event, "hot").classicAddress
const cold_address = get_address_2(event, "cold") const cold_address = get_wallet_2(event, "cold").classicAddress
block.find(".loader").show() block.find(".loader").show()
try { try {
const hot_balances = await api.request("account_lines", { const hot_balances = await api.request({
account: hot_address, "command": "account_lines",
ledger_index: "validated" "account": hot_address,
"ledger_index": "validated"
}) })
block.find(".output-area").append(` block.find(".output-area").append(`
<p>Hot address (<a href="https://testnet.xrpl.org/accounts/${hot_address}">${hot_address}</a>) account_lines result:</p> <p>Hot address (<a href="https://testnet.xrpl.org/accounts/${hot_address}">${hot_address}</a>) account_lines result:</p>
<pre><code>${pretty_print(hot_balances)}</code></pre> <pre><code>${pretty_print(hot_balances.result)}</code></pre>
`) `)
const cold_balances = await api.request("gateway_balances", { const cold_balances = await api.request({
account: cold_address, "command": "gateway_balances",
ledger_index: "validated", "account": cold_address,
hotwallet: [hot_address] "ledger_index": "validated",
"hotwallet": [hot_address]
}) })
block.find(".output-area").append(` block.find(".output-area").append(`
<p>Issuer (<a href="https://testnet.xrpl.org/accounts/${cold_address}">${cold_address}</a>) gateway_balances result:</p> <p>Issuer (<a href="https://testnet.xrpl.org/accounts/${cold_address}">${cold_address}</a>) gateway_balances result:</p>
<pre><code>${pretty_print(cold_balances)}</code></pre> <pre><code>${pretty_print(cold_balances.result)}</code></pre>
`) `)
block.find(".loader").hide() block.find(".loader").hide()

View File

@@ -43,8 +43,8 @@ $(document).ready(() => {
block.find(".loader").hide() block.find(".loader").hide()
block.find(".output-area").append( block.find(".output-area").append(
`<pre><code>${pretty_print(flags)}</code></pre>`) `<pre><code>${pretty_print(account_info.result.account_data)}</code></pre>`)
//if (flags.requireDestinationTag) { // if (flags.requireDestinationTag) {
if (account_info.result.account_data.Flags | 0x00020000) { // TODO: change this back if there's a better way if (account_info.result.account_data.Flags | 0x00020000) { // TODO: change this back if there's a better way
block.find(".output-area").append(`<p><i class="fa fa-check-circle"></i> block.find(".output-area").append(`<p><i class="fa fa-check-circle"></i>
Require Destination Tag is enabled.</p>`) Require Destination Tag is enabled.</p>`)
@@ -62,32 +62,29 @@ $(document).ready(() => {
// from the faucet in data attributes on the block so we don't have to get a // from the faucet in data attributes on the block so we don't have to get a
// new sending address every time. // new sending address every time.
async function get_test_sender(block) { async function get_test_sender(block) {
let address = block.data("testSendAddress") let test_sender_wallet
let secret = block.data("testSendSecret") let seed = block.data("testSendSecret")
if (!address || !secret) { if (!seed) {
console.debug("First-time setup for test sender...") console.debug("First-time setup for test sender...")
// Old way: test_sender_wallet = await api.generateFaucetWallet()
// const faucet_url = $("#generate-creds-button").data("fauceturl")
// const data = await call_faucet(faucet_url)
// address = data.account.classicAddress
// block.data("testSendAddress", address)
// secret = data.account.secret
// block.data("testSendSecret", secret)
// New way: get a wallet
let test_sender_wallet = await api.generateFaucetWallet()
block.data("testSendAddress", test_sender_wallet.classicAddress)
block.data("testSendSecret", test_sender_wallet.seed) block.data("testSendSecret", test_sender_wallet.seed)
// First time: Wait for our test sender to be fully funded, so we don't // First time: Wait for our test sender to be fully funded, so we don't
// get the wrong starting sequence number. // get the wrong starting sequence number.
while (true) { while (true) {
try { try {
await api.request({command: "account_info", account: address, ledger_index: "validated"}) await api.request({
"command": "account_info",
"account": test_sender_wallet.classicAddress,
"ledger_index": "validated"
})
break break
} catch(e) { } catch(e) {
await new Promise(resolve => setTimeout(resolve, 1000)) await new Promise(resolve => setTimeout(resolve, 1000))
} }
} }
} else {
test_sender_wallet = xrpl.Wallet.fromSeed(seed)
} }
return test_sender_wallet return test_sender_wallet
} }

View File

@@ -2,6 +2,7 @@
// 2. Connect // 2. Connect
// The code for these steps is handled by interactive-tutorial.js // The code for these steps is handled by interactive-tutorial.js
$(document).ready(() => { $(document).ready(() => {
const LLS_OFFSET = 75 // Expire unconfirmed transactions after about ~5 min
// 3. Check Sequence Number // 3. Check Sequence Number
$("#check-sequence").click( async function(event) { $("#check-sequence").click( async function(event) {
@@ -12,12 +13,14 @@ $("#check-sequence").click( async function(event) {
// Wipe previous output // Wipe previous output
block.find(".output-area").html("") block.find(".output-area").html("")
block.find(".loader").show() block.find(".loader").show()
const account_info = await api.request("account_info", {"account": address}) const account_info = await api.request({
"command": "account_info", "account": address
})
block.find(".loader").hide() block.find(".loader").hide()
block.find(".output-area").append( block.find(".output-area").append(
`<p>Current sequence: `<p>Current sequence:
<code id="current_sequence">${account_info.account_data.Sequence}</code> <code id="current_sequence">${account_info.result.account_data.Sequence}</code>
</p>`) </p>`)
complete_step("Check Sequence") complete_step("Check Sequence")
@@ -26,10 +29,8 @@ $("#check-sequence").click( async function(event) {
// 4. Prepare and Sign TicketCreate -------------------------------------------- // 4. Prepare and Sign TicketCreate --------------------------------------------
$("#prepare-and-sign").click( async function(event) { $("#prepare-and-sign").click( async function(event) {
const block = $(event.target).closest(".interactive-block") const block = $(event.target).closest(".interactive-block")
const address = get_address(event) const wallet = get_wallet(event)
if (!address) {return} if (!wallet) {return}
const secret = get_secret(event)
if (!secret) {return}
let current_sequence let current_sequence
try { try {
current_sequence = parseInt($("#current_sequence").text()) current_sequence = parseInt($("#current_sequence").text())
@@ -47,24 +48,23 @@ $("#prepare-and-sign").click( async function(event) {
return; return;
} }
let prepared = await api.prepareTransaction({ const vli = await api.getLedgerIndex()
let prepared = await api.autofill({
"TransactionType": "TicketCreate", "TransactionType": "TicketCreate",
"Account": address, "Account": wallet.classicAddress,
"TicketCount": 10, "TicketCount": 10,
"Sequence": current_sequence "Sequence": current_sequence,
}, { "LastLedgerSequence": vli+LLS_OFFSET
maxLedgerVersionOffset: 20
}) })
block.find(".output-area").append( block.find(".output-area").append(
`<p>Prepared transaction:</p> `<p>Prepared transaction:</p>
<pre><code>${pretty_print(prepared.txJSON)}</code></pre>`) <pre><code>${pretty_print(prepared)}</code></pre>`)
let signed = api.sign(prepared.txJSON, secret) let tx_blob = wallet.signTransaction(prepared)
let tx_id = xrpl.computeSignedTransactionHash(tx_blob)
block.find(".output-area").append( block.find(".output-area").append(
`<p>Transaction hash: <code id="tx_id">${signed.id}</code></p>`) `<p>Transaction hash: <code id="tx_id">${tx_id}</code></p>`)
let tx_blob = signed.signedTransaction
block.find(".output-area").append( block.find(".output-area").append(
`<p>Signed blob:</p><pre class="tx-blob"><code id="tx_blob">${tx_blob}</code></pre>`) `<p>Signed blob:</p><pre class="tx-blob"><code id="tx_blob">${tx_blob}</code></pre>`)
@@ -80,18 +80,21 @@ $("#ticketcreate-submit").click( submit_handler )
// Intermission ---------------------------------------------------------------- // Intermission ----------------------------------------------------------------
async function intermission_submit(event, tx_json) { async function intermission_submit(event, tx_json) {
const secret = get_secret(event)
if (!secret) {return}
const block = $(event.target).closest(".interactive-block") const block = $(event.target).closest(".interactive-block")
let prepared = await api.prepareTransaction(tx_json) const wallet = get_wallet(event)
let signed = api.sign(prepared.txJSON, secret) if (!wallet) {return}
let prelim_result = await api.request("submit", const prepared = await api.autofill(tx_json)
{"tx_blob": signed.signedTransaction}) const tx_blob = wallet.signTransaction(prepared)
const prelim = await api.request({
"command": "submit",
"tx_blob": tx_blob
})
const tx_id = xrpl.computeSignedTransactionHash(tx_blob)
block.find(".output-area").append(`<p>${tx_json.TransactionType} block.find(".output-area").append(`<p>${prepared.TransactionType}
${prepared.instructions.sequence}: ${prepared.Sequence}:
<a href="https://devnet.xrpl.org/transactions/${signed.id}" <a href="https://devnet.xrpl.org/transactions/${tx_id}"
target="_blank">${prelim_result.engine_result}</a></p>`) target="_blank">${prelim.result.engine_result}</a></p>`)
} }
$("#intermission-payment").click( async function(event) { $("#intermission-payment").click( async function(event) {
@@ -102,7 +105,7 @@ $("#intermission-payment").click( async function(event) {
"TransactionType": "Payment", "TransactionType": "Payment",
"Account": address, "Account": address,
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe", // Testnet Faucet "Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe", // Testnet Faucet
"Amount": api.xrpToDrops("201") "Amount": xrpl.xrpToDrops("201")
}) })
complete_step("Intermission") complete_step("Intermission")
@@ -116,8 +119,8 @@ $("#intermission-escrowcreate").click( async function(event) {
"TransactionType": "EscrowCreate", "TransactionType": "EscrowCreate",
"Account": address, "Account": address,
"Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", // Genesis acct "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", // Genesis acct
"Amount": api.xrpToDrops("0.13"), // Arbitrary amount "Amount": xrpl.xrpToDrops("0.13"), // Arbitrary amount
"FinishAfter": api.iso8601ToRippleTime(Date()) + 30 // 30 seconds from now "FinishAfter": xrpl.ISOTimeToRippleTime(Date()) + 30 // 30 seconds from now
}) })
complete_step("Intermission") complete_step("Intermission")
@@ -144,7 +147,8 @@ $("#check-tickets").click( async function(event) {
block.find(".output-area").html("") block.find(".output-area").html("")
block.find(".loader").show() block.find(".loader").show()
let response = await api.request("account_objects", { let response = await api.request({
"command": "account_objects",
"account": address, "account": address,
"type": "ticket" "type": "ticket"
}) })
@@ -155,7 +159,7 @@ $("#check-tickets").click( async function(event) {
// Reset the next step's form & add these tickets // Reset the next step's form & add these tickets
$("#ticket-selector .form-area").html("") $("#ticket-selector .form-area").html("")
response.account_objects.forEach((ticket, i) => { response.result.account_objects.forEach((ticket, i) => {
$("#ticket-selector .form-area").append( $("#ticket-selector .form-area").append(
`<div class="form-check form-check-inline"> `<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="ticket${i}" <input class="form-check-input" type="radio" id="ticket${i}"
@@ -169,10 +173,8 @@ $("#check-tickets").click( async function(event) {
// 8. Prepare Ticketed Transaction --------------------------------------------- // 8. Prepare Ticketed Transaction ---------------------------------------------
$("#prepare-ticketed-tx").click(async function(event) { $("#prepare-ticketed-tx").click(async function(event) {
const address = get_address(event) const wallet = get_wallet(event)
if (!address) {return} if (!wallet) {return}
const secret = get_secret(event)
if (!secret) {return}
const block = $(event.target).closest(".interactive-block") const block = $(event.target).closest(".interactive-block")
block.find(".output-area").html("") block.find(".output-area").html("")
@@ -181,25 +183,25 @@ $("#prepare-ticketed-tx").click(async function(event) {
show_error(block, "You must choose a ticket first.") show_error(block, "You must choose a ticket first.")
return return
} }
const vli = await api.getLedgerIndex()
let prepared_t = await api.prepareTransaction({ const prepared_t = await api.autofill({
"TransactionType": "AccountSet", "TransactionType": "AccountSet",
"Account": address, "Account": wallet.classicAddress,
"TicketSequence": use_ticket, "TicketSequence": use_ticket,
"Sequence": 0 "Sequence": 0,
}, { "LastLedgerSequence": vli+LLS_OFFSET
maxLedgerVersionOffset: 20
}) })
block.find(".output-area").append( block.find(".output-area").append(
`<p>Prepared transaction:</p> `<p>Prepared transaction:</p>
<pre><code>${pretty_print(prepared_t.txJSON)}</code></pre>`) <pre><code>${pretty_print(prepared_t)}</code></pre>`)
let signed_t = api.sign(prepared_t.txJSON, secret) const tx_blob_t = wallet.signTransaction(prepared_t)
const tx_id_t = xrpl.computeSignedTransactionHash(tx_blob_t)
block.find(".output-area").append( block.find(".output-area").append(
`<p>Transaction hash: <code id="tx_id_t">${signed_t.id}</code></p>`) `<p>Transaction hash: <code id="tx_id_t">${tx_id_t}</code></p>`)
let tx_blob_t = signed_t.signedTransaction
block.find(".output-area").append( block.find(".output-area").append(
`<pre style="visibility: none"> `<pre style="visibility: none">
<code id="tx_blob_t">${tx_blob_t}</code></pre>`) <code id="tx_blob_t">${tx_blob_t}</code></pre>`)

View File

@@ -157,6 +157,7 @@ const set_up_tx_sender = async function() {
try { try {
// use lookup_tx_final() from submit-and-verify2.js // use lookup_tx_final() from submit-and-verify2.js
let final_result_data = await lookup_tx_final(api, hash, max_ledger, min_ledger) let final_result_data = await lookup_tx_final(api, hash, max_ledger, min_ledger)
console.log("final_result_data is", final_result_data)
let final_result = final_result_data.result.meta.TransactionResult let final_result = final_result_data.result.meta.TransactionResult
if (!silent) { if (!silent) {
if (final_result === "tesSUCCESS") { if (final_result === "tesSUCCESS") {