docco documentation
This commit is contained in:
parent
0c8a582522
commit
ec2299362c
|
@ -17,7 +17,7 @@ module.exports = function(grunt) {
|
||||||
stderr: true
|
stderr: true
|
||||||
},
|
},
|
||||||
command: grunt.option('target') === 'dev' ?
|
command: grunt.option('target') === 'dev' ?
|
||||||
'node ./browser/build.js -a -d ' : 'node ./browser/build.js -a'
|
'node ./browser/build.js -a -d; docco lib/* ' : 'node ./browser/build.js -a'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -1,80 +1,51 @@
|
||||||
|
|
||||||
/*
|
// Creates a bitcore Transaction object
|
||||||
var tx = (new TransactionBuilder(opts))
|
//
|
||||||
.setUnspent(utxos)
|
//
|
||||||
.setOutputs(outs)
|
// Synopsis
|
||||||
.sign(keys)
|
// --------
|
||||||
.build();
|
// ```
|
||||||
|
// var tx = (new TransactionBuilder(opts))
|
||||||
|
// .setUnspent(utxos)
|
||||||
var builder = (new TransactionBuilder(opts))
|
// .setOutputs(outs)
|
||||||
.setUnspent(spent)
|
// .sign(keys)
|
||||||
.setOutputs(outs);
|
// .build();
|
||||||
|
//
|
||||||
// Uncomplete tx (no signed or partially signed)
|
//
|
||||||
var tx = builder.build();
|
// var builder = (new TransactionBuilder(opts))
|
||||||
|
// .setUnspent(spent)
|
||||||
..later..
|
// .setOutputs(outs);
|
||||||
|
//
|
||||||
builder.sign(keys);
|
// // Uncomplete tx (no signed or partially signed)
|
||||||
while ( builder.isFullySigned() ) {
|
// var tx = builder.build();
|
||||||
|
//
|
||||||
... get new keys ...
|
// ..later..
|
||||||
|
//
|
||||||
builder.sign(keys);
|
// builder.sign(keys);
|
||||||
}
|
// while ( builder.isFullySigned() ) {
|
||||||
|
//
|
||||||
var tx = builder.build();
|
// ... get new keys ...
|
||||||
broadcast(tx.serialize());
|
//
|
||||||
|
// builder.sign(keys);
|
||||||
To get selected unspent outputs:
|
// }
|
||||||
var selectedUnspent = builder.getSelectedUnspent();
|
//
|
||||||
|
// var tx = builder.build();
|
||||||
|
// broadcast(tx.serialize());
|
||||||
@unspent
|
//
|
||||||
* unspent outputs array (UTXO), using the following format:
|
// //Searialize it and pass it around...
|
||||||
* [{
|
// var string = JSON.serialize(builder.toObj());
|
||||||
* address: "mqSjTad2TKbPcKQ3Jq4kgCkKatyN44UMgZ",
|
// // then...
|
||||||
* hash: "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1",
|
// var builder = TransactionBuilder.fromObj(JSON.parse(str);
|
||||||
* scriptPubKey: "76a9146ce4e1163eb18939b1440c42844d5f0261c0338288ac",
|
// builder.sign(keys);
|
||||||
* vout: 1,
|
// // Also
|
||||||
* amount: 0.01,
|
// var builder2 = TransactionBuilder.fromObj(JSON.parse(str2);
|
||||||
* confirmations: 3
|
// builder2.merge(builder); // Will merge signatures for p2sh mulsig txs.
|
||||||
* }, ...
|
//
|
||||||
* ]
|
//
|
||||||
* This is compatible con insight's utxo API.
|
// ```
|
||||||
* That amount is in BTCs (as returned in insight and bitcoind).
|
//
|
||||||
* amountSat (instead of amount) can be given to provide amount in satochis.
|
//
|
||||||
*
|
//
|
||||||
* @outs
|
|
||||||
* an array of [{
|
|
||||||
* address: xx,
|
|
||||||
* amount:0.001
|
|
||||||
* },...]
|
|
||||||
*
|
|
||||||
* @keys
|
|
||||||
* an array of strings representing private keys to sign the
|
|
||||||
* transaction in WIF private key format OR WalletKey objects
|
|
||||||
*
|
|
||||||
* @opts
|
|
||||||
* {
|
|
||||||
* remainderOut: null,
|
|
||||||
* fee: 0.001,
|
|
||||||
* lockTime: null,
|
|
||||||
* spendUnconfirmed: false,
|
|
||||||
* signhash: SIGHASH_ALL
|
|
||||||
* }
|
|
||||||
* Amounts are in BTC. instead of fee and amount; feeSat and amountSat can be given,
|
|
||||||
* repectively, to provide amounts in satoshis.
|
|
||||||
*
|
|
||||||
* If no remainderOut is given, and there are remainder coins, the
|
|
||||||
* first IN out will be used to return the coins. remainderOut has the form:
|
|
||||||
* remainderOut = { address: 1xxxxx}
|
|
||||||
* or
|
|
||||||
* remainderOut = { pubkeys: ['hex1','hex2',...} for multisig
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -94,6 +65,35 @@ var log = imports.log || require('../util/log');
|
||||||
var Transaction = imports.Transaction || require('./Transaction');
|
var Transaction = imports.Transaction || require('./Transaction');
|
||||||
var FEE_PER_1000B_SAT = parseInt(0.0001 * util.COIN);
|
var FEE_PER_1000B_SAT = parseInt(0.0001 * util.COIN);
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
// -------
|
||||||
|
//
|
||||||
|
// TransactionBuilder
|
||||||
|
// ------------------
|
||||||
|
// Creates a TransactionBuilder instance
|
||||||
|
// `opts`
|
||||||
|
// ```
|
||||||
|
// {
|
||||||
|
// remainderOut: null,
|
||||||
|
// fee: 0.001,
|
||||||
|
// lockTime: null,
|
||||||
|
// spendUnconfirmed: false,
|
||||||
|
// signhash: SIGHASH_ALL
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// Amounts are in BTC. instead of fee and amount; feeSat and amountSat can be given,
|
||||||
|
// repectively, to provide amounts in satoshis.
|
||||||
|
//
|
||||||
|
// If no remainderOut is given, and there are remainder coins, the
|
||||||
|
// first IN out will be used to return the coins. remainderOut has the form:
|
||||||
|
// ```
|
||||||
|
// remainderOut = { address: 1xxxxx}
|
||||||
|
// ```
|
||||||
|
// or
|
||||||
|
// ```
|
||||||
|
// remainderOut = { pubkeys: ['hex1','hex2',...} for multisig
|
||||||
|
// ```
|
||||||
|
|
||||||
function TransactionBuilder(opts) {
|
function TransactionBuilder(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
this.lockTime = opts.lockTime || 0;
|
this.lockTime = opts.lockTime || 0;
|
||||||
|
@ -179,8 +179,27 @@ TransactionBuilder.infoForP2sh = function(opts, networkName) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype.setUnspent = function(utxos) {
|
// setUnspent
|
||||||
this.utxos = utxos;
|
// ----------
|
||||||
|
// Sets the `unspent` available for the transaction. Some (or all)
|
||||||
|
// of them to fullfil the transaction's outputs and fee.
|
||||||
|
// The expected format is:
|
||||||
|
// ```
|
||||||
|
// [{
|
||||||
|
// address: "mqSjTad2TKbPcKQ3Jq4kgCkKatyN44UMgZ",
|
||||||
|
// hash: "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1",
|
||||||
|
// scriptPubKey: "76a9146ce4e1163eb18939b1440c42844d5f0261c0338288ac",
|
||||||
|
// vout: 1,
|
||||||
|
// amount: 0.01,
|
||||||
|
// confirmations: 3
|
||||||
|
// }, ...
|
||||||
|
// ]
|
||||||
|
// ```
|
||||||
|
// This is compatible con insight's utxo API.
|
||||||
|
// That amount is in BTCs (as returned in insight and bitcoind).
|
||||||
|
// amountSat (instead of amount) can be given to provide amount in satochis.
|
||||||
|
TransactionBuilder.prototype.setUnspent = function(unspent) {
|
||||||
|
this.utxos = unspent;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -209,6 +228,12 @@ TransactionBuilder.prototype._setInputMap = function() {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// getSelectedUnspent
|
||||||
|
// ------------------
|
||||||
|
//
|
||||||
|
// Returns the selected unspent outputs, to be used in the transaction.
|
||||||
|
|
||||||
TransactionBuilder.prototype.getSelectedUnspent = function() {
|
TransactionBuilder.prototype.getSelectedUnspent = function() {
|
||||||
return this.selectedUtxos;
|
return this.selectedUtxos;
|
||||||
};
|
};
|
||||||
|
@ -312,12 +337,12 @@ TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) {
|
||||||
typeof this.valueOutSat === 'undefined')
|
typeof this.valueOutSat === 'undefined')
|
||||||
throw new Error('valueInSat / valueOutSat undefined');
|
throw new Error('valueInSat / valueOutSat undefined');
|
||||||
|
|
||||||
// add remainder (without modifying outs[])
|
/* add remainder (without modifying outs[]) */
|
||||||
var remainderSat = this.valueInSat.sub(this.valueOutSat).sub(this.feeSat);
|
var remainderSat = this.valueInSat.sub(this.valueOutSat).sub(this.feeSat);
|
||||||
var l =txobj.outs.length;
|
var l =txobj.outs.length;
|
||||||
this.remainderSat = bignum(0);
|
this.remainderSat = bignum(0);
|
||||||
|
|
||||||
//remove old remainder?
|
/*remove old remainder? */
|
||||||
if (l > remainderIndex) {
|
if (l > remainderIndex) {
|
||||||
txobj.outs.pop();
|
txobj.outs.pop();
|
||||||
}
|
}
|
||||||
|
@ -339,10 +364,10 @@ TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) {
|
||||||
|
|
||||||
TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
|
TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
|
||||||
|
|
||||||
//starting size estimation
|
/* starting size estimation */
|
||||||
var size = 500, maxSizeK, remainderIndex = txobj.outs.length;
|
var size = 500, maxSizeK, remainderIndex = txobj.outs.length;
|
||||||
do {
|
do {
|
||||||
// based on https://en.bitcoin.it/wiki/Transaction_fees
|
/* based on https://en.bitcoin.it/wiki/Transaction_fees */
|
||||||
maxSizeK = parseInt(size / 1000) + 1;
|
maxSizeK = parseInt(size / 1000) + 1;
|
||||||
|
|
||||||
var feeSat = this.givenFeeSat ?
|
var feeSat = this.givenFeeSat ?
|
||||||
|
@ -361,6 +386,21 @@ TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// setOutputs
|
||||||
|
// ----------
|
||||||
|
// Sets the outputs for the transaction. Format is:
|
||||||
|
// ```
|
||||||
|
// an array of [{
|
||||||
|
// address: xx,
|
||||||
|
// amount:0.001
|
||||||
|
// },...]
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Note that only some of this outputs will be selected
|
||||||
|
// to create the transaction. The selected ones can be checked
|
||||||
|
// after calling `setOutputs`, with `.getSelectedUnspent`
|
||||||
|
//
|
||||||
|
|
||||||
TransactionBuilder.prototype.setOutputs = function(outs) {
|
TransactionBuilder.prototype.setOutputs = function(outs) {
|
||||||
var valueOutSat = bignum(0);
|
var valueOutSat = bignum(0);
|
||||||
|
|
||||||
|
@ -394,7 +434,7 @@ TransactionBuilder.prototype.setOutputs = function(outs) {
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder._mapKeys = function(keys) {
|
TransactionBuilder._mapKeys = function(keys) {
|
||||||
//prepare keys
|
/* prepare keys */
|
||||||
var walletKeyMap = {};
|
var walletKeyMap = {};
|
||||||
var l = keys.length;
|
var l = keys.length;
|
||||||
var wk;
|
var wk;
|
||||||
|
@ -505,15 +545,15 @@ TransactionBuilder.prototype._signPubKeyHash = function(walletKeyMap, input, txS
|
||||||
return {inputFullySigned: true, signaturesAdded: 1, script: scriptSig.getBuffer()};
|
return {inputFullySigned: true, signaturesAdded: 1, script: scriptSig.getBuffer()};
|
||||||
};
|
};
|
||||||
|
|
||||||
// FOR TESTING
|
/* FOR TESTING
|
||||||
// var _dumpChunks = function (scriptSig, label) {
|
var _dumpChunks = function (scriptSig, label) {
|
||||||
// console.log('## DUMP: ' + label + ' ##');
|
console.log('## DUMP: ' + label + ' ##');
|
||||||
// for(var i=0; i<scriptSig.chunks.length; i++) {
|
for(var i=0; i<scriptSig.chunks.length; i++) {
|
||||||
// console.log('\tCHUNK ', i, Buffer.isBuffer(scriptSig.chunks[i])
|
console.log('\tCHUNK ', i, Buffer.isBuffer(scriptSig.chunks[i])
|
||||||
// ?scriptSig.chunks[i].toString('hex'):scriptSig.chunks[i] );
|
?scriptSig.chunks[i].toString('hex'):scriptSig.chunks[i] );
|
||||||
// }
|
}
|
||||||
// };
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
TransactionBuilder.prototype._chunkSignedWithKey = function(scriptSig, txSigHash, publicKey) {
|
TransactionBuilder.prototype._chunkSignedWithKey = function(scriptSig, txSigHash, publicKey) {
|
||||||
var ret;
|
var ret;
|
||||||
|
@ -599,7 +639,6 @@ TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSig
|
||||||
var signaturesAdded = 0;
|
var signaturesAdded = 0;
|
||||||
|
|
||||||
for(var j=0; j<l && scriptSig.countSignatures() < nreq ; j++) {
|
for(var j=0; j<l && scriptSig.countSignatures() < nreq ; j++) {
|
||||||
//console.log('[TransactionBuilder.js] pubkey [j]',j, pubkeys[j].toString('hex')); //TODO
|
|
||||||
var wk = this._findWalletKey(walletKeyMap, {pubKeyBuf: pubkeys[j]});
|
var wk = this._findWalletKey(walletKeyMap, {pubKeyBuf: pubkeys[j]});
|
||||||
if (!wk) continue;
|
if (!wk) continue;
|
||||||
|
|
||||||
|
@ -609,8 +648,6 @@ TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSig
|
||||||
signaturesAdded++;
|
signaturesAdded++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scriptSig.countSignatures() === nreq) {
|
|
||||||
}
|
|
||||||
|
|
||||||
var ret = {
|
var ret = {
|
||||||
inputFullySigned: scriptSig.countSignatures() === nreq,
|
inputFullySigned: scriptSig.countSignatures() === nreq,
|
||||||
|
@ -621,7 +658,6 @@ TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSig
|
||||||
};
|
};
|
||||||
|
|
||||||
var fnToSign = {};
|
var fnToSign = {};
|
||||||
|
|
||||||
TransactionBuilder.prototype._scriptIsAppended = function(script, scriptToAddBuf) {
|
TransactionBuilder.prototype._scriptIsAppended = function(script, scriptToAddBuf) {
|
||||||
var len = script.chunks.length;
|
var len = script.chunks.length;
|
||||||
|
|
||||||
|
@ -647,7 +683,7 @@ TransactionBuilder.prototype._addScript = function(scriptBuf, scriptToAddBuf) {
|
||||||
|
|
||||||
TransactionBuilder.prototype._getInputForP2sh = function(script, index) {
|
TransactionBuilder.prototype._getInputForP2sh = function(script, index) {
|
||||||
var scriptType = script.classify();
|
var scriptType = script.classify();
|
||||||
// pubKeyHash is needed for TX_PUBKEYHASH and TX_PUBKEY to retrieve the keys.
|
/* pubKeyHash is needed for TX_PUBKEYHASH and TX_PUBKEY to retrieve the keys. */
|
||||||
var pubKeyHash;
|
var pubKeyHash;
|
||||||
switch(scriptType) {
|
switch(scriptType) {
|
||||||
case Script.TX_PUBKEYHASH:
|
case Script.TX_PUBKEYHASH:
|
||||||
|
@ -705,6 +741,20 @@ fnToSign[Script.TX_PUBKEY] = TransactionBuilder.prototype._signPubKey;
|
||||||
fnToSign[Script.TX_MULTISIG] = TransactionBuilder.prototype._signMultiSig;
|
fnToSign[Script.TX_MULTISIG] = TransactionBuilder.prototype._signMultiSig;
|
||||||
fnToSign[Script.TX_SCRIPTHASH] = TransactionBuilder.prototype._signScriptHash;
|
fnToSign[Script.TX_SCRIPTHASH] = TransactionBuilder.prototype._signScriptHash;
|
||||||
|
|
||||||
|
// sign
|
||||||
|
// ----
|
||||||
|
// Signs a transaction.
|
||||||
|
// `keys`: an array of strings representing private keys to sign the
|
||||||
|
// transaction in WIF private key format OR bitcore's `WalletKey` objects
|
||||||
|
//
|
||||||
|
// If multiple keys are given, each will be tested against the transaction's
|
||||||
|
// scriptPubKeys. Only the valid private keys will be used to sign.
|
||||||
|
// This method is fully compatible with *multisig* transactions.
|
||||||
|
//
|
||||||
|
// `.isFullySigned` can be queried to check is the transactions have all the needed
|
||||||
|
// signatures.
|
||||||
|
//
|
||||||
|
//
|
||||||
TransactionBuilder.prototype.sign = function(keys) {
|
TransactionBuilder.prototype.sign = function(keys) {
|
||||||
this._checkTx();
|
this._checkTx();
|
||||||
var tx = this.tx,
|
var tx = this.tx,
|
||||||
|
@ -728,13 +778,24 @@ TransactionBuilder.prototype.sign = function(keys) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
// [ { address:scriptHex }]
|
// setHashToScriptMap
|
||||||
|
// ------------------
|
||||||
|
// Needed for setup Address to Script maps
|
||||||
|
// for p2sh transactions. See `.infoForP2sh`
|
||||||
|
// for generate the input for this call.
|
||||||
|
//
|
||||||
TransactionBuilder.prototype.setHashToScriptMap = function(hashToScriptMap) {
|
TransactionBuilder.prototype.setHashToScriptMap = function(hashToScriptMap) {
|
||||||
this.hashToScriptMap= hashToScriptMap;
|
this.hashToScriptMap= hashToScriptMap;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// isFullySigned
|
||||||
|
// -------------
|
||||||
|
// Checks if the transaction have all the necesary signatures.
|
||||||
|
// Also, `.signaturesAdded` and `.inputsSigned` can be queried
|
||||||
|
// for more information about the transaction signature status.
|
||||||
|
//
|
||||||
TransactionBuilder.prototype.isFullySigned = function() {
|
TransactionBuilder.prototype.isFullySigned = function() {
|
||||||
return this.inputsSigned === this.tx.ins.length;
|
return this.inputsSigned === this.tx.ins.length;
|
||||||
};
|
};
|
||||||
|
@ -744,7 +805,13 @@ TransactionBuilder.prototype.build = function() {
|
||||||
return this.tx;
|
return this.tx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// toObj
|
||||||
|
// -----
|
||||||
|
// Returns a plain Javascript object that contains
|
||||||
|
// the full status of the TransactionBuilder instance,
|
||||||
|
// suitable for serialization, storage and transmition.
|
||||||
|
// See `.fromObj`
|
||||||
|
//
|
||||||
TransactionBuilder.prototype.toObj = function() {
|
TransactionBuilder.prototype.toObj = function() {
|
||||||
var data = {
|
var data = {
|
||||||
valueInSat : this.valueInSat.toString(),
|
valueInSat : this.valueInSat.toString(),
|
||||||
|
@ -758,7 +825,6 @@ TransactionBuilder.prototype.toObj = function() {
|
||||||
inputsSigned : this.inputsSigned,
|
inputsSigned : this.inputsSigned,
|
||||||
signaturesAdded : this.signaturesAdded,
|
signaturesAdded : this.signaturesAdded,
|
||||||
|
|
||||||
//opts :
|
|
||||||
signhash : this.signhash,
|
signhash : this.signhash,
|
||||||
spendUnconfirmed : this.spendUnconfirmed,
|
spendUnconfirmed : this.spendUnconfirmed,
|
||||||
};
|
};
|
||||||
|
@ -768,6 +834,11 @@ TransactionBuilder.prototype.toObj = function() {
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// fromObj
|
||||||
|
// -------
|
||||||
|
// Returns a TransactionBuilder instance given
|
||||||
|
// a plain Javascript object created previously
|
||||||
|
// with `.toObj`. See `.toObj`.
|
||||||
|
|
||||||
TransactionBuilder.fromObj = function(data) {
|
TransactionBuilder.fromObj = function(data) {
|
||||||
var b = new TransactionBuilder();
|
var b = new TransactionBuilder();
|
||||||
|
@ -950,6 +1021,11 @@ TransactionBuilder.prototype._mergeTx = function(tx, ignoreConflictingSignatures
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// merge
|
||||||
|
// -----
|
||||||
|
// Merge to TransactionBuilder objects, merging inputs signatures.
|
||||||
|
// This function supports multisig p2sh inputs.
|
||||||
|
|
||||||
TransactionBuilder.prototype.merge = function(b) {
|
TransactionBuilder.prototype.merge = function(b) {
|
||||||
this._checkMergeability(b);
|
this._checkMergeability(b);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue