Update floBlockchainAPI.js
This commit is contained in:
parent
09210c14c6
commit
aba6d204ed
@ -1,4 +1,4 @@
|
|||||||
(function (EXPORTS) { //floBlockchainAPI v2.3.3e
|
(function (EXPORTS) { //floBlockchainAPI v2.4.3
|
||||||
/* FLO Blockchain Operator to send/receive data from blockchain using API calls*/
|
/* FLO Blockchain Operator to send/receive data from blockchain using API calls*/
|
||||||
'use strict';
|
'use strict';
|
||||||
const floBlockchainAPI = EXPORTS;
|
const floBlockchainAPI = EXPORTS;
|
||||||
@ -15,6 +15,13 @@
|
|||||||
receiverID: floGlobals.adminID
|
receiverID: floGlobals.adminID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SATOSHI_IN_BTC = 1e8;
|
||||||
|
|
||||||
|
const util = floBlockchainAPI.util = {};
|
||||||
|
|
||||||
|
util.Sat_to_FLO = value => parseFloat((value / SATOSHI_IN_BTC).toFixed(8));
|
||||||
|
util.FLO_to_Sat = value => parseInt(value * SATOSHI_IN_BTC);
|
||||||
|
|
||||||
Object.defineProperties(floBlockchainAPI, {
|
Object.defineProperties(floBlockchainAPI, {
|
||||||
sendAmt: {
|
sendAmt: {
|
||||||
get: () => DEFAULT.sendAmt,
|
get: () => DEFAULT.sendAmt,
|
||||||
@ -121,17 +128,15 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Send Tx to blockchain
|
//create a transaction with single sender
|
||||||
const sendTx = floBlockchainAPI.sendTx = function (senderAddr, receiverAddr, sendAmt, privKey, floData = '', strict_utxo = true) {
|
const createTx = function (senderAddr, receiverAddr, sendAmt, floData = '', strict_utxo = true) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateASCII(floData))
|
if (!floCrypto.validateASCII(floData))
|
||||||
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
||||||
else if (!floCrypto.validateFloID(senderAddr))
|
else if (!floCrypto.validateFloID(senderAddr, true))
|
||||||
return reject(`Invalid address : ${senderAddr}`);
|
return reject(`Invalid address : ${senderAddr}`);
|
||||||
else if (!floCrypto.validateFloID(receiverAddr))
|
else if (!floCrypto.validateFloID(receiverAddr))
|
||||||
return reject(`Invalid address : ${receiverAddr}`);
|
return reject(`Invalid address : ${receiverAddr}`);
|
||||||
else if (privKey.length < 1 || !floCrypto.verifyPrivKey(privKey, senderAddr))
|
|
||||||
return reject("Invalid Private key!");
|
|
||||||
else if (typeof sendAmt !== 'number' || sendAmt <= 0)
|
else if (typeof sendAmt !== 'number' || sendAmt <= 0)
|
||||||
return reject(`Invalid sendAmt : ${sendAmt}`);
|
return reject(`Invalid sendAmt : ${sendAmt}`);
|
||||||
|
|
||||||
@ -175,15 +180,36 @@
|
|||||||
if (change > DEFAULT.minChangeAmt)
|
if (change > DEFAULT.minChangeAmt)
|
||||||
trx.addoutput(senderAddr, change);
|
trx.addoutput(senderAddr, change);
|
||||||
trx.addflodata(floData.replace(/\n/g, ' '));
|
trx.addflodata(floData.replace(/\n/g, ' '));
|
||||||
var signedTxHash = trx.sign(privKey, 1);
|
resolve(trx);
|
||||||
broadcastTx(signedTxHash)
|
|
||||||
.then(txid => resolve(txid))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
}
|
}
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
floBlockchainAPI.createTx = function (senderAddr, receiverAddr, sendAmt, floData = '', strict_utxo = true) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
createTx(senderAddr, receiverAddr, sendAmt, floData, strict_utxo)
|
||||||
|
.then(trx => resolve(trx.serialize()))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send Tx to blockchain
|
||||||
|
const sendTx = floBlockchainAPI.sendTx = function (senderAddr, receiverAddr, sendAmt, privKey, floData = '', strict_utxo = true) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!floCrypto.validateFloID(senderAddr, true))
|
||||||
|
return reject(`Invalid address : ${senderAddr}`);
|
||||||
|
else if (privKey.length < 1 || !floCrypto.verifyPrivKey(privKey, senderAddr))
|
||||||
|
return reject("Invalid Private key!");
|
||||||
|
createTx(senderAddr, receiverAddr, sendAmt, floData, strict_utxo).then(trx => {
|
||||||
|
var signedTxHash = trx.sign(privKey, 1);
|
||||||
|
broadcastTx(signedTxHash)
|
||||||
|
.then(txid => resolve(txid))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +229,7 @@
|
|||||||
//merge all UTXOs of a given floID into a single UTXO
|
//merge all UTXOs of a given floID into a single UTXO
|
||||||
floBlockchainAPI.mergeUTXOs = function (floID, privKey, floData = '') {
|
floBlockchainAPI.mergeUTXOs = function (floID, privKey, floData = '') {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateFloID(floID))
|
if (!floCrypto.validateFloID(floID, true))
|
||||||
return reject(`Invalid floID`);
|
return reject(`Invalid floID`);
|
||||||
if (!floCrypto.verifyPrivKey(privKey, floID))
|
if (!floCrypto.verifyPrivKey(privKey, floID))
|
||||||
return reject("Invalid Private Key");
|
return reject("Invalid Private Key");
|
||||||
@ -381,7 +407,6 @@
|
|||||||
for (let floID in senders)
|
for (let floID in senders)
|
||||||
promises.push(promisedAPI(`api/addr/${floID}/utxo`));
|
promises.push(promisedAPI(`api/addr/${floID}/utxo`));
|
||||||
Promise.all(promises).then(results => {
|
Promise.all(promises).then(results => {
|
||||||
let wifSeq = [];
|
|
||||||
var trx = bitjs.transaction();
|
var trx = bitjs.transaction();
|
||||||
for (let floID in senders) {
|
for (let floID in senders) {
|
||||||
let utxos = results.shift();
|
let utxos = results.shift();
|
||||||
@ -391,13 +416,11 @@
|
|||||||
sendAmt = totalSendAmt * ratio;
|
sendAmt = totalSendAmt * ratio;
|
||||||
} else
|
} else
|
||||||
sendAmt = senders[floID].coins + dividedFee;
|
sendAmt = senders[floID].coins + dividedFee;
|
||||||
let wif = senders[floID].wif;
|
|
||||||
let utxoAmt = 0.0;
|
let utxoAmt = 0.0;
|
||||||
for (let i = utxos.length - 1;
|
for (let i = utxos.length - 1;
|
||||||
(i >= 0) && (utxoAmt < sendAmt); i--) {
|
(i >= 0) && (utxoAmt < sendAmt); i--) {
|
||||||
if (utxos[i].confirmations) {
|
if (utxos[i].confirmations) {
|
||||||
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i].scriptPubKey);
|
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i].scriptPubKey);
|
||||||
wifSeq.push(wif);
|
|
||||||
utxoAmt += utxos[i].amount;
|
utxoAmt += utxos[i].amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -410,8 +433,8 @@
|
|||||||
for (let floID in receivers)
|
for (let floID in receivers)
|
||||||
trx.addoutput(floID, receivers[floID]);
|
trx.addoutput(floID, receivers[floID]);
|
||||||
trx.addflodata(floData.replace(/\n/g, ' '));
|
trx.addflodata(floData.replace(/\n/g, ' '));
|
||||||
for (let i = 0; i < wifSeq.length; i++)
|
for (let floID in senders)
|
||||||
trx.signinput(i, wifSeq[i], 1);
|
trx.sign(senders[floID].wif, 1);
|
||||||
var signedTxHash = trx.serialize();
|
var signedTxHash = trx.serialize();
|
||||||
broadcastTx(signedTxHash)
|
broadcastTx(signedTxHash)
|
||||||
.then(txid => resolve(txid))
|
.then(txid => resolve(txid))
|
||||||
@ -421,6 +444,273 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Create a multisig transaction
|
||||||
|
const createMultisigTx = function (redeemScript, receivers, amounts, floData = '', strict_utxo = true) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var multisig = floCrypto.decodeRedeemScript(redeemScript);
|
||||||
|
|
||||||
|
//validate multisig script and flodata
|
||||||
|
if (!multisig)
|
||||||
|
return reject(`Invalid redeemScript`);
|
||||||
|
var senderAddr = multisig.address;
|
||||||
|
if (!floCrypto.validateFloID(senderAddr))
|
||||||
|
return reject(`Invalid multisig : ${senderAddr}`);
|
||||||
|
else if (!floCrypto.validateASCII(floData))
|
||||||
|
return reject("Invalid FLO_Data: only printable ASCII characters are allowed");
|
||||||
|
//validate receiver addresses
|
||||||
|
if (!Array.isArray(receivers))
|
||||||
|
receivers = [receivers];
|
||||||
|
for (let r of receivers)
|
||||||
|
if (!floCrypto.validateFloID(r))
|
||||||
|
return reject(`Invalid address : ${r}`);
|
||||||
|
//validate amounts
|
||||||
|
if (!Array.isArray(amounts))
|
||||||
|
amounts = [amounts];
|
||||||
|
if (amounts.length != receivers.length)
|
||||||
|
return reject("Receivers and amounts have different length");
|
||||||
|
var sendAmt = 0;
|
||||||
|
for (let a of amounts) {
|
||||||
|
if (typeof a !== 'number' || a <= 0)
|
||||||
|
return reject(`Invalid amount : ${a}`);
|
||||||
|
sendAmt += a;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBalance(senderAddr).then(balance => {
|
||||||
|
var fee = DEFAULT.fee;
|
||||||
|
if (balance < sendAmt + fee)
|
||||||
|
return reject("Insufficient FLO balance!");
|
||||||
|
//get unconfirmed tx list
|
||||||
|
promisedAPI(`api/addr/${senderAddr}`).then(result => {
|
||||||
|
readTxs(senderAddr, 0, result.unconfirmedTxApperances).then(result => {
|
||||||
|
let unconfirmedSpent = {};
|
||||||
|
for (let tx of result.items)
|
||||||
|
if (tx.confirmations == 0)
|
||||||
|
for (let vin of tx.vin)
|
||||||
|
if (vin.addr === senderAddr) {
|
||||||
|
if (Array.isArray(unconfirmedSpent[vin.txid]))
|
||||||
|
unconfirmedSpent[vin.txid].push(vin.vout);
|
||||||
|
else
|
||||||
|
unconfirmedSpent[vin.txid] = [vin.vout];
|
||||||
|
}
|
||||||
|
//get utxos list
|
||||||
|
promisedAPI(`api/addr/${senderAddr}/utxo`).then(utxos => {
|
||||||
|
//form/construct the transaction data
|
||||||
|
var trx = bitjs.transaction();
|
||||||
|
var utxoAmt = 0.0;
|
||||||
|
for (var i = utxos.length - 1;
|
||||||
|
(i >= 0) && (utxoAmt < sendAmt + fee); i--) {
|
||||||
|
//use only utxos with confirmations (strict_utxo mode)
|
||||||
|
if (utxos[i].confirmations || !strict_utxo) {
|
||||||
|
if (utxos[i].txid in unconfirmedSpent && unconfirmedSpent[utxos[i].txid].includes(utxos[i].vout))
|
||||||
|
continue; //A transaction has already used the utxo, but is unconfirmed.
|
||||||
|
trx.addinput(utxos[i].txid, utxos[i].vout, redeemScript); //for multisig, script=redeemScript
|
||||||
|
utxoAmt += utxos[i].amount;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (utxoAmt < sendAmt + fee)
|
||||||
|
reject("Insufficient FLO: Some UTXOs are unconfirmed");
|
||||||
|
else {
|
||||||
|
for (let i in receivers)
|
||||||
|
trx.addoutput(receivers[i], amounts[i]);
|
||||||
|
var change = utxoAmt - sendAmt - fee;
|
||||||
|
if (change > DEFAULT.minChangeAmt)
|
||||||
|
trx.addoutput(senderAddr, change);
|
||||||
|
trx.addflodata(floData.replace(/\n/g, ' '));
|
||||||
|
resolve(trx);
|
||||||
|
}
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Same as above, but explict call should return serialized tx-hex
|
||||||
|
floBlockchainAPI.createMultisigTx = function (redeemScript, receivers, amounts, floData = '', strict_utxo = true) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
createMultisigTx(redeemScript, receivers, amounts, floData, strict_utxo)
|
||||||
|
.then(trx => resolve(trx.serialize()))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create and send multisig transaction
|
||||||
|
const sendMultisigTx = floBlockchainAPI.sendMultisigTx = function (redeemScript, privateKeys, receivers, amounts, floData = '', strict_utxo = true) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var multisig = floCrypto.decodeRedeemScript(redeemScript);
|
||||||
|
if (!multisig)
|
||||||
|
return reject(`Invalid redeemScript`);
|
||||||
|
if (privateKeys.length < multisig.required)
|
||||||
|
return reject(`Insufficient privateKeys (required ${multisig.required})`);
|
||||||
|
for (let pk of privateKeys) {
|
||||||
|
var flag = false;
|
||||||
|
for (let pub of multisig.pubkeys)
|
||||||
|
if (floCrypto.verifyPrivKey(pk, pub, false))
|
||||||
|
flag = true;
|
||||||
|
if (!flag)
|
||||||
|
return reject(`Invalid Private key`);
|
||||||
|
}
|
||||||
|
createMultisigTx(redeemScript, receivers, amounts, floData, strict_utxo).then(trx => {
|
||||||
|
for (let pk of privateKeys)
|
||||||
|
trx.sign(pk, 1);
|
||||||
|
var signedTxHash = trx.serialize();
|
||||||
|
broadcastTx(signedTxHash)
|
||||||
|
.then(txid => resolve(txid))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
floBlockchainAPI.writeMultisigData = function (redeemScript, data, privatekeys, receiverAddr = DEFAULT.receiverID, options = {}) {
|
||||||
|
let strict_utxo = options.strict_utxo === false ? false : true,
|
||||||
|
sendAmt = isNaN(options.sendAmt) ? DEFAULT.sendAmt : options.sendAmt;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!floCrypto.validateFloID(receiverAddr))
|
||||||
|
return reject(`Invalid receiver: ${receiverAddr}`);
|
||||||
|
sendMultisigTx(redeemScript, privatekeys, receiverAddr, sendAmt, data, strict_utxo)
|
||||||
|
.then(txid => resolve(txid))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserializeTx(tx) {
|
||||||
|
if (typeof tx === 'string' || Array.isArray(tx)) {
|
||||||
|
try {
|
||||||
|
tx = bitjs.transaction(tx);
|
||||||
|
} catch {
|
||||||
|
throw "Invalid transaction hex";
|
||||||
|
}
|
||||||
|
} else if (typeof tx !== 'object' || typeof tx.sign !== 'function')
|
||||||
|
throw "Invalid transaction object";
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
floBlockchainAPI.signTx = function (tx, privateKey, sighashtype = 1) {
|
||||||
|
if (!floCrypto.getFloID(privateKey))
|
||||||
|
throw "Invalid Private key";
|
||||||
|
//deserialize if needed
|
||||||
|
tx = deserializeTx(tx);
|
||||||
|
var signedTxHex = tx.sign(privateKey, sighashtype);
|
||||||
|
return signedTxHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkSigned = floBlockchainAPI.checkSigned = function (tx, bool = true) {
|
||||||
|
tx = deserializeTx(tx);
|
||||||
|
let n = [];
|
||||||
|
for (let i = 0; i < tx.inputs.length; i++) {
|
||||||
|
var s = tx.scriptDecode(i);
|
||||||
|
if (s['type'] === 'scriptpubkey')
|
||||||
|
n.push(s.signed);
|
||||||
|
else if (s['type'] === 'multisig') {
|
||||||
|
var rs = tx.decodeRedeemScript(s['rs']);
|
||||||
|
let x = {
|
||||||
|
s: 0,
|
||||||
|
r: rs['required'],
|
||||||
|
t: rs['pubkeys'].length
|
||||||
|
};
|
||||||
|
//check input script for signatures
|
||||||
|
var script = Array.from(tx.inputs[i].script);
|
||||||
|
if (script[0] == 0) { //script with signatures
|
||||||
|
script = tx.parseScript(script);
|
||||||
|
for (var k = 0; k < script.length; k++)
|
||||||
|
if (Array.isArray(script[k]) && script[k][0] == 48) //0x30 DERSequence
|
||||||
|
x.s++;
|
||||||
|
}
|
||||||
|
//validate counts
|
||||||
|
if (x.r > x.t)
|
||||||
|
throw "signaturesRequired is more than publicKeys";
|
||||||
|
else if (x.s < x.r)
|
||||||
|
n.push(x);
|
||||||
|
else
|
||||||
|
n.push(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bool ? !(n.filter(x => x !== true).length) : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
floBlockchainAPI.checkIfSameTx = function (tx1, tx2) {
|
||||||
|
tx1 = deserializeTx(tx1);
|
||||||
|
tx2 = deserializeTx(tx2);
|
||||||
|
//compare input and output length
|
||||||
|
if (tx1.inputs.length !== tx2.inputs.length || tx1.outputs.length !== tx2.outputs.length)
|
||||||
|
return false;
|
||||||
|
//compare flodata
|
||||||
|
if (tx1.floData !== tx2.floData)
|
||||||
|
return false
|
||||||
|
//compare inputs
|
||||||
|
for (let i = 0; i < tx1.inputs.length; i++)
|
||||||
|
if (tx1.inputs[i].outpoint.hash !== tx2.inputs[i].outpoint.hash || tx1.inputs[i].outpoint.index !== tx2.inputs[i].outpoint.index)
|
||||||
|
return false;
|
||||||
|
//compare outputs
|
||||||
|
for (let i = 0; i < tx1.outputs.length; i++)
|
||||||
|
if (tx1.outputs[i].value !== tx2.outputs[i].value || Crypto.util.bytesToHex(tx1.outputs[i].script) !== Crypto.util.bytesToHex(tx2.outputs[i].script))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
floBlockchainAPI.transactionID = function (tx) {
|
||||||
|
tx = deserializeTx(tx);
|
||||||
|
let clone = bitjs.clone(tx);
|
||||||
|
let raw_bytes = Crypto.util.hexToBytes(clone.serialize());
|
||||||
|
let txid = Crypto.SHA256(Crypto.SHA256(raw_bytes, { asBytes: true }), { asBytes: true }).reverse();
|
||||||
|
return Crypto.util.bytesToHex(txid);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTxOutput = (txid, i) => new Promise((resolve, reject) => {
|
||||||
|
fetch_api(`api/tx/${txid}`)
|
||||||
|
.then(result => resolve(result.vout[i]))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
});
|
||||||
|
|
||||||
|
function getOutputAddress(outscript) {
|
||||||
|
var bytes, version;
|
||||||
|
switch (outscript[0]) {
|
||||||
|
case 118: //legacy
|
||||||
|
bytes = outscript.slice(3, outscript.length - 2);
|
||||||
|
version = bitjs.pub;
|
||||||
|
break
|
||||||
|
case 169: //multisig
|
||||||
|
bytes = outscript.slice(2, outscript.length - 1);
|
||||||
|
version = bitjs.multisig;
|
||||||
|
break;
|
||||||
|
default: return; //unknown
|
||||||
|
}
|
||||||
|
bytes.unshift(version);
|
||||||
|
var hash = Crypto.SHA256(Crypto.SHA256(bytes, { asBytes: true }), { asBytes: true });
|
||||||
|
var checksum = hash.slice(0, 4);
|
||||||
|
return bitjs.Base58.encode(bytes.concat(checksum));
|
||||||
|
}
|
||||||
|
|
||||||
|
floBlockchainAPI.parseTransaction = function (tx) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
tx = deserializeTx(tx);
|
||||||
|
let result = {};
|
||||||
|
let promises = [];
|
||||||
|
//Parse Inputs
|
||||||
|
for (let i = 0; i < tx.inputs.length; i++)
|
||||||
|
promises.push(getTxOutput(tx.inputs[i].outpoint.hash, tx.inputs[i].outpoint.index));
|
||||||
|
Promise.all(promises).then(inputs => {
|
||||||
|
result.inputs = inputs.map(inp => Object({
|
||||||
|
address: inp.scriptPubKey.addresses[0],
|
||||||
|
value: parseFloat(inp.value)
|
||||||
|
}));
|
||||||
|
let signed = checkSigned(tx, false);
|
||||||
|
result.inputs.forEach((inp, i) => inp.signed = signed[i]);
|
||||||
|
//Parse Outputs
|
||||||
|
result.outputs = tx.outputs.map(out => Object({
|
||||||
|
address: getOutputAddress(out.script),
|
||||||
|
value: util.Sat_to_FLO(out.value)
|
||||||
|
}))
|
||||||
|
//Parse Totals
|
||||||
|
result.total_input = parseFloat(result.inputs.reduce((a, inp) => a += inp.value, 0).toFixed(8));
|
||||||
|
result.total_output = parseFloat(result.outputs.reduce((a, out) => a += out.value, 0).toFixed(8));
|
||||||
|
result.fee = parseFloat((result.total_input - result.total_output).toFixed(8));
|
||||||
|
result.floData = tx.floData;
|
||||||
|
resolve(result);
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//Broadcast signed Tx in blockchain using API
|
//Broadcast signed Tx in blockchain using API
|
||||||
const broadcastTx = floBlockchainAPI.broadcastTx = function (signedTxHash) {
|
const broadcastTx = floBlockchainAPI.broadcastTx = function (signedTxHash) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user