secret
Created

  • Download Gist
sweep.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
var BitcoinTools = require('bitcoin-tools')
, debug = require('debug')('snow:bitcoin-sweep')
, BitcoinLib = require('bitcoinjs-lib')
, blockchaininfo = require('./blockchaininfo.js')
 
function reverseHex(hash) {
var res = ''
for (var i = 0; i < hash.length; i++) {
res = hash.substr(i * 2, 2) + res
}
return res
}
 
var SIGHASH_ALL = 1
 
// See https://github.com/kyledrake/coinpunk/blob/master/public/js/coinpunk/models/wallet.js
module.exports = function(privKeys, destAddr, feeSatoshis, cb) {
var sourceAddrs = privKeys.map(BitcoinTools.addressFromPrivateKey)
, tx = new BitcoinLib.Transaction()
 
debug('gathering unspent outputs from blockchain.info...')
 
// Retrieve the unspent outputs for the source address
blockchaininfo.unspent(sourceAddrs, function(err, unspent) {
debug('found %s unspent outputs', unspent.length)
 
if (!unspent.length) return cb()
 
// Sum the unspent values
var value = unspent.reduce(function(p, c) {
return p + c.value
}, 0)
 
value = value - feeSatoshis
 
debug('will sweep %s BTC from the private key', value / 1e8)
 
tx.addOutput(destAddr, value)
 
// Add inputs
unspent.forEach(function(unspentOutput) {
// For some reason blockchain.info returns the unspent transaction
// hashes reversed. ABCDEF is returned EFCDAB
var hashReversed = reverseHex(unspentOutput.tx_hash)
 
// Add the input
tx.addInput({ hash: hashReversed }, unspentOutput.tx_output_n)
})
 
unspent.forEach(function(unspentOutput, i) {
// Sign the input
var unspentOutScript = new BitcoinLib.Script(BitcoinLib.convert.hexToBytes(unspentOutput.script))
 
// Determine which private key will need to sign the input
var pubKeyHash = unspentOutScript.simpleOutHash()
, pubKeyHashHex = BitcoinLib.convert.bytesToHex(pubKeyHash)
, key
 
privKeys.some(function(privKey) {
var privKeyEc = new BitcoinLib.Key(privKey)
, addr = privKeyEc.getBitcoinAddress()
, addrHashHex = BitcoinLib.convert.bytesToHex(addr.hash)
if (addrHashHex != pubKeyHashHex) return
key = privKeyEc
return true
})
 
if (!key) {
return cb(new Error('No private key found for public key with hash ' + pubKeyHashHex))
}
 
debug('signing input %s with priv key %s', i, key.toString('base58').substr(0, 6))
 
var hash = tx.hashTransactionForSignature(unspentOutScript, i, SIGHASH_ALL)
, signature = key.sign(hash)
 
// Push the signature type
signature.push(SIGHASH_ALL)
 
tx.ins[i].script = BitcoinLib.Script.createInputScript(signature, key.getPub())
})
 
// Serialize the transaction, convert to hex and push
var hex = BitcoinLib.convert.bytesToHex(tx.serialize())
 
debug('transaction (hex):\n%s', hex)
 
debug('pushing transaction...')
 
blockchaininfo.pushtx(hex, cb)
})
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.