mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-20 11:45:50 +00:00
Merge pull request #561 from mDuo13/tx_sender_tool
Transaction sender tool
This commit is contained in:
@@ -1137,6 +1137,7 @@ a.current {
|
||||
}
|
||||
|
||||
.page-test-net .throbber,
|
||||
.page-tx-sender .throbber,
|
||||
.interactive-block .throbber {
|
||||
-webkit-animation: rotating 1s linear infinite;
|
||||
-moz-animation: rotating 1s linear infinite;
|
||||
@@ -1146,6 +1147,31 @@ a.current {
|
||||
width: 25px;height:25px;
|
||||
}
|
||||
|
||||
#connection-status-item.active {
|
||||
background-color: #2BCB96;
|
||||
border-color: #2BCB96;
|
||||
}
|
||||
|
||||
#tx-sender-history ul {
|
||||
overflow: auto;
|
||||
height: 220px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.125)
|
||||
}
|
||||
|
||||
#tx-sender-history .list-group-item {
|
||||
font-size: small;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.page-tx-sender .input-group .form-control {
|
||||
flex: 1 1 20%;
|
||||
}
|
||||
|
||||
.bootstrap-growl {
|
||||
max-width: 90vw !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* Print styles ------------------------------------------------------------- */
|
||||
@media print {
|
||||
|
||||
478
assets/js/tx-sender.js
Normal file
478
assets/js/tx-sender.js
Normal file
@@ -0,0 +1,478 @@
|
||||
const set_up_tx_sender = async function() {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Notification helpers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function successNotif(msg) {
|
||||
$.bootstrapGrowl(msg, {
|
||||
delay: 7000,
|
||||
offset: {from: 'bottom', amount: 68},
|
||||
type: 'success',
|
||||
width: 'auto'
|
||||
})
|
||||
}
|
||||
function errorNotif(msg) {
|
||||
$.bootstrapGrowl(msg, {
|
||||
delay: 7000,
|
||||
offset: {from: 'bottom', amount: 68},
|
||||
type: 'danger',
|
||||
width: 'auto'
|
||||
})
|
||||
}
|
||||
|
||||
function logTx(txtype, hash, result) {
|
||||
let li = "wtf"
|
||||
// Future feature: link hash to a testnet txsplainer
|
||||
if (result === "tesSUCCESS") {
|
||||
li = '<li class="list-group-item fade-in p-1 text-muted"><i class="fa fa-check-circle"></i> '+txtype+": "+hash+'</li>'
|
||||
} else {
|
||||
li = '<li class="list-group-item fade-in p-1 list-group-item-danger"><i class="fa fa-times-circle"></i> '+txtype+": "+hash+'</li>'
|
||||
}
|
||||
|
||||
$("#tx-sender-history ul").prepend(li)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Connection / Setup
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const FAUCET_URL = "https://faucet.altnet.rippletest.net/accounts"
|
||||
const TESTNET_URL = "wss://s.altnet.rippletest.net:51233"
|
||||
|
||||
let connection_ready = false
|
||||
|
||||
let sending_address
|
||||
let sending_secret
|
||||
let xrp_balance
|
||||
|
||||
|
||||
console.debug("Getting a sending address from the faucet...")
|
||||
|
||||
faucet_response = function(data) {
|
||||
sending_address = data.account.address
|
||||
sending_secret = data.account.secret
|
||||
xrp_balance = Number(data.balance) // Faucet only delivers ~10,000 XRP,
|
||||
// so this won't go over JavaScript's
|
||||
// 64-bit double precision
|
||||
|
||||
$("#balance-item").text(xrp_balance)
|
||||
$(".sending-address-item").text(sending_address)
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: FAUCET_URL,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: faucet_response,
|
||||
error: function() {
|
||||
errorNotif("There was an error with the XRP Ledger Test Net Faucet. Reload this page to try again.")
|
||||
}
|
||||
})
|
||||
|
||||
api = new ripple.RippleAPI({server: TESTNET_URL})
|
||||
api.on('connected', () => {
|
||||
connection_ready = true
|
||||
$("#connection-status-item").text("Connected")
|
||||
$("#connection-status-item").removeClass("disabled").addClass("active")
|
||||
})
|
||||
api.on('disconnected', (code) => {
|
||||
connection_ready = false
|
||||
$("#connection-status-item").text("Not connected")
|
||||
$("#connection-status-item").removeClass("active").addClass("disabled")
|
||||
})
|
||||
console.log("Connecting to Test Net WebSocket...")
|
||||
api.connect()
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Generic Transaction Submission
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Helper function for await-able timeouts
|
||||
function timeout(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
const INTERVAL = 1000 // milliseconds to wait for new ledger versions
|
||||
async function verify_transaction(hash, options) {
|
||||
try {
|
||||
data = await api.getTransaction(hash, options)
|
||||
return data
|
||||
} catch(error) {
|
||||
/* If transaction not in latest validated ledger,
|
||||
try again until max ledger hit */
|
||||
if (error instanceof api.errors.PendingLedgerVersionError) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => verify_transaction(hash, options)
|
||||
.then(resolve, reject), INTERVAL)
|
||||
})
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function update_xrp_balance() {
|
||||
balances = await api.getBalances(sending_address, {currency: "XRP"})
|
||||
$("#balance-item").text(balances[0].value)
|
||||
}
|
||||
|
||||
async function submit_and_verify(tx_object, use_secret, silent) {
|
||||
if (use_secret === undefined) {
|
||||
use_secret = sending_secret
|
||||
}
|
||||
try {
|
||||
// Auto-fill fields like Fee and Sequence
|
||||
prepared = await api.prepareTransaction(tx_object)
|
||||
console.debug("Prepared:", prepared)
|
||||
} catch(error) {
|
||||
console.log(error)
|
||||
if (!silent) {
|
||||
errorNotif("Error preparing tx: "+error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Determine first and last ledger the tx could be validated in *BEFORE*
|
||||
// signing it.
|
||||
const options = {
|
||||
minLedgerVersion: (await api.getLedger()).ledgerVersion,
|
||||
maxLedgerVersion: prepared.instructions.maxLedgerVersion
|
||||
}
|
||||
|
||||
let sign_response
|
||||
try {
|
||||
// Sign, submit
|
||||
sign_response = api.sign(prepared.txJSON, use_secret)
|
||||
await api.submit(sign_response.signedTransaction)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
if (!silent) {
|
||||
errorNotif("Error signing & submitting "+tx_object.TransactionType+" tx: "+error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Wait for tx to be in a validated ledger or to expire
|
||||
try {
|
||||
const data = await verify_transaction(sign_response.id, options)
|
||||
const final_result = data.outcome.result
|
||||
// Future feature: output should link to a TestNet tx lookup/explainer
|
||||
if (final_result === "tesSUCCESS") {
|
||||
if (!silent) {
|
||||
successNotif(tx_object.TransactionType+" tx succeeded (hash: "+sign_response.id+")")
|
||||
logTx(tx_object.TransactionType, sign_response.id, final_result)
|
||||
}
|
||||
} else {
|
||||
if (!silent) {
|
||||
errorNotif(tx_object.TransactionType+" tx failed w/ code "+final_result+
|
||||
" (hash: "+sign_response.id+")")
|
||||
logTx(tx_object.TransactionType, sign_response.id, final_result)
|
||||
}
|
||||
}
|
||||
update_xrp_balance()
|
||||
return data
|
||||
} catch(error) {
|
||||
console.log(error)
|
||||
if (!silent) {
|
||||
errorNotif("Error submitting "+tx_object.TransactionType+" tx: "+error)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Issuer Setup for Partial Payments
|
||||
// (Partial payments must involve at least one issued currency, so we set up
|
||||
// an issuer for a fake currency to ripple through.)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let pp_issuer_address
|
||||
let pp_sending_currency = "BAR"
|
||||
async function set_up_for_partial_payments() {
|
||||
while (!connection_ready) {
|
||||
console.debug("... waiting for connection before doing partial payment setup")
|
||||
await timeout(200)
|
||||
}
|
||||
console.debug("Starting partial payment setup...")
|
||||
$("#pp_progress .progress-bar").addClass("progress-bar-animated")
|
||||
// 1. Get a funded address to use as issuer
|
||||
let pp_issuer_secret
|
||||
try {
|
||||
const faucet_response = await ($.ajax({
|
||||
url: FAUCET_URL,
|
||||
type: 'POST',
|
||||
dataType: 'json'
|
||||
}))
|
||||
pp_issuer_address = faucet_response.account.address
|
||||
pp_issuer_secret = faucet_response.account.secret
|
||||
} catch(error) {
|
||||
console.log("Error getting issuer address for partial payments:", error)
|
||||
return
|
||||
}
|
||||
$("#pp_progress .progress-bar").width("20%")
|
||||
|
||||
// 2. Set DefaultRipple on issuer
|
||||
let resp = await submit_and_verify({
|
||||
TransactionType: "AccountSet",
|
||||
Account: pp_issuer_address,
|
||||
SetFlag: 8
|
||||
}, pp_issuer_secret, true)
|
||||
if (resp === undefined) {
|
||||
console.log("Couldn't set DefaultRipple for partial payment issuer")
|
||||
return
|
||||
}
|
||||
$("#pp_progress .progress-bar").width("40%")
|
||||
|
||||
// 3. Make a trust line from sending address to issuer
|
||||
resp = await submit_and_verify({
|
||||
TransactionType: "TrustSet",
|
||||
Account: sending_address,
|
||||
LimitAmount: {
|
||||
currency: pp_sending_currency,
|
||||
value: "1000000000", // arbitrarily, 1 billion fake currency
|
||||
issuer: pp_issuer_address
|
||||
}
|
||||
}, sending_secret, true)
|
||||
if (resp === undefined) {
|
||||
console.log("Error making trust line to partial payment issuer")
|
||||
return
|
||||
}
|
||||
$("#pp_progress .progress-bar").width("60%")
|
||||
|
||||
// 4. Issue fake currency to main sending address
|
||||
resp = await submit_and_verify({
|
||||
TransactionType: "Payment",
|
||||
Account: pp_issuer_address,
|
||||
Destination: sending_address,
|
||||
Amount: {
|
||||
currency: pp_sending_currency,
|
||||
value: "1000000000",
|
||||
issuer: pp_issuer_address
|
||||
}
|
||||
}, pp_issuer_secret, true)
|
||||
if (resp === undefined) {
|
||||
console.log("Error sending fake currency from partial payment issuer")
|
||||
return
|
||||
}
|
||||
$("#pp_progress .progress-bar").width("80%")
|
||||
|
||||
// 5. Place offer to buy issued currency for XRP
|
||||
// When sending the partial payment, the sender consumes their own offer (!)
|
||||
// so they end up paying themselves issued currency then delivering XRP.
|
||||
resp = await submit_and_verify({
|
||||
TransactionType: "OfferCreate",
|
||||
Account: sending_address,
|
||||
TakerGets: "1000000000000000", // 1 billion XRP
|
||||
TakerPays: {
|
||||
currency: pp_sending_currency,
|
||||
value: "1000000000",
|
||||
issuer: pp_issuer_address
|
||||
}
|
||||
}, sending_secret, true)
|
||||
if (resp === undefined) {
|
||||
console.log("Error placing order to enable partial payments")
|
||||
return
|
||||
}
|
||||
$("#pp_progress .progress-bar").width("100%").removeClass("progress-bar-animated")
|
||||
$("#pp_progress").hide()
|
||||
|
||||
// Done. Enable "Send Partial Payment" button
|
||||
console.log("Done getting ready to send partial payments.")
|
||||
$("#send_partial_payment button").prop("disabled",false)
|
||||
$("#send_partial_payment button").attr("title", "")
|
||||
}
|
||||
set_up_for_partial_payments()
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Button Handlers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 1. Send XRP Payment Handler -------------------------------------------
|
||||
async function on_click_send_xrp_payment(event) {
|
||||
const destination_address = $("#destination_address").val()
|
||||
const xrp_drops_input = $("#send_xrp_payment_amount").val()
|
||||
$("#send_xrp_payment .loader").show()
|
||||
$("#send_xrp_payment button").attr("disabled","disabled")
|
||||
await submit_and_verify({
|
||||
TransactionType: "Payment",
|
||||
Account: sending_address,
|
||||
Destination: destination_address,
|
||||
Amount: xrp_drops_input
|
||||
})
|
||||
$("#send_xrp_payment .loader").hide()
|
||||
$("#send_xrp_payment button").attr("disabled",false)
|
||||
|
||||
}
|
||||
$("#send_xrp_payment button").click(on_click_send_xrp_payment)
|
||||
|
||||
// 2. Send Partial Payment Handler ---------------------------------------
|
||||
async function on_click_send_partial_payment(event) {
|
||||
const destination_address = $("#destination_address").val()
|
||||
$("#send_partial_payment .loader").show()
|
||||
$("#send_partial_payment button").attr("disabled","disabled")
|
||||
|
||||
// const path_find_result = await api.request("ripple_path_find", {
|
||||
// source_account: sending_address,
|
||||
// destination_account: destination_address,
|
||||
// destination_amount: "-1", // as much XRP as possible
|
||||
// source_currencies: [{currency: pp_sending_currency, issuer: pp_issuer_address}]
|
||||
// })
|
||||
// console.log("Path find result:", path_find_result)
|
||||
// use_path = path_find_result.alternatives[0].paths_computed
|
||||
|
||||
await submit_and_verify({
|
||||
TransactionType: "Payment",
|
||||
Account: sending_address,
|
||||
Destination: destination_address,
|
||||
Amount: "1000000000000000", // 1 billion XRP
|
||||
SendMax: {
|
||||
value: (Math.random()*.01).toPrecision(15), // random very small amount
|
||||
currency: pp_sending_currency,
|
||||
issuer: pp_issuer_address
|
||||
},
|
||||
Flags: api.txFlags.Payment.PartialPayment | api.txFlags.Universal.FullyCanonicalSig
|
||||
})
|
||||
$("#send_partial_payment .loader").hide()
|
||||
$("#send_partial_payment button").attr("disabled",false)
|
||||
}
|
||||
$("#send_partial_payment button").click(on_click_send_partial_payment)
|
||||
|
||||
|
||||
// 3. Create Escrow Handler ----------------------------------------------
|
||||
async function on_click_create_escrow(event) {
|
||||
const destination_address = $("#destination_address").val()
|
||||
const duration_seconds_txt = $("#create_escrow_duration_seconds").val()
|
||||
const release_auto = $("#create_escrow_release_automatically").prop("checked")
|
||||
|
||||
const duration_seconds = parseInt(duration_seconds_txt, 10)
|
||||
if (duration_seconds === NaN || duration_seconds < 1) {
|
||||
errorNotif("Error: Escrow duration must be a positive number of seconds")
|
||||
return
|
||||
}
|
||||
const finish_after = api.iso8601ToRippleTime(Date()) + duration_seconds
|
||||
|
||||
$("#create_escrow .loader").show()
|
||||
$("#create_escrow button").attr("disabled","disabled")
|
||||
const escrowcreate_tx_data = await submit_and_verify({
|
||||
TransactionType: "EscrowCreate",
|
||||
Account: sending_address,
|
||||
Destination: destination_address,
|
||||
Amount: "1000000",
|
||||
FinishAfter: finish_after
|
||||
})
|
||||
|
||||
if (release_auto) {
|
||||
// Wait until there's a ledger with a close time > FinishAfter
|
||||
// to submit the EscrowFinish
|
||||
$("#escrow_progress .progress-bar").width("0%").addClass("progress-bar-animated")
|
||||
$("#escrow_progress").show()
|
||||
let seconds_left
|
||||
let pct_done
|
||||
let latestCloseTimeRipple
|
||||
while (true) {
|
||||
seconds_left = (finish_after - api.iso8601ToRippleTime(Date()))
|
||||
pct_done = Math.min(99, Math.max(0, (1-(seconds_left / duration_seconds)) * 100))
|
||||
$("#escrow_progress .progress-bar").width(pct_done+"%")
|
||||
if (seconds_left <= 0) {
|
||||
// System time has advanced past FinishAfter. But is there a new
|
||||
// enough validated ledger?
|
||||
latestCloseTimeRipple = api.iso8601ToRippleTime((await api.getLedger()).closeTime)
|
||||
if (latestCloseTimeRipple > finish_after) {
|
||||
$("#escrow_progress .progress-bar").width("100%").removeClass("progress-bar-animated")
|
||||
break
|
||||
}
|
||||
}
|
||||
// Update the progress bar & check again in 1 second.
|
||||
await timeout(1000)
|
||||
}
|
||||
$("#escrow_progress").hide()
|
||||
|
||||
// Now submit the EscrowFinish
|
||||
// Future feature: submit from a different sender, just to prove that
|
||||
// escrows can be finished by a third party
|
||||
await submit_and_verify({
|
||||
Account: sending_address,
|
||||
TransactionType: "EscrowFinish",
|
||||
Owner: sending_address,
|
||||
OfferSequence: escrowcreate_tx_data.sequence
|
||||
})
|
||||
}
|
||||
$("#create_escrow .loader").hide()
|
||||
$("#create_escrow button").attr("disabled",false)
|
||||
}
|
||||
$("#create_escrow button").click(on_click_create_escrow)
|
||||
|
||||
// 4. Create Payment Channel Handler -------------------------------------
|
||||
async function on_click_create_payment_channel(event) {
|
||||
const destination_address = $("#destination_address").val()
|
||||
const xrp_drops_input = $("#create_payment_channel_amount").val()
|
||||
const pubkey = api.deriveKeypair(sending_secret).publicKey
|
||||
$("#create_payment_channel .loader").show()
|
||||
$("#create_payment_channel button").attr("disabled","disabled")
|
||||
await submit_and_verify({
|
||||
TransactionType: "PaymentChannelCreate",
|
||||
Account: sending_address,
|
||||
Destination: destination_address,
|
||||
Amount: xrp_drops_input,
|
||||
SettleDelay: 30,
|
||||
PublicKey: pubkey
|
||||
})
|
||||
$("#create_payment_channel .loader").hide()
|
||||
$("#create_payment_channel button").attr("disabled",false)
|
||||
|
||||
// Future feature: figure out channel ID and enable a button that creates
|
||||
// valid claims for the given payment channel to help test redeeming
|
||||
}
|
||||
$("#create_payment_channel button").click(on_click_create_payment_channel)
|
||||
|
||||
|
||||
// 5. Send Issued Currency Handler ---------------------------------------
|
||||
async function on_click_send_issued_currency(event) {
|
||||
const destination_address = $("#destination_address").val()
|
||||
const issue_amount = $("#send_issued_currency_amount").val()
|
||||
const issue_code = $("#send_issued_currency_code").text()
|
||||
$("#send_issued_currency .loader").show()
|
||||
$("#send_issued_currency button").attr("disabled","disabled")
|
||||
// Future feature: cross-currency sending with paths?
|
||||
await submit_and_verify({
|
||||
TransactionType: "Payment",
|
||||
Account: sending_address,
|
||||
Destination: destination_address,
|
||||
Amount: {
|
||||
"currency": issue_code,
|
||||
"value": issue_amount,
|
||||
"issuer": sending_address
|
||||
}
|
||||
})
|
||||
$("#send_issued_currency .loader").hide()
|
||||
$("#send_issued_currency button").attr("disabled",false)
|
||||
}
|
||||
$("#send_issued_currency button").click(on_click_send_issued_currency)
|
||||
|
||||
// 6. Trust For Handler
|
||||
async function on_trust_for(event) {
|
||||
const destination_address = $("#destination_address").val()
|
||||
const trust_limit = $("#trust_for_amount").val()
|
||||
const trust_currency_code = $("#trust_for_currency_code").text()
|
||||
$("#trust_for .loader").show()
|
||||
$("#trust_for button").attr("disabled","disabled")
|
||||
await submit_and_verify({
|
||||
TransactionType: "TrustSet",
|
||||
Account: sending_address,
|
||||
LimitAmount: {
|
||||
currency: trust_currency_code,
|
||||
value: trust_limit,
|
||||
issuer: destination_address
|
||||
}
|
||||
})
|
||||
$("#trust_for .loader").hide()
|
||||
$("#trust_for button").attr("disabled",false)
|
||||
}
|
||||
$("#trust_for button").click(on_trust_for)
|
||||
|
||||
}
|
||||
|
||||
|
||||
$(document).ready( function() {
|
||||
set_up_tx_sender()
|
||||
} )
|
||||
101
assets/vendor/bootstrap-growl.jquery.js
vendored
Normal file
101
assets/vendor/bootstrap-growl.jquery.js
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
The MIT License
|
||||
|
||||
Copyright (c) Nick Larson, http://github.com/ifightcrime
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var $;
|
||||
|
||||
$ = jQuery;
|
||||
|
||||
$.bootstrapGrowl = function(message, options) {
|
||||
var $alert, css, offsetAmount;
|
||||
options = $.extend({}, $.bootstrapGrowl.default_options, options);
|
||||
$alert = $("<div>");
|
||||
$alert.attr("class", "bootstrap-growl alert");
|
||||
if (options.type) {
|
||||
$alert.addClass("alert-" + options.type);
|
||||
}
|
||||
if (options.allow_dismiss) {
|
||||
$alert.addClass("alert-dismissible");
|
||||
$alert.append("<button class=\"close\" data-dismiss=\"alert\" type=\"button\"><span aria-hidden=\"true\">×</span><span class=\"sr-only\">Close</span></button>");
|
||||
}
|
||||
$alert.append(message);
|
||||
if (options.top_offset) {
|
||||
options.offset = {
|
||||
from: "top",
|
||||
amount: options.top_offset
|
||||
};
|
||||
}
|
||||
offsetAmount = options.offset.amount;
|
||||
$(".bootstrap-growl").each(function() {
|
||||
return offsetAmount = Math.max(offsetAmount, parseInt($(this).css(options.offset.from)) + $(this).outerHeight() + options.stackup_spacing);
|
||||
});
|
||||
css = {
|
||||
"position": (options.ele === "body" ? "fixed" : "absolute"),
|
||||
"margin": 0,
|
||||
"z-index": "9999",
|
||||
"display": "none"
|
||||
};
|
||||
css[options.offset.from] = offsetAmount + "px";
|
||||
$alert.css(css);
|
||||
if (options.width !== "auto") {
|
||||
$alert.css("width", options.width + "px");
|
||||
}
|
||||
$(options.ele).append($alert);
|
||||
switch (options.align) {
|
||||
case "center":
|
||||
$alert.css({
|
||||
"left": "50%",
|
||||
"margin-left": "-" + ($alert.outerWidth() / 2) + "px"
|
||||
});
|
||||
break;
|
||||
case "left":
|
||||
$alert.css("left", "20px");
|
||||
break;
|
||||
default:
|
||||
$alert.css("right", "20px");
|
||||
}
|
||||
$alert.fadeIn();
|
||||
if (options.delay > 0) {
|
||||
$alert.delay(options.delay).fadeOut(function() {
|
||||
return $(this).alert("close");
|
||||
});
|
||||
}
|
||||
return $alert;
|
||||
};
|
||||
|
||||
$.bootstrapGrowl.default_options = {
|
||||
ele: "body",
|
||||
type: "info",
|
||||
offset: {
|
||||
from: "top",
|
||||
amount: 20
|
||||
},
|
||||
align: "right",
|
||||
width: 250,
|
||||
delay: 4000,
|
||||
allow_dismiss: true,
|
||||
stackup_spacing: 10
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
@@ -5,24 +5,29 @@ Ripple provides a set of developer tools to help you test, explore, and validate
|
||||
|
||||
* **[XRP Ledger Lookup Tool](xrp-ledger-rpc-tool.html)**
|
||||
|
||||
Use this JSON-RPC-based debugging tool to print raw information about a XRP Ledger account, transaction, or ledger.
|
||||
|
||||
* **[XRP Ledger Test Net Faucet](xrp-test-net-faucet.html)**
|
||||
|
||||
Use the WebSocket and JSON-RPC Test Net endpoints to test software built on the XRP Ledger without using real funds. Generate Test Net credentials and funds for testing purposes. Test net ledger and balances are reset on a regular basis.
|
||||
<!--{# TODO: For information about how to connect your `rippled` test server to the Test Net, see [XXXXX](x). #}-->
|
||||
Use this JSON-RPC-based debugging tool to print raw information about a XRP Ledger account, transaction, or ledger.
|
||||
|
||||
* **[rippled API WebSocket Tool](websocket-api-tool.html)**
|
||||
|
||||
Need to see the rippled API in action ASAP? Use this tool to send prepopulated sample requests and get responses. No setup required.
|
||||
<!--{# TODO: which methods are surfaced here -- is this all of them? #}-->
|
||||
Need to see the rippled API in action ASAP? Use this tool to send sample requests and get responses. No setup required.
|
||||
|
||||
* **[Data API v2 Tool](data-api-v2-tool.html)**
|
||||
|
||||
Need to see the Data API v2 in action ASAP? Use this tool to send prepopulated sample requests and get responses. No setup required.
|
||||
Need to see the Data API v2 in action ASAP? Use this tool to send prepopulated sample requests and get responses. No setup required.
|
||||
|
||||
* **[rippled.txt Validator](ripple-txt-validator.html)**
|
||||
* **[XRP Ledger Test Net Faucet](xrp-test-net-faucet.html)**
|
||||
|
||||
Use the WebSocket and JSON-RPC Test Net endpoints to test software built on the XRP Ledger without using real funds. Generate Test Net credentials and funds for testing purposes. Test Net ledger and balances are reset on a regular basis.
|
||||
|
||||
* **[ripple.txt Validator](ripple-txt-validator.html)**
|
||||
|
||||
Use this tool to verify that your `ripple.txt` is syntactically correct and deployed properly.
|
||||
|
||||
**Warning:** The `ripple.txt` file definition has been deprecated. Use an [xrp-ledger.toml file](xrp-ledger-toml.html) instead.
|
||||
|
||||
* **[Transaction Sender](tx-sender.html)**
|
||||
|
||||
Test how your code handles various XRP Ledger transactions by sending them over the Test Net to the address of your choice.
|
||||
|
||||
|
||||
Have an idea for a tool not provided here? [Contact us >](mailto:docs@ripple.com)
|
||||
|
||||
@@ -2870,12 +2870,21 @@ pages:
|
||||
|
||||
# Dev Tools --------------------------------------------------------------------
|
||||
- md: dev-tools/dev-tools.md
|
||||
html: dev-tools.html
|
||||
funnel: Dev Tools
|
||||
filters:
|
||||
- buttonize
|
||||
targets:
|
||||
- local
|
||||
|
||||
- name: Dev Tools # Redirect page for old broken URL
|
||||
html: dev-tools-dev-tools.html
|
||||
template: template-redirect.html
|
||||
redirect_url: dev-tools.html
|
||||
funnel: Dev Tools
|
||||
targets:
|
||||
- local
|
||||
|
||||
- name: RPC Tool
|
||||
funnel: Dev Tools
|
||||
html: xrp-ledger-rpc-tool.html
|
||||
@@ -2915,6 +2924,13 @@ pages:
|
||||
- local
|
||||
template: template-test-net.html
|
||||
|
||||
- name: Transaction Sender
|
||||
funnel: Dev Tools
|
||||
html: tx-sender.html
|
||||
targets:
|
||||
- local
|
||||
template: template-tx-sender.html
|
||||
|
||||
# News -------------------------------------------------------------------------
|
||||
|
||||
- md: news/news.md
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
{% set printed_next_levels = [] %}
|
||||
{% for onepage in thosepages %}
|
||||
{% if onepage == parent %}{# pass #}
|
||||
{% elif onepage.template == "template-redirect.html" %}{# don't list redirects #}
|
||||
{% elif next_level_field == None or (onepage[next_level_field] is undefined and next_level_field != "supercategory") %}
|
||||
{# direct child, print it! #}
|
||||
<li class="level-{{indent_level}}"><a href="{{onepage.html}}">{{onepage.name}}</a>{% if show_blurbs and onepage.blurb is defined and indent_level == 1%}<p class="blurb child-blurb">{{onepage.blurb}}</p>{% endif %}</li>
|
||||
|
||||
14
tool/template-redirect.html
Normal file
14
tool/template-redirect.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{% extends "template-base.html" %}
|
||||
{% block head %}
|
||||
|
||||
<meta http-equiv="refresh" content="0;url={{currentpage.redirect_url}}" />
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main %}
|
||||
<article class="p-3">
|
||||
<div class="content">
|
||||
<p>This page has been moved! You should be redirected automatically. If not, <a href="{{currentpage.redirect_url}}">click here to go to the new {{currentpage.name}} page</a>.
|
||||
</div>
|
||||
</article>
|
||||
{% endblock %}
|
||||
@@ -38,6 +38,7 @@
|
||||
<ul class="sidebar_pagelist">
|
||||
{% for page in funnelpages %}
|
||||
{% if loop.index == 1 %}{# Skip the first element since it's linked by the funnel header #}
|
||||
{% elif page.template == "template-redirect.html" %}{# skip redirects #}
|
||||
{% elif page == currentpage %}
|
||||
<li><a class="active nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
@@ -82,33 +83,34 @@
|
||||
{% set printed_subcategories = [] %}
|
||||
{% for page in catpages %}
|
||||
{% if loop.index != 1 %}{# Skip the first element since it's linked by the category header #}
|
||||
{% if page.subcategory is undefined %}
|
||||
{% if page == currentpage %}
|
||||
<li><a class="active nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% elif page.subcategory not in printed_subcategories %}
|
||||
{% if page == currentpage %}
|
||||
<li><a class="subcat-title active" href="#main_content_body">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% elif currentpage.subcategory is defined and page.subcategory == currentpage.subcategory %}
|
||||
<li><a class="subcat-title active-parent" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="subcat-title" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
|
||||
{% for subpage in catpages|selectattr('subcategory', 'defined_and_equalto', page.subcategory) %}
|
||||
{% if subpage != page %}
|
||||
{% if subpage == currentpage %}
|
||||
<li><a class="active subpage" href="#main_content_body">{{ subpage.name }}{% if subpage.status is defined and subpage.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="subpage" href="{{ subpage.html }}">{{ subpage.name }}{% if subpage.status is defined and subpage.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% if page.template == "template-redirect.html" %}{# skip redirects #}
|
||||
{% elif page.subcategory is undefined %}
|
||||
{% if page == currentpage %}
|
||||
<li><a class="active nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% elif page.subcategory not in printed_subcategories %}
|
||||
{% if page == currentpage %}
|
||||
<li><a class="subcat-title active" href="#main_content_body">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% elif currentpage.subcategory is defined and page.subcategory == currentpage.subcategory %}
|
||||
<li><a class="subcat-title active-parent" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="subcat-title" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% set _ = printed_subcategories.append(page.subcategory) %}
|
||||
|
||||
{% endif %}
|
||||
{% for subpage in catpages|selectattr('subcategory', 'defined_and_equalto', page.subcategory) %}
|
||||
{% if subpage != page %}
|
||||
{% if subpage == currentpage %}
|
||||
<li><a class="active subpage" href="#main_content_body">{{ subpage.name }}{% if subpage.status is defined and subpage.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="subpage" href="{{ subpage.html }}">{{ subpage.name }}{% if subpage.status is defined and subpage.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% set _ = printed_subcategories.append(page.subcategory) %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -154,7 +156,8 @@
|
||||
{% set printed_categories = [] %}
|
||||
{% for subpage in supercatpages %}
|
||||
{% if loop.index != 1 %}{# Skip the first element since it's linked by the supercategory header #}
|
||||
{% if subpage.category not in printed_categories %}
|
||||
{% if subpage.template == "template-redirect.html" %}{# skip redirects #}
|
||||
{% elif subpage.category not in printed_categories %}
|
||||
<li><a class="subcat-title" href="{{ subpage.html }}">{{ subpage.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
|
||||
{% set category_members = supercatpages|selectattr('category', 'defined_and_equalto', subpage.category)|list %}
|
||||
@@ -204,33 +207,34 @@
|
||||
{% set printed_subcategories = [] %}
|
||||
{% for page in catpages %}
|
||||
{% if loop.index != 1 %}{# Skip the first element since it's linked by the category header #}
|
||||
{% if page.subcategory is undefined %}
|
||||
{% if page == currentpage %}
|
||||
<li><a class="active nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% elif page.subcategory not in printed_subcategories %}
|
||||
{% if page == currentpage %}
|
||||
<li><a class="subcat-title active" href="#main_content_body">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% elif page.subcategory is defined and currentpage.subcategory is defined and page.subcategory == currentpage.subcategory %}
|
||||
<li><a class="subcat-title active-parent" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="subcat-title" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
|
||||
{% for subpage in catpages|selectattr('subcategory', 'defined_and_equalto', page.subcategory) %}
|
||||
{% if subpage != page %}
|
||||
{% if subpage == currentpage %}
|
||||
<li><a class="active subpage" href="#main_content_body">{{ subpage.name }}{% if subpage.status is defined and subpage.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="subpage" href="{{ subpage.html }}">{{ subpage.name }}{% if subpage.status is defined and subpage.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% if page.template == "template-redirect.html" %}{# skip redirects #}
|
||||
{% elif page.subcategory is undefined %}
|
||||
{% if page == currentpage %}
|
||||
<li><a class="active nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="nosubcat-page" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% elif page.subcategory not in printed_subcategories %}
|
||||
{% if page == currentpage %}
|
||||
<li><a class="subcat-title active" href="#main_content_body">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% elif page.subcategory is defined and currentpage.subcategory is defined and page.subcategory == currentpage.subcategory %}
|
||||
<li><a class="subcat-title active-parent" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="subcat-title" href="{{ page.html }}">{{ page.name }}{% if page.status is defined and page.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% set _ = printed_subcategories.append(page.subcategory) %}
|
||||
|
||||
{% endif %}
|
||||
{% for subpage in catpages|selectattr('subcategory', 'defined_and_equalto', page.subcategory) %}
|
||||
{% if subpage != page %}
|
||||
{% if subpage == currentpage %}
|
||||
<li><a class="active subpage" href="#main_content_body">{{ subpage.name }}{% if subpage.status is defined and subpage.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="subpage" href="{{ subpage.html }}">{{ subpage.name }}{% if subpage.status is defined and subpage.status == "not_enabled" %} {% include 'template-status_not_enabled.html' %}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% set _ = printed_subcategories.append(page.subcategory) %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
158
tool/template-tx-sender.html
Normal file
158
tool/template-tx-sender.html
Normal file
@@ -0,0 +1,158 @@
|
||||
{% extends "template-base.html" %}
|
||||
|
||||
{% block bodyclasses %}page-tx-sender{% endblock %}
|
||||
|
||||
{% block right_sidebar %}
|
||||
<div id="connection-status" class="card">
|
||||
<div class="card-header bg-dark">
|
||||
<h3 class="card-title">Status</h3>
|
||||
</div><!--/.card-header-->
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item" id="connection-status-label">XRP Test Net:</li>
|
||||
<li class="list-group-item disabled" id="connection-status-item">Not Connected</li>
|
||||
<li class="list-group-item" id="sending-address-label">Sending Address:</li>
|
||||
<li class="list-group-item disabled sending-address-item">(None)</li>
|
||||
<li class="list-group-item" id="balance-label">Test XRP Available:</li>
|
||||
<li class="list-group-item disabled" id="balance-item">(None)</li>
|
||||
</ul>
|
||||
<div id="tx-sender-history">
|
||||
<h5 class="m-3">Transaction History</h5>
|
||||
<ul class="list-group list-group-flush">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<section class="container-fluid p-3">
|
||||
<h1>Transaction Sender</h1>
|
||||
|
||||
<div class="content">
|
||||
<p>This tool sends transactions to the <a href="xrp-test-net-faucet.html">XRP Test Net</a> address of your choice so you can test how you monitor and respond to incoming transactions.</p>
|
||||
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="destination_address">Destination Address</label>
|
||||
<input type="text" class="form-control" id="destination_address" aria-describedby="destination_address_help" value="rUCzEr6jrEyMpjhs4wSdQdz4g8Y382NxfM" />
|
||||
<small id="destination_address_help" class="form-text text-muted">Send transactions to this XRP Test Net address</small>
|
||||
</div>
|
||||
|
||||
<h3>Send Transaction</h3>
|
||||
|
||||
<div class="form-group" id="send_xrp_payment">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text loader" style="display: none"><img class="throbber" src="assets/img/rippleThrobber.png" /></span>
|
||||
</div>
|
||||
<button class="btn btn-primary form-control" type="button" id="send_xrp_payment_btn">Send XRP Payment</button>
|
||||
<input id="send_xrp_payment_amount" class="form-control" type="number" aria-describedby="send_xrp_payment_amount_help" value="100000" min="1" max="10000000000" />
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="send_xrp_payment_amount_help">drops of XRP</span>
|
||||
</div>
|
||||
<!-- Future feature: Optional custom destination tag -->
|
||||
</div>
|
||||
<small class="form-text text-muted">Send a <a href="send-xrp.html">simple XRP-to-XRP payment</a>.</small>
|
||||
</div><!-- /#send_xrp_payment -->
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group" id="send_partial_payment">
|
||||
<div class="progress mb-1" id="pp_progress">
|
||||
<div class="progress-bar progress-bar-striped w-0"> </div>
|
||||
<small class="justify-content-center d-flex position-absolute w-100">(Getting ready to send partial payments)</small>
|
||||
</div>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text loader" style="display: none"><img class="throbber" src="assets/img/rippleThrobber.png" /></span>
|
||||
</div>
|
||||
<button class="btn btn-primary form-control" type="button" id="send_partial_payment_btn" disabled="disabled" autocomplete="off" title="(Please wait for partial payments setup to finish)">Send Partial Payment</button>
|
||||
</div>
|
||||
<small class="form-text text-muted">Delivers a small amount of XRP with a large <code>Amount</code> value, to test your handling of <a href="partial-payments.html">partial payments</a>.</small>
|
||||
</div><!-- /.form group for partial payment -->
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group" id="create_escrow">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text loader" style="display: none"><img class="throbber" src="assets/img/rippleThrobber.png" /></span>
|
||||
</div>
|
||||
<button class="btn btn-primary form-control" type="button" id="create_escrow_btn">Create Escrow</button>
|
||||
<input class="form-control" type="number" value="60" min="5" max="10000" id="create_escrow_duration_seconds" />
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">seconds</span>
|
||||
</div>
|
||||
<span class="input-group-text">
|
||||
(
|
||||
<input type="checkbox" id="create_escrow_release_automatically" value="1" />
|
||||
<label class="form-check-label" for="create_escrow_release_automatically">Finish automatically</label>)
|
||||
</span>
|
||||
</div>
|
||||
<small class="form-text text-muted">Create a <a href="escrow.html">time-based escrow</a> of 1 XRP for the specified number of seconds.</small>
|
||||
<div class="progress mb-1" style="display:none" id="escrow_progress">
|
||||
<div class="progress-bar progress-bar-striped w-0"> </div>
|
||||
<small class="justify-content-center d-flex position-absolute w-100">(Waiting to release Escrow when it's ready)</small>
|
||||
</div>
|
||||
</div><!-- /.form group for create escrow -->
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group" id="create_payment_channel">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text loader" style="display: none"><img class="throbber" src="assets/img/rippleThrobber.png" /></span>
|
||||
</div>
|
||||
<button class="btn btn-primary form-control" type="button" id="create_payment_channel_btn">Create Payment Channel</button>
|
||||
<input id="create_payment_channel_amount" class="form-control" type="number" aria-describedby="create_payment_channel_amount_help" value="100000" min="1" max="10000000000" />
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="create_payment_channel_amount_help">drops of XRP</span>
|
||||
</div>
|
||||
</div>
|
||||
<small class="form-text text-muted">Create a <a href="payment-channels.html">payment channel</a> and fund it with the specified amount of XRP.</small>
|
||||
</div><!-- /.form group for create paychan -->
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group" id="send_issued_currency">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text loader" style="display: none"><img class="throbber" src="assets/img/rippleThrobber.png" /></span>
|
||||
</div>
|
||||
<button class="btn btn-primary form-control" type="button" id="send_issued_currency_btn">Send Issued Currency</button>
|
||||
<input id="send_issued_currency_amount" class="form-control" type="text" value="100" /><!-- Note: HTML limits "number" inputs to IEEE 764 double precision, which isn't enough for the full range of issued currency amounts -->
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="send_issued_currency_code">FOO</span><!-- TODO: custom currency codes -->
|
||||
</div>
|
||||
</div>
|
||||
<small class="form-text text-muted">Your destination address needs a <a href="trust-lines-and-issuing.html">trust line</a> to <span class="sending-address-item">(the test sender)</span> for the currency in question. Otherwise, you'll get tecPATH_DRY.</small>
|
||||
</div><!-- /.form group for issued currency payment -->
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group" id="trust_for">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text loader" style="display: none"><img class="throbber" src="assets/img/rippleThrobber.png" /></span>
|
||||
</div>
|
||||
<button class="btn btn-primary form-control" type="button" id="trust_for_btn">Trust for</button>
|
||||
<input id="trust_for_amount" class="form-control disabled" type="number" value="100000" />
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="trust_for_currency_code">FOO</span>
|
||||
</div>
|
||||
</div>
|
||||
<small class="form-text text-muted">The test sender creates a <a href="trust-lines-and-issuing.html">trust line</a> to your account for the given currency.</small>
|
||||
</div><!-- /.form group for create trust line -->
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block endbody %}
|
||||
<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.1.2-min.js"></script>
|
||||
<script type="application/javascript" src="assets/vendor/bootstrap-growl.jquery.js"></script>
|
||||
<script type='application/javascript' src='assets/js/tx-sender.js'></script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user