You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
5.7 KiB
213 lines
5.7 KiB
// Address
|
|
// =======
|
|
//
|
|
// Handles a bitcoin address
|
|
//
|
|
//
|
|
// Synopsis
|
|
// --------
|
|
// ```
|
|
// var address = new Address('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa');
|
|
// if (address.isValid()) {
|
|
// //...
|
|
// }
|
|
//
|
|
// // Also an address can be created from
|
|
// // public keys
|
|
// var address = Address.fromPubKey(myPubkey);
|
|
//
|
|
// // Or from a ScriptPubKey (from a transaction output)
|
|
// var address = Address.fromScriptPubKey(scriptPubKey);
|
|
//
|
|
// // Multisig address p2sh handling
|
|
// var myPukeys = [pubkey0, pubkey1, pubkey2];
|
|
// var p2shAddress = Address.fromPubKeys(2, myPubkeys);
|
|
// if (p2shAddress.isScript()) { //true
|
|
// }
|
|
//
|
|
//
|
|
// ```
|
|
|
|
|
|
'use strict';
|
|
var coinUtil = require('../util');
|
|
var VersionedData = require('../util/VersionedData');
|
|
var EncodedData = require('../util/EncodedData');
|
|
var networks = require('../networks');
|
|
var Script = require('./Script');
|
|
var util = require('util');
|
|
|
|
function Address(version, hash) {
|
|
if (hash && hash.length && (!Buffer.isBuffer(hash) || hash.length != 20))
|
|
throw new Error('Hash must be 20 bytes');
|
|
Address.super_.call(this, version, hash);
|
|
}
|
|
|
|
util.inherits(Address, VersionedData);
|
|
EncodedData.applyEncodingsTo(Address);
|
|
|
|
// create a pubKeyHash address
|
|
Address.fromPubKey = function(pubKey, network) {
|
|
if (!network)
|
|
network = 'livenet';
|
|
|
|
if (pubKey.length !== 33 && pubKey.length !== 65)
|
|
throw new Error('Invalid public key');
|
|
|
|
var version = networks[network].addressVersion;
|
|
var hash = coinUtil.sha256ripe160(pubKey);
|
|
|
|
return new Address(version, hash);
|
|
};
|
|
|
|
// create an address from a Key object
|
|
Address.fromKey = function(key, network) {
|
|
return Address.fromPubKey(key.public, network);
|
|
};
|
|
|
|
// create a p2sh m-of-n multisig address
|
|
Address.fromPubKeys = function(mReq, pubKeys, network, opts) {
|
|
if (!network)
|
|
network = 'livenet';
|
|
|
|
for (var i in pubKeys) {
|
|
var pubKey = pubKeys[i];
|
|
if (pubKey.length != 33 && pubKey.length != 65)
|
|
throw new Error('Invalid public key');
|
|
}
|
|
|
|
var script = Script.createMultisig(mReq, pubKeys, opts);
|
|
return Address.fromScript(script, network);
|
|
};
|
|
|
|
//create a p2sh address from redeemScript
|
|
Address.fromScript = function(script, network) {
|
|
if (!network)
|
|
network = 'livenet';
|
|
|
|
if (typeof script === 'string') {
|
|
script = new Script(new Buffer(script, 'hex'));
|
|
}
|
|
|
|
var version = networks[network].P2SHVersion;
|
|
var buf = script.getBuffer();
|
|
var hash = coinUtil.sha256ripe160(buf);
|
|
|
|
return new Address(version, hash);
|
|
};
|
|
|
|
//extract an address from scriptPubKey
|
|
Address.fromScriptPubKey = function(scriptPubKey, network) {
|
|
|
|
if (typeof scriptPubKey === 'string') {
|
|
scriptPubKey = new Script(new Buffer(scriptPubKey, 'hex'));
|
|
}
|
|
|
|
if (!network)
|
|
network = 'livenet';
|
|
|
|
var ret = [],
|
|
version;
|
|
var payload = scriptPubKey.capture();
|
|
|
|
if (payload) {
|
|
var txType = scriptPubKey.classify();
|
|
switch (txType) {
|
|
case Script.TX_PUBKEY:
|
|
payload[0] = coinUtil.sha256ripe160(payload[0]);
|
|
version = networks[network].addressVersion;
|
|
break;
|
|
case Script.TX_PUBKEYHASH:
|
|
version = networks[network].addressVersion;
|
|
break;
|
|
case Script.TX_MULTISIG:
|
|
version = networks[network].addressVersion;
|
|
for (var i in payload)
|
|
payload[i] = coinUtil.sha256ripe160(payload[i]);
|
|
break;
|
|
case Script.TX_SCRIPTHASH:
|
|
version = networks[network].P2SHVersion;
|
|
break;
|
|
}
|
|
for (var i in payload)
|
|
ret.push(new Address(version, payload[i]));
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
// validates the address
|
|
Address.prototype.validate = function() {
|
|
this.doAsBinary(function() {
|
|
Address.super_.prototype.validate.apply(this);
|
|
if (this.data.length !== 21) throw new Error('invalid data length');
|
|
});
|
|
if (typeof this.network() === 'undefined') throw new Error('invalid network');
|
|
};
|
|
|
|
// returns the network information (livenet or testnet, as described on networks.js) of the address
|
|
Address.prototype.network = function() {
|
|
var version = this.version();
|
|
|
|
var livenet = networks.livenet;
|
|
var testnet = networks.testnet;
|
|
|
|
var answer;
|
|
if (version === livenet.addressVersion || version === livenet.P2SHVersion)
|
|
answer = livenet;
|
|
else if (version === testnet.addressVersion || version === testnet.P2SHVersion)
|
|
answer = testnet;
|
|
|
|
return answer;
|
|
};
|
|
|
|
// returns true is the address is a pay-to-script (P2SH) address type.
|
|
Address.prototype.isScript = function() {
|
|
return this.isValid() && this.version() === this.network().P2SHVersion;
|
|
};
|
|
|
|
// returns the scriptPubKey
|
|
Address.prototype.getScriptPubKey = function() {
|
|
var version = this.version();
|
|
var livenet = networks.livenet;
|
|
var testnet = networks.testnet;
|
|
|
|
var script;
|
|
if (version === livenet.addressVersion || version === testnet.addressVersion)
|
|
script = Script.createPubKeyHashOut(this.payload());
|
|
else if (version === livenet.P2SHVersion || version === testnet.P2SHVersion)
|
|
script = Script.createP2SH(this.payload());
|
|
else
|
|
throw new Error('invalid address - unknown version');
|
|
|
|
return script;
|
|
};
|
|
|
|
Address.fromPubkeyHashScriptSig = function(scriptSig, network) {
|
|
return Address.fromPubKey(scriptSig.chunks[1], network);
|
|
};
|
|
|
|
//extract an address from scriptSig
|
|
Address.fromScriptSig = function(scriptSig, network) {
|
|
if (typeof scriptSig === 'string') {
|
|
scriptSig = new Script(new Buffer(scriptSig, 'hex'));
|
|
}
|
|
if (!network)
|
|
network = 'livenet';
|
|
|
|
var payload = scriptSig.chunks;
|
|
if (scriptSig.chunks.length === 2)
|
|
return Address.fromPubkeyHashScriptSig(scriptSig, network);
|
|
// TODO: support other scriptSig types
|
|
return null;
|
|
};
|
|
|
|
Address.getScriptPubKeyFor = function(s) {
|
|
return new Address(s).getScriptPubKey();
|
|
};
|
|
|
|
Address.validate = function(s) {
|
|
return new Address(s).isValid();
|
|
};
|
|
|
|
|
|
module.exports = Address;
|
|
|