Merge pull request #17 from sairajzero/master
This commit is contained in:
commit
ce2a0daaa5
@ -1,4 +1,4 @@
|
|||||||
(function (EXPORTS) { //btcOperator v1.1.1
|
(function (EXPORTS) { //btcOperator v1.1.2a
|
||||||
/* BTC Crypto and API Operator */
|
/* BTC Crypto and API Operator */
|
||||||
const btcOperator = EXPORTS;
|
const btcOperator = EXPORTS;
|
||||||
|
|
||||||
@ -130,50 +130,84 @@
|
|||||||
return coinjs.pubkeys2MultisigAddress(pubKeys, minRequired);
|
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)
|
//convert from one blockchain to another blockchain (target version)
|
||||||
btcOperator.convert = {};
|
btcOperator.convert = {};
|
||||||
|
|
||||||
btcOperator.convert.wif = function (source_wif, target_version = coinjs.priv) {
|
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))
|
if (!keyHex || keyHex.length < 66 || !/01$/.test(keyHex))
|
||||||
return null;
|
return null;
|
||||||
else
|
else
|
||||||
return encodeLegacy(keyHex, target_version);
|
return util.encodeLegacy(keyHex, target_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
btcOperator.convert.legacy2legacy = function (source_addr, target_version = coinjs.pub) {
|
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)
|
if (!rawHex)
|
||||||
return null;
|
return null;
|
||||||
else
|
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) {
|
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)
|
if (!rawHex)
|
||||||
return null;
|
return null;
|
||||||
else
|
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) {
|
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)
|
if (!rawHex)
|
||||||
return null;
|
return null;
|
||||||
else
|
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) {
|
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)
|
if (!rawHex)
|
||||||
return null;
|
return null;
|
||||||
else
|
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 decode = coinjs.base58decode(source);
|
||||||
var raw = decode.slice(0, decode.length - 4),
|
var raw = decode.slice(0, decode.length - 4),
|
||||||
checksum = decode.slice(decode.length - 4);
|
checksum = decode.slice(decode.length - 4);
|
||||||
@ -183,7 +217,7 @@
|
|||||||
asBytes: true
|
asBytes: true
|
||||||
});
|
});
|
||||||
if (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3])
|
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();
|
let version = raw.shift();
|
||||||
return {
|
return {
|
||||||
version: version,
|
version: version,
|
||||||
@ -191,7 +225,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodeLegacy(hex, version) {
|
util.encodeLegacy = function (hex, version) {
|
||||||
var bytes = Crypto.util.hexToBytes(hex);
|
var bytes = Crypto.util.hexToBytes(hex);
|
||||||
bytes.unshift(version);
|
bytes.unshift(version);
|
||||||
var hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
var hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
@ -203,10 +237,10 @@
|
|||||||
return coinjs.base58encode(bytes.concat(checksum));
|
return coinjs.base58encode(bytes.concat(checksum));
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodeBech32(source) {
|
util.decodeBech32 = function (source) {
|
||||||
let decode = coinjs.bech32_decode(source);
|
let decode = coinjs.bech32_decode(source);
|
||||||
if (!decode)
|
if (!decode)
|
||||||
return null;
|
return false;
|
||||||
var raw = decode.data;
|
var raw = decode.data;
|
||||||
let version = raw.shift();
|
let version = raw.shift();
|
||||||
raw = coinjs.bech32_convert(raw, 5, 8, false);
|
raw = coinjs.bech32_convert(raw, 5, 8, false);
|
||||||
@ -217,7 +251,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodeBech32(hex, version, hrp) {
|
util.encodeBech32 = function (hex, version, hrp) {
|
||||||
var bytes = Crypto.util.hexToBytes(hex);
|
var bytes = Crypto.util.hexToBytes(hex);
|
||||||
bytes = coinjs.bech32_convert(bytes, 8, 5, true);
|
bytes = coinjs.bech32_convert(bytes, 8, 5, true);
|
||||||
bytes.unshift(version)
|
bytes.unshift(version)
|
||||||
@ -669,12 +703,15 @@
|
|||||||
btcOperator.checkIfSameTx = function (tx1, tx2) {
|
btcOperator.checkIfSameTx = function (tx1, tx2) {
|
||||||
tx1 = deserializeTx(tx1);
|
tx1 = deserializeTx(tx1);
|
||||||
tx2 = deserializeTx(tx2);
|
tx2 = deserializeTx(tx2);
|
||||||
|
//compare input and output length
|
||||||
if (tx1.ins.length !== tx2.ins.length || tx1.outs.length !== tx2.outs.length)
|
if (tx1.ins.length !== tx2.ins.length || tx1.outs.length !== tx2.outs.length)
|
||||||
return false;
|
return false;
|
||||||
|
//compare inputs
|
||||||
for (let i = 0; i < tx1.ins.length; i++)
|
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)
|
if (tx1.ins[i].outpoint.hash !== tx2.ins[i].outpoint.hash || tx1.ins[i].outpoint.index !== tx2.ins[i].outpoint.index)
|
||||||
return false;
|
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))
|
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 false;
|
||||||
return true;
|
return true;
|
||||||
@ -706,13 +743,13 @@
|
|||||||
var address;
|
var address;
|
||||||
switch (out.script.chunks[0]) {
|
switch (out.script.chunks[0]) {
|
||||||
case 0: //bech32, multisig-bech32
|
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;
|
break;
|
||||||
case 169: //segwit, multisig-segwit
|
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;
|
break;
|
||||||
case 118: //legacy
|
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 {
|
return {
|
||||||
address,
|
address,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
(function (EXPORTS) { //floBlockchainAPI v2.4.0
|
(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,8 +128,8 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//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");
|
||||||
@ -130,8 +137,6 @@
|
|||||||
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))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +445,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Create a multisig transaction
|
//Create a multisig transaction
|
||||||
const createMultisigTx = floBlockchainAPI.createMultisigTx = function (redeemScript, receivers, amounts, floData = '', strict_utxo = true) {
|
const createMultisigTx = function (redeemScript, receivers, amounts, floData = '', strict_utxo = true) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var multisig = floCrypto.decodeRedeemScript(redeemScript);
|
var multisig = floCrypto.decodeRedeemScript(redeemScript);
|
||||||
|
|
||||||
@ -499,6 +525,15 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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
|
//Create and send multisig transaction
|
||||||
const sendMultisigTx = floBlockchainAPI.sendMultisigTx = function (redeemScript, privateKeys, receivers, amounts, floData = '', strict_utxo = true) {
|
const sendMultisigTx = floBlockchainAPI.sendMultisigTx = function (redeemScript, privateKeys, receivers, amounts, floData = '', strict_utxo = true) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -538,6 +573,144 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
|||||||
56
floCrypto.js
56
floCrypto.js
@ -1,4 +1,4 @@
|
|||||||
(function (EXPORTS) { //floCrypto v2.3.4a
|
(function (EXPORTS) { //floCrypto v2.3.5
|
||||||
/* FLO Crypto Operators */
|
/* FLO Crypto Operators */
|
||||||
'use strict';
|
'use strict';
|
||||||
const floCrypto = EXPORTS;
|
const floCrypto = EXPORTS;
|
||||||
@ -290,13 +290,15 @@
|
|||||||
return false;
|
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) {
|
floCrypto.verifyPubKey = function (pubKeyHex, address) {
|
||||||
let raw = decodeAddress(address),
|
let raw = decodeAddress(address);
|
||||||
pub_hash = Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex), {
|
if (!raw)
|
||||||
asBytes: true
|
return;
|
||||||
})));
|
let pub_hash = Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex), { asBytes: true })));
|
||||||
return raw ? pub_hash === raw.hex : false;
|
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
|
//Convert the given address (any blockchain) to equivalent floID
|
||||||
@ -306,7 +308,7 @@
|
|||||||
let raw = decodeAddress(address);
|
let raw = decodeAddress(address);
|
||||||
if (!raw)
|
if (!raw)
|
||||||
return;
|
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)))
|
if (typeof raw.version !== 'undefined' && (!options.std || !options.std.includes(raw.version)))
|
||||||
return;
|
return;
|
||||||
if (typeof raw.bech_version !== 'undefined' && (!options.bech || !options.bech.includes(raw.bech_version)))
|
if (typeof raw.bech_version !== 'undefined' && (!options.bech || !options.bech.includes(raw.bech_version)))
|
||||||
@ -321,6 +323,35 @@
|
|||||||
return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0, 4)));
|
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)
|
//Checks if the given addresses (any blockchain) are same (w.r.t keys)
|
||||||
floCrypto.isSameAddr = function (addr1, addr2) {
|
floCrypto.isSameAddr = function (addr1, addr2) {
|
||||||
if (!addr1 || !addr2)
|
if (!addr1 || !addr2)
|
||||||
@ -329,9 +360,14 @@
|
|||||||
raw2 = decodeAddress(addr2);
|
raw2 = decodeAddress(addr2);
|
||||||
if (!raw1 || !raw2)
|
if (!raw1 || !raw2)
|
||||||
return false;
|
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;
|
return raw1.hex === raw2.hex;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const decodeAddress = floCrypto.decodeAddr = function (address) {
|
const decodeAddress = floCrypto.decodeAddr = function (address) {
|
||||||
if (!address)
|
if (!address)
|
||||||
@ -350,7 +386,7 @@
|
|||||||
hex: Crypto.util.bytesToHex(bytes),
|
hex: Crypto.util.bytesToHex(bytes),
|
||||||
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);
|
let decode = coinjs.bech32_decode(address);
|
||||||
if (decode) {
|
if (decode) {
|
||||||
let bytes = decode.data;
|
let bytes = decode.data;
|
||||||
|
|||||||
86
lib.js
86
lib.js
@ -1,4 +1,4 @@
|
|||||||
(function (GLOBAL) { //lib v1.4.1a
|
(function (GLOBAL) { //lib v1.4.2
|
||||||
'use strict';
|
'use strict';
|
||||||
/* Utility Libraries required for Standard operations
|
/* Utility Libraries required for Standard operations
|
||||||
* All credits for these codes belong to their respective creators, moderators and owners.
|
* All credits for these codes belong to their respective creators, moderators and owners.
|
||||||
@ -4492,7 +4492,7 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bitjs.transaction = function () {
|
bitjs.transaction = function (tx_data = undefined) {
|
||||||
var btrx = {};
|
var btrx = {};
|
||||||
btrx.version = 2; //flochange look at this version
|
btrx.version = 2; //flochange look at this version
|
||||||
btrx.inputs = [];
|
btrx.inputs = [];
|
||||||
@ -4992,6 +4992,78 @@
|
|||||||
return Crypto.util.bytesToHex(buffer);
|
return Crypto.util.bytesToHex(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* deserialize a transaction */
|
||||||
|
function deserialize(buffer) {
|
||||||
|
if (typeof buffer == "string") {
|
||||||
|
buffer = Crypto.util.hexToBytes(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = 0;
|
||||||
|
|
||||||
|
var readAsInt = function (bytes) {
|
||||||
|
if (bytes == 0) return 0;
|
||||||
|
pos++;
|
||||||
|
return buffer[pos - 1] + readAsInt(bytes - 1) * 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
var readVarInt = function () {
|
||||||
|
pos++;
|
||||||
|
if (buffer[pos - 1] < 253) {
|
||||||
|
return buffer[pos - 1];
|
||||||
|
}
|
||||||
|
return readAsInt(buffer[pos - 1] - 251);
|
||||||
|
}
|
||||||
|
|
||||||
|
var readBytes = function (bytes) {
|
||||||
|
pos += bytes;
|
||||||
|
return buffer.slice(pos - bytes, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
var readVarString = function () {
|
||||||
|
var size = readVarInt();
|
||||||
|
return readBytes(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytesToStr = function (bytes) {
|
||||||
|
return bytes.map(b => String.fromCharCode(b)).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
const self = btrx;
|
||||||
|
|
||||||
|
self.version = readAsInt(4);
|
||||||
|
|
||||||
|
var ins = readVarInt();
|
||||||
|
for (var i = 0; i < ins; i++) {
|
||||||
|
self.inputs.push({
|
||||||
|
outpoint: {
|
||||||
|
hash: Crypto.util.bytesToHex(readBytes(32).reverse()),
|
||||||
|
index: readAsInt(4)
|
||||||
|
},
|
||||||
|
script: readVarString(),
|
||||||
|
sequence: readAsInt(4)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var outs = readVarInt();
|
||||||
|
for (var i = 0; i < outs; i++) {
|
||||||
|
self.outputs.push({
|
||||||
|
value: bitjs.bytesToNum(readBytes(8)),
|
||||||
|
script: readVarString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.lock_time = readAsInt(4);
|
||||||
|
|
||||||
|
//flochange - floData field
|
||||||
|
self.floData = bytesToStr(readVarString());
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
//deserialize the data if passed
|
||||||
|
if (tx_data)
|
||||||
|
deserialize(tx_data);
|
||||||
|
|
||||||
return btrx;
|
return btrx;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -6704,6 +6776,7 @@
|
|||||||
return {
|
return {
|
||||||
'address': address,
|
'address': address,
|
||||||
'redeemScript': r.redeemScript,
|
'redeemScript': r.redeemScript,
|
||||||
|
'scripthash': Crypto.util.bytesToHex(program),
|
||||||
'size': r.size
|
'size': r.size
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -6797,15 +6870,16 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
coinjs.multisigBech32Address = function (raw_redeemscript) {
|
coinjs.multisigBech32Address = function (redeemscript) {
|
||||||
var program = Crypto.SHA256(Crypto.util.hexToBytes(raw_redeemscript), {
|
var program = Crypto.SHA256(Crypto.util.hexToBytes(redeemscript), {
|
||||||
asBytes: true
|
asBytes: true
|
||||||
});
|
});
|
||||||
var address = coinjs.bech32_encode(coinjs.bech32.hrp, [coinjs.bech32.version].concat(coinjs.bech32_convert(program, 8, 5, true)));
|
var address = coinjs.bech32_encode(coinjs.bech32.hrp, [coinjs.bech32.version].concat(coinjs.bech32_convert(program, 8, 5, true)));
|
||||||
return {
|
return {
|
||||||
'address': address,
|
'address': address,
|
||||||
'type': 'multisigBech32',
|
'type': 'multisigBech32',
|
||||||
'redeemscript': Crypto.util.bytesToHex(program)
|
'redeemScript': redeemscript,
|
||||||
|
'scripthash': Crypto.util.bytesToHex(program)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7803,7 +7877,7 @@
|
|||||||
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
|
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
|
||||||
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
|
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
|
||||||
|
|
||||||
if (segwit) { //also for MULTISIG_BECH32 (p2wsh-multisig)(script = raw_redeemscript; for p2wsh-multisig)
|
if (segwit) { //also for MULTISIG_BECH32 (p2wsh-multisig)(script = redeemscript; for p2wsh-multisig)
|
||||||
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
|
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
|
||||||
It is not standard and removed during the signing procedure. */
|
It is not standard and removed during the signing procedure. */
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user