UNPKG

4.96 kBJavaScriptView Raw
1var bitcoin = require('bitcoinjs-lib')
2
3var headerHex = 'e299a5' // ♥
4
5var signFromTransactionHex = function (signTransactionHex) {
6 if (!signTransactionHex) {
7 return false
8 }
9 return function (tx, callback) {
10 var txHex = tx.tx.toHex()
11 signTransactionHex(txHex, function (error, signedTxHex) {
12 var signedTx = bitcoin.TransactionBuilder.fromTransaction(bitcoin.Transaction.fromHex(signedTxHex))
13 callback(error, signedTx)
14 })
15 }
16}
17
18var create = function (options, callback) {
19 var commonWallet = options.commonWallet
20 var commonBlockchain = options.commonBlockchain
21 var openpublishSha1 = options.openpublishSha1
22 var tipDestinationAddress = options.tipDestinationAddress
23 var tipAmount = options.tipAmount || 10000
24 var data = new Buffer(headerHex + openpublishSha1, 'hex')
25 var signTransaction = signFromTransactionHex(commonWallet.signRawTransaction)
26 options.signTransaction = signTransaction
27 var address = commonWallet.address
28 var fee = options.fee || 1000
29 var payloadScript = bitcoin.Script.fromChunks([bitcoin.opcodes.OP_RETURN, data])
30 var tx = new bitcoin.TransactionBuilder()
31 commonBlockchain.Addresses.Unspents([address], function (err, addresses_unspents) {
32 if (err || addresses_unspents.length === 0) {
33 callback('error: possibly no unspents associated with address', null)
34 } else {
35 var unspentOutputs = addresses_unspents[0]
36 var compare = function (a, b) {
37 if (a.value < b.value) {
38 return -1
39 }
40 if (a.value > b.value) {
41 return 1
42 }
43 return 0
44 }
45 unspentOutputs.sort(compare)
46 var unspentValue = 0
47 for (var i = unspentOutputs.length - 1; i >= 0; i--) {
48 var unspentOutput = unspentOutputs[i]
49 if (unspentOutput.value === 0) {
50 continue
51 }
52 unspentValue += unspentOutput.value
53 tx.addInput(unspentOutput.txid, unspentOutput.vout)
54 if (unspentValue - fee - tipAmount >= 0) {
55 break
56 }
57 }
58 tx.addOutput(payloadScript, 0)
59 tx.addOutput(tipDestinationAddress, tipAmount)
60
61 if (unspentValue - fee - tipAmount > 0) {
62 tx.addOutput(address, unspentValue - fee - tipAmount)
63 }
64
65 signTransaction(tx, function (err, signedTx) {
66 if (err) { } // TODO
67 var signedTxBuilt = signedTx.build()
68 var signedTxHex = signedTxBuilt.toHex()
69 var txid = signedTxBuilt.getId()
70 callback(false, signedTxHex, txid)
71 })
72 }
73 })
74}
75
76var scanSingle = function (options, callback) {
77 if (options.tx) {
78 return scan({transactions: [options.tx]}, function (err, tips) {
79 if (err) { } // TODO
80 callback(err, tips[0])
81 })
82 } else {
83 var txid = options.txid
84 var commonBlockchain = options.commonBlockchain
85 return commonBlockchain.Transactions.Get([txid], function (err, txs) {
86 if (err) { } // TODO
87 var tx = txs[0]
88 scan({transactions: [tx]}, function (err, tips) {
89 callback(err, tips[0])
90 })
91 })
92 }
93}
94
95var scan = function (options, callback) {
96 var transactions = options.transactions
97 var tips = []
98 transactions.forEach(function (tx) {
99 if (!tx) {
100 return
101 }
102 var tip = {}
103 var sources = []
104 var value
105 var tipDestinationAddresses = []
106 var tipAmount = 0
107 tx.vin.forEach(function (input) {
108 var sourceAddress = input.addresses[0]
109 if (sourceAddress) {
110 sources.push(sourceAddress)
111 }
112 })
113 tx.vout.forEach(function (output) {
114 if (output.scriptPubKey.type === 'nulldata') {
115 var scriptPubKey = output.scriptPubKey.hex
116 if (scriptPubKey.slice(0, 2) === '6a') {
117 var data = scriptPubKey.slice(4, 84)
118 if (data.slice(0, 6) === headerHex && data.length === 46) {
119 tip.openpublishSha1 = data.slice(6, 46)
120 }
121 }
122 } else if (output.scriptPubKey.type === 'pubkeyhash') {
123 var destinationAddress = output.scriptPubKey.addresses[0]
124 if (!value || output.value < value) {
125 value = output.value
126 }
127 if (sources.indexOf(destinationAddress) < 0) {
128 tipAmount += output.value
129 tipDestinationAddresses.push(destinationAddress)
130 }
131 }
132 })
133 tip.tipDestinationAddresses = tipDestinationAddresses
134 tip.tipAmount = tipAmount
135 tip.tipSourceAddresses = []
136 tip.txid = tx.txid
137 sources.forEach(function (source) {
138 if (tipDestinationAddresses.indexOf(source) === -1) {
139 tip.tipSourceAddresses.push(source)
140 }
141 })
142 if (tip.tipDestinationAddresses.length === 0 && typeof (value) !== 'undefined') {
143 tip.tipDestinationAddresses = [sources]
144 tip.tipAmount = value
145 }
146 if (tip.openpublishSha1 && tip.tipDestinationAddresses && tip.tipAmount) {
147 tips.push(tip)
148 }
149 })
150 callback(false, tips)
151}
152
153var opentip = {
154 create: create,
155 scan: scan,
156 scanSingle: scanSingle
157}
158
159module.exports = opentip