btcOperator v1.0.7c

- Fixed: createTransaction not returning promise
- Fixed: script not correctly added for multisig inputs
- Fixed: signTx throwing syntax error
- Added checkSigned(tx, bool?): check if the tx is signed or not. (bool is optional, default=true, if true returns a boolean value, else returns a detailed array of input's length)

- Fixed minor bugs in lib.js
This commit is contained in:
sairajzero 2022-08-16 03:24:55 +05:30
parent 6e5cdbd820
commit f0a4837222
2 changed files with 67 additions and 33 deletions

View File

@ -1,4 +1,4 @@
(function(EXPORTS) { //btcOperator v1.0.7b (function(EXPORTS) { //btcOperator v1.0.7c
/* BTC Crypto and API Operator */ /* BTC Crypto and API Operator */
const btcOperator = EXPORTS; const btcOperator = EXPORTS;
@ -268,26 +268,28 @@
const TMP_FEE = 0.00001; const TMP_FEE = 0.00001;
function createTransaction(senders, redeemScripts, receivers, amounts, fee, change_addr) { function createTransaction(senders, redeemScripts, receivers, amounts, fee, change_addr) {
let auto_fee = false, return new Promise((resolve, reject) => {
total_amount = parseFloat(amounts.reduce((t, a) => t + a, 0).toFixed(8)); let auto_fee = false,
if (fee === null) { total_amount = parseFloat(amounts.reduce((t, a) => t + a, 0).toFixed(8));
auto_fee = true; if (fee === null) {
fee = TMP_FEE; auto_fee = true;
} fee = TMP_FEE;
const tx = coinjs.transaction(); }
addUTXOs(tx, senders, redeemScripts, total_amount + fee).then(result => { const tx = coinjs.transaction();
if (result > 0) addUTXOs(tx, senders, redeemScripts, total_amount + fee).then(result => {
return reject("Insufficient Balance"); if (result > 0)
let change = addOutputs(tx, receivers, amounts, Math.abs(result), change_addr); return reject("Insufficient Balance");
if (!auto_fee) let change = addOutputs(tx, receivers, amounts, Math.abs(result), change_addr);
return resolve(tx); if (!auto_fee)
autoFeeCalc(tx).then(fee_calc => { return resolve(tx);
fee = Math.round((fee * 1) * 1e8); //satoshi convertion autoFeeCalc(tx).then(fee_calc => {
if (!change) fee = Math.round((fee * 1) * 1e8); //satoshi convertion
tx.addoutput(change_addr, 0); if (!change)
editFee(tx, fee, fee_calc); tx.addoutput(change_addr, 0);
resolve(tx); editFee(tx, fee, fee_calc);
}).catch(error => reject(error)) resolve(tx);
}).catch(error => reject(error))
})
}) })
} }
@ -306,14 +308,17 @@
continue; continue;
required_amount -= parseFloat(utxos[i].value); required_amount -= parseFloat(utxos[i].value);
var script; var script;
if (rs) { //redeemScript for segwit/bech32 if (!rs || !rs.length) //legacy script
script = utxos[i].script_hex;
else if (((rs.match(/^00/) && rs.length == 44)) || (rs.length == 40 && rs.match(/^[a-f0-9]+$/gi))) {
//redeemScript for segwit/bech32
let s = coinjs.script(); let s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(rs)); s.writeBytes(Crypto.util.hexToBytes(rs));
s.writeOp(0); s.writeOp(0);
s.writeBytes(coinjs.numToBytes((utxos[i].value * 100000000).toFixed(0), 8)); s.writeBytes(coinjs.numToBytes((utxos[i].value * 100000000).toFixed(0), 8));
script = Crypto.util.bytesToHex(s.buffer); script = Crypto.util.bytesToHex(s.buffer);
} else //legacy script } else //redeemScript for multisig
script = utxos[i].script_hex; script = rs;
tx.addinput(utxos[i].txid, utxos[i].output_no, script, 0xfffffffd /*sequence*/ ); //0xfffffffd for Replace-by-fee tx.addinput(utxos[i].txid, utxos[i].output_no, script, 0xfffffffd /*sequence*/ ); //0xfffffffd for Replace-by-fee
} }
addUTXOs(tx, senders, redeemScripts, required_amount, n + 1) addUTXOs(tx, senders, redeemScripts, required_amount, n + 1)
@ -466,7 +471,7 @@
}) })
} }
btcOperator.signTx = function(tx, privKeys) { function deserializeTx(tx) {
if (typeof tx === 'string' || Array.isArray(tx)) { if (typeof tx === 'string' || Array.isArray(tx)) {
try { try {
tx = coinjs.transaction().deserialize(tx); tx = coinjs.transaction().deserialize(tx);
@ -475,16 +480,45 @@
} }
} else if (typeof tx !== 'object' || typeof tx.sign !== 'function') } else if (typeof tx !== 'object' || typeof tx.sign !== 'function')
throw "Invalid transaction object"; throw "Invalid transaction object";
return tx;
}
btcOperator.signTx = function(tx, privkeys, sighashtype = 1) {
tx = deserializeTx(tx);
if (!Array.isArray(privkeys)) if (!Array.isArray(privkeys))
privkeys = [privkeys]; privkeys = [privkeys];
for (let i in privKeys) for (let i in privkeys)
if (privKeys[i].length === 64) if (privkeys[i].length === 64)
privkeys[i] = coinjs.privkey2wif(privKeys[i]); privkeys[i] = coinjs.privkey2wif(privkeys[i]);
new Set(privKeys).forEach(key => console.debug("Signing key:", key, tx.sign(key, 1 /*sighashtype*/ ))); //Sign the tx using private key WIF new Set(privkeys).forEach(key => tx.sign(key, sighashtype)); //Sign the tx using private key WIF
return tx.serialize(); return tx.serialize();
} }
btcOperator.checkSigned = function(tx, bool = true) {
tx = deserializeTx(tx);
let n = [];
for (let i in tx.ins) {
var s = tx.extractScriptKey(i);
if (s['type'] !== 'multisig')
n.push(s.signed == 'true' || (tx.witness[i] && tx.witness[i].length == 2))
else {
var rs = coinjs.script().decodeRedeemScript(s.script);
let x = {
s: s['signatures'],
r: rs['signaturesRequired'],
t: rs['pubkeys'].length
};
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;
}
btcOperator.getTx = txid => new Promise((resolve, reject) => { btcOperator.getTx = txid => new Promise((resolve, reject) => {
fetch_api(`get_tx/BTC/${txid}`) fetch_api(`get_tx/BTC/${txid}`)
.then(result => resolve(result.data)) .then(result => resolve(result.data))

8
lib.js
View File

@ -1,4 +1,4 @@
(function(GLOBAL) { //lib v1.3.0b (function(GLOBAL) { //lib v1.3.0c
'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.
@ -7814,7 +7814,7 @@
} else if (this.ins[index].script.chunks[0] == 0 && this.ins[index].script.chunks[this.ins[index].script.chunks.length - 1][this.ins[index].script.chunks[this.ins[index].script.chunks.length - 1].length - 1] == 174) { // OP_CHECKMULTISIG } else if (this.ins[index].script.chunks[0] == 0 && this.ins[index].script.chunks[this.ins[index].script.chunks.length - 1][this.ins[index].script.chunks[this.ins[index].script.chunks.length - 1].length - 1] == 174) { // OP_CHECKMULTISIG
// multisig script, with signature(s) included // multisig script, with signature(s) included
var sigcount = 0; var sigcount = 0;
for (i = 1; i < this.ins[index].script.chunks.length - 1; i++) { for (let i = 1; i < this.ins[index].script.chunks.length - 1; i++) {
if (this.ins[index].script.chunks[i] != 0) { if (this.ins[index].script.chunks[i] != 0) {
sigcount++; sigcount++;
} }
@ -8057,8 +8057,8 @@
s.writeOp(0); s.writeOp(0);
for (x in pubkeyList) { for (let x in pubkeyList) {
for (y in sigsList) { for (let y in sigsList) {
this.ins[index].script.buffer = redeemScript; this.ins[index].script.buffer = redeemScript;
sighash = Crypto.util.hexToBytes(this.transactionHash(index, sigsList[y].slice(-1)[0] * 1)); sighash = Crypto.util.hexToBytes(this.transactionHash(index, sigsList[y].slice(-1)[0] * 1));
if (coinjs.verifySignature(sighash, sigsList[y], pubkeyList[x])) { if (coinjs.verifySignature(sighash, sigsList[y], pubkeyList[x])) {