🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

jeton-lib

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jeton-lib - npm Package Compare versions

Comparing version
2.0.1
to
2.1.0
+109
examples/covenant/anyonecanspend.js
const jeton = require('../../index')
const PrivateKey = jeton.PrivateKey
const Signature = jeton.Signature
const Script = jeton.Script
const OutputScript = jeton.covenant.OutputScript
const Transaction = jeton.Transaction
const Sighash = Transaction.Sighash
const Output = Transaction.Output
// Create keypairs for 3 players and a referee
const priv1 = new PrivateKey("L1wChPjacPamAFVbUsZZi5cEd3kMysZSgfDGprGEj91wTP6sh7KH")
const pub1 = priv1.toPublicKey()
const priv2 = new PrivateKey("KzyhHmmxwFbv2Mo8bQsJQwXhrCgAtjsCmuqBBmGZrcjfTn1Xvzw1")
const pub2 = priv2.toPublicKey()
const priv3 = new PrivateKey("KzwmMwHjbmRRdtwVUowKpYmpnJmMaVyGTwYLmh2qmiWcqgd7W9fG")
const pub3 = priv3.toPublicKey()
var refPriv = new PrivateKey('L5FDo3MEb2QNs2aQJ5DVGSDE5eBzVsgZny15Ri649RjysWAeLkTs')
var refpk = refPriv.toPublicKey();
var utxoForPub2 = new Transaction.UnspentOutput({
txid:
'b2b671f0cb3d7710b5d8a8420fff14b18173de876da710438dafa0ae6e8f5357',
vout: 1,
satoshis: 10200,
scriptPubKey: '76a9149383fa6588a176c2592cb2f4008d779293246adb88ac'
})
var utxoForPub3 = new Transaction.UnspentOutput({
txid:
'ee874221a431cf09d3373c4b9ffbb1e8fe80526d4304695e2f97541fc084c8f4',
vout: 1,
satoshis: 10200,
scriptPubKey: '76a914b011100d12d0537232692b3c113be5a8f505395588ac'
})
// Create array of UTXO arrays
var splitUtxos = [utxoForPub2, utxoForPub3]
// Create the final covenant destination outputs
var output1 = new Output ({
script: Script.fromAddress(priv1.toAddress()),
satoshis: 10010
})
var output2 = new Output ({
script: Script.fromAddress(priv2.toAddress()),
satoshis: 3003
})
var output3 = new Output ({
script: Script.fromAddress(priv3.toAddress()),
satoshis: 4004
})
// Create the output script
var outputScriptData = {
outputs: [output1, output2, output3],
}
outScript = new OutputScript(outputScriptData)
var outScriptHex = outScript.toScript().toBuffer().toString('hex')
var parsedScript = OutputScript.parseScriptPubKey(outScriptHex)
var outScript2 = new OutputScript(parsedScript)
var areEqual = outScript.toAddress().toString() == outScript2.toAddress().toString()
// Set miner fee and total amount to send (will be split between UTXOs from useUTXOs array)
var splitUtxoMinerFee = 200
var amountToSend = 20000
var splitTxSendAmount = (amountToSend / splitUtxos.length)
// Create two separate transactions from players 2 and 3 to fund the escrow
var sighash = (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_ANYONECANPAY)
var txArray = []
for (let i = 0; i < splitUtxos.length; i++) {
txArray[i] = new Transaction()
.from(splitUtxos[i]) // Feed information about what unspent outputs one can use
.toP2SH(outScript, amountToSend)
.sign([priv2, priv3], sighash) // Signs all the inputs it can
}
// Combine the transactions by merging the inputs
var fundTx = Transaction.mergeTransactionInputs(txArray)
var itx = new Transaction(fundTx.toString())
// Now spend the escrow transaction...
sighash = (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID )
var escrowUtxo = Transaction.utxoFromTxOutput(fundTx, 0)
// Make Transaction from escrow UTXO
var spendTx = new Transaction()
.from(escrowUtxo)
.addOutput(output1)
.addOutput(output2)
.addOutput(output3)
var spendTxBuf = spendTx.toBuffer()
// Sign covenant input at index 0 as party 1
spendTx.signCovenant(0, [priv1], outScript.toScript(), sighash, true) // note the "true" boolean as final argument
console.log(spendTx.toObject())
console.log('OutputScript parsing correctly?', areEqual)
console.log('scriptSig size', Buffer.from(spendTx.toObject().inputs[0].script, 'hex').byteLength)
console.log('estimated size', spendTx._estimateSize())
console.log('verify tx full sig', spendTx.verify())
console.log('jeton signature verified?', spendTx.verifyScriptSig(0))
const jeton = require('../../index')
const PrivateKey = jeton.PrivateKey
const Signature = jeton.Signature
const Script = jeton.Script
const OutputScript = jeton.covenant.OutputScript
const Transaction = jeton.Transaction
const Sighash = Transaction.Sighash
const Output = Transaction.Output
// Create keypairs for 3 players and a referee
const priv1 = new PrivateKey("L1wChPjacPamAFVbUsZZi5cEd3kMysZSgfDGprGEj91wTP6sh7KH")
const pub1 = priv1.toPublicKey()
const priv2 = new PrivateKey("KzyhHmmxwFbv2Mo8bQsJQwXhrCgAtjsCmuqBBmGZrcjfTn1Xvzw1")
const pub2 = priv2.toPublicKey()
const priv3 = new PrivateKey("KzwmMwHjbmRRdtwVUowKpYmpnJmMaVyGTwYLmh2qmiWcqgd7W9fG")
const pub3 = priv3.toPublicKey()
var refPriv = new PrivateKey('L5FDo3MEb2QNs2aQJ5DVGSDE5eBzVsgZny15Ri649RjysWAeLkTs')
var refpk = refPriv.toPublicKey();
var utxoForPub2 = new Transaction.UnspentOutput({
txid:
'b2b671f0cb3d7710b5d8a8420fff14b18173de876da710438dafa0ae6e8f5357',
vout: 1,
satoshis: 10200,
scriptPubKey: '76a9149383fa6588a176c2592cb2f4008d779293246adb88ac'
})
var utxoForPub3 = new Transaction.UnspentOutput({
txid:
'ee874221a431cf09d3373c4b9ffbb1e8fe80526d4304695e2f97541fc084c8f4',
vout: 1,
satoshis: 10200,
scriptPubKey: '76a914b011100d12d0537232692b3c113be5a8f505395588ac'
})
// Create array of UTXO arrays
var splitUtxos = [utxoForPub2, utxoForPub3]
// Create the final covenant destination outputs
var output1 = new Output ({
script: Script.fromAddress(priv1.toAddress()),
satoshis: 10010
})
var output2 = new Output ({
script: Script.fromAddress(priv2.toAddress()),
satoshis: 3003
})
var output3 = new Output ({
script: Script.fromAddress(priv3.toAddress()),
satoshis: 4004
})
// Create the output script
var outputScriptData = {
pubKeys: [pub1, pub2], // multiple signatures are required, submitted in proper
outputs: [output1, output2, output3]
}
outScript = new OutputScript(outputScriptData)
var outScriptHex = outScript.toScript().toBuffer().toString('hex')
var parsedScript = OutputScript.parseScriptPubKey(outScriptHex)
var outScript2 = new OutputScript(parsedScript)
var areEqual = outScript.toAddress().toString() == outScript2.toAddress().toString()
// Set miner fee and total amount to send (will be split between UTXOs from useUTXOs array)
var splitUtxoMinerFee = 200
var amountToSend = 20000
var splitTxSendAmount = (amountToSend / splitUtxos.length)
// Create two separate transactions from players 2 and 3 to fund the escrow
var sighash = (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_ANYONECANPAY)
var txArray = []
for (let i = 0; i < splitUtxos.length; i++) {
txArray[i] = new Transaction()
.from(splitUtxos[i]) // Feed information about what unspent outputs one can use
.toP2SH(outScript, amountToSend)
.sign([priv2, priv3], sighash) // Signs all the inputs it can
}
// Combine the transactions by merging the inputs
var fundTx = Transaction.mergeTransactionInputs(txArray)
var itx = new Transaction(fundTx.toString())
// Now spend the escrow transaction...
sighash = (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID )
var escrowUtxo = Transaction.utxoFromTxOutput(fundTx, 0)
// Make Transaction from escrow UTXO
var spendTx = new Transaction()
.from(escrowUtxo)
.addOutput(output1)
.addOutput(output2)
.addOutput(output3)
var spendTxBuf = spendTx.toBuffer()
// Get signature for index 0 as party 2 (necessary for multisig)
var sigForParty2 = spendTx.getCovenantSignatureScript(0, priv2, outScript.toScript(), sighash)
// Sign covenant input at index 0 as party 1 and add signature Script from party 2
spendTx.signCovenant(0, [priv1, sigForParty2], outScript.toScript(), sighash)
console.log(spendTx.toObject())
console.log('OutputScript parsing correctly?', areEqual)
console.log('scriptSig size', Buffer.from(spendTx.toObject().inputs[0].script, 'hex').byteLength)
console.log('estimated size', spendTx._estimateSize())
console.log('verify tx full sig', spendTx.verify())
console.log('jeton signature verified?', spendTx.verifyScriptSig(0))
const jeton = require('../../index')
const PrivateKey = jeton.PrivateKey
const Signature = jeton.Signature
const Script = jeton.Script
const OutputScript = jeton.covenant.OutputScript
const Transaction = jeton.Transaction
const Sighash = Transaction.Sighash
const Output = Transaction.Output
// Create keypairs for 3 players and a referee
const priv1 = new PrivateKey("L1wChPjacPamAFVbUsZZi5cEd3kMysZSgfDGprGEj91wTP6sh7KH")
const pub1 = priv1.toPublicKey()
const priv2 = new PrivateKey("KzyhHmmxwFbv2Mo8bQsJQwXhrCgAtjsCmuqBBmGZrcjfTn1Xvzw1")
const pub2 = priv2.toPublicKey()
const priv3 = new PrivateKey("KzwmMwHjbmRRdtwVUowKpYmpnJmMaVyGTwYLmh2qmiWcqgd7W9fG")
const pub3 = priv3.toPublicKey()
var refPriv = new PrivateKey('L5FDo3MEb2QNs2aQJ5DVGSDE5eBzVsgZny15Ri649RjysWAeLkTs')
var refpk = refPriv.toPublicKey();
var utxoForPub2 = new Transaction.UnspentOutput({
txid:
'b2b671f0cb3d7710b5d8a8420fff14b18173de876da710438dafa0ae6e8f5357',
vout: 1,
satoshis: 10200,
scriptPubKey: '76a9149383fa6588a176c2592cb2f4008d779293246adb88ac'
})
var utxoForPub3 = new Transaction.UnspentOutput({
txid:
'ee874221a431cf09d3373c4b9ffbb1e8fe80526d4304695e2f97541fc084c8f4',
vout: 1,
satoshis: 10200,
scriptPubKey: '76a914b011100d12d0537232692b3c113be5a8f505395588ac'
})
// Create array of UTXO arrays
var splitUtxos = [utxoForPub2, utxoForPub3]
// Create the final covenant destination outputs
var output1 = new Output ({
script: Script.fromAddress(priv1.toAddress()),
satoshis: 10010
})
var output2 = new Output ({
script: Script.fromAddress(priv2.toAddress()),
satoshis: 3003
})
var output3 = new Output ({
script: Script.fromAddress(priv3.toAddress()),
satoshis: 2002
})
var output4 = new Output ({
script: Script.fromAddress(priv3.toAddress()),
satoshis: 1001
})
var output5 = new Output ({
script: Script.fromAddress(priv3.toAddress()),
satoshis: 1001
})
var output6 = new Output ({
script: Script.fromAddress(priv3.toAddress()),
satoshis: 1001
})
// Create the output script
var outputScriptData = {
outputs: [output1, output2, output3, output4, output5, output6], // For pay-to-addresses
prorata: [10, 3, 2, 1, 1, 1] // Amounts must be in this proportion
}
outScript = new OutputScript(outputScriptData)
var outScriptHex = outScript.toScript().toBuffer().toString('hex')
var parsedScript = OutputScript.parseScriptPubKey(outScriptHex)
var outScript2 = new OutputScript(parsedScript)
var areEqual = outScript.toAddress().toString() == outScript2.toAddress().toString()
// Set miner fee and total amount to send (will be split between UTXOs from useUTXOs array)
var splitUtxoMinerFee = 200
var amountToSend = 20000
var splitTxSendAmount = (amountToSend / splitUtxos.length)
// Create two separate transactions from players 2 and 3 to fund the escrow
var sighash = (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_ANYONECANPAY)
var txArray = []
for (let i = 0; i < splitUtxos.length; i++) {
txArray[i] = new Transaction()
.from(splitUtxos[i]) // Feed information about what unspent outputs one can use
.toP2SH(outScript, amountToSend)
.sign([priv2, priv3], sighash) // Signs all the inputs it can
}
// Combine the transactions by merging the inputs
var fundTx = Transaction.mergeTransactionInputs(txArray)
var itx = new Transaction(fundTx.toString())
// Now spend the escrow transaction...
sighash = (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID )
var escrowUtxo = Transaction.utxoFromTxOutput(fundTx, 0)
// Make Transaction from escrow UTXO
var spendTx = new Transaction()
.from(escrowUtxo)
.addOutput(output1)
.addOutput(output2)
.addOutput(output3)
.addOutput(output4)
.addOutput(output5)
.addOutput(output6)
var spendTxBuf = spendTx.toBuffer()
// Sign covenant input at index 0 as party 1 and add signature Script from party 2
spendTx.signCovenant(0, [priv1], outScript.toScript(), sighash, true) // Note the "true" boolean as final argument (anyonecanspend)
console.log(spendTx.toObject())
console.log('OutputScript parsing correctly?', areEqual)
console.log('scriptSig size', Buffer.from(spendTx.toObject().inputs[0].script, 'hex').byteLength)
console.log('estimated size', spendTx._estimateSize())
console.log('verify tx full sig', spendTx.verify())
console.log('jeton signature verified?', spendTx.verifyScriptSig(0))
# Jeton Lib
**Extension of bitcore-lib-cash for advanced Bitcoin Cash transaction types**
## Examples
Contained in this directory are complete examples for funding and spending of the transaction types made possible by jeton-lib.
[escrow.js](https://github.com/jeton-tech/jeton-lib/tree/master/examples/escrow.js) - Multi-Party escrow where an oracle provides a signature for a given message based on the outcome of an event
[threshold.js](https://github.com/jeton-tech/jeton-lib/tree/master/examples/threshold.js) - Multi-Party escrow where an oracle provides a signature for a message containing blockheight and a value (such as price). The party who is either "greater than" or "less than or equal to" the value in the message can collect after the given blockheight
[covenant/multisig.js](https://github.com/jeton-tech/jeton-lib/tree/master/examples/covenant/multisig.js) - A covenant escrow requiring multiple signatures in which specific amounts must be paid to specific addresses
[covenant/anyonecanpay.js](https://github.com/jeton-tech/jeton-lib/tree/master/examples/covenant/anyonecanpay.js) - A covenant escrow in which specific amounts must be paid to specific addresses and any private key holder can sign
[covenant/proportional.js](https://github.com/jeton-tech/jeton-lib/tree/master/examples/covenant/proportional.js) - A covenant escrow in which amounts must be paid to specific addresses in a prescribed proportion (prorata) and any private key holder can sign
## License
Code released under [the MIT license](https://github.com/jeton-tech/jeton-lib/blob/master/LICENSE).
module.exports.InputScript = require('./InputScript')
module.exports.OutputScript = require('./OutputScript')
const bitcore = require('bitcore-lib-cash')
const Hash = bitcore.crypto.Hash
const Script = bitcore.Script
const PublicKey = bitcore.PublicKey
/**
* Instantiate an object to create covenant scriptSig
*
* @param {object} data - The encoded data in various formats
* @param {Script[]} data.sigScripts - Array of P2PKH signatures for the transaction, in proper order
* @param {Script} data.outputScript - The original (non-P2SH) scriptPubKey for this input
*
* @constructor
*/
var InputScript = function (data) {
this.sigScripts = data.sigScripts
this.outputScript = data.outputScript
this.preimage = data.preimage
}
/**
* @returns {Script}
*/
InputScript.prototype.toScript = function () {
let outputBuf = this.outputScript.toBuffer()
let inScript = Script()
.add(this.preimage.outputs)
.add(this.preimage.preimage)
for (let i = this.sigScripts.length - 1; i >=0; i--) {
inScript.add(this.sigScripts[i])
}
inScript.add(outputBuf)
return inScript
}
/**
* @returns {Buffer}
*/
InputScript.prototype.toBuffer = function () {
let outScript = this.toScript()
return outScript.toBuffer()
}
module.exports = InputScript
const bitcore = require('bitcore-lib-cash')
const Address = bitcore.Address
const Hash = bitcore.crypto.Hash
const Script = bitcore.Script
const PublicKey = bitcore.PublicKey
const BufferReader = bitcore.encoding.BufferReader
const Output = bitcore.Transaction.Output
const ScriptNumber = require('../threshold/ScriptNumber')
const gcd = function (input) {
if (toString.call(input) !== "[object Array]")
return false;
var len, a, b;
len = input.length;
if ( !len ) {
return null;
}
a = input[ 0 ];
for ( var i = 1; i < len; i++ ) {
b = input[ i ];
a = gcd_two_numbers( a, b );
}
return a;
};
const gcd_two_numbers = function(x, y) {
if ((typeof x !== 'number') || (typeof y !== 'number'))
return false;
x = Math.abs(x);
y = Math.abs(y);
while(y) {
var t = y;
y = x % y;
x = t;
}
return x;
};
/**
* Instantiate an object to create covenant scriptPubKey
*
* @param {object} data - The encoded data in various formats
* @param {PublicKey[]} data.pubKeys - (optional) The public keys for required signatures
* @param {Output[] | object[]} data.outputs - array of party objects
* @param {int[]} data.prorata - array of integers corresponding to the proportional representation of data.output values
*
* @constructor
*/
var OutputScript = function (data) {
this.pubKeys = data.pubKeys ? data.pubKeys : []
if (data.outputs) {
try {
this.outputs = data.outputs.map(function (out) {
if (!(out instanceof Output)) {
out = new Output(out)
}
return out
})
} catch(err) {
throw new Error ('Invalid format for outputs')
}
}
this.prorata = !Array.isArray(data.prorata) ? null : data.prorata.map(x => x / gcd(data.prorata))
}
/**
* @returns {Script}
*/
OutputScript.prototype.toScript = function () {
//Output Script
let outScript = new Script()
// MultiSig
.add(this.buildMultiSigOut(this.pubKeys))
.add('OP_2DUP')
.add('OP_CHECKSIGVERIFY')
.add('OP_SWAP')
.add('OP_SIZE')
.add('OP_1SUB')
.add('OP_SPLIT')
.add('OP_DROP')
.add('OP_SWAP')
.add('OP_ROT')
// Get outputs
.add('OP_DUP')
.add('OP_SIZE')
.add(ScriptNumber.encode(40))
.add('OP_SUB')
.add('OP_SPLIT')
.add('OP_NIP')
.add(ScriptNumber.encode(32))
.add('OP_SPLIT')
.add('OP_DROP')
.add('OP_4')
.add('OP_ROLL')
.add('OP_DUP')
// Begin output checks
for (let i = 0; i < this.outputs.length; i++) {
let output = this.outputs[i]
let fullOutBuf = output.toBufferWriter().toBuffer()
// Proportional
if (this.prorata && this.prorata.length > 0) {
if (this.prorata.length < 2) {
throw new Error ('Prorportional convenants must have at least 2 amounts in prorata array')
}
if (this.prorata.length != this.outputs.length) {
throw new Error ('Proportional covenants must have a prorata value for every specified output')
}
outScript.add(this.buildProrataCheck(i))
let outScriptBuf = fullOutBuf.slice(8)
outScript.add(outScriptBuf)
}
else {
// Exact amount
outScript.add(fullOutBuf)
}
outScript.add(this.buildOutputCheck(output))
}
outScript.add('OP_DROP')
.add('OP_HASH256')
.add('OP_EQUALVERIFY') // End Outputs
.add('OP_SHA256')
.add('OP_SWAP')
.add('OP_CHECKDATASIG')
return outScript
}
/**
* @returns {Buffer}
*/
OutputScript.prototype.toBuffer = function () {
let outScript = this.toScript()
return outScript.toBuffer()
}
/**
* Return P2SH version of script
*
* @returns {Script}
*/
OutputScript.prototype.toScriptHash = function () {
let outputBuf = this.toBuffer()
var outputP2SH = new Script()
.add('OP_HASH160')
.add(Hash.sha256ripemd160(outputBuf))
.add('OP_EQUAL')
return outputP2SH
}
/**
* Return P2SH address
* @param {Network|string=} network - a {@link Network} object, or a string with the network name ('livenet' or 'testnet')
*
* @returns {Address}
*/
OutputScript.prototype.toAddress = function (network) {
network = network || 'livenet'
let address = new Address(this.toScriptHash(), network, 'scripthash')
return address
}
/**
* @returns {Script}
*/
OutputScript.prototype.buildProrataCheck = function(index) {
let value = ScriptNumber.encode(this.prorata[index])
// Enforce minimum encoding
if (this.prorata[index] <= 16) {
if (this.prorata[index] <= 0) {
throw new Error ('Invalid value in prorata array at index ' + index)
}
value = 'OP_' + this.prorata[index]
}
let s = new Script()
.add('OP_8')
.add('OP_SPLIT')
.add('OP_SWAP')
.add('OP_BIN2NUM')
.add('OP_DUP')
.add(value)
.add('OP_BIN2NUM')
.add('OP_MOD')
.add('OP_0')
.add('OP_EQUALVERIFY')
.add(value)
.add('OP_BIN2NUM')
.add('OP_DIV')
// Logic for inputs after the first
if (index > 0) {
s.add('OP_DUP')
.add('OP_FROMALTSTACK')
.add('OP_EQUALVERIFY')
}
s.add('OP_TOALTSTACK')
return s
}
/**
* @returns {Script}
*/
OutputScript.prototype.buildOutputCheck = function(output) {
let s = new Script()
.add('OP_SIZE')
.add('OP_ROT')
.add('OP_SWAP')
.add('OP_SPLIT')
.add('OP_SWAP')
.add('OP_ROT')
.add('OP_EQUALVERIFY')
return s
}
/**
* @returns {Script}
*/
OutputScript.prototype.buildMultiSigOut = function(pubKeys) {
let s = new Script()
for (i = 0; i < pubKeys.length; i++) {
s.add(pubKeys[i].toBuffer())
if (pubKeys.length > i + 1) {
s.add('OP_CHECKSIGVERIFY')
}
}
return s
}
/**
* Parse scriptPubKey into object reflecting inputs
* @param {string}
*
* @returns {object}
*/
OutputScript.parseScriptPubKey = function(hexString) {
let getAllIndexes = function (arr, val) {
var indexes = [], i;
for(i = 0; i < arr.length; i++)
if (arr[i] === val)
indexes.push(i);
return indexes;
}
let parsedData = {
pubKeys: [],
outputs: [],
prorata: null
}
let raw_script = Buffer.from(hexString, 'hex')
let script = new Script(raw_script)
let outscriptArr = script.toASM().split(' ')
// console.log('outscriptArr',outscriptArr)
// Get OutputScript.pubKeys
let csvAppearances = getAllIndexes(outscriptArr, 'OP_CHECKSIGVERIFY')
// console.log('csvAppearances', csvAppearances)
for(let i = 0; i < csvAppearances.length; i++) {
let csvIndex = csvAppearances[i]
if (outscriptArr[csvIndex - 1] == 'OP_2DUP') {
if (csvIndex - 2 >= 0)
parsedData.pubKeys.push(PublicKey.fromString(outscriptArr[csvIndex - 2]))
} else {
parsedData.pubKeys.push(PublicKey.fromString(outscriptArr[csvIndex - 1]))
}
}
// Get OutputScript.prorata
let b2nAppearances = getAllIndexes(outscriptArr, 'OP_BIN2NUM')
for(let i = 0; i < b2nAppearances.length; i++) {
if (!parsedData.prorata)
parsedData.prorata = []
let b2nIndex = b2nAppearances[i]
if (outscriptArr[b2nIndex + 1] == 'OP_MOD') {
let proNum = outscriptArr[b2nIndex - 1]
// Handle 1-16 as versus all other byte-encoded numbers
if (proNum.includes('OP_')) {
proNum = parseInt(proNum.replace('OP_', ''))
} else {
let proNumBuf = Buffer.from(proNum, 'hex')
proNum = ScriptNumber.decode(proNumBuf)
}
parsedData.prorata.push(proNum)
}
}
// Get OutputScript.outputs if prorata versus exact
let altStackAppearances = getAllIndexes(outscriptArr, 'OP_TOALTSTACK')
if (altStackAppearances.length > 0) {
for(let i = 0; i < altStackAppearances.length; i++) {
let altStackIndex = altStackAppearances[i]
// Slice off first 2 bytes (length) to get scriptPubkey
let scriptPubKey = outscriptArr[altStackIndex + 1].slice(2)
let outObj = {
script: scriptPubKey,
satoshis: 0
}
parsedData.outputs.push(Output.fromObject(outObj))
}
} else {
let evAppearances = getAllIndexes(outscriptArr, 'OP_EQUALVERIFY')
for(let i = 0; i < evAppearances.length; i++) {
let evIndex = evAppearances[i]
if (outscriptArr[evIndex - 1] == 'OP_ROT') {
let outBuf = Buffer.from(outscriptArr[evIndex - 7], 'hex')
let reader = new BufferReader(outBuf)
parsedData.outputs.push(Output.fromBufferReader(reader))
}
}
}
return parsedData
}
module.exports = OutputScript
module.exports = require('./Transaction');
module.exports.Sighash = require('./Sighash');
const bitcore = require('bitcore-lib-cash')
const Sighash = bitcore.Transaction.Sighash
const BufferWriter = bitcore.encoding.BufferWriter;
const BufferReader = bitcore.encoding.BufferReader;
const BN = bitcore.crypto.BN;
const Hash = bitcore.crypto.Hash;
const Signature = bitcore.crypto.Signature;
const BufferUtil = bitcore.util.buffer;
const $ = bitcore.util.preconditions;
const _ = bitcore.deps._;
Sighash.getPreimage = function(transaction, sighashType, inputNumber, subscript) {
var input = transaction.inputs[inputNumber];
var satoshisBN = input.output.satoshisBN;
$.checkArgument(
satoshisBN instanceof BN,
'For ForkId=0 signatures, satoshis or complete input must be provided'
);
function GetForkId() {
return 0; // In the UAHF, a fork id of 0 is used (see [4] REQ-6-2 NOTE 4)
};
function GetPrevouts(tx) {
var writer = new BufferWriter()
_.each(tx.inputs, function(input) {
writer.writeReverse(input.prevTxId);
writer.writeUInt32LE(input.outputIndex);
});
var buf = writer.toBuffer();
return buf
}
function GetSequences(tx) {
var writer = new BufferWriter()
_.each(tx.inputs, function(input) {
writer.writeUInt32LE(input.sequenceNumber);
});
var buf = writer.toBuffer();
return buf;
}
function GetOutputs(tx, n) {
var writer = new BufferWriter()
if ( _.isUndefined(n)) {
_.each(tx.outputs, function(output) {
output.toBufferWriter(writer);
});
} else {
tx.outputs[n].toBufferWriter(writer);
}
var buf = writer.toBuffer();
return buf;
}
var hashPrevouts = BufferUtil.emptyBuffer(32);
var hashSequences = BufferUtil.emptyBuffer(32);
var hashOutputs = BufferUtil.emptyBuffer(32);
var prevouts = GetPrevouts(transaction);
if (!(sighashType & Signature.SIGHASH_ANYONECANPAY)) {
hashPrevouts = Hash.sha256sha256(prevouts);
}
var sequences = GetSequences(transaction);
if (!(sighashType & Signature.SIGHASH_ANYONECANPAY) &&
(sighashType & 31) != Signature.SIGHASH_SINGLE &&
(sighashType & 31) != Signature.SIGHASH_NONE) {
hashSequences = Hash.sha256sha256(sequences);
}
var outputs = GetOutputs(transaction);
if ((sighashType & 31) != Signature.SIGHASH_SINGLE && (sighashType & 31) != Signature.SIGHASH_NONE) {
hashOutputs = Hash.sha256sha256(outputs);
} else if ((sighashType & 31) == Signature.SIGHASH_SINGLE && inputNumber < transaction.outputs.length) {
outputs = GetOutputs(transaction, inputNumber)
hashOutputs = Hash.sha256sha256(outputs);
}
var writer = new BufferWriter()
// Version
writer.writeInt32LE(transaction.version);
// Input prevouts/nSequence (none/all, depending on flags)
writer.write(hashPrevouts);
writer.write(hashSequences);
// outpoint (32-byte hash + 4-byte little endian)
writer.writeReverse(input.prevTxId);
writer.writeUInt32LE(input.outputIndex);
// scriptCode of the input (serialized as scripts inside CTxOuts)
writer.writeVarintNum(subscript.toBuffer().length)
writer.write(subscript.toBuffer());
// value of the output spent by this input (8-byte little endian)
writer.writeUInt64LEBN(satoshisBN);
// nSequence of the input (4-byte little endian)
var sequenceNumber = input.sequenceNumber;
writer.writeUInt32LE(sequenceNumber);
// Outputs (none/one/all, depending on flags)
writer.write(hashOutputs);
// Locktime
writer.writeUInt32LE(transaction.nLockTime);
// sighashType
writer.writeUInt32LE(sighashType >>>0);
// console.log('preimage', [
// transaction.version,
// hashPrevouts.toString('hex'),
// hashSequences.toString('hex'),
// input.prevTxId.toString('hex'),
// input.outputIndex,
// subscript.toBuffer().length,
// subscript.toBuffer().toString('hex'),
// satoshisBN,
// sequenceNumber,
// hashOutputs.toString('hex'),
// transaction.nLockTime,
// sighashType >>>0
// ])
var buf = writer.toBuffer();
var buf256 = Hash.sha256(buf);
var ret = Hash.sha256sha256(buf);
// ret = new BufferReader(ret).readReverse();
resObj = {
prevouts: prevouts,
prevoutsHash: hashPrevouts,
sequences: sequences,
hashSequences: hashSequences,
outputs: outputs,
hashOutputs: hashOutputs,
preimage: buf,
// preimage256: buf256,
// hashPreimage: ret,
}
return resObj;
}
module.exports = Sighash
const bitcore = require('bitcore-lib-cash')
const Transaction = bitcore.Transaction
const Script = bitcore.Script
const PrivateKey = bitcore.PrivateKey
const Hash = bitcore.crypto.Hash
const Interpreter = bitcore.Script.Interpreter
const BN = bitcore.crypto.BN
const BufferUtil = bitcore.util.buffer
const Sighash = require('./Sighash')
const Signature = require('../Signature')
const InputScript = require('../escrow/InputScript')
const ThresholdInputScript = require('../threshold/InputScript')
const CovenantInputScript = require('../covenant/InputScript')
Transaction.P2SHFlags = Interpreter.SCRIPT_VERIFY_P2SH
| Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
| Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
| Interpreter.SCRIPT_ENABLE_CHECKDATASIG
| Interpreter.SCRIPT_VERIFY_STRICTENC
| Interpreter.SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE
/**
* Adds a Pay-to-Script-Hash input to transaction
*
* @param {Script} subScript - original Script
* @param {number} satoshis - output amount
*
* @returns {Transaction}
*/
Transaction.prototype.toP2SH = function (subScript, satoshis) {
let outputBuf = subScript.toBuffer()
let outputP2SH = new Script()
.add('OP_HASH160')
.add(Hash.sha256ripemd160(outputBuf))
.add('OP_EQUAL')
this.addOutput(new Transaction.Output({
script: outputP2SH,
satoshis: satoshis
}))
return this
}
/**
* Signs an escrow transaction as defined in jeton.escrow.OutputScript
*
* @param {number} inputIndex - index of the input to sign
* @param {PrivateKey} winnerPrivKey - the private key of the escrow beneficiary
* @param {string} refMsg - the message for the outcome
* @param {Signature} refSig - the signature for the message and referee public key
* @param {Script} subscript - the non-P2SH (original) scriptPubKey
* @param {number} sighash - the type of signature
*
* @returns {Transaction}
*/
Transaction.prototype.signEscrow = function (inputIndex, winnerPrivKey, refMsg, refSig, subscript, sighash) {
sighash = sighash || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
let input = this.toObject()['inputs'][inputIndex]
let p2pkhSig = Sighash.sign(this, winnerPrivKey, sighash, inputIndex, subscript, BN.fromNumber(input.output.satoshis), Transaction.P2SHFlags)
let winnerScript = Script.buildPublicKeyHashIn(winnerPrivKey.toPublicKey(), p2pkhSig, sighash)
// Generate scriptSig
let inputScriptData = {
refereeSig: refSig,
message: refMsg,
winnerScript: winnerScript,
outputScript: subscript
}
inScript = new InputScript(inputScriptData)
// Set scriptSig for inputIndex
this.inputs[inputIndex].setScript(inScript.toScript())
return this
}
/**
* Signs an threshold escrow transaction as defined in jeton.threshold.OutputScript
*
* @param {number} inputIndex - index of the input to sign
* @param {PrivateKey} winnerPrivKey - the private key of the escrow beneficiary
* @param {string} oracleMsg - the message for the outcome
* @param {Signature} oracleSig - the signature for the message and referee public key
* @param {Script} subscript - the non-P2SH (original) scriptPubKey
* @param {number} sighash - the type of signature
*
* @returns {Transaction}
*/
Transaction.prototype.signThreshold = function (inputIndex, winnerPrivKey, oracleMsg, oracleSig, subscript, sighash) {
sighash = sighash || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
let input = this.toObject()['inputs'][inputIndex]
let p2pkhSig = Sighash.sign(this, winnerPrivKey, sighash, inputIndex, subscript, BN.fromNumber(input.output.satoshis), Transaction.P2SHFlags)
let winnerScript = Script.buildPublicKeyHashIn(winnerPrivKey.toPublicKey(), p2pkhSig, sighash)
// Generate scriptSig
let inputScriptData = {
oracleSig: oracleSig,
message: oracleMsg,
winnerScript: winnerScript,
outputScript: subscript
}
inScript = new ThresholdInputScript(inputScriptData)
// Set scriptSig for inputIndex
this.inputs[inputIndex].setScript(inScript.toScript())
return this
}
/**
* Signs an threshold escrow transaction as defined in jeton.covenant.OutputScript
*
* @param {number} inputIndex - index of the input to sign
* @param {PrivateKey[] | Script[]} privKeysOrScripts - mixed array of PrivateKeys or Scripts representing signing parties. Must be in order.
* @param {Script} subscript - the non-P2SH (original) scriptPubKey
* @param {number} sighash - the type of signature
* @param {boolean} anyoneCanSpend - signifies if there are no specific required signatures
*
* @returns {Transaction}
*/
Transaction.prototype.signCovenant = function (inputIndex, privKeysOrScripts, subscript, sighash, anyoneCanSpend = false) {
sighash = sighash || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
let sigScripts = []
for (let i = 0; i < privKeysOrScripts.length; i++) {
let sigScript = privKeysOrScripts[i]
if (sigScript instanceof PrivateKey) {
let privKey = sigScript
if(!anyoneCanSpend) {
sigScript = this.getCovenantSignatureScript(inputIndex, privKey, subscript, sighash)
} else {
if (privKeysOrScripts.length > 1) {
throw new Error('For anyoneCanSpend inputs, privKeysOrScripts must have a length of 1 and consist of a single PrivateKey')
}
let input = this.toObject()['inputs'][inputIndex]
let p2pkhSig = Sighash.sign(this, privKey, sighash, inputIndex, subscript, BN.fromNumber(input.output.satoshis), Transaction.P2SHFlags)
sigScript = Script.buildPublicKeyHashIn(privKey.toPublicKey(), p2pkhSig, sighash)
}
}
sigScripts.push(sigScript)
}
let preimage = Sighash.getPreimage(this, sighash, inputIndex, subscript)
// Generate scriptSig
let inputScriptData = {
sigScripts: sigScripts,
outputScript: subscript,
preimage: preimage
}
inScript = new CovenantInputScript(inputScriptData)
// Set scriptSig for inputIndex
this.inputs[inputIndex].setScript(inScript.toScript())
return this
}
/**
* Returns a signature, in Script form, that can be used in covenant multisig
*
* @param {number} inputIndex - index of the input to sign
* @param {PrivateKey} privKey - the private key of the escrow beneficiary
* @param {Script} subscript - the non-P2SH (original) scriptPubKey
* @param {number} sighash - the type of signature
*
* @returns {Script}
*/
Transaction.prototype.getCovenantSignatureScript = function (inputIndex, privKey, subscript, sighash) {
sighash = sighash || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
let input = this.toObject()['inputs'][inputIndex]
let p2pkhSig = Sighash.sign(this, privKey, sighash, inputIndex, subscript, BN.fromNumber(input.output.satoshis), Transaction.P2SHFlags)
let sigScript = new Script()
.add(BufferUtil.concat([
p2pkhSig.toBuffer(),
BufferUtil.integerAsSingleByteBuffer(sighash)
]))
return sigScript
}
/**
* Verify that a P2SH input is properly signed
*
* @param {number} inputIndex - the index of the input to be verified
*
* @returns {boolean}
*/
Transaction.prototype.verifyScriptSig = function (inputIndex) {
let input = this.toObject()['inputs'][inputIndex]
let inScriptHex = input.script
let inScript = Script.fromHex(inScriptHex)
let outScriptHex = input.output.script
let outScript = Script.fromHex(outScriptHex)
let verified = Interpreter().verify(inScript, outScript, this, inputIndex, Transaction.P2SHFlags, BN.fromNumber(input.output.satoshis))
return verified
}
/**
* Merges transactions (must use SIGHASH_ANYONECANPAY)
*
* @param {Transaction[]} txArray
*
* @returns {Transaction}
*/
Transaction.mergeTransactionInputs = function (txArray) {
let baseTx = txArray.shift()
for(let i = 0; i < txArray.length; i++) {
let param = {}
param.prevTxId = txArray[i].inputs[0].prevTxId
param.outputIndex = txArray[i].inputs[0].outputIndex
param.sequenceNumber = txArray[i].inputs[0].sequenceNumber
param.script = txArray[i].inputs[0].script
let input = new Transaction.Input(param)
baseTx.addInput(input, param.script, 1000)
}
return baseTx
}
/**
* Format UTXOs for easy use with Transaction.to()
*
* @param {object[]} utxoArray
*
* @returns {UnspentOutput[][]}
*/
Transaction.formatUtxos = function (utxoArray) {
let result = []
for (let i = 0; i < utxoArray.length; i++) {
let scriptPubKey = utxoArray[i].scriptPubKey
let utxos = utxoArray[i].utxos
utxos = utxos.map(function addScriptPubKey(utxo) {
utxo.scriptPubKey = scriptPubKey
return new Transaction.UnspentOutput(utxo)
})
result[i] = utxos
}
return result
}
/**
* Get the satoshi total for an array of utxos
*
* @param {object[] | UnspentOutput[]} utxos
*
* @returns {number}
*/
Transaction.utxosTotalSatoshis = function (utxos) {
let totalSats = utxos.reduce(function sumSats(total, utxo) {
return total + utxo.satoshis
}, 0)
return totalSats
}
Transaction.constructSplitTx = function (inputUtxos, destinationAddr, amountToSend, minerFee) {
totalSats = Transaction.utxosTotalSatoshis(inputUtxos)
tx = new Transaction()
for (let i=0; i < inputUtxos.length; i++) {
tx.from(inputUtxos[i])
}
tx.to(destinationAddr, amountToSend)
tx.to(destinationAddr, totalSats - amountToSend - minerFee)
return tx
}
/**
* Generate an UnspentOutput from the output of a transaction
* @param {Transaction} transaction
* @param {number} outputIndex
*
* @returns {UnspentOutput}
*/
Transaction.utxoFromTxOutput = function (transaction, outputIndex) {
txObj = transaction.toObject()
return new Transaction.UnspentOutput({
"txId" : txObj.hash,
"outputIndex" : outputIndex,
"script" : txObj.outputs[outputIndex].script,
"satoshis" : txObj.outputs[outputIndex].satoshis
})
}
module.exports = Transaction
+1
-1

@@ -112,5 +112,5 @@ const jeton = require('../index')

// console.log(spendTx.toObject())
console.log(spendTx.toObject())
console.log('estimated size', spendTx._estimateSize())
console.log('verify tx full sig', spendTx.verify())
console.log('jeton signature verified?', spendTx.verifyScriptSig(0))

@@ -12,5 +12,5 @@ 'use strict';

// Escrow
jeton.escrow = {}
jeton.escrow.InputScript = require('./lib/escrow/InputScript')
jeton.escrow.OutputScript = require('./lib/escrow/OutputScript')
jeton.escrow = require('./lib/escrow')
// jeton.escrow.InputScript = require('./lib/escrow/InputScript')
// jeton.escrow.OutputScript = require('./lib/escrow/OutputScript')

@@ -22,2 +22,5 @@ // Threshold

// Covenant
jeton.covenant = require('./lib/covenant')
module.exports = jeton
{
"name": "jeton-lib",
"version": "2.0.1",
"version": "2.1.0",
"description": "Extension of bitcore-lib-cash for advanced Bitcoin Cash transaction types",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -19,3 +19,3 @@ # Jeton Lib

"dependencies": {
"jeton-lib": "^2.0.1",
"jeton-lib": "^2.1.0",
...

@@ -29,2 +29,7 @@ }

Examples include:
* Multi-party escrow with an arbitrary message signed by an oracle
* Multi-party escrow with a price message signed by an oracle
* Covenant escrow - multisig, anyone-can-spend, and proportional
### Include jeton-lib wherever you use bitcore-lib-cash

@@ -31,0 +36,0 @@

const bitcore = require('bitcore-lib-cash')
const Transaction = bitcore.Transaction
const Script = bitcore.Script
const Hash = bitcore.crypto.Hash
const Interpreter = bitcore.Script.Interpreter
const Sighash = Transaction.Sighash
const BN = bitcore.crypto.BN
const Signature = require('./Signature')
const InputScript = require('./escrow/InputScript')
const ThresholdInputScript = require('./threshold/InputScript')
Transaction.P2SHFlags = Interpreter.SCRIPT_VERIFY_P2SH
| Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
| Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
| Interpreter.SCRIPT_ENABLE_CHECKDATASIG
| Interpreter.SCRIPT_VERIFY_STRICTENC
| Interpreter.SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE
/**
* Adds a Pay-to-Script-Hash input to transaction
*
* @param {Script} scriptPubKey - original Script
* @param {number} satoshis - output amount
*
* @returns {Transaction}
*/
Transaction.prototype.toP2SH = function (scriptPubKey, satoshis) {
let outputBuf = scriptPubKey.toBuffer()
let outputP2SH = new Script()
.add('OP_HASH160')
.add(Hash.sha256ripemd160(outputBuf))
.add('OP_EQUAL')
this.addOutput(new Transaction.Output({
script: outputP2SH,
satoshis: satoshis
}))
return this
}
/**
* Signs an escrow transaction as defined in jeton.escrow.OutputScript
*
* @param {number} inputIndex - index of the input to sign
* @param {PrivateKey} winnerPrivKey - the private key of the escrow beneficiary
* @param {string} refMsg - the message for the outcome
* @param {Signature} refSig - the signature for the message and referee public key
* @param {Script} subscript - the non-P2SH (original) scriptPubKey
* @param {number} sighash - the type of signature
*
* @returns {Transaction}
*/
Transaction.prototype.signEscrow = function (inputIndex, winnerPrivKey, refMsg, refSig, subscript, sighash) {
sighash = sighash || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
let input = this.toObject()['inputs'][inputIndex]
let p2pkhSig = Sighash.sign(this, winnerPrivKey, sighash, inputIndex, subscript, BN.fromNumber(input.output.satoshis), Transaction.P2SHFlags)
let winnerScript = Script.buildPublicKeyHashIn(winnerPrivKey.toPublicKey(), p2pkhSig, sighash)
// Generate scriptSig
let inputScriptData = {
refereeSig: refSig,
message: refMsg,
winnerScript: winnerScript,
outputScript: subscript
}
inScript = new InputScript(inputScriptData)
// Set scriptSig for inputIndex
this.inputs[inputIndex].setScript(inScript.toScript())
return this
}
/**
* Signs an threshold escrow transaction as defined in jeton.threshold.OutputScript
*
* @param {number} inputIndex - index of the input to sign
* @param {PrivateKey} winnerPrivKey - the private key of the escrow beneficiary
* @param {string} oracleMsg - the message for the outcome
* @param {Signature} oracleSig - the signature for the message and referee public key
* @param {Script} subscript - the non-P2SH (original) scriptPubKey
* @param {number} sighash - the type of signature
*
* @returns {Transaction}
*/
Transaction.prototype.signThreshold = function (inputIndex, winnerPrivKey, oracleMsg, oracleSig, subscript, sighash) {
sighash = sighash || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
let input = this.toObject()['inputs'][inputIndex]
let p2pkhSig = Sighash.sign(this, winnerPrivKey, sighash, inputIndex, subscript, BN.fromNumber(input.output.satoshis), Transaction.P2SHFlags)
let winnerScript = Script.buildPublicKeyHashIn(winnerPrivKey.toPublicKey(), p2pkhSig, sighash)
// Generate scriptSig
let inputScriptData = {
oracleSig: oracleSig,
message: oracleMsg,
winnerScript: winnerScript,
outputScript: subscript
}
inScript = new ThresholdInputScript(inputScriptData)
// Set scriptSig for inputIndex
this.inputs[inputIndex].setScript(inScript.toScript())
return this
}
/**
* Verify that a P2SH input is properly signed
*
* @param {number} inputIndex - the index of the input to be verified
*
* @returns {boolean}
*/
Transaction.prototype.verifyScriptSig = function (inputIndex) {
let input = this.toObject()['inputs'][inputIndex]
let inScriptHex = input.script
let inScript = Script.fromHex(inScriptHex)
let outScriptHex = input.output.script
let outScript = Script.fromHex(outScriptHex)
let verified = Interpreter().verify(inScript, outScript, this, inputIndex, Transaction.P2SHFlags, BN.fromNumber(input.output.satoshis))
return verified
}
/**
* Merges transactions (must use SIGHASH_ANYONECANPAY)
*
* @param {Transaction[]} txArray
*
* @returns {Transaction}
*/
Transaction.mergeTransactionInputs = function (txArray) {
let baseTx = txArray.shift()
for(let i = 0; i < txArray.length; i++) {
let param = {}
param.prevTxId = txArray[i].inputs[0].prevTxId
param.outputIndex = txArray[i].inputs[0].outputIndex
param.sequenceNumber = txArray[i].inputs[0].sequenceNumber
param.script = txArray[i].inputs[0].script
let input = new Transaction.Input(param)
baseTx.addInput(input, param.script, 1000)
}
return baseTx
}
/**
* Format UTXOs for easy use with Transaction.to()
*
* @param {object[]} utxoArray
*
* @returns {UnspentOutput[][]}
*/
Transaction.formatUtxos = function (utxoArray) {
let result = []
for (let i = 0; i < utxoArray.length; i++) {
let scriptPubKey = utxoArray[i].scriptPubKey
let utxos = utxoArray[i].utxos
utxos = utxos.map(function addScriptPubKey(utxo) {
utxo.scriptPubKey = scriptPubKey
return new Transaction.UnspentOutput(utxo)
})
result[i] = utxos
}
return result
}
/**
* Get the satoshi total for an array of utxos
*
* @param {object[] | UnspentOutput[]} utxos
*
* @returns {number}
*/
Transaction.utxosTotalSatoshis = function (utxos) {
let totalSats = utxos.reduce(function sumSats(total, utxo) {
return total + utxo.satoshis
}, 0)
return totalSats
}
Transaction.constructSplitTx = function (inputUtxos, destinationAddr, amountToSend, minerFee) {
totalSats = Transaction.utxosTotalSatoshis(inputUtxos)
tx = new Transaction()
for (let i=0; i < inputUtxos.length; i++) {
tx.from(inputUtxos[i])
}
tx.to(destinationAddr, amountToSend)
tx.to(destinationAddr, totalSats - amountToSend - minerFee)
return tx
}
/**
* Generate an UnspentOutput from the output of a transaction
* @param {Transaction} transaction
* @param {number} outputIndex
*
* @returns {UnspentOutput}
*/
Transaction.utxoFromTxOutput = function (transaction, outputIndex) {
txObj = transaction.toObject()
return new Transaction.UnspentOutput({
"txId" : txObj.hash,
"outputIndex" : outputIndex,
"script" : txObj.outputs[outputIndex].script,
"satoshis" : txObj.outputs[outputIndex].satoshis
})
}
module.exports = Transaction