diff --git a/Gruntfile.js b/Gruntfile.js index f7d6193..5b29abe 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,7 +17,7 @@ module.exports = function(grunt) { stderr: true }, 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: { diff --git a/lib/TransactionBuilder.js b/lib/TransactionBuilder.js index c4172d1..cf6f2ed 100644 --- a/lib/TransactionBuilder.js +++ b/lib/TransactionBuilder.js @@ -1,80 +1,51 @@ -/* - var tx = (new TransactionBuilder(opts)) - .setUnspent(utxos) - .setOutputs(outs) - .sign(keys) - .build(); - - - var builder = (new TransactionBuilder(opts)) - .setUnspent(spent) - .setOutputs(outs); - - // Uncomplete tx (no signed or partially signed) - var tx = builder.build(); - - ..later.. - - builder.sign(keys); - while ( builder.isFullySigned() ) { - - ... get new keys ... - - builder.sign(keys); - } - - var tx = builder.build(); - broadcast(tx.serialize()); - - To get selected unspent outputs: - var selectedUnspent = builder.getSelectedUnspent(); - - - @unspent - * unspent outputs array (UTXO), using the following format: - * [{ - * 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. - * - * @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 - * - * - */ +// Creates a bitcore Transaction object +// +// +// Synopsis +// -------- +// ``` +// var tx = (new TransactionBuilder(opts)) +// .setUnspent(utxos) +// .setOutputs(outs) +// .sign(keys) +// .build(); +// +// +// var builder = (new TransactionBuilder(opts)) +// .setUnspent(spent) +// .setOutputs(outs); +// +// // Uncomplete tx (no signed or partially signed) +// var tx = builder.build(); +// +// ..later.. +// +// builder.sign(keys); +// while ( builder.isFullySigned() ) { +// +// ... get new keys ... +// +// builder.sign(keys); +// } +// +// var tx = builder.build(); +// broadcast(tx.serialize()); +// +// //Searialize it and pass it around... +// var string = JSON.serialize(builder.toObj()); +// // then... +// var builder = TransactionBuilder.fromObj(JSON.parse(str); +// builder.sign(keys); +// // Also +// var builder2 = TransactionBuilder.fromObj(JSON.parse(str2); +// builder2.merge(builder); // Will merge signatures for p2sh mulsig txs. +// +// +// ``` +// +// +// 'use strict'; @@ -94,6 +65,35 @@ var log = imports.log || require('../util/log'); var Transaction = imports.Transaction || require('./Transaction'); 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) { opts = opts || {}; this.lockTime = opts.lockTime || 0; @@ -179,8 +179,27 @@ TransactionBuilder.infoForP2sh = function(opts, networkName) { }; }; -TransactionBuilder.prototype.setUnspent = function(utxos) { - this.utxos = utxos; +// setUnspent +// ---------- +// 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; }; @@ -209,6 +228,12 @@ TransactionBuilder.prototype._setInputMap = function() { return this; }; + +// getSelectedUnspent +// ------------------ +// +// Returns the selected unspent outputs, to be used in the transaction. + TransactionBuilder.prototype.getSelectedUnspent = function() { return this.selectedUtxos; }; @@ -312,12 +337,12 @@ TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) { typeof this.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 l =txobj.outs.length; this.remainderSat = bignum(0); - //remove old remainder? + /*remove old remainder? */ if (l > remainderIndex) { txobj.outs.pop(); } @@ -339,10 +364,10 @@ TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) { TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) { - //starting size estimation + /* starting size estimation */ var size = 500, maxSizeK, remainderIndex = txobj.outs.length; do { - // based on https://en.bitcoin.it/wiki/Transaction_fees + /* based on https://en.bitcoin.it/wiki/Transaction_fees */ maxSizeK = parseInt(size / 1000) + 1; var feeSat = this.givenFeeSat ? @@ -361,6 +386,21 @@ TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) { 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) { var valueOutSat = bignum(0); @@ -394,7 +434,7 @@ TransactionBuilder.prototype.setOutputs = function(outs) { }; TransactionBuilder._mapKeys = function(keys) { - //prepare keys + /* prepare keys */ var walletKeyMap = {}; var l = keys.length; var wk; @@ -505,15 +545,15 @@ TransactionBuilder.prototype._signPubKeyHash = function(walletKeyMap, input, txS return {inputFullySigned: true, signaturesAdded: 1, script: scriptSig.getBuffer()}; }; -// FOR TESTING -// var _dumpChunks = function (scriptSig, label) { -// console.log('## DUMP: ' + label + ' ##'); -// for(var i=0; i