Daniel Cousens
7 years ago
committed by
Daniel Cousens
12 changed files with 359 additions and 296 deletions
@ -0,0 +1,3 @@ |
|||
var Blockchain = require('cb-http-client') |
|||
var BLOCKTRAIL_API_KEY = process.env.BLOCKTRAIL_API_KEY || 'c0bd8155c66e3fb148bb1664adc1e4dacd872548' |
|||
module.exports = new Blockchain('https://api.blocktrail.com/cb/v0.2.1/BTC', { api_key: BLOCKTRAIL_API_KEY }) |
@ -0,0 +1,92 @@ |
|||
/* global describe, it */ |
|||
|
|||
var assert = require('assert') |
|||
var bigi = require('bigi') |
|||
var bitcoin = require('../../') |
|||
var dhttp = require('dhttp/200') |
|||
|
|||
// deterministic RNG for testing only
|
|||
function rng () { return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } |
|||
|
|||
describe('bitcoinjs-lib (addresses)', function () { |
|||
it('can generate a random address', function () { |
|||
var keyPair = bitcoin.ECPair.makeRandom({ rng: rng }) |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') |
|||
}) |
|||
|
|||
it('can generate an address from a SHA256 hash', function () { |
|||
var hash = bitcoin.crypto.sha256('correct horse battery staple') |
|||
var d = bigi.fromBuffer(hash) |
|||
|
|||
var keyPair = new bitcoin.ECPair(d) |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') |
|||
}) |
|||
|
|||
it('can import an address via WIF', function () { |
|||
var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') |
|||
}) |
|||
|
|||
it('can generate a 2-of-3 multisig P2SH address', function () { |
|||
var pubKeys = [ |
|||
'026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', |
|||
'02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', |
|||
'03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9' |
|||
].map(function (hex) { |
|||
return Buffer.from(hex, 'hex') |
|||
}) |
|||
|
|||
var redeemScript = bitcoin.script.multisig.output.encode(2, pubKeys) // 2 of 3
|
|||
var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript)) |
|||
var address = bitcoin.address.fromOutputScript(scriptPubKey) |
|||
|
|||
assert.strictEqual(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') |
|||
}) |
|||
|
|||
it('can support the retrieval of transactions for an address (3rd party blockchain)', function (done) { |
|||
var keyPair = bitcoin.ECPair.makeRandom() |
|||
var address = keyPair.getAddress() |
|||
|
|||
dhttp({ |
|||
method: 'POST', |
|||
url: 'https://api.ei8ht.com.au/3/addrtxs', |
|||
body: { |
|||
addrs: [address], |
|||
height: 0 |
|||
} |
|||
}, function (err, transactions) { |
|||
if (err) return done(err) |
|||
|
|||
// random private keys [probably] have no transactions
|
|||
assert.strictEqual(Object.keys(transactions).length, 0) |
|||
done() |
|||
}) |
|||
}) |
|||
|
|||
// other networks
|
|||
it('can generate a Testnet address', function () { |
|||
var testnet = bitcoin.networks.testnet |
|||
var keyPair = bitcoin.ECPair.makeRandom({ network: testnet, rng: rng }) |
|||
var wif = keyPair.toWIF() |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, 'mubSzQNtZfDj1YdNP6pNDuZy6zs6GDn61L') |
|||
assert.strictEqual(wif, 'cRgnQe9MUu1JznntrLaoQpB476M8PURvXVQB5R2eqms5tXnzNsrr') |
|||
}) |
|||
|
|||
it('can generate a Litecoin address', function () { |
|||
var litecoin = bitcoin.networks.litecoin |
|||
var keyPair = bitcoin.ECPair.makeRandom({ network: litecoin, rng: rng }) |
|||
var wif = keyPair.toWIF() |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, 'LZJSxZbjqJ2XVEquqfqHg1RQTDdfST5PTn') |
|||
assert.strictEqual(wif, 'T7A4PUSgTDHecBxW1ZiYFrDNRih2o7M8Gf9xpoCgudPF9gDiNvuS') |
|||
}) |
|||
}) |
@ -1,30 +0,0 @@ |
|||
/* global describe, it */ |
|||
|
|||
var bitcoin = require('../../') |
|||
var blockchain = require('./_blockchain') |
|||
|
|||
describe('bitcoinjs-lib (advanced)', function () { |
|||
it('can create an OP_RETURN transaction', function (done) { |
|||
this.timeout(30000) |
|||
|
|||
var network = bitcoin.networks.testnet |
|||
var keyPair = bitcoin.ECPair.makeRandom({ network: network }) |
|||
var address = keyPair.getAddress() |
|||
|
|||
blockchain.t.faucet(address, 5e4, function (err, unspent) { |
|||
if (err) return done(err) |
|||
|
|||
var tx = new bitcoin.TransactionBuilder(network) |
|||
var data = Buffer.from('bitcoinjs-lib') |
|||
var dataScript = bitcoin.script.nullData.output.encode(data) |
|||
|
|||
tx.addInput(unspent.txId, unspent.vout) |
|||
tx.addOutput(dataScript, 1000) |
|||
tx.addOutput(blockchain.t.RETURN, 4e4) |
|||
tx.sign(0, keyPair) |
|||
var txRaw = tx.build() |
|||
|
|||
blockchain.t.transactions.propagate(txRaw.toHex(), done) |
|||
}) |
|||
}) |
|||
}) |
@ -1,94 +0,0 @@ |
|||
/* global describe, it */ |
|||
|
|||
var assert = require('assert') |
|||
var bigi = require('bigi') |
|||
var bitcoin = require('../../') |
|||
var blockchain = require('./_blockchain') |
|||
|
|||
describe('bitcoinjs-lib (basic)', function () { |
|||
it('can generate a random bitcoin address', function () { |
|||
// for testing only
|
|||
function rng () { return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } |
|||
|
|||
// generate random keyPair
|
|||
var keyPair = bitcoin.ECPair.makeRandom({ rng: rng }) |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') |
|||
}) |
|||
|
|||
it('can generate an address from a SHA256 hash', function () { |
|||
var hash = bitcoin.crypto.sha256('correct horse battery staple') |
|||
var d = bigi.fromBuffer(hash) |
|||
|
|||
var keyPair = new bitcoin.ECPair(d) |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') |
|||
}) |
|||
|
|||
it('can generate a random keypair for alternative networks', function () { |
|||
// for testing only
|
|||
function rng () { return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } |
|||
|
|||
var litecoin = bitcoin.networks.litecoin |
|||
|
|||
var keyPair = bitcoin.ECPair.makeRandom({ network: litecoin, rng: rng }) |
|||
var wif = keyPair.toWIF() |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, 'LZJSxZbjqJ2XVEquqfqHg1RQTDdfST5PTn') |
|||
assert.strictEqual(wif, 'T7A4PUSgTDHecBxW1ZiYFrDNRih2o7M8Gf9xpoCgudPF9gDiNvuS') |
|||
}) |
|||
|
|||
it('can import an address via WIF', function () { |
|||
var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') |
|||
var address = keyPair.getAddress() |
|||
|
|||
assert.strictEqual(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') |
|||
}) |
|||
|
|||
it('can create a Transaction', function () { |
|||
var keyPair = bitcoin.ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') |
|||
var tx = new bitcoin.TransactionBuilder() |
|||
|
|||
tx.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0) |
|||
tx.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000) |
|||
tx.sign(0, keyPair) |
|||
|
|||
assert.strictEqual(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000') |
|||
}) |
|||
|
|||
it('can create a [complex] Transaction', function (done) { |
|||
this.timeout(30000) |
|||
|
|||
var testnet = bitcoin.networks.testnet |
|||
var alice = bitcoin.ECPair.makeRandom({ network: testnet }) |
|||
var bob = bitcoin.ECPair.makeRandom({ network: testnet }) |
|||
var alicesAddress = alice.getAddress() |
|||
var bobsAddress = bob.getAddress() |
|||
|
|||
blockchain.t.faucetMany([ |
|||
{ |
|||
address: alicesAddress, |
|||
value: 4e4 |
|||
}, |
|||
{ |
|||
address: bobsAddress, |
|||
value: 2e4 |
|||
} |
|||
], function (err, unspents) { |
|||
if (err) return done(err) |
|||
|
|||
var tx = new bitcoin.TransactionBuilder(testnet) |
|||
tx.addInput(unspents[0].txId, unspents[0].vout) |
|||
tx.addInput(unspents[1].txId, unspents[1].vout) |
|||
tx.addOutput(blockchain.t.RETURN, 3e4) |
|||
tx.addOutput('mvGVHWi6gbkBZZPaqBVRcxvKVPYd9r3fp7', 1e4) |
|||
tx.sign(0, alice) |
|||
tx.sign(1, bob) |
|||
|
|||
blockchain.t.transactions.propagate(tx.build().toHex(), done) |
|||
}) |
|||
}) |
|||
}) |
@ -1,76 +0,0 @@ |
|||
/* global describe, it */ |
|||
|
|||
var async = require('async') |
|||
var assert = require('assert') |
|||
var bitcoin = require('../../') |
|||
var blockchain = require('./_blockchain') |
|||
|
|||
describe('bitcoinjs-lib (multisig)', function () { |
|||
it('can create a 2-of-3 multisig P2SH address', function () { |
|||
var pubKeys = [ |
|||
'026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', |
|||
'02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', |
|||
'03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9' |
|||
].map(function (hex) { |
|||
return Buffer.from(hex, 'hex') |
|||
}) |
|||
|
|||
var redeemScript = bitcoin.script.multisig.output.encode(2, pubKeys) // 2 of 3
|
|||
var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript)) |
|||
var address = bitcoin.address.fromOutputScript(scriptPubKey) |
|||
|
|||
assert.strictEqual(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') |
|||
}) |
|||
|
|||
it('can spend from a 2-of-4 multsig P2SH address', function (done) { |
|||
this.timeout(30000) |
|||
|
|||
var keyPairs = [ |
|||
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx', |
|||
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT', |
|||
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe', |
|||
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx9rcrL7' |
|||
].map(function (wif) { return bitcoin.ECPair.fromWIF(wif, bitcoin.networks.testnet) }) |
|||
var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() }) |
|||
|
|||
var redeemScript = bitcoin.script.multisig.output.encode(2, pubKeys) // 2 of 4
|
|||
var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript)) |
|||
var address = bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet) |
|||
|
|||
// attempt to send funds to the source address
|
|||
blockchain.t.faucet(address, 2e4, function (err, unspent) { |
|||
if (err) return done(err) |
|||
|
|||
var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet) |
|||
txb.addInput(unspent.txId, unspent.vout) |
|||
txb.addOutput(blockchain.t.RETURN, 1e4) |
|||
|
|||
// sign with 1st and 3rd key
|
|||
txb.sign(0, keyPairs[0], redeemScript) |
|||
txb.sign(0, keyPairs[2], redeemScript) |
|||
|
|||
// broadcast our transaction
|
|||
var tx = txb.build() |
|||
var txId = tx.getId() |
|||
|
|||
blockchain.t.transactions.propagate(tx.toHex(), function (err) { |
|||
if (err) return done(err) |
|||
|
|||
// wait for TX to be accepted
|
|||
async.retry(5, function (callback) { |
|||
setTimeout(function () { |
|||
// check that the above transaction included the intended address
|
|||
blockchain.t.addresses.unspents(blockchain.t.RETURN, function (err, unspents) { |
|||
if (err) return callback(err) |
|||
if (!unspents.some(function (x) { |
|||
return x.txId === txId && x.value === 1e4 |
|||
})) return callback(new Error('Could not find unspent after broadcast')) |
|||
|
|||
callback() |
|||
}) |
|||
}, 600) |
|||
}, done) |
|||
}) |
|||
}) |
|||
}) |
|||
}) |
@ -0,0 +1,157 @@ |
|||
/* global describe, it */ |
|||
|
|||
var assert = require('assert') |
|||
var bitcoin = require('../../') |
|||
var dhttp = require('dhttp/200') |
|||
var testnet = bitcoin.networks.testnet |
|||
var testnetUtils = require('./_testnet') |
|||
|
|||
function rng () { |
|||
return Buffer.from('YT8dAtK4d16A3P1z+TpwB2jJ4aFH3g9M1EioIBkLEV4=', 'base64') |
|||
} |
|||
|
|||
describe('bitcoinjs-lib (transactions)', function () { |
|||
it('can create a 1-to-1 Transaction', function () { |
|||
var alice = bitcoin.ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') |
|||
var tx = new bitcoin.TransactionBuilder() |
|||
|
|||
tx.addInput('61d520ccb74288c96bc1a2b20ea1c0d5a704776dd0164a396efec3ea7040349d', 0) // Alice's previous transaction output, has 15000 satoshis
|
|||
tx.addOutput('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP', 12000) |
|||
// (in)15000 - (out)12000 = (fee)3000, this is the miner fee
|
|||
|
|||
tx.sign(0, alice) |
|||
|
|||
// build, prepare for broadcast to the Bitcoin network, see "can broadcast a Transaction" below
|
|||
assert.strictEqual(tx.build().toHex(), '01000000019d344070eac3fe6e394a16d06d7704a7d5c0a10eb2a2c16bc98842b7cc20d561000000006b48304502210088828c0bdfcdca68d8ae0caeb6ec62cd3fd5f9b2191848edae33feb533df35d302202e0beadd35e17e7f83a733f5277028a9b453d525553e3f5d2d7a7aa8010a81d60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01e02e0000000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00000000') |
|||
}) |
|||
|
|||
it('can create a 2-to-2 Transaction', function () { |
|||
var alice = bitcoin.ECPair.fromWIF('L1Knwj9W3qK3qMKdTvmg3VfzUs3ij2LETTFhxza9LfD5dngnoLG1') |
|||
var bob = bitcoin.ECPair.fromWIF('KwcN2pT3wnRAurhy7qMczzbkpY5nXMW2ubh696UBc1bcwctTx26z') |
|||
|
|||
var tx = new bitcoin.TransactionBuilder() |
|||
tx.addInput('b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c', 6) // Alice's previous transaction output, has 200000 satoshis
|
|||
tx.addInput('7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730', 0) // Bob's previous transaction output, has 300000 satoshis
|
|||
tx.addOutput('1CUNEBjYrCn2y1SdiUMohaKUi4wpP326Lb', 180000) |
|||
tx.addOutput('1JtK9CQw1syfWj1WtFMWomrYdV3W2tWBF9', 170000) |
|||
// (in)(200000 + 300000) - (out)(180000 + 150000) = (fee)170000, this is the miner fee
|
|||
|
|||
tx.sign(1, bob) // Bob signs his input, which was the second input (1th)
|
|||
tx.sign(0, alice) // Alice signs her input, which was the first input (0th)
|
|||
|
|||
// build, prepare for broadcast to the Bitcoin network, see "can broadcast a Transaction" below
|
|||
assert.strictEqual(tx.build().toHex(), '01000000024c94e48a870b85f41228d33cf25213dfcc8dd796e7211ed6b1f9a014809dbbb5060000006a473044022041450c258ce7cac7da97316bf2ea1ce66d88967c4df94f3e91f4c2a30f5d08cb02203674d516e6bb2b0afd084c3551614bd9cec3c2945231245e891b145f2d6951f0012103e05ce435e462ec503143305feb6c00e06a3ad52fbf939e85c65f3a765bb7baacffffffff3077d9de049574c3af9bc9c09a7c9db80f2d94caaf63988c9166249b955e867d000000006b483045022100aeb5f1332c79c446d3f906e4499b2e678500580a3f90329edf1ba502eec9402e022072c8b863f8c8d6c26f4c691ac9a6610aa4200edc697306648ee844cfbc089d7a012103df7940ee7cddd2f97763f67e1fb13488da3fbdd7f9c68ec5ef0864074745a289ffffffff0220bf0200000000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac10980200000000001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000') |
|||
}) |
|||
|
|||
it('can create (and broadcast via 3PBP) a typical Transaction', function (done) { |
|||
this.timeout(30000) |
|||
|
|||
var alice1 = bitcoin.ECPair.makeRandom({ network: testnet }) |
|||
var alice2 = bitcoin.ECPair.makeRandom({ network: testnet }) |
|||
var aliceChange = bitcoin.ECPair.makeRandom({ rng: rng, network: testnet }) |
|||
|
|||
// "simulate" on testnet that Alice has 2 unspent outputs
|
|||
testnetUtils.faucetMany([ |
|||
{ |
|||
address: alice1.getAddress(), |
|||
value: 4e4 |
|||
}, |
|||
{ |
|||
address: alice2.getAddress(), |
|||
value: 2e4 |
|||
} |
|||
], function (err, unspents) { |
|||
if (err) return done(err) |
|||
|
|||
var tx = new bitcoin.TransactionBuilder(testnet) |
|||
tx.addInput(unspents[0].txId, unspents[0].vout) // alice1 unspent
|
|||
tx.addInput(unspents[1].txId, unspents[1].vout) // alice2 unspent
|
|||
tx.addOutput('mvGVHWi6gbkBZZPaqBVRcxvKVPYd9r3fp7', 1e4) // the actual "spend"
|
|||
tx.addOutput(aliceChange.getAddress(), 3e4) // Alice's change
|
|||
// (in)(4e4 + 2e4) - (out)(1e4 + 3e4) = (fee)2e4 = 20000, this is the miner fee
|
|||
|
|||
// Alice signs each input with the respective private keys
|
|||
tx.sign(0, alice1) |
|||
tx.sign(1, alice2) |
|||
|
|||
// build and broadcast to the Bitcoin Testnet network
|
|||
dhttp({ |
|||
method: 'POST', |
|||
url: 'https://api.ei8ht.com.au:9443/3/pushtx', |
|||
// url: 'http://tbtc.blockr.io/api/v1/tx/push',
|
|||
body: tx.build().toHex() |
|||
}, done) |
|||
// to build and broadcast to the actual Bitcoin network, see https://github.com/bitcoinjs/bitcoinjs-lib/issues/839
|
|||
}) |
|||
}) |
|||
|
|||
it('can create (and broadcast via 3PBP) a Transaction with an OP_RETURN output', function (done) { |
|||
this.timeout(30000) |
|||
|
|||
var keyPair = bitcoin.ECPair.makeRandom({ network: testnet }) |
|||
var address = keyPair.getAddress() |
|||
|
|||
testnetUtils.faucet(address, 5e4, function (err, unspent) { |
|||
if (err) return done(err) |
|||
|
|||
var tx = new bitcoin.TransactionBuilder(testnet) |
|||
var data = Buffer.from('bitcoinjs-lib', 'utf8') |
|||
var dataScript = bitcoin.script.nullData.output.encode(data) |
|||
|
|||
tx.addInput(unspent.txId, unspent.vout) |
|||
tx.addOutput(dataScript, 1000) |
|||
tx.addOutput(testnetUtils.RETURN_ADDRESS, 4e4) |
|||
tx.sign(0, keyPair) |
|||
|
|||
// build and broadcast to the Bitcoin Testnet network
|
|||
dhttp({ |
|||
method: 'POST', |
|||
url: 'https://api.ei8ht.com.au:9443/3/pushtx', |
|||
body: tx.build().toHex() |
|||
}, done) |
|||
}) |
|||
}) |
|||
|
|||
it('can create (and broadcast via 3PBP) a Transaction with a 2-of-4 multisig P2SH input', function (done) { |
|||
this.timeout(30000) |
|||
|
|||
var keyPairs = [ |
|||
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx', |
|||
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT', |
|||
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe', |
|||
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx9rcrL7' |
|||
].map(function (wif) { return bitcoin.ECPair.fromWIF(wif, testnet) }) |
|||
var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() }) |
|||
|
|||
var redeemScript = bitcoin.script.multisig.output.encode(2, pubKeys) // 2 of 4
|
|||
var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript)) |
|||
var address = bitcoin.address.fromOutputScript(scriptPubKey, testnet) |
|||
|
|||
// attempt to send funds to the source address
|
|||
testnetUtils.faucet(address, 2e4, function (err, unspent) { |
|||
if (err) return done(err) |
|||
|
|||
var txb = new bitcoin.TransactionBuilder(testnet) |
|||
txb.addInput(unspent.txId, unspent.vout) |
|||
txb.addOutput(testnetUtils.RETURN_ADDRESS, 1e4) |
|||
|
|||
// sign with 1st and 3rd key
|
|||
txb.sign(0, keyPairs[0], redeemScript) |
|||
txb.sign(0, keyPairs[2], redeemScript) |
|||
|
|||
// broadcast our transaction
|
|||
var tx = txb.build() |
|||
var txId = tx.getId() |
|||
|
|||
dhttp({ |
|||
method: 'POST', |
|||
url: 'https://api.ei8ht.com.au:9443/3/pushtx', |
|||
body: tx.toHex() |
|||
}, function (err) { |
|||
if (err) return done(err) |
|||
|
|||
testnetUtils.verify(address, txId, 1e4, done) |
|||
}) |
|||
}) |
|||
}) |
|||
}) |
Loading…
Reference in new issue