Tx sender improvements

- Stick to proper precision when forming partial payments
- Use growl-like notifs to report tx success/failure
This commit is contained in:
mDuo13
2019-04-23 18:50:19 -07:00
parent 032e2d28b4
commit 269d889fcf
3 changed files with 155 additions and 26 deletions

View File

@@ -1,10 +1,31 @@
const set_up_tx_sender = async function() { 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'
})
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Connection / Setup // Connection / Setup
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
FAUCET_URL = "https://faucet.altnet.rippletest.net/accounts" const FAUCET_URL = "https://faucet.altnet.rippletest.net/accounts"
TESTNET_URL = "wss://s.altnet.rippletest.net:51233" const TESTNET_URL = "wss://s.altnet.rippletest.net:51233"
let connection_ready = false let connection_ready = false
@@ -12,6 +33,7 @@ const set_up_tx_sender = async function() {
let sending_secret let sending_secret
let xrp_balance let xrp_balance
console.debug("Getting a sending address from the faucet...") console.debug("Getting a sending address from the faucet...")
faucet_response = function(data) { faucet_response = function(data) {
@@ -25,20 +47,15 @@ const set_up_tx_sender = async function() {
$(".sending-address-item").text(sending_address) $(".sending-address-item").text(sending_address)
} }
// TEMP: reuse same address for testing $.ajax({
faucet_response({account:{address:"r6f2viHtMjNSfERbZmXXkJnMmkBAN6d9X", secret:"spyTc4y4GAQwBfQHCxiJ1Xd2mmnM2"},balance:10000}) url: FAUCET_URL,
type: 'POST',
// POST-TEMP: Version that actually uses the faucet on every run: dataType: 'json',
// $.ajax({ success: faucet_response,
// url: FAUCET_URL, error: function() {
// type: 'POST', errorNotif("There was an error with the XRP Ledger Test Net Faucet. Reload this page to try again.")
// dataType: 'json', }
// success: faucet_response, })
// error: function() {
// alert("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 = new ripple.RippleAPI({server: TESTNET_URL})
api.on('connected', () => { api.on('connected', () => {
@@ -97,7 +114,9 @@ const set_up_tx_sender = async function() {
console.debug("Prepared:", prepared) console.debug("Prepared:", prepared)
} catch(error) { } catch(error) {
console.log(error) console.log(error)
if (!silent) { alert("Error preparing tx: "+error) } if (!silent) {
errorNotif("Error preparing tx: "+error)
}
return return
} }
@@ -114,7 +133,9 @@ const set_up_tx_sender = async function() {
await api.submit(sign_response.signedTransaction) await api.submit(sign_response.signedTransaction)
} catch (error) { } catch (error) {
console.log(error) console.log(error)
if (!silent) { alert("Error signing & submitting tx: "+error) } if (!silent) {
errorNotif("Error signing & submitting "+tx_object.TransactionType+" tx: "+error)
}
return return
} }
@@ -122,18 +143,24 @@ const set_up_tx_sender = async function() {
try { try {
const data = await verify_transaction(sign_response.id, options) const data = await verify_transaction(sign_response.id, options)
const final_result = data.outcome.result const final_result = data.outcome.result
// TODO: more "notification-like" system // Future feature: output should link to a TestNet tx lookup/explainer
// TODO: output should link to a tx lookup/explainer
if (final_result === "tesSUCCESS") { if (final_result === "tesSUCCESS") {
if (!silent) { alert("Tx succeeded (hash:"+sign_response.id+")") } if (!silent) {
successNotif(tx_object.TransactionType+" tx succeeded (hash: "+sign_response.id+")")
}
} else { } else {
if (!silent) { alert("Tx failed w/ code "+final_result+" (hash: "+sign_response.id+")") } if (!silent) {
errorNotif(tx_object.TransactionType+" tx failed w/ code "+final_result+
" (hash: "+sign_response.id+")")
}
} }
update_xrp_balance() update_xrp_balance()
return data return data
} catch(error) { } catch(error) {
console.log(error) console.log(error)
if (!silent) { alert("Error submitting tx: "+error) } if (!silent) {
errorNotif("Error submitting "+tx_object.TransactionType+" tx: "+error)
}
} }
} }
@@ -284,7 +311,7 @@ const set_up_tx_sender = async function() {
Destination: destination_address, Destination: destination_address,
Amount: "1000000000000000", // 1 billion XRP Amount: "1000000000000000", // 1 billion XRP
SendMax: { SendMax: {
value: String(Math.random()*.01), // random very small amount value: (Math.random()*.01).toPrecision(15), // random very small amount
currency: pp_sending_currency, currency: pp_sending_currency,
issuer: pp_issuer_address issuer: pp_issuer_address
}, },
@@ -306,7 +333,7 @@ const set_up_tx_sender = async function() {
const duration_seconds = parseInt(duration_seconds_txt, 10) const duration_seconds = parseInt(duration_seconds_txt, 10)
if (duration_seconds === NaN || duration_seconds < 1) { if (duration_seconds === NaN || duration_seconds < 1) {
alert("Error: Escrow duration must be a positive number of seconds") errorNotif("Error: Escrow duration must be a positive number of seconds")
return return
} }
const finish_after = api.iso8601ToRippleTime(Date()) + duration_seconds const finish_after = api.iso8601ToRippleTime(Date()) + duration_seconds

101
assets/vendor/bootstrap-growl.jquery.js vendored Normal file
View 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\">&#215;</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);

View File

@@ -150,5 +150,6 @@
{% block endbody %} {% block endbody %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script> <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/js/ripple-lib-1.1.2-min.js"></script>
<script type='text/javascript' src='assets/js/tx-sender.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 %} {% endblock %}