diff --git a/lib/address.js b/lib/address.js index f9177eea4..abc0acae0 100644 --- a/lib/address.js +++ b/lib/address.js @@ -234,9 +234,17 @@ Address._transformScript = function(script, network){ if (!script.constructor || (script.constructor.name && script.constructor.name !== 'Script')) { throw new TypeError('Address must be an instance of Script.'); } + if (script.isScriptHashOut()) { + info.hashBuffer = script.getData(); + info.type = Address.PayToScriptHash; + } else if (script.isPublicKeyHashOut()) { + info.hashBuffer = script.getData(); + info.type = Address.PayToPublicKeyHash; + } else { + info.hashBuffer = Hash.sha256ripemd160(script.toBuffer()); + info.type = Address.PayToScriptHash; + } info.network = network || Networks.defaultNetwork; - info.hashBuffer = Hash.sha256ripemd160(script.toBuffer()); - info.type = Address.PayToScriptHash; return info; }; diff --git a/lib/script/script.js b/lib/script/script.js index 8e557ef7d..aadd2dbf2 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -8,6 +8,7 @@ var Hash = require('../crypto/hash'); var Opcode = require('../opcode'); var PublicKey = require('../publickey'); var Signature = require('../crypto/signature'); +var Networks = require('../networks'); var $ = require('../util/preconditions'); var _ = require('lodash'); @@ -700,6 +701,21 @@ Script.fromAddress = function(address) { throw new errors.Script.UnrecognizedAddress(address); }; +/** + * @return Address the associated address for this script + */ +Script.prototype.toAddress = function(network) { + network = Networks.get(network); + $.checkArgument(network, 'Must provide a network'); + if (this.isPublicKeyHashOut()) { + return new Address(this.getData(), network, Address.PayToPublicKeyHash); + } + if (this.isScriptHashOut()) { + return new Address(this.getData(), network, Address.PayToScriptHash); + } + throw new Error('The script type needs to be PayToPublicKeyHash or PayToScriptHash'); +}; + /** * Analagous to bitcoind's FindAndDelete. Find and delete equivalent chunks, * typically used with push data chunks. Note that this will find and delete diff --git a/test/address.js b/test/address.js index 0e8a1fb46..b75c7ae46 100644 --- a/test/address.js +++ b/test/address.js @@ -320,23 +320,36 @@ describe('Address', function() { b.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX'); }); - it('should make this address from a script', function() { - var s = Script.fromString('OP_CHECKMULTISIG'); - var buf = s.toBuffer(); - var a = Address.fromScript(s); - a.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); - var b = new Address(s); - b.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); - var c = Address.fromScriptHash(bitcore.crypto.Hash.sha256ripemd160(buf)); - c.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); - }); + describe('from a script', function() { + it('should make this address from a script', function() { + var s = Script.fromString('OP_CHECKMULTISIG'); + var buf = s.toBuffer(); + var a = Address.fromScript(s); + a.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); + var b = new Address(s); + b.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); + var c = Address.fromScriptHash(bitcore.crypto.Hash.sha256ripemd160(buf)); + c.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); + }); - it('should make this address from other script', function() { - var s = Script.fromString('OP_CHECKSIG OP_HASH160'); - var a = Address.fromScript(s); - a.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7'); - var b = new Address(s); - b.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7'); + it('should make this address from other script', function() { + var s = Script.fromString('OP_CHECKSIG OP_HASH160'); + var a = Address.fromScript(s); + a.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7'); + var b = new Address(s); + b.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7'); + }); + + it('returns the same address if the script is a pay to public key hash out', function() { + var address = '16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX'; + var script = Script.buildPublicKeyHashOut(new Address(address)); + Address(script, Networks.livenet).toString().should.equal(address); + }); + it('returns the same address if the script is a pay to script hash out', function() { + var address = '3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'; + var script = Script.buildScriptHashOut(new Address(address)); + Address(script, Networks.livenet).toString().should.equal(address); + }); }); it('should derive from this known address string livenet', function() { diff --git a/test/script/script.js b/test/script/script.js index 7fc66d099..5ea71769c 100644 --- a/test/script/script.js +++ b/test/script/script.js @@ -6,6 +6,7 @@ var bitcore = require('../..'); var BufferUtil = bitcore.util.buffer; var Script = bitcore.Script; +var Networks = bitcore.Networks; var Opcode = bitcore.Opcode; var PublicKey = bitcore.PublicKey; var Address = bitcore.Address; @@ -584,9 +585,37 @@ describe('Script', function() { expect(BufferUtil.equal(Script('OP_RETURN 1 0xFF').getData(), new Buffer([255]))).to.be.true(); }); it('fails if content is not recognized', function() { - expect(function() { - return Script('1 0xFF').getData(); - }).to.throw(); + var failed = false; + try { + Script('1 0xFF').getData(); + } catch (e) { + failed = true; + } + failed.should.equal(true); + }); + }); + + describe('toAddress', function() { + it('for a P2PKH address', function() { + var stringAddress = '1NaTVwXDDUJaXDQajoa9MqHhz4uTxtgK14'; + var address = new Address(stringAddress); + var script = new Script(address); + script.toAddress(Networks.livenet).toString().should.equal(stringAddress); + }); + it('for a P2SH address', function() { + var stringAddress = '3GhtMmAbWrUf6Y8vDxn9ETB14R6V7Br3mt'; + var address = new Address(stringAddress); + var script = new Script(address); + script.toAddress(Networks.livenet).toString().should.equal(stringAddress); + }); + it('fails if content is not recognized', function() { + var failed = false; + try { + Script().toAddress(); + } catch (e) { + failed = true; + } + failed.should.equal(true); }); });