// Variant setup for generate creds button from interactive-tutorial.js. // This version generates two sets of creds, one for the issuer and one for // the hot wallet / receiver const EXAMPLE_COLD_ADDR = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe" const EXAMPLE_COLD_SECRET = "sIss█████████████████████████" function setup_2x_generate_step() { $("#generate-2x-creds-button").click( async (event) => { const block = $(event.target).closest(".interactive-block") block.find(".output-area").html("") block.find(".loader").show() // Get faucet URL (Testnet/Devnet/etc.) const faucet_url = $("#generate-2x-creds-button").data("fauceturl") try { // destination not defined - API will create account. const data = await call_faucet(faucet_url,undefined, event) const data2 = await call_faucet(faucet_url, undefined, event) block.find(".loader").hide() block.find(".output-area").html(`
${tl("Cold Address:")} ${data.account.address}
${tl("Cold Secret:")} ${data.seed}
${tl("Hot Address:")} ${data2.account.address}
${tl("Hot Secret:")} ${data2.seed}
`) // TODO: Automatically populate all examples in the page with the // generated credentials... // $("code span:contains('"+EXAMPLE_ADDR+"')").each( function() { // let eltext = $(this).text() // $(this).text( eltext.replace(EXAMPLE_ADDR, data.account.address) ) // }) // $("code span:contains('"+EXAMPLE_SECRET+"')").each( function() { // let eltext = $(this).text() // $(this).text( eltext.replace(EXAMPLE_SECRET, data.account.secret) ) // }) // // block.find(".output-area").append(`

${tl("Populated this page's examples with these credentials.")}

`) complete_step("Generate") } catch(err) { console.error(err) block.find(".loader").hide() block.find(".output-area").html( `

${tl("Error:")} ${tl("There was an error connecting to the Faucet. Please try again.")}

