Skip to content

Instantly share code, notes, and snippets.

@abrkn

abrkn/sweep.js Secret

Created January 6, 2014 12:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abrkn/e770e24455fbe0065f74 to your computer and use it in GitHub Desktop.
Save abrkn/e770e24455fbe0065f74 to your computer and use it in GitHub Desktop.
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)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment