Add Bitcoin/Dogecoin paper wallet spending (#9)
This commit is contained in:
parent
c173912190
commit
f44a3c8479
1
www/assets/js/bitcore-lib-doge.min.js
vendored
Normal file
1
www/assets/js/bitcore-lib-doge.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
www/assets/js/bitcore-lib.min.js
vendored
Normal file
1
www/assets/js/bitcore-lib.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var walletPubKeyRegex = /^(bc1|[13]|D)[a-zA-HJ-NP-Z0-9]{25,}$/;
|
var walletPubKeyRegex = /^(bc1|[13]|D)[a-zA-HJ-NP-Z0-9]{25,}$/;
|
||||||
|
var paymentRequestRegex = /^(bitcoin|dogecoin):(bc1|[13]|D)[a-zA-HJ-NP-Z0-9]{25,}$/;
|
||||||
|
var walletPrivateKeyRegex = /^[0-9A-Za-z]+$/;
|
||||||
|
|
||||||
function scanWalletQrCode(callback) {
|
function scanWalletQrCode(callback) {
|
||||||
scanBarcode(function (result) {
|
scanBarcode(function (result) {
|
||||||
@ -19,6 +21,182 @@ function scanWalletQrCode(callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scanPrivateKeyQrCode(callback) {
|
||||||
|
scanBarcode(function (result) {
|
||||||
|
if (walletPrivateKeyRegex.test(result)) {
|
||||||
|
callback(result);
|
||||||
|
} else {
|
||||||
|
app.dialog.alert("That doesn't look like a valid wallet address.", "Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, function () {
|
||||||
|
app.dialog.alert("Something went wrong and we can't scan right now.", "Error");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and sign a crypto transaction.
|
||||||
|
*
|
||||||
|
* @param {type} bitcoreLib Bitcore, Litecore, Dogecore, etc.
|
||||||
|
* @param {type} privateKeyString Private key from wallet QR code
|
||||||
|
* @param {type} sourceAddress Sender's wallet address
|
||||||
|
* @param {type} destinationAddress Recipient's wallet address
|
||||||
|
* @param {type} txHash From UXTO (unspent output)
|
||||||
|
* @param {type} txOutputIndex From UXTO (unspent output)
|
||||||
|
* @param {type} script From UXTO (unspent output)
|
||||||
|
* @param {type} inputSatoshis From UXTO (unspent output)
|
||||||
|
* @param {type} outputSatoshis Amount to send to recipient's wallet
|
||||||
|
* @returns {string} Hex of serialized transaction, suitable for broadcast via Bitcoin Core or an API.
|
||||||
|
*/
|
||||||
|
function createSignedTransaction(bitcoreLib, privateKeyString, sourceAddress, destinationAddress, txHash, txOutputIndex, script, inputSatoshis, outputSatoshis) {
|
||||||
|
var privateKey = new bitcoreLib.PrivateKey(privateKeyString);
|
||||||
|
var utxo = {
|
||||||
|
"txId": txHash,
|
||||||
|
"outputIndex": txOutputIndex,
|
||||||
|
"address": sourceAddress,
|
||||||
|
"script": script,
|
||||||
|
"satoshis": inputSatoshis
|
||||||
|
};
|
||||||
|
|
||||||
|
var transaction = new bitcoreLib.Transaction()
|
||||||
|
.from(utxo)
|
||||||
|
.to(destinationAddress, outputSatoshis)
|
||||||
|
.change(sourceAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
|
||||||
|
return transaction.serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unspent outputs for a wallet address.
|
||||||
|
* @param {string} walletaddress
|
||||||
|
* @param {function} successCallback Passes object with {uxtos: [{txHash,txOutputIndex,script,value}], currency: "DOGE", label: "Dogecoin"}
|
||||||
|
* @param {function} errorCallback Passes string error message suitable for display
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function getUXTOData(walletaddress, successCallback, errorCallback) {
|
||||||
|
apirequest(SETTINGS.apis.getuxto, {
|
||||||
|
walletaddress: walletaddress
|
||||||
|
}, function (resp) {
|
||||||
|
if (resp.status == "OK") {
|
||||||
|
successCallback({
|
||||||
|
uxtos: resp.unspent_outputs,
|
||||||
|
currency: resp.currency,
|
||||||
|
label: resp.label
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
errorCallback(resp.msg);
|
||||||
|
}
|
||||||
|
}, function (errorData) {
|
||||||
|
try {
|
||||||
|
var error = $.parseJSON(errorData.responseText);
|
||||||
|
if (error && typeof error.msg != 'undefined') {
|
||||||
|
errorCallback(resp.msg);
|
||||||
|
sendErrorReport("Crypto", "Couldn't get UXTO data", error.msg);
|
||||||
|
} else {
|
||||||
|
errorCallback("There's a server or network problem. Check your Internet connection or try again later. Your funds are safe.");
|
||||||
|
sendErrorReport("Crypto", "Couldn't get UXTO data", "Server/network problem: " + xhr.status + ": " + xhr.statusText);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
errorCallback("There's a server or network problem. Check your Internet connection or try again later. Your funds are safe.");
|
||||||
|
sendErrorReport("Crypto", "Couldn't get UXTO data", "Server/network problem: " + xhr.status + ": " + xhr.statusText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendCoins(privatekey, fromaddress, toaddress, satoshis) {
|
||||||
|
var progressdialog = app.dialog.progress("Querying blockchain...", 25);
|
||||||
|
getUXTOData(fromaddress, function (success) {
|
||||||
|
progressdialog.setProgress(50);
|
||||||
|
progressdialog.setText("Creating transaction...");
|
||||||
|
if (success.uxtos.length == 0) {
|
||||||
|
app.dialog.close();
|
||||||
|
app.dialog.alert("Your wallet has no available funds (ZERO_LENGTH_UXTO).", "Error");
|
||||||
|
return;
|
||||||
|
} else if (success.uxtos.length > 1) {
|
||||||
|
app.dialog.close();
|
||||||
|
app.dialog.alert("For technical reasons, your wallet isn't compatible with this app right now. You can still sweep this wallet into an alternative app to spend it. (MULTIPLE_UXTO)", "Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var bitcore = null;
|
||||||
|
switch (success.currency) {
|
||||||
|
case "DOGE":
|
||||||
|
bitcore = require("bitcore-lib-doge");
|
||||||
|
break;
|
||||||
|
case "BTC":
|
||||||
|
bitcore = require("bitcore-lib");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
app.dialog.close();
|
||||||
|
app.dialog.alert("This app version doesn't support " + success.currency + ".", "Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var txdata = createSignedTransaction(bitcore, privatekey, fromaddress, toaddress,
|
||||||
|
success.uxtos[0].txHash, success.uxtos[0].txOutputIndex, success.uxtos[0].script,
|
||||||
|
success.uxtos[0].value, satoshis);
|
||||||
|
|
||||||
|
progressdialog.setProgress(75);
|
||||||
|
progressdialog.setText("Sending payment...");
|
||||||
|
|
||||||
|
apirequest(SETTINGS.apis.broadcasttransaction, {
|
||||||
|
transactiondata: txdata,
|
||||||
|
currency: success.currency
|
||||||
|
}, function (resp) {
|
||||||
|
if (resp.status == "OK") {
|
||||||
|
app.dialog.close();
|
||||||
|
app.dialog.alert("Sent " + (satoshis / 100000000) + " " + success.currency + " to " + toaddress, "Success!");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
app.dialog.close();
|
||||||
|
}
|
||||||
|
}, function (errorData) {
|
||||||
|
app.dialog.close();
|
||||||
|
try {
|
||||||
|
var error = $.parseJSON(errorData.responseText);
|
||||||
|
if (error && typeof error.msg != 'undefined') {
|
||||||
|
app.dialog.alert(error.msg, "Error");
|
||||||
|
sendErrorReport("Crypto", "Couldn't broadcast transaction", error.msg);
|
||||||
|
} else {
|
||||||
|
app.dialog.alert("There's a server or network problem. Check your Internet connection or try again later. Your funds are safe.", "Error");
|
||||||
|
sendErrorReport("Crypto", "Couldn't broadcast transaction", "Server/network problem: " + xhr.status + ": " + xhr.statusText);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
app.dialog.alert("There's a server or network problem. Check your Internet connection or try again later. Your funds are safe.", "Error");
|
||||||
|
sendErrorReport("Crypto", "Couldn't broadcast transaction", "Server/network problem: " + xhr.status + ": " + xhr.statusText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, function (error) {
|
||||||
|
app.dialog.close();
|
||||||
|
app.dialog.alert(error, "Error");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function walletGUISendCoins() {
|
||||||
|
if (!walletPubKeyRegex.test($('#walletFromAddress').val())) {
|
||||||
|
app.dialog.alert("Your wallet address doesn't look right. Check it and try again.", "Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN($('#transactionAmount').val()) || $('#transactionAmount').val() < 0.00000001) {
|
||||||
|
app.dialog.alert("The amount to send doesn't look right. Check it and try again.", "Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove payment request URL stuff
|
||||||
|
if ($('#walletToAddress').val().startsWith("bitcoin:")) {
|
||||||
|
$('#walletToAddress').val($('#walletToAddress').val().replace("bitcoin:", ""));
|
||||||
|
}
|
||||||
|
if ($('#walletToAddress').val().startsWith("dogecoin:")) {
|
||||||
|
$('#walletToAddress').val($('#walletToAddress').val().replace("dogecoin:", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!walletPubKeyRegex.test($('#walletToAddress').val())) {
|
||||||
|
app.dialog.alert("The recipient's wallet address doesn't look right. Check it and try again.", "Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendCoins($('#walletPrivateKey').val(), $('#walletFromAddress').val(), $('#walletToAddress').val(), $('#transactionAmount').val() * 100000000);
|
||||||
|
}
|
||||||
|
|
||||||
function displayWalletBalance(address) {
|
function displayWalletBalance(address) {
|
||||||
if (!walletPubKeyRegex.test(address)) {
|
if (!walletPubKeyRegex.test(address)) {
|
||||||
app.dialog.alert("That doesn't look like a valid wallet address.", "Error");
|
app.dialog.alert("That doesn't look like a valid wallet address.", "Error");
|
||||||
|
@ -24,6 +24,9 @@ function openGenericBarcodeScanner() {
|
|||||||
code = result.split("#")[1];
|
code = result.split("#")[1];
|
||||||
action = "track";
|
action = "track";
|
||||||
}
|
}
|
||||||
|
} else if (paymentRequestRegex.test(result)) {
|
||||||
|
code = result;
|
||||||
|
action = "sendcrypto";
|
||||||
} else if (walletPubKeyRegex.test(result)) {
|
} else if (walletPubKeyRegex.test(result)) {
|
||||||
code = result;
|
code = result;
|
||||||
action = "cryptowallet";
|
action = "cryptowallet";
|
||||||
@ -42,6 +45,9 @@ function openGenericBarcodeScanner() {
|
|||||||
case "cryptowallet":
|
case "cryptowallet":
|
||||||
router.navigate("/crypto/balance/" + code);
|
router.navigate("/crypto/balance/" + code);
|
||||||
break;
|
break;
|
||||||
|
case "sendcrypto":
|
||||||
|
app.dialog.alert("Not implemented.");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
app.dialog.alert("This app can't understand what's in that barcode.", "Error");
|
app.dialog.alert("This app can't understand what's in that barcode.", "Error");
|
||||||
return;
|
return;
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
<script src="node_modules/template7/dist/template7.min.js"></script>
|
<script src="node_modules/template7/dist/template7.min.js"></script>
|
||||||
<script src="node_modules/jquery/dist/jquery.min.js"></script>
|
<script src="node_modules/jquery/dist/jquery.min.js"></script>
|
||||||
<script src="node_modules/maplibre-gl/dist/maplibre-gl.js"></script>
|
<script src="node_modules/maplibre-gl/dist/maplibre-gl.js"></script>
|
||||||
|
<script src="assets/js/bitcore-lib.min.js"></script>
|
||||||
|
<script src="assets/js/bitcore-lib-doge.min.js"></script>
|
||||||
|
|
||||||
<script src="settings.js"></script>
|
<script src="settings.js"></script>
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-100 medium-90 xlarge-75 margin-horizontal">
|
<div class="col-100 medium-50 xlarge-50 margin-horizontal">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">Check Wallet Balance</div>
|
<div class="card-header">Check Wallet Balance</div>
|
||||||
<div class="card-content card-content-padding">
|
<div class="card-content card-content-padding">
|
||||||
@ -46,6 +46,123 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-100 medium-50 xlarge-50 margin-horizontal">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Send Crypto</div>
|
||||||
|
<div class="card-content card-content-padding">
|
||||||
|
Spend your Helena Express paper wallet.
|
||||||
|
</div>
|
||||||
|
<div class="card-content card-content-padding">
|
||||||
|
<div class="list margin-bottom-half">
|
||||||
|
<ul>
|
||||||
|
<li class="item-divider">Step 1</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="item-inner">
|
||||||
|
Scan or type your wallet address. This tells the network where to take the money from.
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="item-content item-input">
|
||||||
|
<div class="item-inner">
|
||||||
|
<div class="item-input-wrap">
|
||||||
|
<input type="text" id="walletFromAddress" placeholder="1X68a3n1..." />
|
||||||
|
<span class="input-clear-button"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="button hapticbtn button-fill" onclick="scanWalletQrCode(function (d) {
|
||||||
|
$('#walletFromAddress').val(d);
|
||||||
|
});"><i class="fa-solid fa-inbox-out"></i> Scan Your Wallet Address
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="item-divider">Step 2</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="item-inner">
|
||||||
|
Scan or type your private key. The private key unlocks your wallet and authorizes the transfer.
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="item-content item-input">
|
||||||
|
<div class="item-inner">
|
||||||
|
<div class="item-input-wrap">
|
||||||
|
<input type="text" id="walletPrivateKey" placeholder="6JJRxyW..." />
|
||||||
|
<span class="input-clear-button"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="button hapticbtn button-fill" onclick="scanPrivateKeyQrCode(function (d) {
|
||||||
|
$('#walletToAddress').val(d);
|
||||||
|
});"><i class="fa-solid fa-key"></i> Scan Your Private Key
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="item-divider">Step 3</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="item-inner">
|
||||||
|
Scan or paste the recipient's wallet address.
|
||||||
|
The money will be sent here. Important: the recipient must be expecting the
|
||||||
|
same cryptocurrency your wallet uses. Otherwise the money will
|
||||||
|
be lost forever.
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="item-content item-input">
|
||||||
|
<div class="item-inner">
|
||||||
|
<div class="item-input-wrap">
|
||||||
|
<input type="text" id="walletToAddress" placeholder="1X68a3n1..." />
|
||||||
|
<span class="input-clear-button"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="button hapticbtn button-fill" onclick="scanWalletQrCode(function (d) {
|
||||||
|
$('#walletToAddress').val(d);
|
||||||
|
});"><i class="fa-solid fa-inbox-in"></i> Scan Recipient's Wallet
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="item-divider">Step 4</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="item-inner">
|
||||||
|
Enter the amount to send, in cryptocurrency (not in dollars).
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="item-content item-input">
|
||||||
|
<div class="item-inner">
|
||||||
|
<div class="item-input-wrap">
|
||||||
|
<input type="number" id="transactionAmount" step="0.00000001" min="0.00000001" max="999999.99999999"/>
|
||||||
|
<span class="input-clear-button"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<!--
|
||||||
|
TODO: add conversion tool here
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="button hapticbtn button-fill" onclick="scanWalletQrCode(function (d) {
|
||||||
|
$('#walletToAddress').val(d);
|
||||||
|
});"><i class="fa-solid fa-inbox-in"></i> Scan Recipient's Wallet
|
||||||
|
</div>
|
||||||
|
</li> -->
|
||||||
|
|
||||||
|
<li class="item-divider">Step 5</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="item-inner">
|
||||||
|
<div><span class="taptext">Tap</span><span class="clicktext">Click</span> the button to send the transaction.</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="item-content">
|
||||||
|
<div class="button hapticbtn button-fill" onclick="walletGUISendCoins()">
|
||||||
|
<i class="fa-solid fa-paper-plane"></i> Send Transaction
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -6,26 +6,42 @@
|
|||||||
|
|
||||||
var SETTINGS = {
|
var SETTINGS = {
|
||||||
apis: {
|
apis: {
|
||||||
|
// Tracking
|
||||||
track: "http://localhost/helena.express/apis/track/",
|
track: "http://localhost/helena.express/apis/track/",
|
||||||
trackmultiple: "http://localhost/helena.express/apis/trackmultiple/",
|
trackmultiple: "http://localhost/helena.express/apis/trackmultiple/",
|
||||||
|
// Shipping rates
|
||||||
rates: "http://localhost/helena.express/apis/rates/",
|
rates: "http://localhost/helena.express/apis/rates/",
|
||||||
|
// Get appointment iframe URL
|
||||||
appointmentredirect: "http://localhost/helena.express/apis/appointmentredirect/",
|
appointmentredirect: "http://localhost/helena.express/apis/appointmentredirect/",
|
||||||
|
// Request home pickup
|
||||||
requestpickup: "http://localhost/helena.express/apis/requestpickup/",
|
requestpickup: "http://localhost/helena.express/apis/requestpickup/",
|
||||||
|
// Drop and Send
|
||||||
dropandsendlocations: "http://localhost/helena.express/apis/dropandsend/locations/",
|
dropandsendlocations: "http://localhost/helena.express/apis/dropandsend/locations/",
|
||||||
dropandsendpickup: "http://localhost/helena.express/apis/dropandsend/requestpickup/",
|
dropandsendpickup: "http://localhost/helena.express/apis/dropandsend/requestpickup/",
|
||||||
|
// Fetch account data
|
||||||
getaccountinfo: "http://localhost/helena.express/apis/account/getinfo/",
|
getaccountinfo: "http://localhost/helena.express/apis/account/getinfo/",
|
||||||
|
// Fetch tracking numbers associated with account
|
||||||
gettrackingnumbers: "http://localhost/helena.express/apis/account/gettrackingnumbers/",
|
gettrackingnumbers: "http://localhost/helena.express/apis/account/gettrackingnumbers/",
|
||||||
|
// Account login/registration/onboarding endpoints
|
||||||
authorstartverify: "http://localhost/helena.express/apis/account/authorstartverify/",
|
authorstartverify: "http://localhost/helena.express/apis/account/authorstartverify/",
|
||||||
verifyauthcode: "http://localhost/helena.express/apis/account/verifyauthcode/",
|
verifyauthcode: "http://localhost/helena.express/apis/account/verifyauthcode/",
|
||||||
accountregister: "http://localhost/helena.express/apis/account/register/",
|
accountregister: "http://localhost/helena.express/apis/account/register/",
|
||||||
|
// Setup saved payment method
|
||||||
redirecttopaymentsetup: "http://localhost/helena.express/apis/account/redirecttopaymentsetup/",
|
redirecttopaymentsetup: "http://localhost/helena.express/apis/account/redirecttopaymentsetup/",
|
||||||
finishpaymentsetup: "http://localhost/helena.express/apis/account/finishpaymentsetup/",
|
finishpaymentsetup: "http://localhost/helena.express/apis/account/finishpaymentsetup/",
|
||||||
|
// Send a telegram message
|
||||||
sendtelegram: "http://localhost/helena.express/apis/telegram",
|
sendtelegram: "http://localhost/helena.express/apis/telegram",
|
||||||
|
// Fetch shop items
|
||||||
shopitems: "http://localhost/helena.express/apis/shop/items",
|
shopitems: "http://localhost/helena.express/apis/shop/items",
|
||||||
|
// Create a shop order
|
||||||
shopbuy: "http://localhost/helena.express/apis/shop/buy",
|
shopbuy: "http://localhost/helena.express/apis/shop/buy",
|
||||||
|
// Get receipts linked with account
|
||||||
getreceipts: "http://localhost/helena.express/apis/account/getreceipts",
|
getreceipts: "http://localhost/helena.express/apis/account/getreceipts",
|
||||||
getreceipt: "http://localhost/helena.express/apis/account/getreceipt",
|
getreceipt: "http://localhost/helena.express/apis/account/getreceipt",
|
||||||
walletbalance: "http://localhost/helena.express/apis/walletbalance"
|
// Crypto: check balance and send transactions
|
||||||
|
walletbalance: "http://localhost/helena.express/apis/crypto/walletbalance",
|
||||||
|
getuxto: "http://localhost/helena.express/apis/crypto/getuxto",
|
||||||
|
broadcasttransaction: "http://localhost/helena.express/apis/crypto/broadcasttransaction"
|
||||||
},
|
},
|
||||||
stripe_pubkey: "pk_test_51J6qFXCa1Fboir5UzPO3LCiMsVNiFP2lq4wR0dEcjJJVzAaJ3uRggDekZPB3qeYpMD3ayIYHKyD5sSn0IFLlEXMW001LqrvGSH",
|
stripe_pubkey: "pk_test_51J6qFXCa1Fboir5UzPO3LCiMsVNiFP2lq4wR0dEcjJJVzAaJ3uRggDekZPB3qeYpMD3ayIYHKyD5sSn0IFLlEXMW001LqrvGSH",
|
||||||
branding: {
|
branding: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user