Daniel Cousens
8 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