fcoin/lib/bcoin/wallet.js
2014-05-06 21:33:05 +04:00

199 lines
4.6 KiB
JavaScript

var assert = require('assert');
var bcoin = require('../bcoin');
var hash = require('hash.js');
var utils = bcoin.utils;
function Wallet(options, passphrase) {
if (!(this instanceof Wallet))
return new Wallet(options, passphrase);
// bcoin.wallet('scope', 'password')
if (typeof options === 'string' && typeof passphrase === 'string') {
options = {
scope: options,
passphrase: passphrase
};
}
if (!options)
options = {};
this.compressed = true;
this.tx = new bcoin.txPool(this);
this.key = null;
if (options.passphrase) {
this.key = bcoin.ecdsa.genKeyPair({
pers: options.scope,
entropy: hash.sha256().update(options.passphrase).digest()
});
} else if (options.priv) {
this.key = bcoin.ecdsa.keyPair(options.priv);
} else {
this.key = bcoin.ecdsa.genKeyPair();
}
}
module.exports = Wallet;
Wallet.prototype.getPrivateKey = function getPrivateKey(enc) {
var priv = this.key.getPrivate().toArray();
if (!enc)
return priv;
if (enc === 'base58') {
// We'll be using ncompressed public key as an address
var arr = [ 128 ];
// 0-pad key
while (arr.length + priv.length < 33)
arr.push(0);
arr = arr.concat(priv);
if (this.compressed)
arr.push(1);
var chk = utils.checksum(arr);
return utils.toBase58(arr.concat(chk));
} else {
return priv;
}
};
Wallet.prototype.getPublicKey = function getPublicKey() {
return this.key.getPublic(this.compressed, 'array');
};
Wallet.prototype.getHash = function getHash() {
return utils.ripesha(this.getPublicKey());
};
Wallet.prototype.getAddress = function getAddress() {
return Wallet.hash2addr(this.getHash());
};
Wallet.hash2addr = function hash2addr(hash) {
hash = utils.toArray(hash, 'hex');
// Add version
hash = [ 0 ].concat(hash);
var addr = hash.concat(utils.checksum(hash));
return utils.toBase58(addr);
};
Wallet.addr2hash = function addr2hash(addr) {
if (!Array.isArray(addr))
addr = utils.fromBase58(addr);
if (addr.length !== 25)
return [];
if (addr[0] !== 0)
return [];
var chk = utils.checksum(addr.slice(0, -4));
if (utils.readU32(chk, 0) !== utils.readU32(addr, 21))
return [];
return addr.slice(1, -4);
};
Wallet.prototype.validateAddress = function validateAddress(addr) {
var p = Wallet.addr2hash(addr);
return p.length !== 0;
};
Wallet.validateAddress = Wallet.prototype.validateAddress;
Wallet.prototype.own = function own(tx, index) {
var hash = this.getHash();
var key = this.getPublicKey();
var outputs = tx.outputs.filter(function(output, i) {
if (index && index !== i)
return false;
var s = output.script;
if (bcoin.script.isPubkeyhash(s, hash))
return true;
if (bcoin.script.isMultisig(s, key))
return true;
return false;
}, this);
if (outputs.length === 0)
return false;
return outputs;
};
Wallet.prototype.sign = function sign(tx, type) {
if (!type)
type = 'all';
assert.equal(type, 'all');
// Filter inputs that this wallet own
var inputs = tx.inputs.filter(function(input) {
return input.out.tx && this.own(input.out.tx);
}, this);
var pub = this.getPublicKey();
// Add signature script to each input
inputs.forEach(function(input, i) {
var s = input.out.tx.getSubscript(input.out.index);
var hash = tx.subscriptHash(i, s, type);
var signature = bcoin.ecdsa.sign(hash, this.key).toDER();
signature = signature.concat(bcoin.protocol.constants.hashType[type]);
if (bcoin.script.isPubkeyhash(s)) {
input.script = [ signature, pub ];
return;
}
// Multisig
input.script = [ [], signature ];
}, this);
return inputs.length;
};
Wallet.prototype.addTX = function addTX(tx) {
return this.tx.add(tx);
};
Wallet.prototype.unspent = function unspent() {
return this.tx.unspent();
};
Wallet.prototype.balance = function balance() {
return this.tx.balance();
};
Wallet.prototype.toJSON = function toJSON() {
return {
v: 1,
type: 'wallet',
key: this.getPrivateKey('base58'),
tx: this.tx.toJSON()
};
};
Wallet.prototype.fromJSON = function fromJSON(json) {
assert.equal(json.v, 1);
assert.equal(json.type, 'wallet');
var key = bcoin.utils.fromBase58(json.key);
assert(utils.isEqual(key.slice(-4), utils.checksum(key.slice(0, -4))));
assert.equal(key[0], 128);
key = key.slice(0, -4);
if (key.length === 34) {
assert.equal(key[33], 1);
this.key = bcoin.ecdsa.keyPair(key.slice(1, -1));
this.compressed = true;
} else {
this.key = bcoin.ecdsa.keyPair(key.slice(1));
this.compressed = false;
}
this.tx.fromJSON(json.tx);
return this;
};