This commit is contained in:
commit
00c0d37912
@ -2,7 +2,7 @@
|
||||
|
||||
CREATE TABLE LastTx(
|
||||
floID CHAR(34) NOT NULL,
|
||||
num INT,
|
||||
txid VARCHAR(128),
|
||||
PRIMARY KEY(floID)
|
||||
);
|
||||
|
||||
|
||||
@ -453,24 +453,6 @@ ul {
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 0 0.3rem;
|
||||
margin-right: auto;
|
||||
}
|
||||
.logo h4 {
|
||||
text-transform: capitalize;
|
||||
font-weight: 600;
|
||||
}
|
||||
.logo .main-logo {
|
||||
height: 1.4rem;
|
||||
width: 1.4rem;
|
||||
fill: rgba(var(--text-color), 1);
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
details:not(:last-of-type) {
|
||||
border-bottom: thin solid rgba(var(--text-color), 0.3);
|
||||
}
|
||||
@ -683,6 +665,22 @@ sm-checkbox {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.app-brand {
|
||||
display: flex;
|
||||
gap: 0.3rem;
|
||||
align-items: center;
|
||||
}
|
||||
.app-brand .icon {
|
||||
height: 1.7rem;
|
||||
width: 1.7rem;
|
||||
}
|
||||
|
||||
.app-name__company {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
}
|
||||
|
||||
#user_popup_button {
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
border-radius: 2rem;
|
||||
|
||||
2
docs/css/main.min.css
vendored
2
docs/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -427,24 +427,6 @@ ul {
|
||||
align-content: flex-start;
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 0 0.3rem;
|
||||
margin-right: auto;
|
||||
h4 {
|
||||
text-transform: capitalize;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.main-logo {
|
||||
height: 1.4rem;
|
||||
width: 1.4rem;
|
||||
fill: rgba(var(--text-color), 1);
|
||||
stroke: none;
|
||||
}
|
||||
}
|
||||
details {
|
||||
&:not(:last-of-type) {
|
||||
border-bottom: thin solid rgba(var(--text-color), 0.3);
|
||||
@ -643,6 +625,22 @@ sm-checkbox {
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
.app-brand{
|
||||
display: flex;
|
||||
gap: 0.3rem;
|
||||
align-items: center;
|
||||
.icon{
|
||||
height: 1.7rem;
|
||||
width: 1.7rem;
|
||||
}
|
||||
}
|
||||
.app-name{
|
||||
&__company{
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
}
|
||||
}
|
||||
#user_popup_button {
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
border-radius: 2rem;
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RanchiMall exchange</title>
|
||||
<title>RanchiMall Exchange</title>
|
||||
<meta name="description" content="Trade FLO and FLO based RanchiMall tokens.">
|
||||
<meta name="theme-color" content="#516beb" />
|
||||
<script src="scripts/components.js" defer></script>
|
||||
@ -71,14 +71,17 @@
|
||||
</div>
|
||||
<article id="home" class="page hidden">
|
||||
<header id="main_header">
|
||||
<div class="logo">
|
||||
<svg class="main-logo" viewBox="0 0 27.25 32">
|
||||
<div class="app-brand margin-right-auto">
|
||||
<svg id="main_logo" class="icon" viewBox="0 0 27.25 32">
|
||||
<title>RanchiMall</title>
|
||||
<path
|
||||
d="M27.14,30.86c-.74-2.48-3-4.36-8.25-6.94a20,20,0,0,1-4.2-2.49,6,6,0,0,1-1.25-1.67,4,4,0,0,1,0-2.26c.37-1.08.79-1.57,3.89-4.55a11.66,11.66,0,0,0,3.34-4.67,6.54,6.54,0,0,0,.05-2.82C20,3.6,18.58,2,16.16.49c-.89-.56-1.29-.64-1.3-.24a3,3,0,0,1-.3.72l-.3.55L13.42.94C13,.62,12.4.26,12.19.15c-.4-.2-.73-.18-.72.05a9.39,9.39,0,0,1-.61,1.33s-.14,0-.27-.13C8.76.09,8-.27,8,.23A11.73,11.73,0,0,1,6.76,2.6C4.81,5.87,2.83,7.49.77,7.49c-.89,0-.88,0-.61,1,.22.85.33.92,1.09.69A5.29,5.29,0,0,0,3,8.33c.23-.17.45-.29.49-.26a2,2,0,0,1,.22.63A1.31,1.31,0,0,0,4,9.34a5.62,5.62,0,0,0,2.27-.87L7,8l.13.55c.19.74.32.82,1,.65a7.06,7.06,0,0,0,3.46-2.47l.6-.71-.06.64c-.17,1.63-1.3,3.42-3.39,5.42L6.73,14c-3.21,3.06-3,5.59.6,8a46.77,46.77,0,0,0,4.6,2.41c.28.13,1,.52,1.59.87,3.31,2,4.95,3.92,4.95,5.93a2.49,2.49,0,0,0,.07.77h0c.09.09,0,.1.9-.14a2.61,2.61,0,0,0,.83-.32,3.69,3.69,0,0,0-.55-1.83A11.14,11.14,0,0,0,17,26.81a35.7,35.7,0,0,0-5.1-2.91C9.37,22.64,8.38,22,7.52,21.17a3.53,3.53,0,0,1-1.18-2.48c0-1.38.71-2.58,2.5-4.23,2.84-2.6,3.92-3.91,4.67-5.65a3.64,3.64,0,0,0,.42-2A3.37,3.37,0,0,0,13.61,5l-.32-.74.29-.48c.17-.27.37-.63.46-.8l.15-.3.44.64a5.92,5.92,0,0,1,1,2.81,5.86,5.86,0,0,1-.42,1.94c0,.12-.12.3-.15.4a9.49,9.49,0,0,1-.67,1.1,28,28,0,0,1-4,4.29C8.62,15.49,8.05,16.44,8,17.78a3.28,3.28,0,0,0,1.11,2.76c.95,1,2.07,1.74,5.25,3.32,3.64,1.82,5.22,2.9,6.41,4.38A4.78,4.78,0,0,1,21.94,31a3.21,3.21,0,0,0,.14.92,1.06,1.06,0,0,0,.43-.05l.83-.22.46-.12-.06-.46c-.21-1.53-1.62-3.25-3.94-4.8a37.57,37.57,0,0,0-5.22-2.82A13.36,13.36,0,0,1,11,21.19a3.36,3.36,0,0,1-.8-4.19c.41-.85.83-1.31,3.77-4.15,2.39-2.31,3.43-4.13,3.43-6a5.85,5.85,0,0,0-2.08-4.29c-.23-.21-.44-.43-.65-.65A2.5,2.5,0,0,1,15.27.69a10.6,10.6,0,0,1,2.91,2.78A4.16,4.16,0,0,1,19,6.16a4.91,4.91,0,0,1-.87,3c-.71,1.22-1.26,1.82-4.27,4.67a9.47,9.47,0,0,0-2.07,2.6,2.76,2.76,0,0,0-.33,1.54,2.76,2.76,0,0,0,.29,1.47c.57,1.21,2.23,2.55,4.65,3.73a32.41,32.41,0,0,1,5.82,3.24c2.16,1.6,3.2,3.16,3.2,4.8a1.94,1.94,0,0,0,.09.76,4.54,4.54,0,0,0,1.66-.4C27.29,31.42,27.29,31.37,27.14,30.86ZM6.1,7h0a3.77,3.77,0,0,1-1.46.45L4,7.51l.68-.83a25.09,25.09,0,0,0,3-4.82A12,12,0,0,1,8.28.76c.11-.12.77.32,1.53,1l.63.58-.57.84A10.34,10.34,0,0,1,6.1,7Zm5.71-1.78A9.77,9.77,0,0,1,9.24,7.18h0a5.25,5.25,0,0,1-1.17.28l-.58,0,.65-.78a21.29,21.29,0,0,0,2.1-3.12c.22-.41.42-.76.44-.79s.5.43.9,1.24L12,5ZM13.41,3a2.84,2.84,0,0,1-.45.64,11,11,0,0,1-.9-.91l-.84-.9.19-.45c.34-.79.39-.8,1-.31A9.4,9.4,0,0,1,13.8,2.33q-.18.34-.39.69Z" />
|
||||
</svg>
|
||||
<div class="grid">
|
||||
<h4>RanchiMall Exchange</h4>
|
||||
<div class="app-name">
|
||||
<div class="app-name__company">RanchiMall</div>
|
||||
<h4 class="app-name__title">
|
||||
Exchange
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<theme-toggle id="theme_toggle"></theme-toggle>
|
||||
@ -1814,6 +1817,7 @@
|
||||
return parseFloat(match[0]);
|
||||
}
|
||||
|
||||
|
||||
function getSuggestedPrice(asset = pagesData.params.asset || 'FLO') {
|
||||
return toFixed(parseFloat(floGlobals.exchangeRates[asset]) * deviation[tradeType])
|
||||
}
|
||||
@ -2718,10 +2722,10 @@
|
||||
getRef('market_asset_rates').append(createElement('li', {
|
||||
className: 'listed-asset grid align-center',
|
||||
innerHTML: `
|
||||
<div class="listed-asset__icon">${getIcon(asset)}</div>
|
||||
<h4 class="listed-asset__name">${asset}</h4>
|
||||
<b class="listed-asset__rate">${formatAmount(rate)}</b>
|
||||
`
|
||||
<div class="listed-asset__icon">${getIcon(asset)}</div>
|
||||
<h4 class="listed-asset__name">${asset}</h4>
|
||||
<b class="listed-asset__rate">${formatAmount(rate)}</b>
|
||||
`
|
||||
}))
|
||||
})
|
||||
resolve();
|
||||
@ -2786,7 +2790,7 @@
|
||||
if (refreshButton)
|
||||
buttonLoader('portfolio_balance_refresh_button', false);
|
||||
}
|
||||
})
|
||||
}).catch(error => console.error(error))
|
||||
}
|
||||
|
||||
let accountDetails = {}
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
(function (EXPORTS) { //btcOperator v1.1.1
|
||||
(function (EXPORTS) { //btcOperator v1.1.3b
|
||||
/* BTC Crypto and API Operator */
|
||||
const btcOperator = EXPORTS;
|
||||
|
||||
//This library uses API provided by chain.so (https://chain.so/)
|
||||
const URL = "https://blockchain.info/";
|
||||
|
||||
const DUST_AMT = 546,
|
||||
MIN_FEE_UPDATE = 219;
|
||||
|
||||
const fetch_api = btcOperator.fetch = function (api, json_res = true) {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.debug(URL + api);
|
||||
@ -130,50 +133,84 @@
|
||||
return coinjs.pubkeys2MultisigAddress(pubKeys, minRequired);
|
||||
}
|
||||
|
||||
btcOperator.decodeRedeemScript = function (redeemScript, bech32 = true) {
|
||||
let script = coinjs.script();
|
||||
let decoded = (bech32) ?
|
||||
script.decodeRedeemScriptBech32(redeemScript) :
|
||||
script.decodeRedeemScript(redeemScript);
|
||||
if (!decoded)
|
||||
return null;
|
||||
return {
|
||||
address: decoded.address,
|
||||
pubKeys: decoded.pubkeys,
|
||||
redeemScript: decoded.redeemscript,
|
||||
required: decoded.signaturesRequired
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//convert from one blockchain to another blockchain (target version)
|
||||
btcOperator.convert = {};
|
||||
|
||||
btcOperator.convert.wif = function (source_wif, target_version = coinjs.priv) {
|
||||
let keyHex = decodeLegacy(source_wif).hex;
|
||||
let keyHex = util.decodeLegacy(source_wif).hex;
|
||||
if (!keyHex || keyHex.length < 66 || !/01$/.test(keyHex))
|
||||
return null;
|
||||
else
|
||||
return encodeLegacy(keyHex, target_version);
|
||||
return util.encodeLegacy(keyHex, target_version);
|
||||
}
|
||||
|
||||
btcOperator.convert.legacy2legacy = function (source_addr, target_version = coinjs.pub) {
|
||||
let rawHex = decodeLegacy(source_addr).hex;
|
||||
let rawHex = util.decodeLegacy(source_addr).hex;
|
||||
if (!rawHex)
|
||||
return null;
|
||||
else
|
||||
return encodeLegacy(rawHex, target_version);
|
||||
return util.encodeLegacy(rawHex, target_version);
|
||||
}
|
||||
|
||||
btcOperator.convert.legacy2bech = function (source_addr, target_version = coinjs.bech32.version, target_hrp = coinjs.bech32.hrp) {
|
||||
let rawHex = decodeLegacy(source_addr).hex;
|
||||
let rawHex = util.decodeLegacy(source_addr).hex;
|
||||
if (!rawHex)
|
||||
return null;
|
||||
else
|
||||
return encodeBech32(rawHex, target_version, target_hrp);
|
||||
return util.encodeBech32(rawHex, target_version, target_hrp);
|
||||
}
|
||||
|
||||
btcOperator.convert.bech2bech = function (source_addr, target_version = coinjs.bech32.version, target_hrp = coinjs.bech32.hrp) {
|
||||
let rawHex = decodeBech32(source_addr).hex;
|
||||
let rawHex = util.decodeBech32(source_addr).hex;
|
||||
if (!rawHex)
|
||||
return null;
|
||||
else
|
||||
return encodeBech32(rawHex, target_version, target_hrp);
|
||||
return util.encodeBech32(rawHex, target_version, target_hrp);
|
||||
}
|
||||
|
||||
btcOperator.convert.bech2legacy = function (source_addr, target_version = coinjs.pub) {
|
||||
let rawHex = decodeBech32(source_addr).hex;
|
||||
let rawHex = util.decodeBech32(source_addr).hex;
|
||||
if (!rawHex)
|
||||
return null;
|
||||
else
|
||||
return encodeLegacy(rawHex, target_version);
|
||||
return util.encodeLegacy(rawHex, target_version);
|
||||
}
|
||||
|
||||
function decodeLegacy(source) {
|
||||
btcOperator.convert.multisig2multisig = function (source_addr, target_version = coinjs.multisig) {
|
||||
let rawHex = util.decodeLegacy(source_addr).hex;
|
||||
if (!rawHex)
|
||||
return null;
|
||||
else
|
||||
return util.encodeLegacy(rawHex, target_version);
|
||||
}
|
||||
|
||||
btcOperator.convert.bech2multisig = function (source_addr, target_version = coinjs.multisig) {
|
||||
let rawHex = util.decodeBech32(source_addr).hex;
|
||||
if (!rawHex)
|
||||
return null;
|
||||
else {
|
||||
rawHex = Crypto.util.bytesToHex(ripemd160(Crypto.util.hexToBytes(rawHex), { asBytes: true }));
|
||||
return util.encodeLegacy(rawHex, target_version);
|
||||
}
|
||||
}
|
||||
|
||||
util.decodeLegacy = function (source) {
|
||||
var decode = coinjs.base58decode(source);
|
||||
var raw = decode.slice(0, decode.length - 4),
|
||||
checksum = decode.slice(decode.length - 4);
|
||||
@ -183,7 +220,7 @@
|
||||
asBytes: true
|
||||
});
|
||||
if (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3])
|
||||
return null;
|
||||
return false;
|
||||
let version = raw.shift();
|
||||
return {
|
||||
version: version,
|
||||
@ -191,7 +228,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function encodeLegacy(hex, version) {
|
||||
util.encodeLegacy = function (hex, version) {
|
||||
var bytes = Crypto.util.hexToBytes(hex);
|
||||
bytes.unshift(version);
|
||||
var hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||
@ -203,10 +240,10 @@
|
||||
return coinjs.base58encode(bytes.concat(checksum));
|
||||
}
|
||||
|
||||
function decodeBech32(source) {
|
||||
util.decodeBech32 = function (source) {
|
||||
let decode = coinjs.bech32_decode(source);
|
||||
if (!decode)
|
||||
return null;
|
||||
return false;
|
||||
var raw = decode.data;
|
||||
let version = raw.shift();
|
||||
raw = coinjs.bech32_convert(raw, 5, 8, false);
|
||||
@ -217,7 +254,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function encodeBech32(hex, version, hrp) {
|
||||
util.encodeBech32 = function (hex, version, hrp) {
|
||||
var bytes = Crypto.util.hexToBytes(hex);
|
||||
bytes = coinjs.bech32_convert(bytes, 8, 5, true);
|
||||
bytes.unshift(version)
|
||||
@ -366,7 +403,12 @@
|
||||
return reject("Send amount is less than fee");
|
||||
|
||||
}
|
||||
tx.outs = tx.outs.filter(o => o.value != 0); //remove all output with value 0
|
||||
//remove all output with value less than DUST amount
|
||||
let filtered_outputs = [], dust_value = 0;
|
||||
tx.outs.forEach(o => o.value >= DUST_AMT ? filtered_outputs.push(o) : dust_value += o.value);
|
||||
tx.outs = filtered_outputs;
|
||||
//update result values
|
||||
result.fee += util.Sat_to_BTC(dust_value);
|
||||
result.output_size = output_size;
|
||||
result.output_amount = total_amount - (fee_from_receiver ? result.fee : 0);
|
||||
result.total_size = BASE_TX_SIZE + output_size + result.input_size;
|
||||
@ -422,7 +464,7 @@
|
||||
let size_per_input = _sizePerInput(addr, rs);
|
||||
fetch_api(`unspent?active=${addr}`).then(result => {
|
||||
let utxos = result.unspent_outputs;
|
||||
console.debug("add-utxo", addr, rs, required_amount, utxos);
|
||||
//console.debug("add-utxo", addr, rs, required_amount, utxos);
|
||||
for (let i = 0; i < utxos.length && required_amount > 0; i++) {
|
||||
if (!utxos[i].confirmations) //ignore unconfirmed utxo
|
||||
continue;
|
||||
@ -502,6 +544,106 @@
|
||||
}
|
||||
*/
|
||||
|
||||
function tx_fetch_for_editing(tx) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof tx == 'string' && /^[0-9a-f]{64}$/i.test(tx)) { //tx is txid
|
||||
getTx.hex(tx)
|
||||
.then(txhex => resolve(deserializeTx(txhex)))
|
||||
.catch(error => reject(error))
|
||||
} else resolve(deserializeTx(tx));
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
btcOperator.editFee = function (tx_hex, new_fee, private_keys, change_only = true) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!Array.isArray(private_keys))
|
||||
private_keys = [private_keys];
|
||||
tx_fetch_for_editing(tx_hex).then(tx => {
|
||||
parseTransaction(tx).then(tx_parsed => {
|
||||
if (tx_parsed.fee >= new_fee)
|
||||
return reject("Fees can only be increased");
|
||||
|
||||
//editable addresses in output values (for fee increase)
|
||||
var edit_output_address = new Set();
|
||||
if (change_only === true) //allow only change values (ie, sender address) to be edited to inc fee
|
||||
tx_parsed.inputs.forEach(inp => edit_output_address.add(inp.address));
|
||||
else if (change_only === false) //allow all output values to be edited
|
||||
tx_parsed.outputs.forEach(out => edit_output_address.add(out.address));
|
||||
else if (typeof change_only == 'string') // allow only given receiver id output to be edited
|
||||
edit_output_address.add(change_only);
|
||||
else if (Array.isArray(change_only)) //allow only given set of receiver id outputs to be edited
|
||||
change_only.forEach(id => edit_output_address.add(id));
|
||||
|
||||
//edit output values to increase fee
|
||||
let inc_fee = util.BTC_to_Sat(new_fee - tx_parsed.fee);
|
||||
if (inc_fee < MIN_FEE_UPDATE)
|
||||
return reject(`Insufficient additional fee. Minimum increment: ${MIN_FEE_UPDATE}`);
|
||||
for (let i = tx.outs.length - 1; i >= 0 && inc_fee > 0; i--) //reduce in reverse order
|
||||
if (edit_output_address.has(tx_parsed.outputs[i].address)) {
|
||||
let current_value = tx.outs[i].value;
|
||||
if (current_value instanceof BigInteger) //convert BigInteger class to inv value
|
||||
current_value = current_value.intValue();
|
||||
//edit the value as required
|
||||
if (current_value > inc_fee) {
|
||||
tx.outs[i].value = current_value - inc_fee;
|
||||
inc_fee = 0;
|
||||
} else {
|
||||
inc_fee -= current_value;
|
||||
tx.outs[i].value = 0;
|
||||
}
|
||||
}
|
||||
if (inc_fee > 0) {
|
||||
let max_possible_fee = util.BTC_to_Sat(new_fee) - inc_fee; //in satoshi
|
||||
return reject(`Insufficient output values to increase fee. Maximum fee possible: ${util.Sat_to_BTC(max_possible_fee)}`);
|
||||
}
|
||||
tx.outs = tx.outs.filter(o => o.value >= DUST_AMT); //remove all output with value less than DUST amount
|
||||
|
||||
//remove existing signatures and reset the scripts
|
||||
let wif_keys = [];
|
||||
for (let i in tx.ins) {
|
||||
var addr = tx_parsed.inputs[i].address,
|
||||
value = util.BTC_to_Sat(tx_parsed.inputs[i].value);
|
||||
let addr_decode = coinjs.addressDecode(addr);
|
||||
//find the correct key for addr
|
||||
var privKey = private_keys.find(pk => verifyKey(addr, pk));
|
||||
if (!privKey)
|
||||
return reject(`Private key missing for ${addr}`);
|
||||
//find redeemScript (if any)
|
||||
const rs = _redeemScript(addr, privKey);
|
||||
rs === false ? wif_keys.unshift(privKey) : wif_keys.push(privKey); //sorting private-keys (wif)
|
||||
//reset the script for re-signing
|
||||
var script;
|
||||
if (!rs || !rs.length) {
|
||||
//legacy script (derive from address)
|
||||
let s = coinjs.script();
|
||||
s.writeOp(118); //OP_DUP
|
||||
s.writeOp(169); //OP_HASH160
|
||||
s.writeBytes(addr_decode.bytes);
|
||||
s.writeOp(136); //OP_EQUALVERIFY
|
||||
s.writeOp(172); //OP_CHECKSIG
|
||||
script = Crypto.util.bytesToHex(s.buffer);
|
||||
} else if (((rs.match(/^00/) && rs.length == 44)) || (rs.length == 40 && rs.match(/^[a-f0-9]+$/gi)) || addr_decode.type === 'multisigBech32') {
|
||||
//redeemScript for segwit/bech32 and multisig (bech32)
|
||||
let s = coinjs.script();
|
||||
s.writeBytes(Crypto.util.hexToBytes(rs));
|
||||
s.writeOp(0);
|
||||
s.writeBytes(coinjs.numToBytes(value.toFixed(0), 8));
|
||||
script = Crypto.util.bytesToHex(s.buffer);
|
||||
} else //redeemScript for multisig (segwit)
|
||||
script = rs;
|
||||
tx.ins[i].script = coinjs.script(script);
|
||||
}
|
||||
tx.witness = false; //remove all witness signatures
|
||||
console.debug("Unsigned:", tx.serialize());
|
||||
//re-sign the transaction
|
||||
new Set(wif_keys).forEach(key => tx.sign(key, 1 /*sighashtype*/)); //Sign the tx using private key WIF
|
||||
resolve(tx.serialize());
|
||||
}).catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
btcOperator.sendTx = function (senders, privkeys, receivers, amounts, fee = null, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
createSignedTx(senders, privkeys, receivers, amounts, fee, options).then(result => {
|
||||
@ -545,7 +687,7 @@
|
||||
createTransaction(senders, redeemScripts, receivers, amounts, fee, options.change_address || senders[0], options.fee_from_receiver).then(result => {
|
||||
let tx = result.transaction;
|
||||
console.debug("Unsigned:", tx.serialize());
|
||||
new Set(wif_keys).forEach(key => console.debug("Signing key:", key, tx.sign(key, 1 /*sighashtype*/))); //Sign the tx using private key WIF
|
||||
new Set(wif_keys).forEach(key => tx.sign(key, 1 /*sighashtype*/)); //Sign the tx using private key WIF
|
||||
console.debug("Signed:", tx.serialize());
|
||||
resolve(result);
|
||||
}).catch(error => reject(error));
|
||||
@ -669,12 +811,15 @@
|
||||
btcOperator.checkIfSameTx = function (tx1, tx2) {
|
||||
tx1 = deserializeTx(tx1);
|
||||
tx2 = deserializeTx(tx2);
|
||||
//compare input and output length
|
||||
if (tx1.ins.length !== tx2.ins.length || tx1.outs.length !== tx2.outs.length)
|
||||
return false;
|
||||
//compare inputs
|
||||
for (let i = 0; i < tx1.ins.length; i++)
|
||||
if (tx1.ins[i].outpoint.hash !== tx2.ins[i].outpoint.hash || tx1.ins[i].outpoint.index !== tx2.ins[i].outpoint.index)
|
||||
return false;
|
||||
for (let i = 0; i < tx2.ins.length; i++)
|
||||
//compare outputs
|
||||
for (let i = 0; i < tx1.outs.length; i++)
|
||||
if (tx1.outs[i].value !== tx2.outs[i].value || Crypto.util.bytesToHex(tx1.outs[i].script.buffer) !== Crypto.util.bytesToHex(tx2.outs[i].script.buffer))
|
||||
return false;
|
||||
return true;
|
||||
@ -686,7 +831,7 @@
|
||||
.catch(error => reject(error))
|
||||
});
|
||||
|
||||
btcOperator.parseTransaction = function (tx) {
|
||||
const parseTransaction = btcOperator.parseTransaction = function (tx) {
|
||||
return new Promise((resolve, reject) => {
|
||||
tx = deserializeTx(tx);
|
||||
let result = {};
|
||||
@ -706,13 +851,13 @@
|
||||
var address;
|
||||
switch (out.script.chunks[0]) {
|
||||
case 0: //bech32, multisig-bech32
|
||||
address = encodeBech32(Crypto.util.bytesToHex(out.script.chunks[1]), coinjs.bech32.version, coinjs.bech32.hrp);
|
||||
address = util.encodeBech32(Crypto.util.bytesToHex(out.script.chunks[1]), coinjs.bech32.version, coinjs.bech32.hrp);
|
||||
break;
|
||||
case 169: //segwit, multisig-segwit
|
||||
address = encodeLegacy(Crypto.util.bytesToHex(out.script.chunks[1]), coinjs.multisig);
|
||||
address = util.encodeLegacy(Crypto.util.bytesToHex(out.script.chunks[1]), coinjs.multisig);
|
||||
break;
|
||||
case 118: //legacy
|
||||
address = encodeLegacy(Crypto.util.bytesToHex(out.script.chunks[2]), coinjs.pub);
|
||||
address = util.encodeLegacy(Crypto.util.bytesToHex(out.script.chunks[2]), coinjs.pub);
|
||||
}
|
||||
return {
|
||||
address,
|
||||
@ -743,7 +888,7 @@
|
||||
.catch(error => reject(error))
|
||||
})
|
||||
|
||||
btcOperator.getTx = txid => new Promise((resolve, reject) => {
|
||||
const getTx = btcOperator.getTx = txid => new Promise((resolve, reject) => {
|
||||
fetch_api(`rawtx/${txid}`).then(result => {
|
||||
getLatestBlock().then(latest_block => resolve({
|
||||
block: result.block_height,
|
||||
@ -760,7 +905,7 @@
|
||||
}).catch(error => reject(error))
|
||||
});
|
||||
|
||||
btcOperator.getTx.hex = txid => new Promise((resolve, reject) => {
|
||||
getTx.hex = txid => new Promise((resolve, reject) => {
|
||||
fetch_api(`rawtx/${txid}?format=hex`, false)
|
||||
.then(result => resolve(result))
|
||||
.catch(error => reject(error))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
(function (EXPORTS) { //floCrypto v2.3.3e
|
||||
(function (EXPORTS) { //floCrypto v2.3.6a
|
||||
/* FLO Crypto Operators */
|
||||
'use strict';
|
||||
const floCrypto = EXPORTS;
|
||||
@ -152,6 +152,19 @@
|
||||
newID: {
|
||||
get: () => generateNewID()
|
||||
},
|
||||
hashID: {
|
||||
value: (str) => {
|
||||
let bytes = ripemd160(Crypto.SHA256(str, { asBytes: true }), { asBytes: true });
|
||||
bytes.unshift(bitjs.pub);
|
||||
var hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||
asBytes: true
|
||||
}), {
|
||||
asBytes: true
|
||||
});
|
||||
var checksum = hash.slice(0, 4);
|
||||
return bitjs.Base58.encode(bytes.concat(checksum));
|
||||
}
|
||||
},
|
||||
tmpID: {
|
||||
get: () => {
|
||||
let bytes = Crypto.util.randomBytes(20);
|
||||
@ -222,7 +235,7 @@
|
||||
key.setCompressed(true);
|
||||
if (isfloID && pubKey_floID == key.getBitcoinAddress())
|
||||
return true;
|
||||
else if (!isfloID && pubKey_floID == key.getPubKeyHex())
|
||||
else if (!isfloID && pubKey_floID.toUpperCase() == key.getPubKeyHex().toUpperCase())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -231,12 +244,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
floCrypto.getMultisigAddress = function (publicKeyList, requiredSignatures) {
|
||||
if (!Array.isArray(publicKeyList) || !publicKeyList.length)
|
||||
return null;
|
||||
if (!Number.isInteger(requiredSignatures) || requiredSignatures < 1 || requiredSignatures > publicKeyList.length)
|
||||
return null;
|
||||
try {
|
||||
var multisig = bitjs.pubkeys2multisig(publicKeyList, requiredSignatures);
|
||||
return multisig;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
floCrypto.decodeRedeemScript = function (redeemScript) {
|
||||
try {
|
||||
var decoded = bitjs.transaction().decodeRedeemScript(redeemScript);
|
||||
return decoded;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Check if the given flo-id is valid or not
|
||||
floCrypto.validateFloID = function (floID) {
|
||||
floCrypto.validateFloID = function (floID, regularOnly = false) {
|
||||
if (!floID)
|
||||
return false;
|
||||
try {
|
||||
let addr = new Bitcoin.Address(floID);
|
||||
if (regularOnly && addr.version != Bitcoin.Address.standardVersion)
|
||||
return false;
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
@ -266,13 +303,15 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check the public-key for the address (any blockchain)
|
||||
//Check the public-key (or redeem-script) for the address (any blockchain)
|
||||
floCrypto.verifyPubKey = function (pubKeyHex, address) {
|
||||
let raw = decodeAddress(address),
|
||||
pub_hash = Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex), {
|
||||
asBytes: true
|
||||
})));
|
||||
return raw ? pub_hash === raw.hex : false;
|
||||
let raw = decodeAddress(address);
|
||||
if (!raw)
|
||||
return;
|
||||
let pub_hash = Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex), { asBytes: true })));
|
||||
if (typeof raw.bech_version !== 'undefined' && raw.bytes.length == 32) //bech32-multisig
|
||||
raw.hex = Crypto.util.bytesToHex(ripemd160(raw.bytes, { asBytes: true }));
|
||||
return pub_hash === raw.hex;
|
||||
}
|
||||
|
||||
//Convert the given address (any blockchain) to equivalent floID
|
||||
@ -282,7 +321,7 @@
|
||||
let raw = decodeAddress(address);
|
||||
if (!raw)
|
||||
return;
|
||||
else if (options) {
|
||||
else if (options) { //if (optional) version check is passed
|
||||
if (typeof raw.version !== 'undefined' && (!options.std || !options.std.includes(raw.version)))
|
||||
return;
|
||||
if (typeof raw.bech_version !== 'undefined' && (!options.bech || !options.bech.includes(raw.bech_version)))
|
||||
@ -297,6 +336,50 @@
|
||||
return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0, 4)));
|
||||
}
|
||||
|
||||
//Convert raw address bytes to floID
|
||||
floCrypto.rawToFloID = function (raw_bytes) {
|
||||
if (typeof raw_bytes === 'string')
|
||||
raw_bytes = Crypto.util.hexToBytes(raw_bytes);
|
||||
if (raw_bytes.length != 20)
|
||||
return null;
|
||||
raw_bytes.unshift(bitjs.pub);
|
||||
let hash = Crypto.SHA256(Crypto.SHA256(raw_bytes, {
|
||||
asBytes: true
|
||||
}), {
|
||||
asBytes: true
|
||||
});
|
||||
return bitjs.Base58.encode(raw_bytes.concat(hash.slice(0, 4)));
|
||||
}
|
||||
|
||||
//Convert the given multisig address (any blockchain) to equivalent multisig floID
|
||||
floCrypto.toMultisigFloID = function (address, options = null) {
|
||||
if (!address)
|
||||
return;
|
||||
let raw = decodeAddress(address);
|
||||
if (!raw)
|
||||
return;
|
||||
else if (options) { //if (optional) version check is passed
|
||||
if (typeof raw.version !== 'undefined' && (!options.std || !options.std.includes(raw.version)))
|
||||
return;
|
||||
if (typeof raw.bech_version !== 'undefined' && (!options.bech || !options.bech.includes(raw.bech_version)))
|
||||
return;
|
||||
}
|
||||
if (typeof raw.bech_version !== 'undefined') {
|
||||
if (raw.bytes.length != 32) return; //multisig bech address have 32 bytes
|
||||
//multisig-bech:hash=SHA256 whereas multisig:hash=r160(SHA265), thus ripemd160 the bytes from multisig-bech
|
||||
raw.bytes = ripemd160(raw.bytes, {
|
||||
asBytes: true
|
||||
});
|
||||
}
|
||||
raw.bytes.unshift(bitjs.multisig);
|
||||
let hash = Crypto.SHA256(Crypto.SHA256(raw.bytes, {
|
||||
asBytes: true
|
||||
}), {
|
||||
asBytes: true
|
||||
});
|
||||
return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0, 4)));
|
||||
}
|
||||
|
||||
//Checks if the given addresses (any blockchain) are same (w.r.t keys)
|
||||
floCrypto.isSameAddr = function (addr1, addr2) {
|
||||
if (!addr1 || !addr2)
|
||||
@ -305,8 +388,13 @@
|
||||
raw2 = decodeAddress(addr2);
|
||||
if (!raw1 || !raw2)
|
||||
return false;
|
||||
else
|
||||
else {
|
||||
if (typeof raw1.bech_version !== 'undefined' && raw1.bytes.length == 32) //bech32-multisig
|
||||
raw1.hex = Crypto.util.bytesToHex(ripemd160(raw1.bytes, { asBytes: true }));
|
||||
if (typeof raw2.bech_version !== 'undefined' && raw2.bytes.length == 32) //bech32-multisig
|
||||
raw2.hex = Crypto.util.bytesToHex(ripemd160(raw2.bytes, { asBytes: true }));
|
||||
return raw1.hex === raw2.hex;
|
||||
}
|
||||
}
|
||||
|
||||
const decodeAddress = floCrypto.decodeAddr = function (address) {
|
||||
@ -326,7 +414,7 @@
|
||||
hex: Crypto.util.bytesToHex(bytes),
|
||||
bytes
|
||||
}
|
||||
} else if (address.length == 42) { //bech encoding
|
||||
} else if (address.length == 42 || address.length == 62) { //bech encoding
|
||||
let decode = coinjs.bech32_decode(address);
|
||||
if (decode) {
|
||||
let bytes = decode.data;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
(function (EXPORTS) { //floExchangeAPI v1.2.0
|
||||
(function (EXPORTS) { //floExchangeAPI v1.2.0a
|
||||
const exchangeAPI = EXPORTS;
|
||||
|
||||
const DEFAULT = {
|
||||
@ -1731,19 +1731,20 @@
|
||||
if (typeof nodes !== 'object' || nodes === null)
|
||||
throw Error('nodes must be an object')
|
||||
else
|
||||
lastTx = parseInt(localStorage.getItem(_l('lastTx'))) || 0;
|
||||
lastTx = localStorage.getItem(_l('lastTx'));
|
||||
} catch (error) {
|
||||
nodes = {};
|
||||
trusted = new Set();
|
||||
assets = new Set();
|
||||
tags = new Set();
|
||||
lastTx = 0;
|
||||
}
|
||||
floBlockchainAPI.readData(DEFAULT.marketID, {
|
||||
ignoreOld: lastTx,
|
||||
sentOnly: true,
|
||||
pattern: DEFAULT.marketApp
|
||||
}).then(result => {
|
||||
|
||||
var query_options = { sentOnly: true, pattern: DEFAULT.marketApp };
|
||||
if (typeof lastTx == 'string' && /^[0-9a-f]{64}/i.test(lastTx))//lastTx is txid of last tx
|
||||
query_options.after = lastTx;
|
||||
else if (!isNaN(lastTx))//lastTx is tx count (*backward support)
|
||||
query_options.ignoreOld = parseInt(lastTx);
|
||||
floBlockchainAPI.readData(DEFAULT.marketID, query_options).then(result => {
|
||||
result.data.reverse().forEach(data => {
|
||||
var content = JSON.parse(data)[DEFAULT.marketApp];
|
||||
//Node List
|
||||
@ -1782,7 +1783,7 @@
|
||||
tags.add(t);
|
||||
}
|
||||
});
|
||||
localStorage.setItem(_l('lastTx'), result.totalTxs);
|
||||
localStorage.setItem(_l('lastTx'), result.lastItem);
|
||||
localStorage.setItem(_l('nodes'), JSON.stringify(nodes));
|
||||
localStorage.setItem(_l('trusted'), Array.from(trusted).join(","));
|
||||
localStorage.setItem(_l('assets'), Array.from(assets).join(","));
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
(function(EXPORTS) { //floTokenAPI v1.0.3c
|
||||
(function (EXPORTS) { //floTokenAPI v1.0.4a
|
||||
/* Token Operator to send/receive tokens via blockchain using API calls*/
|
||||
'use strict';
|
||||
const tokenAPI = EXPORTS;
|
||||
|
||||
const DEFAULT = {
|
||||
apiURL: floGlobals.tokenURL || "https://ranchimallflo.duckdns.org/",
|
||||
currency: "rupee"
|
||||
currency: floGlobals.currency || "rupee"
|
||||
}
|
||||
|
||||
Object.defineProperties(tokenAPI, {
|
||||
@ -27,7 +27,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
const fetch_api = tokenAPI.fetch = function(apicall) {
|
||||
const fetch_api = tokenAPI.fetch = function (apicall) {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.debug(DEFAULT.apiURL + apicall);
|
||||
fetch(DEFAULT.apiURL + apicall).then(response => {
|
||||
@ -39,7 +39,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
const getBalance = tokenAPI.getBalance = function(floID, token = DEFAULT.currency) {
|
||||
const getBalance = tokenAPI.getBalance = function (floID, token = DEFAULT.currency) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`)
|
||||
.then(result => resolve(result.balance || 0))
|
||||
@ -47,7 +47,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
tokenAPI.getTx = function(txID) {
|
||||
tokenAPI.getTx = function (txID) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch_api(`api/v1.0/getTransactionDetails/${txID}`).then(res => {
|
||||
if (res.result === "error")
|
||||
@ -62,7 +62,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
tokenAPI.sendToken = function(privKey, amount, receiverID, message = "", token = DEFAULT.currency, options = {}) {
|
||||
tokenAPI.sendToken = function (privKey, amount, receiverID, message = "", token = DEFAULT.currency, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let senderID = floCrypto.getFloID(privKey);
|
||||
if (typeof amount !== "number" || isNaN(amount) || amount <= 0)
|
||||
@ -77,7 +77,71 @@
|
||||
});
|
||||
}
|
||||
|
||||
tokenAPI.getAllTxs = function(floID, token = DEFAULT.currency) {
|
||||
function sendTokens_raw(privKey, receiverID, token, amount, utxo, vout, scriptPubKey) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var trx = bitjs.transaction();
|
||||
trx.addinput(utxo, vout, scriptPubKey)
|
||||
trx.addoutput(receiverID, floBlockchainAPI.sendAmt);
|
||||
trx.addflodata(`send ${amount} ${token}#`);
|
||||
var signedTxHash = trx.sign(privKey, 1);
|
||||
floBlockchainAPI.broadcastTx(signedTxHash)
|
||||
.then(txid => resolve([receiverID, txid]))
|
||||
.catch(error => reject([receiverID, error]))
|
||||
})
|
||||
}
|
||||
|
||||
//bulk transfer tokens
|
||||
tokenAPI.bulkTransferTokens = function (sender, privKey, token, receivers) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof receivers !== 'object')
|
||||
return reject("receivers must be object in format {receiver1: amount1, receiver2:amount2...}")
|
||||
|
||||
let receiver_list = Object.keys(receivers), amount_list = Object.values(receivers);
|
||||
let invalidReceivers = receiver_list.filter(id => !floCrypto.validateFloID(id));
|
||||
let invalidAmount = amount_list.filter(val => typeof val !== 'number' || val <= 0);
|
||||
if (invalidReceivers.length)
|
||||
return reject(`Invalid receivers: ${invalidReceivers}`);
|
||||
else if (invalidAmount.length)
|
||||
return reject(`Invalid amounts: ${invalidAmount}`);
|
||||
|
||||
if (receiver_list.length == 0)
|
||||
return reject("Receivers cannot be empty");
|
||||
|
||||
if (receiver_list.length == 1) {
|
||||
let receiver = receiver_list[0], amount = amount_list[0];
|
||||
floTokenAPI.sendToken(privKey, amount, receiver, "", token)
|
||||
.then(txid => resolve({ success: { [receiver]: txid } }))
|
||||
.catch(error => reject(error))
|
||||
} else {
|
||||
//check for token balance
|
||||
floTokenAPI.getBalance(sender, token).then(token_balance => {
|
||||
let total_token_amout = amount_list.reduce((a, e) => a + e, 0);
|
||||
if (total_token_amout > token_balance)
|
||||
return reject(`Insufficient ${token}# balance`);
|
||||
|
||||
//split utxos
|
||||
floBlockchainAPI.splitUTXOs(sender, privKey, receiver_list.length).then(split_txid => {
|
||||
//wait for the split utxo to get confirmation
|
||||
floBlockchainAPI.waitForConfirmation(split_txid).then(split_tx => {
|
||||
//send tokens using the split-utxo
|
||||
var scriptPubKey = split_tx.vout[0].scriptPubKey.hex;
|
||||
let promises = [];
|
||||
for (let i in receiver_list)
|
||||
promises.push(sendTokens_raw(privKey, receiver_list[i], token, amount_list[i], split_txid, i, scriptPubKey));
|
||||
Promise.allSettled(promises).then(results => {
|
||||
let success = Object.fromEntries(results.filter(r => r.status == 'fulfilled').map(r => r.value));
|
||||
let failed = Object.fromEntries(results.filter(r => r.status == 'rejected').map(r => r.reason));
|
||||
resolve({ success, failed });
|
||||
})
|
||||
}).catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
tokenAPI.getAllTxs = function (floID, token = DEFAULT.currency) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch_api(`api/v1.0/getFloAddressTransactions?token=${token}&floAddress=${floID}`)
|
||||
.then(result => resolve(result))
|
||||
@ -87,7 +151,7 @@
|
||||
|
||||
const util = tokenAPI.util = {};
|
||||
|
||||
util.parseTxData = function(txData) {
|
||||
util.parseTxData = function (txData) {
|
||||
let parsedData = {};
|
||||
for (let p in txData.parsedFloData)
|
||||
parsedData[p] = txData.parsedFloData[p];
|
||||
|
||||
1923
docs/scripts/lib.js
1923
docs/scripts/lib.js
File diff suppressed because it is too large
Load Diff
@ -50,7 +50,7 @@ function confirmDepositFLO() {
|
||||
verifyTx.FLO = function (sender, txid, group) {
|
||||
return new Promise((resolve, reject) => {
|
||||
floBlockchainAPI.getTx(txid).then(tx => {
|
||||
let vin_sender = tx.vin.filter(v => v.addr === sender)
|
||||
let vin_sender = tx.vin.filter(v => v.addresses[0] === sender)
|
||||
if (!vin_sender.length)
|
||||
return reject([true, "Transaction not sent by the sender"]);
|
||||
if (vin_sender.length !== tx.vin.length)
|
||||
@ -502,9 +502,10 @@ function processAll() {
|
||||
var lastSyncBlockHeight = 0;
|
||||
|
||||
function periodicProcess() {
|
||||
floBlockchainAPI.promisedAPI('api/blocks?limit=1').then(result => {
|
||||
if (lastSyncBlockHeight < result.blocks[0].height) {
|
||||
lastSyncBlockHeight = result.blocks[0].height;
|
||||
floBlockchainAPI.promisedAPI('api/status').then(result => {
|
||||
let blockbook_height = result.blockbook.bestHeight;
|
||||
if (lastSyncBlockHeight < blockbook_height) {
|
||||
lastSyncBlockHeight = blockbook_height;
|
||||
processAll();
|
||||
console.log("Last Block :", lastSyncBlockHeight);
|
||||
}
|
||||
|
||||
19
src/main.js
19
src/main.js
@ -40,13 +40,16 @@ function refreshData(startup = false) {
|
||||
|
||||
function refreshDataFromBlockchain() {
|
||||
return new Promise((resolve, reject) => {
|
||||
DB.query("SELECT num FROM LastTx WHERE floID=?", [floGlobals.adminID]).then(result => {
|
||||
let lastTx = result.length ? result[0].num : 0;
|
||||
floBlockchainAPI.readData(floGlobals.adminID, {
|
||||
ignoreOld: lastTx,
|
||||
sentOnly: true,
|
||||
pattern: floGlobals.application
|
||||
}).then(result => {
|
||||
DB.query("SELECT txid FROM LastTx WHERE floID=?", [floGlobals.adminID]).then(result => {
|
||||
var query_options = { sentOnly: true, pattern: floGlobals.application };
|
||||
|
||||
let lastTx = result.length ? result[0].txid : undefined;
|
||||
if (typeof lastTx == 'string' && /^[0-9a-f]{64}/i.test(lastTx))//lastTx is txid of last tx
|
||||
query_options.after = lastTx;
|
||||
else if (!isNaN(lastTx))//lastTx is tx count (*backward support)
|
||||
query_options.ignoreOld = parseInt(lastTx);
|
||||
|
||||
floBlockchainAPI.readData(floGlobals.adminID, query_options).then(result => {
|
||||
let promises = [],
|
||||
nodes_change = false,
|
||||
assets_change = false,
|
||||
@ -96,7 +99,7 @@ function refreshDataFromBlockchain() {
|
||||
promises.push(`UPDATE TagList WHERE tag=? SET ${a}=?`, [t, content.Tag.update[t][a]]);
|
||||
}
|
||||
});
|
||||
promises.push(DB.query("INSERT INTO LastTx (floID, num) VALUE (?) ON DUPLICATE KEY UPDATE num=?", [[floGlobals.adminID, result.totalTxs], result.totalTxs]));
|
||||
promises.push(DB.query("INSERT INTO LastTx (floID, txid) VALUE (?) ON DUPLICATE KEY UPDATE txid=?", [[floGlobals.adminID, result.lastItem], result.lastItem]));
|
||||
//Check if all save process were successful
|
||||
Promise.allSettled(promises).then(results => {
|
||||
//console.debug(results.filter(r => r.status === "rejected"));
|
||||
|
||||
@ -203,16 +203,21 @@ bobsFund.config = {
|
||||
|
||||
function refreshBlockchainData(nodeList = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
DB.query("SELECT num FROM LastTx WHERE floID=?", [bobsFund.config.adminID]).then(result => {
|
||||
let lastTx = result.length ? result[0].num : 0;
|
||||
floBlockchainAPI.readData(bobsFund.config.adminID, {
|
||||
ignoreOld: lastTx,
|
||||
senders: nodeList.concat(bobsFund.config.adminID), //sentOnly: true,
|
||||
tx: true,
|
||||
filter: d => d.startsWith(bobsFund.productStr)
|
||||
}).then(result => {
|
||||
DB.query("SELECT txid FROM LastTx WHERE floID=?", [bobsFund.config.adminID]).then(result => {
|
||||
|
||||
var query_options = {
|
||||
senders: nodeList.concat(bobsFund.config.adminID),
|
||||
tx: true, filter: d => d.startsWith(bobsFund.productStr)
|
||||
};
|
||||
let lastTx = result.length ? result[0].txid : undefined;
|
||||
if (typeof lastTx == 'string' && /^[0-9a-f]{64}/i.test(lastTx))//lastTx is txid of last tx
|
||||
query_options.after = lastTx;
|
||||
else if (!isNaN(lastTx))//lastTx is tx count (*backward support)
|
||||
query_options.ignoreOld = parseInt(lastTx);
|
||||
|
||||
floBlockchainAPI.readData(bobsFund.config.adminID, query_options).then(result => {
|
||||
let txQueries = [];
|
||||
result.data.reverse().forEach(d => {
|
||||
result.items.reverse().forEach(d => {
|
||||
let fund = bobsFund.parse(d.data);
|
||||
if (d.senders.has(bobsFund.config.adminID) && !/close:/.test(d.data)) {
|
||||
let fund_id = d.data.match(/continue: [a-z0-9]{64}\|/);
|
||||
@ -221,7 +226,7 @@ function refreshBlockchainData(nodeList = []) {
|
||||
let values = [fund_id, fund.start_date, fund.BTC_base, fund.USD_base, fund.fee, fund.duration];
|
||||
if (fund.tapoutInterval)
|
||||
values.push(fund.topoutWindow, fund.tapoutInterval.join(','));
|
||||
else
|
||||
else
|
||||
values.push(null, null);
|
||||
txQueries.push(["INSERT INTO BobsFund(fund_id, begin_date, btc_base, usd_base, fee, duration, tapout_window, tapout_interval) VALUE (?) ON DUPLICATE KEY UPDATE fund_id=fund_id", [values]])
|
||||
} else
|
||||
@ -240,10 +245,10 @@ function refreshBlockchainData(nodeList = []) {
|
||||
}
|
||||
}
|
||||
});
|
||||
txQueries.push(["INSERT INTO LastTx (floID, num) VALUE (?) ON DUPLICATE KEY UPDATE num=?",
|
||||
[[bobsFund.config.adminID, result.totalTxs], result.totalTxs]])
|
||||
txQueries.push(["INSERT INTO LastTx (floID, txid) VALUE (?) ON DUPLICATE KEY UPDATE txid=?",
|
||||
[[bobsFund.config.adminID, result.lastItem], result.lastItem]])
|
||||
DB.transaction(txQueries)
|
||||
.then(_ => resolve(result.totalTxs))
|
||||
.then(_ => resolve(result.lastItem))
|
||||
.catch(error => reject(["Bobs-Fund refresh data failed!", error]));
|
||||
}).catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
|
||||
@ -186,16 +186,21 @@ blockchainBond.config = {
|
||||
|
||||
function refreshBlockchainData(nodeList = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
DB.query("SELECT num FROM LastTx WHERE floID=?", [blockchainBond.config.adminID]).then(result => {
|
||||
let lastTx = result.length ? result[0].num : 0;
|
||||
floBlockchainAPI.readData(blockchainBond.config.adminID, {
|
||||
ignoreOld: lastTx,
|
||||
senders: nodeList.concat(blockchainBond.config.adminID), //sentOnly: true,
|
||||
tx: true,
|
||||
filter: d => d.startsWith(blockchainBond.productStr)
|
||||
}).then(result => {
|
||||
DB.query("SELECT txid FROM LastTx WHERE floID=?", [blockchainBond.config.adminID]).then(result => {
|
||||
|
||||
var query_options = {
|
||||
senders: nodeList.concat(blockchainBond.config.adminID),
|
||||
tx: true, filter: d => d.startsWith(blockchainBond.productStr)
|
||||
};
|
||||
let lastTx = result.length ? result[0].txid : undefined;
|
||||
if (typeof lastTx == 'string' && /^[0-9a-f]{64}/i.test(lastTx))//lastTx is txid of last tx
|
||||
query_options.after = lastTx;
|
||||
else if (!isNaN(lastTx))//lastTx is tx count (*backward support)
|
||||
query_options.ignoreOld = parseInt(lastTx);
|
||||
|
||||
floBlockchainAPI.readData(blockchainBond.config.adminID, query_options).then(result => {
|
||||
let txQueries = [];
|
||||
result.data.reverse().forEach(d => {
|
||||
result.items.reverse().forEach(d => {
|
||||
let bond = d.senders.has(blockchainBond.config.adminID) ? blockchainBond.parse.main(d.data) : null;
|
||||
if (bond && bond.amount)
|
||||
txQueries.push(["INSERT INTO BlockchainBonds(bond_id, floID, amount_in, begin_date, btc_base, usd_base, gain_cut, min_ipa, max_period, lockin_period) VALUE (?) ON DUPLICATE KEY UPDATE bond_id=bond_id",
|
||||
@ -207,10 +212,10 @@ function refreshBlockchainData(nodeList = []) {
|
||||
[d.txid, details.amountFinal, details.bondID]]);
|
||||
}
|
||||
});
|
||||
txQueries.push(["INSERT INTO LastTx (floID, num) VALUE (?) ON DUPLICATE KEY UPDATE num=?",
|
||||
[[blockchainBond.config.adminID, result.totalTxs], result.totalTxs]])
|
||||
txQueries.push(["INSERT INTO LastTx (floID, txid) VALUE (?) ON DUPLICATE KEY UPDATE txid=?",
|
||||
[[blockchainBond.config.adminID, result.lastItem], result.lastItem]])
|
||||
DB.transaction(txQueries)
|
||||
.then(_ => resolve(result.totalTxs))
|
||||
.then(_ => resolve(result.lastItem))
|
||||
.catch(error => reject(["Blockchain-bonds refresh data failed!", error]));
|
||||
}).catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user