diff --git a/lib/address.js b/lib/address.js index d1a07be7c..f60fc42ac 100644 --- a/lib/address.js +++ b/lib/address.js @@ -1,5 +1,6 @@ 'use strict'; +var _ = require('lodash'); var $ = require('./util/preconditions'); var base58check = require('./encoding/base58check'); var Networks = require('./networks'); @@ -42,6 +43,10 @@ function Address(data, network, type) { return new Address(data, network, type); } + if (_.isArray(data) && _.isNumber(network)) { + return Address.createMultisig(data, network, type); + } + if (!data) { throw new TypeError('First argument is required, please include address data.'); } @@ -225,6 +230,19 @@ Address._transformScript = function(script, network){ return info; }; +/** + * Creates a P2SH address from a set of public keys and a threshold. + * + * @param {Array} publicKeys + * @param {number} threshold + * @param {Network} network + * @return {Address} + */ +Address.createMultisig = function(publicKeys, threshold, network) { + var Script = require('./script'); + return new Address(Script.buildMultisigOut(publicKeys, threshold), network || Networks.defaultNetwork); +}; + /** * Internal function to transform a bitcoin address string * diff --git a/lib/script/script.js b/lib/script/script.js index c9fbc1256..1ba0f75e9 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -516,32 +516,30 @@ Script.prototype.removeCodeseparators = function() { /** * @returns a new Multisig output script for given public keys, * requiring m of those public keys to spend - * @param {PublicKey[]} pubkeys - list of all public keys controlling the output - * @param {number} m - amount of required signatures to spend the output + * @param {PublicKey[]} publicKeys - list of all public keys controlling the output + * @param {number} threshold - amount of required signatures to spend the output * @param {Object} [opts] - Several options: * - noSorting: defaults to false, if true, don't sort the given * public keys before creating the script */ -Script.buildMultisigOut = function(pubkeys, m, opts) { +Script.buildMultisigOut = function(publicKeys, threshold, opts) { opts = opts || {}; - var s = new Script(); - s.add(Opcode.smallInt(m)); - pubkeys = _.map(pubkeys, function(pubkey) { - return PublicKey(pubkey); - }); - var sorted = pubkeys; + var script = new Script(); + script.add(Opcode.smallInt(threshold)); + publicKeys = _.map(publicKeys, PublicKey); + var sorted = publicKeys; if (!opts.noSorting) { - sorted = _.sortBy(pubkeys, function(pubkey) { - return pubkey.toString('hex'); + sorted = _.sortBy(publicKeys, function(publicKey) { + return publicKey.toString('hex'); }); } for (var i = 0; i < sorted.length; i++) { - var pubkey = sorted[i]; - s.add(pubkey.toBuffer()); + var publicKey = sorted[i]; + script.add(publicKey.toBuffer()); } - s.add(Opcode.smallInt(pubkeys.length)); - s.add(Opcode.OP_CHECKMULTISIG); - return s; + script.add(Opcode.smallInt(publicKeys.length)); + script.add(Opcode.OP_CHECKMULTISIG); + return script; }; /** diff --git a/test/address.js b/test/address.js index fa22ad342..7b6696c5b 100644 --- a/test/address.js +++ b/test/address.js @@ -448,4 +448,28 @@ describe('Address', function() { }); }); + describe('creating a P2SH address from public keys', function() { + + var public1 = '02da5798ed0c055e31339eb9b5cef0d3c0ccdec84a62e2e255eb5c006d4f3e7f5b'; + var public2 = '0272073bf0287c4469a2a011567361d42529cd1a72ab0d86aa104ecc89342ffeb0'; + var public3 = '02738a516a78355db138e8119e58934864ce222c553a5407cf92b9c1527e03c1a2'; + var publics = [public1, public2, public3]; + + it('can create an address from a set of public keys', function() { + var address = new Address(publics, 2); + address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y'); + }); + + it('works on testnet also', function() { + var address = new Address(publics, 2, Networks.testnet); + address.toString().should.equal('2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf'); + }); + + it('can also be created by Address.createMultisig', function() { + var address = Address.createMultisig(publics, 2); + var address2 = Address.createMultisig(publics, 2); + address.toString().should.equal(address2.toString()); + }); + }); + });