Socket
Socket
Sign inDemoInstall

bitcoinjs-lib

Package Overview
Dependencies
Maintainers
4
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bitcoinjs-lib - npm Package Compare versions

Comparing version 1.0.2 to 1.1.0

src/transaction_builder.js

4

package.json
{
"name": "bitcoinjs-lib",
"version": "1.0.2",
"version": "1.1.0",
"description": "Client-side Bitcoin JavaScript library",

@@ -63,3 +63,3 @@ "main": "./src/index.js",

"scripts": {
"compile": "browserify ./src/index.js -s Bitcoin | uglifyjs > bitcoinjs-min.js",
"compile": "browserify ./src/index.js -s bitcoin | uglifyjs > bitcoinjs-min.js",
"coverage": "istanbul cover _mocha -- test/*.js",

@@ -66,0 +66,0 @@ "coveralls": "npm run-script coverage && coveralls < coverage/lcov.info",

# BitcoinJS (bitcoinjs-lib)
[![Build Status](https://travis-ci.org/bitcoinjs/bitcoinjs-lib.png?branch=master)](https://travis-ci.org/bitcoinjs/bitcoinjs-lib) [![Coverage Status](https://coveralls.io/repos/bitcoinjs/bitcoinjs-lib/badge.png)](https://coveralls.io/r/bitcoinjs/bitcoinjs-lib)
[![Build Status](https://travis-ci.org/bitcoinjs/bitcoinjs-lib.png?branch=master)](https://travis-ci.org/bitcoinjs/bitcoinjs-lib)
[![Coverage Status](https://coveralls.io/repos/bitcoinjs/bitcoinjs-lib/badge.png)](https://coveralls.io/r/bitcoinjs/bitcoinjs-lib)
[![tip for next commit](http://tip4commit.com/projects/735.svg)](http://tip4commit.com/projects/735)

@@ -60,3 +62,3 @@ [![NPM](https://nodei.co/npm/bitcoinjs-lib.png)](https://nodei.co/npm/bitcoinjs-lib/)

$ npm -g install bitcoinjs-lib browserify uglify-js
$ browserify -r bitcoinjs-lib -s Bitcoin | uglifyjs > bitcoinjs.min.js
$ browserify -r bitcoinjs-lib -s bitcoin | uglifyjs > bitcoinjs.min.js

@@ -86,2 +88,3 @@ After loading this file in your browser, you will be able to use the global `bitcoin` object.

### Creating a Transaction

@@ -111,2 +114,3 @@

### Creating a P2SH Multsig Address

@@ -116,9 +120,9 @@

var bitcoin = require('bitcoinjs-lib')
var privKeys = [bitcoin.ECKey.makeRandom(), bitcoin.ECKey.makeRandom(), bitcoin.ECKey.makeRandom()]
var pubKeys = privKeys.map(function(x) { return x.pub })
var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3
var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
var multisigAddress = bitcoin.Address.fromOutputScript(scriptPubKey).toString()

@@ -131,3 +135,2 @@

## Projects utilizing BitcoinJS

@@ -145,4 +148,6 @@

- [GreenAddress](https://greenaddress.it)
- [DecentralBank](http://decentralbank.com)
- [DecentralBank](http://decentralbank.co)
- [Quickcoin](https://wallet.quickcoin.co)
## Contributors

@@ -156,2 +161,3 @@

## Contributing

@@ -173,5 +179,5 @@

- [bip39](https://github.com/weilu/bip39) - Wei Lu's Mnemonic code generator
- [BIP39](https://github.com/weilu/bip39) - Mnemonic code for generating deterministic keys
- [BIP38](https://github.com/cryptocoinjs/bip38) - Passphrase-protected private keys
- [BCoin](https://github.com/indutny/bcoin) - BIP37 / Bloom Filters / SPV client
- [scryptsy](https://github.com/cryptocoinjs/scryptsy) - Private key encryption (BIP38)
- [insight](https://github.com/bitpay/insight) - A bitcoin blockchain API for web wallets.

@@ -185,2 +191,3 @@

## License

@@ -193,3 +200,3 @@

BitcoinJS (c) 2011-2012 Stefan Thomas
BitcoinJS (c) 2011-2014 Bitcoinjs-lib contributors
Released under MIT license

@@ -162,2 +162,8 @@ var assert = require('assert')

function reverse(buffer) {
var buffer2 = new Buffer(buffer)
Array.prototype.reverse.call(buffer2)
return buffer2
}
module.exports = {

@@ -168,2 +174,3 @@ pushDataSize: pushDataSize,

readVarInt: readVarInt,
reverse: reverse,
varIntSize: varIntSize,

@@ -170,0 +177,0 @@ writePushDataInt: writePushDataInt,

@@ -34,2 +34,3 @@ var assert = require('assert')

assert(Buffer.isBuffer(chainCode), 'Expected Buffer, got ' + chainCode)
assert.equal(chainCode.length, 32, 'Expected chainCode length of 32, got ' + chainCode.length)
assert(network.bip32, 'Unknown BIP32 constants for network')

@@ -146,2 +147,11 @@

HDNode.prototype.neutered = function() {
var neutered = new HDNode(this.pubKey.Q, this.chainCode, this.network)
neutered.depth = this.depth
neutered.index = this.index
neutered.parentFingerprint = this.parentFingerprint
return neutered
}
HDNode.prototype.toBase58 = function(isPrivate) {

@@ -152,4 +162,10 @@ return base58check.encode(this.toBuffer(isPrivate))

HDNode.prototype.toBuffer = function(isPrivate) {
if (isPrivate == undefined) isPrivate = !!this.privKey
if (isPrivate == undefined) {
isPrivate = !!this.privKey
// FIXME: remove in 2.x.y
} else {
console.warn('isPrivate flag is deprecated, please use the .neutered() method instead')
}
// Version

@@ -179,2 +195,3 @@ var version = isPrivate ? this.network.bip32.private : this.network.bip32.public

if (isPrivate) {
// FIXME: remove in 2.x.y
assert(this.privKey, 'Missing private key')

@@ -181,0 +198,0 @@

@@ -16,4 +16,5 @@ module.exports = {

Transaction: require('./transaction'),
TransactionBuilder: require('./transaction_builder'),
networks: require('./networks'),
Wallet: require('./wallet')
}

@@ -38,10 +38,15 @@ /// Implements Bitcoin's feature for signing arbitrary messages.

// TODO: network could be implied from address
function verify(address, signatureBuffer, message, network) {
function verify(address, signature, message, network) {
if (!Buffer.isBuffer(signature)) {
signature = new Buffer(signature, 'base64')
}
if (address instanceof Address) {
address = address.toString()
}
network = network || networks.bitcoin
var hash = magicHash(message, network)
var parsed = ECSignature.parseCompact(signatureBuffer)
var parsed = ECSignature.parseCompact(signature)
var e = BigInteger.fromBuffer(hash)

@@ -48,0 +53,0 @@ var Q = ecdsa.recoverPubKey(ecparams, e, parsed.signature, parsed.i)

@@ -58,2 +58,30 @@ // https://en.bitcoin.it/wiki/List_of_address_prefixes

estimateFee: estimateFee('testnet')
},
viacoin: {
magicPrefix: '\x18Viacoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4
},
pubKeyHash: 0x47,
scriptHash: 0x21,
wif: 0xc7,
dustThreshold: 560,
dustSoftThreshold: 100000,
feePerKb: 100000, //
estimateFee: estimateFee('viacoin')
},
viacointestnet: {
magicPrefix: '\x18Viacoin Signed Message:\n',
bip32: {
public: 0x043587cf,
private: 0x04358394
},
pubKeyHash: 0x7f,
scriptHash: 0xc4,
wif: 0xff,
dustThreshold: 560,
dustSoftThreshold: 100000,
feePerKb: 100000,
estimateFee: estimateFee('viacointestnet')
}

@@ -60,0 +88,0 @@ }

@@ -241,5 +241,9 @@ var assert = require('assert')

var m = scriptPubKey.chunks[0]
var k = m - (opcodes.OP_1 - 1)
assert(k <= signatures.length, 'Not enough signatures provided')
var mOp = scriptPubKey.chunks[0]
var nOp = scriptPubKey.chunks[scriptPubKey.chunks.length - 2]
var m = mOp - (opcodes.OP_1 - 1)
var n = nOp - (opcodes.OP_1 - 1)
assert(signatures.length >= m, 'Not enough signatures provided')
assert(signatures.length <= n, 'Too many signatures provided')
}

@@ -246,0 +250,0 @@

@@ -40,6 +40,4 @@ var assert = require('assert')

if (typeof tx === 'string') {
hash = new Buffer(tx, 'hex')
// TxId hex is big-endian, we need little-endian
Array.prototype.reverse.call(hash)
hash = bufferutils.reverse(new Buffer(tx, 'hex'))

@@ -55,4 +53,6 @@ } else if (tx instanceof Transaction) {

assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
assert(isFinite(index), 'Expected number index, got ' + index)
assert(isFinite(sequence), 'Expected number sequence, got ' + sequence)
// Add the input and return the input's index
return (this.ins.push({

@@ -83,10 +83,9 @@ hash: hash,

if (scriptPubKey instanceof Address) {
var address = scriptPubKey
scriptPubKey = address.toOutputScript()
scriptPubKey = scriptPubKey.toOutputScript()
}
assert(scriptPubKey instanceof Script, 'Expected Address or Script, got ' + scriptPubKey)
assert.equal(typeof value, 'number', 'Expected number value, got ' + value)
assert(isFinite(value), 'Expected number value, got ' + value)
// Add the output and return the output's index
return (this.outs.push({

@@ -168,3 +167,13 @@ script: scriptPubKey,

*/
Transaction.prototype.hashForSignature = function(prevOutScript, inIndex, hashType) {
Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashType) {
// FIXME: remove in 2.x.y
if (arguments[0] instanceof Script) {
console.warn('hashForSignature(prevOutScript, inIndex, ...) has been deprecated. Use hashForSignature(inIndex, prevOutScript, ...)')
// swap the arguments (must be stored in tmp, arguments is special)
var tmp = arguments[0]
inIndex = arguments[1]
prevOutScript = tmp
}
assert(inIndex >= 0, 'Invalid vin index')

@@ -208,8 +217,4 @@ assert(inIndex < this.ins.length, 'Invalid vin index')

Transaction.prototype.getId = function () {
var buffer = this.getHash()
// Big-endian is used for TxHash
Array.prototype.reverse.call(buffer)
return buffer.toString('hex')
// TxHash is little-endian, we need big-endian
return bufferutils.reverse(this.getHash()).toString('hex')
}

@@ -304,10 +309,13 @@

/**
* Signs a pubKeyHash output at some index with the given key
*/
Transaction.prototype.setInputScript = function(index, script) {
this.ins[index].script = script
}
// FIXME: remove in 2.x.y
Transaction.prototype.sign = function(index, privKey, hashType) {
console.warn("Transaction.prototype.sign is deprecated. Use TransactionBuilder instead.")
var prevOutScript = privKey.pub.getAddress().toOutputScript()
var signature = this.signInput(index, prevOutScript, privKey, hashType)
// FIXME: Assumed prior TX was pay-to-pubkey-hash
var scriptSig = scripts.pubKeyHashInput(signature, privKey.pub)

@@ -317,6 +325,9 @@ this.setInputScript(index, scriptSig)

// FIXME: remove in 2.x.y
Transaction.prototype.signInput = function(index, prevOutScript, privKey, hashType) {
console.warn("Transaction.prototype.signInput is deprecated. Use TransactionBuilder instead.")
hashType = hashType || Transaction.SIGHASH_ALL
var hash = this.hashForSignature(prevOutScript, index, hashType)
var hash = this.hashForSignature(index, prevOutScript, hashType)
var signature = privKey.sign(hash)

@@ -327,10 +338,8 @@

Transaction.prototype.setInputScript = function(index, script) {
this.ins[index].script = script
}
// FIXME: remove in 2.x.y
Transaction.prototype.validateInput = function(index, prevOutScript, pubKey, buffer) {
console.warn("Transaction.prototype.validateInput is deprecated. Use TransactionBuilder instead.")
// FIXME: could be validateInput(index, prevTxOut, pub)
Transaction.prototype.validateInput = function(index, prevOutScript, pubKey, buffer) {
var parsed = ECSignature.parseScriptSignature(buffer)
var hash = this.hashForSignature(prevOutScript, index, parsed.hashType)
var hash = this.hashForSignature(index, prevOutScript, parsed.hashType)

@@ -337,0 +346,0 @@ return pubKey.verify(hash, parsed.signature)

var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('crypto')

@@ -7,29 +8,35 @@ var networks = require('./networks')

var HDNode = require('./hdnode')
var Transaction = require('./transaction')
var TransactionBuilder = require('./transaction_builder')
var Script = require('./script')
function Wallet(seed, network) {
seed = seed || crypto.randomBytes(32)
network = network || networks.bitcoin
// Stored in a closure to make accidental serialization less likely
var masterkey = null
var me = this
var accountZero = null
var internalAccount = null
var externalAccount = null
var masterKey = HDNode.fromSeedBuffer(seed, network)
// Addresses
// HD first-level child derivation method should be hardened
// See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
var accountZero = masterKey.deriveHardened(0)
var externalAccount = accountZero.derive(0)
var internalAccount = accountZero.derive(1)
this.addresses = []
this.changeAddresses = []
this.network = network
this.unspents = []
// Transaction output data
this.outputs = {}
// FIXME: remove in 2.0.0
this.unspentMap = {}
// Make a new master key
// FIXME: remove in 2.0.0
var me = this
this.newMasterKey = function(seed) {
console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')
seed = seed || crypto.randomBytes(32)
masterkey = HDNode.fromSeedBuffer(seed, network)
masterKey = HDNode.fromSeedBuffer(seed, network)
// HD first-level child derivation method should be hardened
// See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
accountZero = masterkey.deriveHardened(0)
accountZero = masterKey.deriveHardened(0)
externalAccount = accountZero.derive(0)

@@ -41,266 +48,311 @@ internalAccount = accountZero.derive(1)

me.outputs = {}
me.unspents = []
me.unspentMap = {}
}
this.newMasterKey(seed)
this.getMasterKey = function() { return masterKey }
this.getAccountZero = function() { return accountZero }
this.getExternalAccount = function() { return externalAccount }
this.getInternalAccount = function() { return internalAccount }
}
this.generateAddress = function() {
var key = externalAccount.derive(this.addresses.length)
this.addresses.push(key.getAddress().toString())
return this.addresses[this.addresses.length - 1]
}
Wallet.prototype.createTransaction = function(to, value, options) {
// FIXME: remove in 2.0.0
if (typeof options !== 'object') {
if (options !== undefined) {
console.warn('Non options object parameters are deprecated, use options object instead')
this.generateChangeAddress = function() {
var key = internalAccount.derive(this.changeAddresses.length)
this.changeAddresses.push(key.getAddress().toString())
return this.changeAddresses[this.changeAddresses.length - 1]
options = {
fixedFee: arguments[2],
changeAddress: arguments[3]
}
}
}
this.getBalance = function() {
return this.getUnspentOutputs().reduce(function(memo, output){
return memo + output.value
}, 0)
}
options = options || {}
this.getUnspentOutputs = function() {
var utxo = []
assert(value > this.network.dustThreshold, value + ' must be above dust threshold (' + this.network.dustThreshold + ' Satoshis)')
for(var key in this.outputs){
var output = this.outputs[key]
if(!output.to) utxo.push(outputToUnspentOutput(output))
}
var changeAddress = options.changeAddress
var fixedFee = options.fixedFee
var minConf = options.minConf === undefined ? 0 : options.minConf // FIXME: change minConf:1 by default in 2.0.0
return utxo
}
// filter by minConf, then pending and sort by descending value
var unspents = this.unspents.filter(function(unspent) {
return unspent.confirmations >= minConf
}).filter(function(unspent) {
return !unspent.pending
}).sort(function(o1, o2) {
return o2.value - o1.value
})
this.setUnspentOutputs = function(utxo) {
var outputs = {}
var accum = 0
var addresses = []
var subTotal = value
utxo.forEach(function(uo){
validateUnspentOutput(uo)
var o = unspentOutputToOutput(uo)
outputs[o.from] = o
})
var txb = new TransactionBuilder()
txb.addOutput(to, value)
this.outputs = outputs
}
for (var i = 0; i < unspents.length; ++i) {
var unspent = unspents[i]
addresses.push(unspent.address)
function outputToUnspentOutput(output){
var hashAndIndex = output.from.split(":")
txb.addInput(unspent.txHash, unspent.index)
return {
hash: hashAndIndex[0],
outputIndex: parseInt(hashAndIndex[1]),
address: output.address,
value: output.value,
pending: output.pending
}
}
var fee = fixedFee === undefined ? estimatePaddedFee(txb.buildIncomplete(), this.network) : fixedFee
function unspentOutputToOutput(o) {
var hash = o.hash
var key = hash + ":" + o.outputIndex
return {
from: key,
address: o.address,
value: o.value,
pending: o.pending
}
}
accum += unspent.value
subTotal = value + fee
function validateUnspentOutput(uo) {
var missingField
if (accum >= subTotal) {
var change = accum - subTotal
if (isNullOrUndefined(uo.hash)) {
missingField = "hash"
}
var requiredKeys = ['outputIndex', 'address', 'value']
requiredKeys.forEach(function (key) {
if (isNullOrUndefined(uo[key])){
missingField = key
if (change > this.network.dustThreshold) {
txb.addOutput(changeAddress || this.getChangeAddress(), change)
}
})
if (missingField) {
var message = [
'Invalid unspent output: key', missingField, 'is missing.',
'A valid unspent output must contain'
]
message.push(requiredKeys.join(', '))
message.push("and hash")
throw new Error(message.join(' '))
break
}
}
function isNullOrUndefined(value) {
return value == undefined
}
assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal)
this.processPendingTx = function(tx){
processTx(tx, true)
}
return this.signWith(txb, addresses).build()
}
this.processConfirmedTx = function(tx){
processTx(tx, false)
}
// FIXME: remove in 2.0.0
Wallet.prototype.processPendingTx = function(tx){
this.__processTx(tx, true)
}
function processTx(tx, isPending) {
var txid = tx.getId()
// FIXME: remove in 2.0.0
Wallet.prototype.processConfirmedTx = function(tx){
this.__processTx(tx, false)
}
tx.outs.forEach(function(txOut, i) {
var address
// FIXME: remove in 2.0.0
Wallet.prototype.__processTx = function(tx, isPending) {
console.warn('processTransaction is considered harmful, see issue #260 for more information')
try {
address = Address.fromOutputScript(txOut.script, network).toString()
} catch(e) {
if (!(e.message.match(/has no matching Address/))) throw e
}
var txId = tx.getId()
var txHash = tx.getHash()
if (isMyAddress(address)) {
var output = txid + ':' + i
tx.outs.forEach(function(txOut, i) {
var address
me.outputs[output] = {
from: output,
value: txOut.value,
address: address,
pending: isPending
}
try {
address = Address.fromOutputScript(txOut.script, this.network).toString()
} catch(e) {
if (!(e.message.match(/has no matching Address/))) throw e
}
var myAddresses = this.addresses.concat(this.changeAddresses)
if (myAddresses.indexOf(address) > -1) {
var lookup = txId + ':' + i
if (lookup in this.unspentMap) return
// its unique, add it
var unspent = {
address: address,
confirmations: 0, // no way to determine this without more information
index: i,
txHash: txHash,
txId: txId,
value: txOut.value,
pending: isPending
}
})
tx.ins.forEach(function(txIn, i) {
// copy and convert to big-endian hex
var txinId = new Buffer(txIn.hash)
Array.prototype.reverse.call(txinId)
txinId = txinId.toString('hex')
this.unspentMap[lookup] = unspent
this.unspents.push(unspent)
}
}, this)
var output = txinId + ':' + txIn.index
tx.ins.forEach(function(txIn, i) {
// copy and convert to big-endian hex
var txInId = bufferutils.reverse(txIn.hash).toString('hex')
if (!(output in me.outputs)) return
var lookup = txInId + ':' + txIn.index
if (!(lookup in this.unspentMap)) return
if (isPending) {
me.outputs[output].to = txid + ':' + i
me.outputs[output].pending = true
} else {
delete me.outputs[output]
}
})
}
var unspent = this.unspentMap[lookup]
this.createTx = function(to, value, fixedFee, changeAddress) {
assert(value > network.dustThreshold, value + ' must be above dust threshold (' + network.dustThreshold + ' Satoshis)')
if (isPending) {
unspent.pending = true
unspent.spent = true
var utxos = getCandidateOutputs(value)
var accum = 0
var subTotal = value
var addresses = []
} else {
delete this.unspentMap[lookup]
var tx = new Transaction()
tx.addOutput(to, value)
this.unspents = this.unspents.filter(function(unspent2) {
return unspent !== unspent2
})
}
}, this)
}
for (var i = 0; i < utxos.length; ++i) {
var utxo = utxos[i]
addresses.push(utxo.address)
Wallet.prototype.generateAddress = function() {
var k = this.addresses.length
var address = this.getExternalAccount().derive(k).getAddress()
var outpoint = utxo.from.split(':')
tx.addInput(outpoint[0], parseInt(outpoint[1]))
this.addresses.push(address.toString())
var fee = fixedFee == undefined ? estimateFeePadChangeOutput(tx) : fixedFee
return this.getReceiveAddress()
}
accum += utxo.value
subTotal = value + fee
if (accum >= subTotal) {
var change = accum - subTotal
Wallet.prototype.generateChangeAddress = function() {
var k = this.changeAddresses.length
var address = this.getInternalAccount().derive(k).getAddress()
if (change > network.dustThreshold) {
tx.addOutput(changeAddress || getChangeAddress(), change)
}
this.changeAddresses.push(address.toString())
break
}
}
return this.getChangeAddress()
}
assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal)
this.signWith(tx, addresses)
return tx
Wallet.prototype.getAddress = function() {
if (this.addresses.length === 0) {
this.generateAddress()
}
function getCandidateOutputs() {
var unspent = []
return this.addresses[this.addresses.length - 1]
}
for (var key in me.outputs) {
var output = me.outputs[key]
if (!output.pending) unspent.push(output)
}
Wallet.prototype.getBalance = function(minConf) {
minConf = minConf || 0
var sortByValueDesc = unspent.sort(function(o1, o2){
return o2.value - o1.value
})
return this.unspents.filter(function(unspent) {
return unspent.confirmations >= minConf
return sortByValueDesc
// FIXME: remove spent filter in 2.0.0
}).filter(function(unspent) {
return !unspent.spent
}).reduce(function(accum, unspent) {
return accum + unspent.value
}, 0)
}
Wallet.prototype.getChangeAddress = function() {
if (this.changeAddresses.length === 0) {
this.generateChangeAddress()
}
function estimateFeePadChangeOutput(tx) {
var tmpTx = tx.clone()
tmpTx.addOutput(getChangeAddress(), network.dustSoftThreshold || 0)
return this.changeAddresses[this.changeAddresses.length - 1]
}
return network.estimateFee(tmpTx)
Wallet.prototype.getInternalPrivateKey = function(index) {
return this.getInternalAccount().derive(index).privKey
}
Wallet.prototype.getPrivateKey = function(index) {
return this.getExternalAccount().derive(index).privKey
}
Wallet.prototype.getPrivateKeyForAddress = function(address) {
var index
if ((index = this.addresses.indexOf(address)) > -1) {
return this.getPrivateKey(index)
}
function getChangeAddress() {
if(me.changeAddresses.length === 0) me.generateChangeAddress();
return me.changeAddresses[me.changeAddresses.length - 1]
if ((index = this.changeAddresses.indexOf(address)) > -1) {
return this.getInternalPrivateKey(index)
}
this.signWith = function(tx, addresses) {
assert.equal(tx.ins.length, addresses.length, 'Number of addresses must match number of transaction inputs')
assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated')
}
addresses.forEach(function(address, i) {
var key = me.getPrivateKeyForAddress(address)
Wallet.prototype.getUnspentOutputs = function(minConf) {
minConf = minConf || 0
tx.sign(i, key)
})
return this.unspents.filter(function(unspent) {
return unspent.confirmations >= minConf
return tx
}
// FIXME: remove spent filter in 2.0.0
}).filter(function(unspent) {
return !unspent.spent
}).map(function(unspent) {
return {
address: unspent.address,
confirmations: unspent.confirmations,
index: unspent.index,
txId: unspent.txId,
value: unspent.value,
this.getMasterKey = function() { return masterkey }
this.getAccountZero = function() { return accountZero }
this.getInternalAccount = function() { return internalAccount }
this.getExternalAccount = function() { return externalAccount }
// FIXME: remove in 2.0.0
hash: unspent.txId,
pending: unspent.pending
}
})
}
this.getPrivateKey = function(index) {
return externalAccount.derive(index).privKey
}
Wallet.prototype.setUnspentOutputs = function(unspents) {
this.unspentMap = {}
this.unspents = unspents.map(function(unspent) {
// FIXME: remove unspent.hash in 2.0.0
var txId = unspent.txId || unspent.hash
var index = unspent.index
this.getInternalPrivateKey = function(index) {
return internalAccount.derive(index).privKey
}
// FIXME: remove in 2.0.0
if (unspent.hash !== undefined) {
console.warn('unspent.hash is deprecated, use unspent.txId instead')
}
this.getPrivateKeyForAddress = function(address) {
var index
if((index = this.addresses.indexOf(address)) > -1) {
return this.getPrivateKey(index)
} else if((index = this.changeAddresses.indexOf(address)) > -1) {
return this.getInternalPrivateKey(index)
} else {
throw new Error('Unknown address. Make sure the address is from the keychain and has been generated.')
// FIXME: remove in 2.0.0
if (index === undefined) {
console.warn('unspent.outputIndex is deprecated, use unspent.index instead')
index = unspent.outputIndex
}
}
function isReceiveAddress(address){
return me.addresses.indexOf(address) > -1
}
assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId)
assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address)
assert(isFinite(index), 'Expected number index, got ' + index)
assert.equal(typeof unspent.value, 'number', 'Expected number value, got ' + unspent.value)
function isChangeAddress(address){
return me.changeAddresses.indexOf(address) > -1
}
// FIXME: remove branch in 2.0.0
if (unspent.confirmations !== undefined) {
assert.equal(typeof unspent.confirmations, 'number', 'Expected number confirmations, got ' + unspent.confirmations)
}
function isMyAddress(address) {
return isReceiveAddress(address) || isChangeAddress(address)
}
var txHash = bufferutils.reverse(new Buffer(txId, 'hex'))
unspent = {
address: unspent.address,
confirmations: unspent.confirmations || 0,
index: index,
txHash: txHash,
txId: txId,
value: unspent.value,
// FIXME: remove in 2.0.0
pending: unspent.pending || false
}
// FIXME: remove in 2.0.0
this.unspentMap[txId + ':' + index] = unspent
return unspent
}, this)
}
Wallet.prototype.signWith = function(tx, addresses) {
addresses.forEach(function(address, i) {
var privKey = this.getPrivateKeyForAddress(address)
tx.sign(i, privKey)
}, this)
return tx
}
function estimatePaddedFee(tx, network) {
var tmpTx = tx.clone()
tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)
return network.estimateFee(tmpTx)
}
// FIXME: 1.0.0 shims, remove in 2.0.0
Wallet.prototype.getReceiveAddress = Wallet.prototype.getAddress
Wallet.prototype.createTx = Wallet.prototype.createTransaction
module.exports = Wallet

@@ -186,3 +186,3 @@ var assert = require('assert')

try {
actualHash = transaction.hashForSignature(script, inIndex, hashType)
actualHash = transaction.hashForSignature(inIndex, script, hashType)
} catch (e) {

@@ -189,0 +189,0 @@ // don't fail if we don't support it yet, TODO

@@ -78,2 +78,15 @@ var assert = require('assert')

describe('reverse', function() {
fixtures.valid.forEach(function(f) {
it('reverses ' + f.hex64 + ' correctly', function() {
var buffer = new Buffer(f.hex64, 'hex')
var buffer2 = bufferutils.reverse(buffer)
Array.prototype.reverse.call(buffer)
assert.deepEqual(buffer, buffer2)
})
})
})
describe('varIntSize', function() {

@@ -80,0 +93,0 @@ fixtures.valid.forEach(function(f) {

@@ -94,3 +94,3 @@ var assert = require('assert')

assert.ok(pubKey.verify(hash, signature))
assert(pubKey.verify(hash, signature))
})

@@ -101,5 +101,5 @@

assert.ok(!pubKey.verify(hash, signature))
assert(!pubKey.verify(hash, signature))
})
})
})

@@ -104,2 +104,15 @@ {

"scriptPubKey": false
},
{
"exception": "Too many signatures provided",
"pubKeys": [
"02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
"0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a"
],
"signatures": [
"304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
"3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
"3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
],
"scriptPubKey": false
}

@@ -106,0 +119,0 @@ ]

@@ -52,4 +52,10 @@ var assert = require('assert')

it('throws an exception when an unknown network is given', function() {
it('throws when an invalid length chain code is given', function() {
assert.throws(function() {
new HDNode(d, chainCode.slice(0, 20), networks.testnet)
}, /Expected chainCode length of 32, got 20/)
})
it('throws when an unknown network is given', function() {
assert.throws(function() {
new HDNode(d, chainCode, {})

@@ -86,5 +92,5 @@ }, /Unknown BIP32 constants for network/)

it('exports ' + f.master.base58 + ' (public) correctly', function() {
var hd = HDNode.fromSeedHex(f.master.seed)
var hd = HDNode.fromSeedHex(f.master.seed).neutered()
assert.equal(hd.toBase58(false), f.master.base58)
assert.equal(hd.toBase58(), f.master.base58)
})

@@ -97,6 +103,7 @@ })

assert.equal(hd.toBase58(true), f.master.base58Priv)
assert.equal(hd.toBase58(), f.master.base58Priv)
})
})
// FIXME: remove in 2.x.y
it('fails when there is no private key', function() {

@@ -166,5 +173,5 @@ var hd = HDNode.fromBase58(fixtures.valid[0].master.base58)

it('exports ' + f.master.hex + ' (public) correctly', function() {
var hd = HDNode.fromSeedHex(f.master.seed)
var hd = HDNode.fromSeedHex(f.master.seed).neutered()
assert.equal(hd.toHex(false), f.master.hex)
assert.equal(hd.toHex(), f.master.hex)
})

@@ -177,6 +184,7 @@ })

assert.equal(hd.toHex(true), f.master.hexPriv)
assert.equal(hd.toHex(), f.master.hexPriv)
})
})
// FIXME: remove in 2.x.y
it('fails when there is no private key', function() {

@@ -228,2 +236,17 @@ var hd = HDNode.fromHex(fixtures.valid[0].master.hex)

describe('neutered', function() {
var f = fixtures.valid[0]
it('strips all private information', function() {
var hd = HDNode.fromBase58(f.master.base58)
var hdn = hd.neutered()
assert.equal(hdn.privKey, undefined)
assert.equal(hdn.pubKey.toHex(), hd.pubKey.toHex())
assert.equal(hdn.chainCode, hd.chainCode)
assert.equal(hdn.depth, hd.depth)
assert.equal(hdn.index, hd.index)
})
})
describe('derive', function() {

@@ -265,8 +288,6 @@ function verifyVector(hd, v, depth) {

var parentNode = HDNode.fromBase58(f.master.base58Priv)
var child = parentNode.derive(c.m)
var master = HDNode.fromBase58(f.master.base58Priv)
var child = master.derive(c.m).neutered()
// FIXME: N(CKDpriv((kpar, cpar), i)), could be done better...
var childNeutered = HDNode.fromBase58(child.toBase58(false)) // neuter
assert.equal(childNeutered.toBase58(), c.base58)
assert.equal(child.toBase58(), c.base58)
})

@@ -278,8 +299,6 @@

var parentNode = HDNode.fromBase58(f.master.base58Priv)
var child = parentNode.deriveHardened(c.m)
var master = HDNode.fromBase58(f.master.base58Priv)
var child = master.deriveHardened(c.m).neutered()
// FIXME: N(CKDpriv((kpar, cpar), i)), could be done better...
var childNeutered = HDNode.fromBase58(child.toBase58(false)) // neuter
assert.equal(childNeutered.toBase58(), c.base58)
assert.equal(child.toBase58(), c.base58)
})

@@ -291,4 +310,4 @@

var parentNode = HDNode.fromBase58(f.master.base58)
var child = parentNode.derive(c.m)
var master = HDNode.fromBase58(f.master.base58)
var child = master.derive(c.m)

@@ -302,6 +321,6 @@ assert.equal(child.toBase58(), c.base58)

var parentNode = HDNode.fromBase58(f.master.base58)
var master = HDNode.fromBase58(f.master.base58)
assert.throws(function() {
parentNode.deriveHardened(c.m)
master.deriveHardened(c.m)
}, /Could not derive hardened child key/)

@@ -308,0 +327,0 @@ })

var assert = require('assert')
var bitcoin = require('../../')
var crypto = bitcoin.crypto
var networks = bitcoin.networks

@@ -10,4 +9,3 @@ var scripts = bitcoin.scripts

var ECKey = bitcoin.ECKey
var Transaction = bitcoin.Transaction
var Script = bitcoin.Script
var TransactionBuilder = bitcoin.TransactionBuilder

@@ -47,23 +45,19 @@ var helloblock = require('helloblock-js')({

// get latest unspents from the multisigAddress
helloblock.addresses.getUnspents(multisigAddress, function(err, resp, resource) {
helloblock.addresses.getUnspents(multisigAddress, function(err, res, unspents) {
if (err) return done(err)
// use the oldest unspent
var unspent = resource[resource.length - 1]
var unspent = unspents[unspents.length - 1]
var spendAmount = Math.min(unspent.value, outputAmount)
var tx = new Transaction()
tx.addInput(unspent.txHash, unspent.index)
tx.addOutput(targetAddress, spendAmount)
var txb = new TransactionBuilder()
txb.addInput(unspent.txHash, unspent.index)
txb.addOutput(targetAddress, spendAmount)
var signatures = privKeys.map(function(privKey) {
return tx.signInput(0, redeemScript, privKey)
privKeys.forEach(function(privKey) {
txb.sign(0, privKey, redeemScript)
})
var redeemScriptSig = scripts.multisigInput(signatures)
var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
tx.setInputScript(0, scriptSig)
// broadcast our transaction
helloblock.transactions.propagate(tx.toHex(), function(err, resp, resource) {
helloblock.transactions.propagate(txb.build().toHex(), function(err, res) {
// no err means that the transaction has been successfully propagated

@@ -73,6 +67,6 @@ if (err) return done(err)

// Check that the funds (spendAmount Satoshis) indeed arrived at the intended address
helloblock.addresses.get(targetAddress, function(err, resp, resource) {
helloblock.addresses.get(targetAddress, function(err, res, addrInfo) {
if (err) return done(err)
assert.equal(resource.balance, spendAmount)
assert.equal(addrInfo.balance, spendAmount)
done()

@@ -79,0 +73,0 @@ })

@@ -29,4 +29,3 @@ var assert = require('assert')

var address = Address.fromBase58Check(f.address)
var signature = new Buffer(f.signature, 'base64')
assert.ok(Message.verify(address, signature, f.message, network))
assert(Message.verify(address, f.signature, f.message, network))
})

@@ -38,9 +37,7 @@

var signature = new Buffer(f.signature, 'base64')
assert.ok(Message.verify(f.address, signature, f.message, network))
var signature = f.signature
assert(Message.verify(f.address, f.signature, f.message, network))
if (f.compressed) {
var compressedSignature = new Buffer(f.compressed.signature, 'base64')
assert.ok(Message.verify(f.compressed.address, compressedSignature, f.message, network))
assert(Message.verify(f.compressed.address, f.compressed.signature, f.message, network))
}

@@ -52,4 +49,3 @@ })

it(f.description, function() {
var signature = new Buffer(f.signature, 'base64')
assert.ok(!Message.verify(f.address, signature, f.message))
assert(!Message.verify(f.address, f.signature, f.message))
})

@@ -56,0 +52,0 @@ })

@@ -224,3 +224,3 @@ var assert = require('assert')

// FIXME: could be better
// FIXME: remove in 2.x.y
describe('signInput/validateInput', function() {

@@ -227,0 +227,0 @@ it('works for multi-sig redeem script', function() {

var assert = require('assert')
var bufferutils = require('../src/bufferutils')
var crypto = require('../src/crypto')

@@ -10,2 +11,3 @@ var networks = require('../src/networks')

var Transaction = require('../src/transaction')
var TransactionBuilder = require('../src/transaction_builder')
var Wallet = require('../src/wallet')

@@ -30,9 +32,13 @@

describe('Wallet', function() {
var seed, wallet
beforeEach(function(){
var seed
beforeEach(function() {
seed = crypto.sha256("don't use a string seed like this in real life")
wallet = new Wallet(seed)
})
describe('constructor', function() {
var wallet
beforeEach(function() {
wallet = new Wallet(seed)
})
it('defaults to Bitcoin network', function() {

@@ -60,6 +66,6 @@ assert.equal(wallet.getMasterKey().network, networks.bitcoin)

describe('when seed is not specified', function(){
it('generates a seed', function(){
describe('when seed is not specified', function() {
it('generates a seed', function() {
var wallet = new Wallet()
assert.ok(wallet.getMasterKey())
assert(wallet.getMasterKey())
})

@@ -79,4 +85,4 @@ })

describe('newMasterKey', function(){
it('resets accounts', function(){
describe('newMasterKey', function() {
it('resets accounts', function() {
var wallet = new Wallet()

@@ -93,3 +99,3 @@ var oldAccountZero = wallet.getAccountZero()

it('resets addresses', function(){
it('resets addresses', function() {
var wallet = new Wallet()

@@ -109,4 +115,4 @@ wallet.generateAddress()

describe('generateAddress', function(){
it('generate receiving addresses', function(){
describe('generateAddress', function() {
it('generate receiving addresses', function() {
var wallet = new Wallet(seed, networks.testnet)

@@ -124,4 +130,9 @@ var expectedAddresses = [

describe('generateChangeAddress', function(){
it('generates change addresses', function(){
describe('generateChangeAddress', function() {
var wallet
beforeEach(function() {
wallet = new Wallet(seed)
})
it('generates change addresses', function() {
var wallet = new Wallet(seed, networks.testnet)

@@ -135,4 +146,9 @@ var expectedAddresses = ["mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn"]

describe('getPrivateKey', function(){
it('returns the private key at the given index of external account', function(){
describe('getPrivateKey', function() {
var wallet
beforeEach(function() {
wallet = new Wallet(seed)
})
it('returns the private key at the given index of external account', function() {
var wallet = new Wallet(seed, networks.testnet)

@@ -145,4 +161,9 @@

describe('getInternalPrivateKey', function(){
it('returns the private key at the given index of internal account', function(){
describe('getInternalPrivateKey', function() {
var wallet
beforeEach(function() {
wallet = new Wallet(seed)
})
it('returns the private key at the given index of internal account', function() {
var wallet = new Wallet(seed, networks.testnet)

@@ -155,4 +176,9 @@

describe('getPrivateKeyForAddress', function(){
it('returns the private key for the given address', function(){
describe('getPrivateKeyForAddress', function() {
var wallet
beforeEach(function() {
wallet = new Wallet(seed)
})
it('returns the private key for the given address', function() {
var wallet = new Wallet(seed, networks.testnet)

@@ -173,45 +199,50 @@ wallet.generateChangeAddress()

it('raises an error when address is not found', function(){
it('raises an error when address is not found', function() {
var wallet = new Wallet(seed, networks.testnet)
assert.throws(function() {
wallet.getPrivateKeyForAddress("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X")
}, /Unknown address. Make sure the address is from the keychain and has been generated./)
}, /Unknown address. Make sure the address is from the keychain and has been generated/)
})
})
describe('Unspent Outputs', function(){
var expectedUtxo, expectedOutputKey
beforeEach(function(){
expectedUtxo = {
"hash":"6a4062273ac4f9ea4ffca52d9fd102b08f6c32faa0a4d1318e3a7b2e437bb9c7",
"outputIndex": 0,
describe('Unspent Outputs', function() {
var utxo, expectedOutputKey
var wallet
beforeEach(function() {
utxo = {
"address" : "1AZpKpcfCzKDUeTFBQUL4MokQai3m3HMXv",
"confirmations": 1,
"index": 0,
"txId": fakeTxId(6),
"value": 20000,
"pending": true
"pending": false
}
expectedOutputKey = expectedUtxo.hash + ":" + expectedUtxo.outputIndex
})
function addUtxoToOutput(utxo){
var key = utxo.hash + ":" + utxo.outputIndex
wallet.outputs[key] = {
from: key,
address: utxo.address,
value: utxo.value,
pending: utxo.pending
}
}
describe('on construction', function() {
beforeEach(function() {
wallet = new Wallet(seed, networks.bitcoin)
wallet.setUnspentOutputs([utxo])
})
describe('getBalance', function(){
var utxo1
it('matches the expected behaviour', function() {
var output = wallet.unspents[0]
beforeEach(function(){
utxo1 = cloneObject(expectedUtxo)
utxo1.hash = utxo1.hash.replace('7', 'l')
assert.equal(output.address, utxo.address)
assert.equal(output.value, utxo.value)
})
})
it('sums over utxo values', function(){
addUtxoToOutput(expectedUtxo)
addUtxoToOutput(utxo1)
describe('getBalance', function() {
beforeEach(function() {
var utxo1 = cloneObject(utxo)
utxo1.hash = fakeTxId(5)
wallet = new Wallet(seed, networks.bitcoin)
wallet.setUnspentOutputs([utxo, utxo1])
})
it('sums over utxo values', function() {
assert.equal(wallet.getBalance(), 40000)

@@ -221,56 +252,81 @@ })

describe('getUnspentOutputs', function(){
beforeEach(function(){
addUtxoToOutput(expectedUtxo)
describe('getUnspentOutputs', function() {
beforeEach(function() {
wallet = new Wallet(seed, networks.bitcoin)
wallet.setUnspentOutputs([utxo])
})
it('parses wallet outputs to the expect format', function(){
assert.deepEqual(wallet.getUnspentOutputs(), [expectedUtxo])
it('parses wallet unspents to the expected format', function() {
var outputs = wallet.getUnspentOutputs()
var output = outputs[0]
assert.equal(utxo.address, output.address)
assert.equal(utxo.index, output.index)
assert.equal(utxo.value, output.value)
// FIXME: remove in 2.0.0
assert.equal(utxo.txId, output.hash)
assert.equal(utxo.pending, output.pending)
// new in 2.0.0
assert.equal(utxo.txId, output.txId)
assert.equal(utxo.confirmations, output.confirmations)
})
it("ignores pending spending outputs (outputs with 'to' property)", function(){
var output = wallet.outputs[expectedOutputKey]
output.to = fakeTxId(0) + ':' + 0
output.pending = true
it("ignores spent unspents (outputs with 'spent' property)", function() {
var unspent = wallet.unspents[0]
unspent.pending = true
unspent.spent = true
assert.deepEqual(wallet.getUnspentOutputs(), [])
})
})
})
describe('setUnspentOutputs', function(){
var utxo
beforeEach(function(){
utxo = cloneObject([expectedUtxo])
})
describe('setUnspentOutputs', function() {
var utxo
var expectedOutputKey
var wallet
it('matches the expected behaviour', function(){
wallet.setUnspentOutputs(utxo)
verifyOutputs()
})
beforeEach(function() {
utxo = {
hash: fakeTxId(0),
index: 0,
address: '115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi',
value: 500000
}
describe('required fields', function(){
['outputIndex', 'address', 'hash', 'value'].forEach(function(field){
it("throws an error when " + field + " is missing", function(){
delete utxo[0][field]
wallet = new Wallet(seed, networks.bitcoin)
})
assert.throws(function() {
wallet.setUnspentOutputs(utxo)
}, new RegExp('Invalid unspent output: key ' + field + ' is missing'))
it('matches the expected behaviour', function() {
wallet.setUnspentOutputs([utxo])
var output = wallet.unspents[0]
assert.equal(output.value, utxo.value)
assert.equal(output.address, utxo.address)
})
describe('required fields', function() {
['index', 'address', 'hash', 'value'].forEach(function(field){
it("throws an error when " + field + " is missing", function() {
delete utxo[field]
assert.throws(function() {
wallet.setUnspentOutputs([utxo])
})
})
})
function verifyOutputs() {
var output = wallet.outputs[expectedOutputKey]
assert(output)
assert.equal(output.value, utxo[0].value)
assert.equal(output.address, utxo[0].address)
}
})
})
describe('Process transaction', function(){
describe('Process transaction', function() {
var wallet
beforeEach(function() {
wallet = new Wallet(seed)
})
var addresses
var tx
beforeEach(function(){
beforeEach(function() {
addresses = [

@@ -285,4 +341,4 @@ '115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi',

describe("processPendingTx", function(){
it("incoming: sets the pending flag on output", function(){
describe("processPendingTx", function() {
it("incoming: sets the pending flag on output", function() {
wallet.addresses = [addresses[0]]

@@ -294,5 +350,5 @@ wallet.processPendingTx(tx)

describe("when tx ins outpoint contains a known txhash:i", function(){
describe("when tx ins outpoint contains a known txhash:i", function() {
var spendTx
beforeEach(function(){
beforeEach(function() {
wallet.addresses = [addresses[0]]

@@ -304,3 +360,3 @@ wallet.processConfirmedTx(tx)

it("outgoing: sets the pending flag and 'to' on output", function(){
it("outgoing: sets the pending flag and 'spent' on output", function() {
var txIn = spendTx.ins[0]

@@ -311,8 +367,8 @@ var txInId = new Buffer(txIn.hash)

var key = txInId + ':' + txIn.index
assert(!wallet.outputs[key].pending)
var unspent = wallet.unspents[0]
assert(!unspent.pending)
wallet.processPendingTx(spendTx)
assert(wallet.outputs[key].pending)
assert.equal(wallet.outputs[key].to, spendTx.getId() + ':' + 0)
assert(unspent.pending)
assert(unspent.spent, true)
})

@@ -322,3 +378,3 @@ })

describe('processConfirmedTx', function(){
describe('processConfirmedTx', function() {
it('does not throw on scripts with no corresponding Address', function() {

@@ -335,4 +391,4 @@ var pubKey = wallet.getPrivateKey(0).pub

describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.outputs", function(){
it("works for receive address", function(){
describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.unspentMap", function() {
it("works for receive address", function() {
var totalOuts = outputCount()

@@ -347,3 +403,3 @@

it("works for change address", function(){
it("works for change address", function() {
var totalOuts = outputCount()

@@ -358,10 +414,10 @@ wallet.changeAddresses = [addresses[1]]

function outputCount(){
return Object.keys(wallet.outputs).length
function outputCount() {
return Object.keys(wallet.unspentMap).length
}
})
describe("when tx ins outpoint contains a known txhash:i", function(){
describe("when tx ins contains a known txhash:i", function() {
var spendTx
beforeEach(function(){
beforeEach(function() {
wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input

@@ -373,32 +429,32 @@ wallet.processConfirmedTx(tx)

it("does not add to wallet.outputs", function(){
it("does not add to wallet.unspentMap", function() {
wallet.processConfirmedTx(spendTx)
assert.deepEqual(wallet.outputs, {})
assert.deepEqual(wallet.unspentMap, {})
})
it("deletes corresponding 'output'", function(){
it("deletes corresponding 'unspent'", function() {
var txIn = spendTx.ins[0]
var txInId = new Buffer(txIn.hash)
Array.prototype.reverse.call(txInId)
txInId = txInId.toString('hex')
var txInId = bufferutils.reverse(txIn.hash).toString('hex')
var expected = txInId + ':' + txIn.index
assert(expected in wallet.outputs)
assert(expected in wallet.unspentMap)
wallet.processConfirmedTx(spendTx)
assert(!(expected in wallet.outputs))
assert(!(expected in wallet.unspentMap))
})
})
})
it("does nothing when none of the involved addresses belong to the wallet", function(){
wallet.processConfirmedTx(tx)
assert.deepEqual(wallet.outputs, {})
})
it("does nothing when none of the involved addresses belong to the wallet", function() {
wallet.processConfirmedTx(tx)
assert.deepEqual(wallet.unspentMap, {})
})
function verifyOutputAdded(index, pending) {
var txOut = tx.outs[index]
var key = tx.getId() + ":" + index
var output = wallet.outputs[key]
assert.equal(output.from, key)
var output = wallet.unspentMap[key]
assert.deepEqual(output.txHash, tx.getHash())
assert.equal(output.value, txOut.value)

@@ -412,31 +468,31 @@ assert.equal(output.pending, pending)

describe('createTx', function(){
describe('createTx', function() {
var wallet
var address1, address2
var to, value
var address1, address2
beforeEach(function(){
to = '15mMHKL96tWAUtqF3tbVf99Z8arcmnJrr3'
beforeEach(function() {
to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue'
value = 500000
// generate 2 addresses
address1 = wallet.generateAddress()
address2 = wallet.generateAddress()
address1 = "n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa"
address2 = "n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X"
// set up 3 utxo
utxo = [
// set up 3 utxos
var utxos = [
{
"hash": fakeTxId(1),
"outputIndex": 0,
"address" : address1,
"txId": fakeTxId(1),
"index": 0,
"address": address1,
"value": 400000 // not enough for value
},
{
"hash": fakeTxId(2),
"outputIndex": 1,
"address" : address1,
"txId": fakeTxId(2),
"index": 1,
"address": address1,
"value": 500000 // enough for only value
},
{
"hash": fakeTxId(3),
"outputIndex": 0,
"txId": fakeTxId(3),
"index": 0,
"address" : address2,

@@ -446,9 +502,13 @@ "value": 510000 // enough for value and fee

]
wallet.setUnspentOutputs(utxo)
wallet = new Wallet(seed, networks.testnet)
wallet.setUnspentOutputs(utxos)
wallet.generateAddress()
wallet.generateAddress()
})
describe('transaction fee', function(){
it('allows fee to be specified', function(){
describe('transaction fee', function() {
it('allows fee to be specified', function() {
var fee = 30000
var tx = wallet.createTx(to, value, fee)
var tx = wallet.createTx(to, value, { fixedFee: fee })

@@ -458,6 +518,6 @@ assert.equal(getFee(wallet, tx), fee)

it('allows fee to be set to zero', function(){
it('allows fee to be set to zero', function() {
value = 510000
var fee = 0
var tx = wallet.createTx(to, value, fee)
var tx = wallet.createTx(to, value, { fixedFee: fee })

@@ -467,14 +527,16 @@ assert.equal(getFee(wallet, tx), fee)

it('does not overestimate fees when network has dustSoftThreshold', function(){
var wallet = new Wallet(seed, networks.litecoin)
var address = wallet.generateAddress()
wallet.setUnspentOutputs([{
hash: fakeTxId(0),
outputIndex: 0,
address: address,
it('does not overestimate fees when network has dustSoftThreshold', function() {
var utxo = {
txId: fakeTxId(0),
index: 0,
address: "LeyySKbQrRRwodKEj1W4a8y3YQupPLw5os",
value: 500000
}])
}
var wallet = new Wallet(seed, networks.litecoin)
wallet.setUnspentOutputs([utxo])
wallet.generateAddress()
value = 200000
var tx = wallet.createTx(address, value)
var tx = wallet.createTx(utxo.address, value)

@@ -485,9 +547,10 @@ assert.equal(getFee(wallet, tx), 100000)

function getFee(wallet, tx) {
var inputValue = tx.ins.reduce(function(memo, input){
var id = Array.prototype.reverse.call(input.hash).toString('hex')
return memo + wallet.outputs[id + ':' + input.index].value
var inputValue = tx.ins.reduce(function(accum, input) {
var txId = bufferutils.reverse(input.hash).toString('hex')
return accum + wallet.unspentMap[txId + ':' + input.index].value
}, 0)
return tx.outs.reduce(function(memo, output){
return memo - output.value
return tx.outs.reduce(function(accum, output) {
return accum - output.value
}, inputValue)

@@ -497,4 +560,4 @@ }

describe('choosing utxo', function(){
it('takes fees into account', function(){
describe('choosing utxo', function() {
it('takes fees into account', function() {
var tx = wallet.createTx(to, value)

@@ -507,65 +570,40 @@

it('ignores pending outputs', function(){
utxo.push(
{
"hash": fakeTxId(4),
"outputIndex": 0,
"address" : address2,
"value": 530000,
"pending": true
}
)
wallet.setUnspentOutputs(utxo)
it('uses confirmed outputs', function() {
var tx2 = new Transaction()
tx2.addInput(fakeTxId(4), 0)
tx2.addOutput(address2, 530000)
wallet.processConfirmedTx(tx2)
var tx = wallet.createTx(to, value)
assert.equal(tx.ins.length, 1)
assert.deepEqual(tx.ins[0].hash, fakeTxHash(3))
assert.deepEqual(tx.ins[0].hash, tx2.getHash())
assert.equal(tx.ins[0].index, 0)
})
})
describe('works for testnet', function(){
it('should create transaction', function(){
var wallet = new Wallet(seed, networks.testnet)
var address = wallet.generateAddress()
it('ignores pending outputs', function() {
var tx2 = new Transaction()
tx2.addInput(fakeTxId(4), 0)
tx2.addOutput(address2, 530000)
wallet.setUnspentOutputs([{
hash: fakeTxId(0),
outputIndex: 0,
address: address,
value: value
}])
wallet.processPendingTx(tx2)
var tx = wallet.createTx(to, value)
var to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue'
var toValue = value - 10000
var tx = wallet.createTx(to, toValue)
assert.equal(tx.outs.length, 1)
var outAddress = Address.fromOutputScript(tx.outs[0].script, networks.testnet)
assert.equal(outAddress.toString(), to)
assert.equal(tx.outs[0].value, toValue)
assert.equal(tx.ins.length, 1)
assert.deepEqual(tx.ins[0].hash, fakeTxHash(3))
assert.equal(tx.ins[0].index, 0)
})
})
describe('changeAddress', function(){
it('should allow custom changeAddress', function(){
var wallet = new Wallet(seed, networks.testnet)
var address = wallet.generateAddress()
wallet.setUnspentOutputs([{
hash: fakeTxId(0),
outputIndex: 0,
address: address,
value: value
}])
assert.equal(wallet.getBalance(), value)
describe('changeAddress', function() {
it('should allow custom changeAddress', function() {
var changeAddress = 'mfrFjnKZUvTcvdAK2fUX5D8v1Epu5H8JCk'
var to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue'
var toValue = value / 2
var fromValue = 510000
var toValue = fromValue / 2
var fee = 1e3
var tx = wallet.createTx(to, toValue, fee, changeAddress)
var tx = wallet.createTx(to, toValue, {
fixedFee: fee,
changeAddress: changeAddress
})
assert.equal(tx.outs.length, 2)

@@ -580,8 +618,8 @@

assert.equal(outAddress1.toString(), changeAddress)
assert.equal(tx.outs[1].value, value - (toValue + fee))
assert.equal(tx.outs[1].value, fromValue - (toValue + fee))
})
})
describe('transaction outputs', function(){
it('includes the specified address and amount', function(){
describe('transaction outputs', function() {
it('includes the specified address and amount', function() {
var tx = wallet.createTx(to, value)

@@ -591,3 +629,3 @@

var out = tx.outs[0]
var outAddress = Address.fromOutputScript(out.script)
var outAddress = Address.fromOutputScript(out.script, networks.testnet)

@@ -598,12 +636,12 @@ assert.equal(outAddress.toString(), to)

describe('change', function(){
it('uses the last change address if there is any', function(){
describe('change', function() {
it('uses the last change address if there is any', function() {
var fee = 0
wallet.generateChangeAddress()
wallet.generateChangeAddress()
var tx = wallet.createTx(to, value, fee)
var tx = wallet.createTx(to, value, { fixedFee: fee })
assert.equal(tx.outs.length, 2)
var out = tx.outs[1]
var outAddress = Address.fromOutputScript(out.script)
var outAddress = Address.fromOutputScript(out.script, networks.testnet)

@@ -614,11 +652,11 @@ assert.equal(outAddress.toString(), wallet.changeAddresses[1])

it('generates a change address if there is not any', function(){
it('generates a change address if there is not any', function() {
var fee = 0
assert.equal(wallet.changeAddresses.length, 0)
var tx = wallet.createTx(to, value, fee)
var tx = wallet.createTx(to, value, { fixedFee: fee })
assert.equal(wallet.changeAddresses.length, 1)
var out = tx.outs[1]
var outAddress = Address.fromOutputScript(out.script)
var outAddress = Address.fromOutputScript(out.script, networks.testnet)

@@ -629,6 +667,8 @@ assert.equal(outAddress.toString(), wallet.changeAddresses[0])

it('skips change if it is not above dust threshold', function(){
var fee = 14570
var tx = wallet.createTx(to, value)
assert.equal(tx.outs.length, 1)
it('skips change if it is not above dust threshold', function() {
var tx1 = wallet.createTx(to, value - 546)
assert.equal(tx1.outs.length, 1)
var tx2 = wallet.createTx(to, value - 547)
assert.equal(tx2.outs.length, 2)
})

@@ -638,20 +678,26 @@ })

describe('signing', function(){
afterEach(function(){
Transaction.prototype.sign.restore()
describe('signing', function() {
afterEach(function() {
TransactionBuilder.prototype.sign.restore()
})
it('signes the inputs with respective keys', function(){
it('signs the inputs with respective keys', function() {
var fee = 30000
sinon.stub(Transaction.prototype, "sign")
sinon.spy(TransactionBuilder.prototype, "sign")
var tx = wallet.createTx(to, value, fee)
wallet.createTx(to, value, { fixedFee: fee })
assert(Transaction.prototype.sign.calledWith(0, wallet.getPrivateKeyForAddress(address2)))
assert(Transaction.prototype.sign.calledWith(1, wallet.getPrivateKeyForAddress(address1)))
var priv1 = wallet.getPrivateKeyForAddress(address1)
var priv2 = wallet.getPrivateKeyForAddress(address2)
// FIXME: boo (required) side effects
priv1.pub.Q.affineX, priv2.pub.Q.affineX
assert(TransactionBuilder.prototype.sign.calledWith(0, priv2))
assert(TransactionBuilder.prototype.sign.calledWith(1, priv1))
})
})
describe('when value is below dust threshold', function(){
it('throws an error', function(){
describe('when value is below dust threshold', function() {
it('throws an error', function() {
var value = 546

@@ -665,4 +711,4 @@

describe('when there is not enough money', function(){
it('throws an error', function(){
describe('when there is not enough money', function() {
it('throws an error', function() {
var value = 1400001

@@ -669,0 +715,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc