Merge branch 'master' of https://github.com/ranchimall/flowallet
This commit is contained in:
commit
aeb3d4845d
@ -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*/
|
||||
'use strict';
|
||||
const floBlockchainAPI = EXPORTS;
|
||||
@ -15,6 +15,13 @@
|
||||
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, {
|
||||
sendAmt: {
|
||||
get: () => DEFAULT.sendAmt,
|
||||
@ -121,17 +128,15 @@
|
||||
});
|
||||
}
|
||||
|
||||
//Send Tx to blockchain
|
||||
const sendTx = floBlockchainAPI.sendTx = function (senderAddr, receiverAddr, sendAmt, privKey, floData = '', strict_utxo = true) {
|
||||
//create a transaction with single sender
|
||||
const createTx = function (senderAddr, receiverAddr, sendAmt, floData = '', strict_utxo = true) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!floCrypto.validateASCII(floData))
|
||||
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}`);
|
||||
else if (!floCrypto.validateFloID(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)
|
||||
return reject(`Invalid sendAmt : ${sendAmt}`);
|
||||
|
||||
@ -175,15 +180,36 @@
|
||||
if (change > DEFAULT.minChangeAmt)
|
||||
trx.addoutput(senderAddr, change);
|
||||
trx.addflodata(floData.replace(/\n/g, ' '));
|
||||
var signedTxHash = trx.sign(privKey, 1);
|
||||
broadcastTx(signedTxHash)
|
||||
.then(txid => resolve(txid))
|
||||
.catch(error => reject(error))
|
||||
resolve(trx);
|
||||
}
|
||||
}).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
|
||||
floBlockchainAPI.mergeUTXOs = function (floID, privKey, floData = '') {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!floCrypto.validateFloID(floID))
|
||||
if (!floCrypto.validateFloID(floID, true))
|
||||
return reject(`Invalid floID`);
|
||||
if (!floCrypto.verifyPrivKey(privKey, floID))
|
||||
return reject("Invalid Private Key");
|
||||
@ -381,7 +407,6 @@
|
||||
for (let floID in senders)
|
||||
promises.push(promisedAPI(`api/addr/${floID}/utxo`));
|
||||
Promise.all(promises).then(results => {
|
||||
let wifSeq = [];
|
||||
var trx = bitjs.transaction();
|
||||
for (let floID in senders) {
|
||||
let utxos = results.shift();
|
||||
@ -391,13 +416,11 @@
|
||||
sendAmt = totalSendAmt * ratio;
|
||||
} else
|
||||
sendAmt = senders[floID].coins + dividedFee;
|
||||
let wif = senders[floID].wif;
|
||||
let utxoAmt = 0.0;
|
||||
for (let i = utxos.length - 1;
|
||||
(i >= 0) && (utxoAmt < sendAmt); i--) {
|
||||
if (utxos[i].confirmations) {
|
||||
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i].scriptPubKey);
|
||||
wifSeq.push(wif);
|
||||
utxoAmt += utxos[i].amount;
|
||||
}
|
||||
}
|
||||
@ -410,8 +433,8 @@
|
||||
for (let floID in receivers)
|
||||
trx.addoutput(floID, receivers[floID]);
|
||||
trx.addflodata(floData.replace(/\n/g, ' '));
|
||||
for (let i = 0; i < wifSeq.length; i++)
|
||||
trx.signinput(i, wifSeq[i], 1);
|
||||
for (let floID in senders)
|
||||
trx.sign(senders[floID].wif, 1);
|
||||
var signedTxHash = trx.serialize();
|
||||
broadcastTx(signedTxHash)
|
||||
.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
|
||||
const broadcastTx = floBlockchainAPI.broadcastTx = function (signedTxHash) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
(function (EXPORTS) { //floCrypto v2.3.3e
|
||||
(function (EXPORTS) { //floCrypto v2.3.5a
|
||||
/* FLO Crypto Operators */
|
||||
'use strict';
|
||||
const floCrypto = EXPORTS;
|
||||
@ -222,7 +222,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 +231,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 +290,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 +308,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 +323,35 @@
|
||||
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 +360,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 +386,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;
|
||||
|
||||
427
scripts/lib.js
427
scripts/lib.js
@ -1,4 +1,4 @@
|
||||
(function (GLOBAL) { //lib v1.3.2
|
||||
(function (GLOBAL) { //lib v1.4.2b
|
||||
'use strict';
|
||||
/* Utility Libraries required for Standard operations
|
||||
* All credits for these codes belong to their respective creators, moderators and owners.
|
||||
@ -4349,20 +4349,18 @@
|
||||
|
||||
var bitjs = GLOBAL.bitjs = function () { };
|
||||
|
||||
function ascii_to_hexa(str) {
|
||||
var arr1 = [];
|
||||
for (var n = 0, l = str.length; n < l; n++) {
|
||||
var hex = Number(str.charCodeAt(n)).toString(16);
|
||||
arr1.push(hex);
|
||||
}
|
||||
return arr1.join('');
|
||||
}
|
||||
|
||||
/* public vars */
|
||||
bitjs.pub = 0x23; // flochange - changed the prefix to FLO Mainnet PublicKey Prefix 0x23
|
||||
bitjs.priv = 0xa3; //flochange - changed the prefix to FLO Mainnet Private key prefix 0xa3
|
||||
bitjs.multisig = 0x5e; //flochange - prefix for FLO Mainnet Multisig 0x5e
|
||||
bitjs.compressed = false;
|
||||
|
||||
if (GLOBAL.cryptocoin == 'FLO_TEST') {
|
||||
bitjs.pub = 0x73; // flochange - changed the prefix to FLO TestNet PublicKey Prefix 0x73
|
||||
bitjs.priv = 0xa3; //flochange - changed the prefix to FLO TestNet Private key prefix 0xa3
|
||||
bitjs.multisig = 0xc6; //flochange - prefix for FLO TestNet Multisig 0xc6
|
||||
}
|
||||
|
||||
/* provide a privkey and return an WIF */
|
||||
bitjs.privkey2wif = function (h) {
|
||||
var r = Crypto.util.hexToBytes(h);
|
||||
@ -4461,7 +4459,46 @@
|
||||
return B58.encode(r.concat(checksum));
|
||||
}
|
||||
|
||||
bitjs.transaction = function () {
|
||||
/* generate a multisig address from pubkeys and required signatures */
|
||||
bitjs.pubkeys2multisig = function (pubkeys, required) {
|
||||
var s = [];
|
||||
s.push(80 + required); //OP_1
|
||||
for (var i = 0; i < pubkeys.length; ++i) {
|
||||
let bytes = Crypto.util.hexToBytes(pubkeys[i]);
|
||||
s.push(bytes.length);
|
||||
s = s.concat(bytes);
|
||||
}
|
||||
s.push(80 + pubkeys.length); //OP_1
|
||||
s.push(174); //OP_CHECKMULTISIG
|
||||
|
||||
if (s.length > 520) { // too large
|
||||
throw Error(`redeemScript size(=${s.length}) too large`)
|
||||
}
|
||||
|
||||
var x = ripemd160(Crypto.SHA256(s, {
|
||||
asBytes: true
|
||||
}), {
|
||||
asBytes: true
|
||||
});
|
||||
x.unshift(bitjs.multisig);
|
||||
var r = x;
|
||||
r = Crypto.SHA256(Crypto.SHA256(r, {
|
||||
asBytes: true
|
||||
}), {
|
||||
asBytes: true
|
||||
});
|
||||
var checksum = r.slice(0, 4);
|
||||
var redeemScript = Crypto.util.bytesToHex(s);
|
||||
var address = B58.encode(x.concat(checksum));
|
||||
|
||||
return {
|
||||
'address': address,
|
||||
'redeemScript': redeemScript,
|
||||
'size': s.length
|
||||
};
|
||||
}
|
||||
|
||||
bitjs.transaction = function (tx_data = undefined) {
|
||||
var btrx = {};
|
||||
btrx.version = 2; //flochange look at this version
|
||||
btrx.inputs = [];
|
||||
@ -4476,7 +4513,6 @@
|
||||
'hash': txid,
|
||||
'index': index
|
||||
};
|
||||
//o.script = []; Signature and Public Key should be added after singning
|
||||
o.script = Crypto.util.hexToBytes(scriptPubKey); //push previous output pubkey script
|
||||
o.sequence = sequence || ((btrx.locktime == 0) ? 4294967295 : 0);
|
||||
return this.inputs.push(o);
|
||||
@ -4485,26 +4521,41 @@
|
||||
btrx.addoutput = function (address, value) {
|
||||
var o = {};
|
||||
var buf = [];
|
||||
var addrDecoded = btrx.addressDecode(address);
|
||||
var addr = this.addressDecode(address);
|
||||
o.value = new BigInteger('' + Math.round((value * 1) * 1e8), 10);
|
||||
buf.push(118); //OP_DUP
|
||||
buf.push(169); //OP_HASH160
|
||||
buf.push(addrDecoded.length);
|
||||
buf = buf.concat(addrDecoded); // address in bytes
|
||||
buf.push(136); //OP_EQUALVERIFY
|
||||
buf.push(172); // OP_CHECKSIG
|
||||
|
||||
if (addr.version === bitjs.pub) { // regular address
|
||||
buf.push(118); //OP_DUP
|
||||
buf.push(169); //OP_HASH160
|
||||
buf = this.writeBytesToScriptBuffer(buf, addr.bytes);// address in bytes
|
||||
buf.push(136); //OP_EQUALVERIFY
|
||||
buf.push(172); //OP_CHECKSIG
|
||||
} else if (addr.version === bitjs.multisig) { // multisig address
|
||||
buf.push(169); //OP_HASH160
|
||||
buf = this.writeBytesToScriptBuffer(buf, addr.bytes);// address in bytes
|
||||
buf.push(135); //OP_EQUAL
|
||||
}
|
||||
|
||||
o.script = buf;
|
||||
return this.outputs.push(o);
|
||||
}
|
||||
|
||||
// flochange - Added fn to assign flodata to tx
|
||||
btrx.addflodata = function (data) {
|
||||
//checks for valid flo-data string
|
||||
if (typeof data !== "string")
|
||||
throw Error("floData should be String");
|
||||
if (data.length > 1040)
|
||||
throw Error("floData Character Limit Exceeded");
|
||||
if (bitjs.strToBytes(data).some(c => c < 32 || c > 127))
|
||||
throw Error("floData contains Invalid characters (only ASCII characters allowed");
|
||||
|
||||
btrx.addflodata = function (txcomments) { // flochange - this whole function needs to be done
|
||||
this.floData = txcomments;
|
||||
return this.floData; //flochange .. returning the txcomments -- check if the function return will assign
|
||||
this.floData = data;
|
||||
return this.floData;
|
||||
}
|
||||
|
||||
|
||||
// Only standard addresses
|
||||
// Only standard addresses (standard multisig supported)
|
||||
btrx.addressDecode = function (address) {
|
||||
var bytes = B58.decode(address);
|
||||
var front = bytes.slice(0, bytes.length - 4);
|
||||
@ -4515,7 +4566,10 @@
|
||||
asBytes: true
|
||||
}).slice(0, 4);
|
||||
if (checksum + "" == back + "") {
|
||||
return front.slice(1);
|
||||
return {
|
||||
version: front[0],
|
||||
bytes: front.slice(1)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -4740,6 +4794,83 @@
|
||||
return KBigInt;
|
||||
};
|
||||
|
||||
btrx.writeBytesToScriptBuffer = function (buf, bytes) {
|
||||
if (bytes.length < 76) { //OP_PUSHDATA1
|
||||
buf.push(bytes.length);
|
||||
} else if (bytes.length <= 0xff) {
|
||||
buf.push(76); //OP_PUSHDATA1
|
||||
buf.push(bytes.length);
|
||||
} else if (bytes.length <= 0xffff) {
|
||||
buf.push(77); //OP_PUSHDATA2
|
||||
buf.push(bytes.length & 0xff);
|
||||
buf.push((bytes.length >>> 8) & 0xff);
|
||||
} else {
|
||||
buf.push(78); //OP_PUSHDATA4
|
||||
buf.push(bytes.length & 0xff);
|
||||
buf.push((bytes.length >>> 8) & 0xff);
|
||||
buf.push((bytes.length >>> 16) & 0xff);
|
||||
buf.push((bytes.length >>> 24) & 0xff);
|
||||
}
|
||||
buf = buf.concat(bytes);
|
||||
return buf;
|
||||
}
|
||||
|
||||
btrx.parseScript = function (script) {
|
||||
|
||||
var chunks = [];
|
||||
var i = 0;
|
||||
|
||||
function readChunk(n) {
|
||||
chunks.push(script.slice(i, i + n));
|
||||
i += n;
|
||||
};
|
||||
|
||||
while (i < script.length) {
|
||||
var opcode = script[i++];
|
||||
if (opcode >= 0xF0) {
|
||||
opcode = (opcode << 8) | script[i++];
|
||||
}
|
||||
|
||||
var len;
|
||||
if (opcode > 0 && opcode < 76) { //OP_PUSHDATA1
|
||||
readChunk(opcode);
|
||||
} else if (opcode == 76) { //OP_PUSHDATA1
|
||||
len = script[i++];
|
||||
readChunk(len);
|
||||
} else if (opcode == 77) { //OP_PUSHDATA2
|
||||
len = (script[i++] << 8) | script[i++];
|
||||
readChunk(len);
|
||||
} else if (opcode == 78) { //OP_PUSHDATA4
|
||||
len = (script[i++] << 24) | (script[i++] << 16) | (script[i++] << 8) | script[i++];
|
||||
readChunk(len);
|
||||
} else {
|
||||
chunks.push(opcode);
|
||||
}
|
||||
|
||||
if (i < 0x00) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
btrx.decodeRedeemScript = function (rs) {
|
||||
if (typeof rs == "string")
|
||||
rs = Crypto.util.hexToBytes(rs);
|
||||
var script = this.parseScript(rs);
|
||||
if (!(script[0] > 80 && script[script.length - 2] > 80 && script[script.length - 1] == 174)) //OP_CHECKMULTISIG
|
||||
throw "Invalid RedeemScript";
|
||||
var r = {};
|
||||
r.required = script[0] - 80;
|
||||
r.pubkeys = [];
|
||||
for (var i = 1; i < script.length - 2; i++)
|
||||
r.pubkeys.push(Crypto.util.bytesToHex(script[i]));
|
||||
r.address = bitjs.pubkeys2multisig(r.pubkeys, r.required).address;
|
||||
r.redeemscript = Crypto.util.bytesToHex(rs);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* sign a "standard" input */
|
||||
btrx.signinput = function (index, wif, sigHashType) {
|
||||
var key = bitjs.wif2pubkey(wif);
|
||||
@ -4747,8 +4878,7 @@
|
||||
var signature = this.transactionSig(index, wif, shType);
|
||||
var buf = [];
|
||||
var sigBytes = Crypto.util.hexToBytes(signature);
|
||||
buf.push(sigBytes.length);
|
||||
buf = buf.concat(sigBytes);
|
||||
buf = this.writeBytesToScriptBuffer(buf, sigBytes);
|
||||
var pubKeyBytes = Crypto.util.hexToBytes(key['pubkey']);
|
||||
buf.push(pubKeyBytes.length);
|
||||
buf = buf.concat(pubKeyBytes);
|
||||
@ -4756,15 +4886,98 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
/* sign a multisig input */
|
||||
btrx.signmultisig = function (index, wif, sigHashType) {
|
||||
|
||||
var script = Array.from(this.inputs[index].script);
|
||||
var redeemScript, sigsList = [];
|
||||
|
||||
if (script[0] == 0) { //script with signatures
|
||||
script = this.parseScript(script);
|
||||
for (var i = 0; i < script.length; i++) {
|
||||
if (Array.isArray(script[i])) {
|
||||
if (script[i][0] == 48) //0x30 DERSequence
|
||||
sigsList.push(script[i]);
|
||||
else if (script[i][0] >= 80 && script[i][script[i].length - 1] == 174) //OP_CHECKMULTISIG
|
||||
redeemScript = script[i];
|
||||
}
|
||||
}
|
||||
} else { //script = redeemscript
|
||||
redeemScript = script;
|
||||
}
|
||||
|
||||
var pubkeyList = this.decodeRedeemScript(redeemScript).pubkeys;
|
||||
var pubkey = bitjs.wif2pubkey(wif)['pubkey'];
|
||||
if (!pubkeyList.includes(pubkey)) //wif not a part of this multisig
|
||||
return false;
|
||||
|
||||
pubkeyList = pubkeyList.map(pub => Crypto.util.hexToBytes(bitjs.pubkeydecompress(pub))); //decompress pubkeys
|
||||
|
||||
var shType = sigHashType || 1;
|
||||
this.inputs[index].script = redeemScript; //script to be signed is redeemscript
|
||||
var signature = Crypto.util.hexToBytes(this.transactionSig(index, wif, shType));
|
||||
sigsList.push(signature);
|
||||
|
||||
var buf = [];
|
||||
buf.push(0);
|
||||
|
||||
//verify signatures and order them (also remove duplicate sigs)
|
||||
for (let x in pubkeyList) {
|
||||
for (let y in sigsList) {
|
||||
var sighash = Crypto.util.hexToBytes(this.transactionHash(index, sigsList[y].slice(-1)[0] * 1));
|
||||
if (bitjs.verifySignature(sighash, sigsList[y], pubkeyList[x])) {
|
||||
buf = this.writeBytesToScriptBuffer(buf, sigsList[y]);
|
||||
break; //ensures duplicate sigs from same pubkey are not added
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//append redeemscript
|
||||
buf = this.writeBytesToScriptBuffer(buf, redeemScript);
|
||||
|
||||
this.inputs[index].script = buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* sign inputs */
|
||||
btrx.sign = function (wif, sigHashType) {
|
||||
var shType = sigHashType || 1;
|
||||
for (var i = 0; i < this.inputs.length; i++) {
|
||||
this.signinput(i, wif, shType);
|
||||
|
||||
var decodedScript = this.scriptDecode(i);
|
||||
|
||||
if (decodedScript.type == "scriptpubkey" && decodedScript.signed == false) { //regular
|
||||
var addr = bitjs.wif2address(wif)["address"];;
|
||||
if (decodedScript.pubhash == Crypto.util.bytesToHex(this.addressDecode(addr).bytes)) //input belongs to wif
|
||||
this.signinput(i, wif, shType);
|
||||
} else if (decodedScript.type == "multisig") { //multisig
|
||||
this.signmultisig(i, wif, shType);
|
||||
}
|
||||
}
|
||||
return this.serialize();
|
||||
}
|
||||
|
||||
// function to find type of the script in input
|
||||
btrx.scriptDecode = function (index) {
|
||||
var script = this.parseScript(this.inputs[index].script);
|
||||
if (script.length == 5 && script[script.length - 1] == 172) {
|
||||
//OP_DUP OP_HASH160 [address bytes] OP_EQUALVERIFY OP_CHECKSIG
|
||||
// regular scriptPubkey (not signed)
|
||||
return { type: 'scriptpubkey', signed: false, pubhash: Crypto.util.bytesToHex(script[2]) };
|
||||
} else if (script.length == 2 && script[0][0] == 48) {
|
||||
//[signature] [pubkey]
|
||||
//(probably) regular signed
|
||||
return { type: 'scriptpubkey', signed: true };
|
||||
} else if (script[0] == 0 && script[script.length - 1][script[script.length - 1].length - 1] == 174) {
|
||||
//0 [signatues] [redeemscript OP_CHECKMULTISIG]
|
||||
// multisig with signature
|
||||
return { type: 'multisig', rs: script[script.length - 1] };
|
||||
} else if (script[0] >= 80 && script[script.length - 1] == 174) {
|
||||
//redeemscript: 80+ [pubkeys] OP_CHECKMULTISIG
|
||||
// multisig without signature
|
||||
return { type: 'multisig', rs: Array.from(this.inputs[index].script) };
|
||||
}
|
||||
}
|
||||
|
||||
/* serialize a transaction */
|
||||
btrx.serialize = function () {
|
||||
@ -4793,28 +5006,85 @@
|
||||
}
|
||||
|
||||
buffer = buffer.concat(bitjs.numToBytes(parseInt(this.locktime), 4));
|
||||
var flohex = ascii_to_hexa(this.floData);
|
||||
var floDataCount = this.floData.length;
|
||||
var floDataCountString;
|
||||
//flochange -- creating unique data character count logic for floData. This string is prefixed before actual floData string in Raw Transaction
|
||||
if (floDataCount < 16) {
|
||||
floDataCountString = floDataCount.toString(16);
|
||||
floDataCountString = "0" + floDataCountString;
|
||||
} else if (floDataCount < 253) {
|
||||
floDataCountString = floDataCount.toString(16);
|
||||
} else if (floDataCount <= 1040) {
|
||||
let floDataCountAdjusted = (floDataCount - 253) + parseInt("0xfd00fd");
|
||||
let floDataCountStringAdjusted = floDataCountAdjusted.toString(16);
|
||||
floDataCountString = floDataCountStringAdjusted.substr(0, 2) + floDataCountStringAdjusted.substr(4, 2) + floDataCountStringAdjusted.substr(2, 2);
|
||||
} else {
|
||||
floDataCountString = "Character Limit Exceeded";
|
||||
}
|
||||
|
||||
//flochange -- append floData field
|
||||
buffer = buffer.concat(bitjs.numToVarInt(this.floData.length));
|
||||
buffer = buffer.concat(bitjs.strToBytes(this.floData))
|
||||
|
||||
return Crypto.util.bytesToHex(buffer) + floDataCountString + flohex; // flochange -- Addition of floDataCountString and floData in serialization
|
||||
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;
|
||||
|
||||
@ -4856,6 +5126,36 @@
|
||||
else return bytes[0] + 256 * bitjs.bytesToNum(bytes.slice(1));
|
||||
}
|
||||
|
||||
//flochange - adding fn to convert string (for flodata) to byte
|
||||
bitjs.strToBytes = function (str) {
|
||||
return str.split('').map(c => c.charCodeAt(0));
|
||||
}
|
||||
|
||||
/* decompress an compressed public key */
|
||||
bitjs.pubkeydecompress = function (pubkey) {
|
||||
if ((typeof (pubkey) == 'string') && pubkey.match(/^[a-f0-9]+$/i)) {
|
||||
var curve = EllipticCurve.getSECCurveByName("secp256k1");
|
||||
try {
|
||||
var pt = curve.curve.decodePointHex(pubkey);
|
||||
var x = pt.getX().toBigInteger();
|
||||
var y = pt.getY().toBigInteger();
|
||||
|
||||
var publicKeyBytes = EllipticCurve.integerToBytes(x, 32);
|
||||
publicKeyBytes = publicKeyBytes.concat(EllipticCurve.integerToBytes(y, 32));
|
||||
publicKeyBytes.unshift(0x04);
|
||||
return Crypto.util.bytesToHex(publicKeyBytes);
|
||||
} catch (e) {
|
||||
// console.log(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bitjs.verifySignature = function (hash, sig, pubkey) {
|
||||
return Bitcoin.ECDSA.verify(hash, sig, pubkey);
|
||||
}
|
||||
|
||||
/* clone an object */
|
||||
bitjs.clone = function (obj) {
|
||||
if (obj == null || typeof (obj) != 'object') return obj;
|
||||
@ -5020,17 +5320,25 @@
|
||||
|
||||
//https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/address.js
|
||||
Bitcoin.Address = function (bytes) {
|
||||
if (GLOBAL.cryptocoin == "FLO")
|
||||
this.version = 0x23; // FLO mainnet public address
|
||||
else if (GLOBAL.cryptocoin == "FLO_TEST")
|
||||
this.version = 0x73; // FLO testnet public address
|
||||
if ("string" == typeof bytes) {
|
||||
bytes = Bitcoin.Address.decodeString(bytes, this.version);
|
||||
var d = Bitcoin.Address.decodeString(bytes);
|
||||
bytes = d.hash;
|
||||
if (d.version == Bitcoin.Address.standardVersion || d.version == Bitcoin.Address.multisigVersion)
|
||||
this.version = d.version;
|
||||
else throw "Version (prefix) " + d.version + " not supported!";
|
||||
} else {
|
||||
this.version = Bitcoin.Address.standardVersion;
|
||||
}
|
||||
this.hash = bytes;
|
||||
};
|
||||
|
||||
Bitcoin.Address.networkVersion = 0x23; // (FLO mainnet 0x23, 35D), (Bitcoin Mainnet, 0x00, 0D) // *this has no effect *
|
||||
Bitcoin.Address.standardVersion = 0x23; // (FLO mainnet 0x23, 35D), (Bitcoin Mainnet, 0x00, 0D)
|
||||
Bitcoin.Address.multisigVersion = 0x5e; // (FLO multisig 0x5e, 94D)
|
||||
|
||||
if (GLOBAL.cryptocoin == "FLO_TEST") {
|
||||
Bitcoin.Address.standardVersion = 0x73; // (FLO testnet 0x73, 115D), (Bitcoin Mainnet, 0x00, 0D)
|
||||
Bitcoin.Address.multisigVersion = 0xc6; // (FLO testnet multisig 0xc6, 198D)
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize this object as a standard Bitcoin address.
|
||||
@ -5059,7 +5367,7 @@
|
||||
/**
|
||||
* Parse a Bitcoin address contained in a string.
|
||||
*/
|
||||
Bitcoin.Address.decodeString = function (string, version) {
|
||||
Bitcoin.Address.decodeString = function (string) {
|
||||
var bytes = Bitcoin.Base58.decode(string);
|
||||
var hash = bytes.slice(0, 21);
|
||||
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {
|
||||
@ -5075,11 +5383,12 @@
|
||||
throw "Checksum validation failed!";
|
||||
}
|
||||
|
||||
if (version != hash.shift()) {
|
||||
/*if (version != hash.shift()) {
|
||||
throw "Version " + hash.shift() + " not supported!";
|
||||
}
|
||||
}*/
|
||||
|
||||
return hash;
|
||||
var version = hash.shift();
|
||||
return { version, hash };
|
||||
};
|
||||
//https://raw.github.com/bitcoinjs/bitcoinjs-lib/e90780d3d3b8fc0d027d2bcb38b80479902f223e/src/ecdsa.js
|
||||
Bitcoin.ECDSA = (function () {
|
||||
@ -6488,6 +6797,7 @@
|
||||
return {
|
||||
'address': address,
|
||||
'redeemScript': r.redeemScript,
|
||||
'scripthash': Crypto.util.bytesToHex(program),
|
||||
'size': r.size
|
||||
};
|
||||
}
|
||||
@ -6581,15 +6891,16 @@
|
||||
};
|
||||
}
|
||||
|
||||
coinjs.multisigBech32Address = function (raw_redeemscript) {
|
||||
var program = Crypto.SHA256(Crypto.util.hexToBytes(raw_redeemscript), {
|
||||
coinjs.multisigBech32Address = function (redeemscript) {
|
||||
var program = Crypto.SHA256(Crypto.util.hexToBytes(redeemscript), {
|
||||
asBytes: true
|
||||
});
|
||||
var address = coinjs.bech32_encode(coinjs.bech32.hrp, [coinjs.bech32.version].concat(coinjs.bech32_convert(program, 8, 5, true)));
|
||||
return {
|
||||
'address': address,
|
||||
'type': 'multisigBech32',
|
||||
'redeemscript': Crypto.util.bytesToHex(program)
|
||||
'redeemScript': redeemscript,
|
||||
'scripthash': Crypto.util.bytesToHex(program)
|
||||
};
|
||||
}
|
||||
|
||||
@ -7587,7 +7898,7 @@
|
||||
var n = u.getElementsByTagName("tx_output_n")[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.
|
||||
It is not standard and removed during the signing procedure. */
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user