`) return } }) } function get_wallet_2(event, which_one) { // which_one should be either "cold" or "hot" (case-sensitive) const secret = $(`#${which_one}-use-secret`).text() if (!secret) { 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 xrpl.Wallet.fromSeed(secret) } // Get the hexadecimal ASCII representation of a domain name string. // Note: if the provided string isn't compatible with 7-bit ASCII, this won't // work. So if you want to use an IDN, you'd need to convert to punycode first. function domain_to_hex(s) { result = "" for (let i=0; i { setup_2x_generate_step() $("#cold-domain-text").keyup( (event) => { $("#cold-domain-hex").text(domain_to_hex($("#cold-domain-text").val())) }) $("#hot-domain-text").keyup( (event) => { $("#hot-domain-hex").text(domain_to_hex($("#hot-domain-text").val())) }) function update_currency_code(event) { let currency_code if ($("#use-std-code").prop("checked")) { const std_code = $("#currency-code-std") currency_code = std_code.val().trim() // std_code.prop("disabled", false).removeClass("disabled") // $("#currency-code-hex").prop("disabled", true).addClass("disabled") } else { const hex_code = $("#currency-code-hex") currency_code = hex_code.val().trim() // hex_code.prop("disabled", false).removeClass("disabled") // $("#currency-code-std").prop("disabled", true).addClass("disabled") } $("#send-currency-code").text(currency_code) } $("#currency-code-std").keyup(update_currency_code) $("#currency-code-hex").keyup(update_currency_code) $("#use-std-code").change(update_currency_code) $("#use-hex-code").change(update_currency_code) // run once on load because some browsers pre-fill values from previous // pageviews. update_currency_code() // Configure Issuer Settings handler ----------------------------------------- $("#config-issuer-button").click( async (event) => { const block = $(event.target).closest(".interactive-block") block.find(".output-area").empty() const cold_wallet = get_wallet_2(event, "cold") let flags = 0 if ($("#cold-require-dest").prop("checked")) { flags |= xrpl.AccountSetTfFlags.tfRequireDestTag } if ($("#cold-disallow-xrp").prop("checked")) { flags |= xrpl.AccountSetTfFlags.tfDisallowXRP } const tick_size = parseInt($("#cold-tick-size").val(), 10) if (Number.isNaN(tick_size) || tick_size < 0 || tick_size > 15) { show_error(block, "TickSize must be an integer from 0 to 15.") return } // Convert transfer fee % to transferrate integer (e.g. 0.5% fee = 1005000000) const transfer_fee = parseFloat($("#cold-transfer-fee").val()) let transfer_rate = (transfer_fee * 10000000) + 1000000000 if (transfer_rate == 1000000000) { transfer_rate = 0 } const domain = $("#cold-domain-hex").text().trim() block.find(".loader").show() try { const cold_settings_tx = { "TransactionType": "AccountSet", "Account": cold_wallet.address, "TransferRate": transfer_rate, "TickSize": tick_size, "SetFlag": xrpl.AccountSetAsfFlags.asfDefaultRipple, "Domain": domain, "Flags": flags } await generic_full_send(event, cold_settings_tx, cold_wallet) complete_step("Configure Issuer") } catch(err) { block.find(".loader").hide() show_error(block, `An error occurred with the transaction: ${err}`) } }) // Configure Hot Address Settings handler ------------------------------------ $("#config-hot-address-button").click( async (event) => { const block = $(event.target).closest(".interactive-block") block.find(".output-area").empty() const hot_wallet = get_wallet_2(event, "hot") let flags = 0 if ($("#hot-require-dest").prop("checked")) { flags |= xrpl.AccountSetTfFlags.tfRequireDestTag } if ($("#hot-disallow-xrp").prop("checked")) { flags |= xrpl.AccountSetTfFlags.tfDisallowXRP } const domain = $("#hot-domain-hex").text().trim() block.find(".loader").show() try { const hot_settings_tx = { "TransactionType": "AccountSet", "Account": hot_wallet.address, // Require Auth so we can't accidentally issue from the hot address "SetFlag": xrpl.AccountSetAsfFlags.asfRequireAuth, "Domain": domain, "Flags": flags } await generic_full_send(event, hot_settings_tx, hot_wallet) complete_step("Configure Hot Address") } catch(err) { block.find(".loader").hide() show_error(block, `An error occurred with the transaction: ${err}`) } }) // Create Trust Line handler ------------------------------------------------- $("#create-trust-line-button").click( async (event) => { const block = $(event.target).closest(".interactive-block") block.find(".output-area").empty() const cold_address = get_wallet_2(event, "cold").address const hot_wallet = get_wallet_2(event, "hot") let currency_code if ($("#use-std-code").prop("checked")) { currency_code = $("#currency-code-std").val().trim() if (!currency_code.match(/[A-Za-z0-9?!@#$%*(){}|\x26\x3c\x3e]{3}/)) { show_error(block, "Standard currency code must be 3 valid characters.") } } else { currency_code = $("#currency-code-hex").val().trim() if (!currency_code.match(/^[0-9A-Fa-f]{40}$/)) { show_error(block, "Nonstandard currency code must be 40 hexadecimal characters.") return } } const limit = $("#trust-limit").val() // limit is a string block.find(".loader").show() try { const trust_set_tx = { "TransactionType": "TrustSet", "Account": hot_wallet.address, "LimitAmount": { "currency": currency_code, "issuer": cold_address, "value": limit } } await generic_full_send(event, trust_set_tx, hot_wallet) complete_step("Make Trust Line") } catch(err) { block.find(".loader").hide() show_error(block, `An error occurred with the transaction: ${err}`) } }) // Send Token handler -------------------------------------------------------- $("#send-token-button").click( async (event) => { const block = $(event.target).closest(".interactive-block") block.find(".output-area").empty() const hot_address = get_wallet_2(event, "hot").address const cold_wallet = get_wallet_2(event, "cold") const currency_code = $("#send-currency-code").text().trim() const issue_quantity = $("#send-amount").val().trim() const use_dest_tag = $("#use-dest-tag").prop("checked") let dest_tag if (use_dest_tag) { dest_tag = parseInt($("#dest-tag").val(), 10) if (Number.isNaN(dest_tag) || dest_tag < 0 || dest_tag > 4294967295) { show_error(block, "Destination Tag must be a valid 32-bit integer.") return } } block.find(".loader").show() try { const send_token_tx = { "TransactionType": "Payment", "Account": cold_wallet.address, "Amount": { "currency": currency_code, "value": issue_quantity, "issuer": cold_wallet.address }, "Destination": hot_address } if (use_dest_tag) { send_token_tx["DestinationTag"] = dest_tag } await generic_full_send(event, send_token_tx, cold_wallet) complete_step("Send Token") } catch(err) { block.find(".loader").hide() show_error(block, `An error occurred with the transaction: ${err}`) } }) // Confirm Balances handler -------------------------------------------------- $("#confirm-balances-button").click( async (event) => { const block = $(event.target).closest(".interactive-block") block.find(".output-area").empty() const hot_address = get_wallet_2(event, "hot").address const cold_address = get_wallet_2(event, "cold").address block.find(".loader").show() try { const hot_balances = await api.request({ "command": "account_lines", "account": hot_address, "ledger_index": "validated" }) block.find(".output-area").append(`

Hot address (${hot_address}) account_lines result:

${pretty_print(hot_balances.result)}
`) const cold_balances = await api.request({ "command": "gateway_balances", "account": cold_address, "ledger_index": "validated", "hotwallet": [hot_address] }) block.find(".output-area").append(`

Issuer (${cold_address}) gateway_balances result:

${pretty_print(cold_balances.result)}
`) block.find(".loader").hide() complete_step("Confirm Balances") } catch(err) { block.find(".loader").hide() show_error(block, `Error looking up balances: ${err}`) } }) })