@smartledger/bsv 9.0.0 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/README.md +152 -1041
  3. package/STABILITY.md +134 -0
  4. package/bsv-gdaf.min.js +53 -48
  5. package/bsv-ltp.min.js +23 -18
  6. package/bsv-smartcontract.min.js +18 -18
  7. package/bsv.bundle.js +53 -48
  8. package/bsv.min.js +53 -48
  9. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  10. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  11. package/docs/getting-started/INSTALLATION.md +23 -23
  12. package/docs/getting-started/QUICK_START.md +7 -7
  13. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  14. package/docs/proposals/10.0.0-package-split.md +131 -0
  15. package/index.js +5 -0
  16. package/lib/block/merkleblock.js +53 -9
  17. package/lib/hdprivatekey.js +15 -0
  18. package/lib/script/interpreter.js +109 -1
  19. package/lib/smart_contract/builder.js +14 -0
  20. package/lib/util/deprecate.js +159 -0
  21. package/package.json +19 -82
  22. package/version.js +1 -1
  23. package/.mocharc.json +0 -5
  24. package/test/address.js +0 -629
  25. package/test/block/block.js +0 -239
  26. package/test/block/blockheader.js +0 -270
  27. package/test/block/merkleblock.js +0 -207
  28. package/test/build/bundle_crypto_shim.js +0 -104
  29. package/test/build/bundle_externals.js +0 -125
  30. package/test/build/bundle_smoke.js +0 -55
  31. package/test/build/esbuild_main.js +0 -65
  32. package/test/build/esm_wrapper.js +0 -97
  33. package/test/build/exports_resolution.js +0 -84
  34. package/test/build/version_sync.js +0 -14
  35. package/test/cli/smoke.js +0 -261
  36. package/test/consensus/base58-vectors.js +0 -120
  37. package/test/consensus/sv-script-vectors.js +0 -81
  38. package/test/consensus/sv-sighash-vectors.js +0 -51
  39. package/test/consensus/sv-tx-vectors.js +0 -48
  40. package/test/credentials-test.js +0 -332
  41. package/test/crypto/backend_selection.js +0 -126
  42. package/test/crypto/bn.js +0 -168
  43. package/test/crypto/ecdsa.js +0 -426
  44. package/test/crypto/elliptic-fixed.js +0 -61
  45. package/test/crypto/hash.browser.js +0 -121
  46. package/test/crypto/hash.js +0 -122
  47. package/test/crypto/point.js +0 -193
  48. package/test/crypto/random.js +0 -105
  49. package/test/crypto/security.js +0 -176
  50. package/test/crypto/shamir.js +0 -177
  51. package/test/crypto/shamir_rngcap.js +0 -29
  52. package/test/crypto/signature.js +0 -399
  53. package/test/data/bip69.json +0 -215
  54. package/test/data/bitcoin-sv/README.md +0 -170
  55. package/test/data/bitcoin-sv/base58_encode_decode.json +0 -14
  56. package/test/data/bitcoin-sv/base58_keys_invalid.json +0 -152
  57. package/test/data/bitcoin-sv/base58_keys_valid.json +0 -452
  58. package/test/data/bitcoin-sv/script_tests.json +0 -2591
  59. package/test/data/bitcoin-sv/sighash.json +0 -1003
  60. package/test/data/bitcoin-sv/tx_invalid.json +0 -285
  61. package/test/data/bitcoin-sv/tx_valid.json +0 -367
  62. package/test/data/bitcoind/base58_keys_invalid.json +0 -152
  63. package/test/data/bitcoind/base58_keys_valid.json +0 -452
  64. package/test/data/bitcoind/blocks.json +0 -27
  65. package/test/data/bitcoind/script_tests.json +0 -2244
  66. package/test/data/bitcoind/sig_canonical.json +0 -7
  67. package/test/data/bitcoind/sig_noncanonical.json +0 -22
  68. package/test/data/bitcoind/tx_invalid.json +0 -177
  69. package/test/data/bitcoind/tx_valid.json +0 -224
  70. package/test/data/blk86756-testnet.dat +0 -0
  71. package/test/data/blk86756-testnet.js +0 -12
  72. package/test/data/blk86756-testnet.json +0 -684
  73. package/test/data/brc220-batch-vector.json +0 -129
  74. package/test/data/ecdsa.json +0 -230
  75. package/test/data/merkleblocks.js +0 -486
  76. package/test/data/messages.json +0 -22
  77. package/test/data/sighash.json +0 -1004
  78. package/test/data/tx_creation.json +0 -85
  79. package/test/didweb/relationships.js +0 -144
  80. package/test/ecies/bitcore-ecies.js +0 -178
  81. package/test/ecies/electrum-ecies.js +0 -206
  82. package/test/encoding/base58.js +0 -131
  83. package/test/encoding/base58check.js +0 -145
  84. package/test/encoding/bufferreader.js +0 -328
  85. package/test/encoding/bufferwriter.js +0 -160
  86. package/test/encoding/varint.js +0 -104
  87. package/test/gdaf/anchor_no_key_leak.js +0 -146
  88. package/test/gdaf/anchor_spv.js +0 -163
  89. package/test/gdaf/canonicalization.js +0 -106
  90. package/test/gdaf/canonicalize.js +0 -140
  91. package/test/gdaf/zk_prover.js +0 -204
  92. package/test/hdkeys.js +0 -365
  93. package/test/hdprivatekey.js +0 -339
  94. package/test/hdpublickey.js +0 -293
  95. package/test/index.js +0 -16
  96. package/test/ltp/ids.js +0 -74
  97. package/test/ltp/right.js +0 -198
  98. package/test/ltp/verify_failclosed.js +0 -134
  99. package/test/message/message.js +0 -190
  100. package/test/mnemonic/data/fixtures.json +0 -300
  101. package/test/mnemonic/mnemonic.js +0 -277
  102. package/test/mnemonic/mocha.opts +0 -1
  103. package/test/mnemonic/pbkdf2.test.js +0 -43
  104. package/test/networks.js +0 -207
  105. package/test/notaryhash/batch_leaf.js +0 -140
  106. package/test/notaryhash/batch_vector.js +0 -282
  107. package/test/notaryhash/certificate.js +0 -249
  108. package/test/notaryhash/encoding.js +0 -186
  109. package/test/notaryhash/interop.js +0 -112
  110. package/test/notaryhash/merkle.js +0 -181
  111. package/test/notaryhash/script.js +0 -270
  112. package/test/notaryhash/verify.js +0 -342
  113. package/test/opcode.js +0 -186
  114. package/test/ordinals/bsv20.js +0 -337
  115. package/test/ordinals/inscription.js +0 -329
  116. package/test/ordinals/ordlock.js +0 -567
  117. package/test/privatekey.js +0 -540
  118. package/test/publickey.js +0 -411
  119. package/test/regressions.js +0 -215
  120. package/test/script/chronicle.js +0 -543
  121. package/test/script/defaults.js +0 -160
  122. package/test/script/genesis_limits.js +0 -203
  123. package/test/script/interpreter.js +0 -776
  124. package/test/script/script.js +0 -1259
  125. package/test/script/string_ops.js +0 -88
  126. package/test/security/fail_closed_contracts.js +0 -104
  127. package/test/security/threat_model_coverage.js +0 -31
  128. package/test/smart_contract/covenants.js +0 -207
  129. package/test/smart_contract/dsl_debugger.js +0 -92
  130. package/test/smart_contract/extract_field.js +0 -61
  131. package/test/smart_contract/nonenforcing_guard.js +0 -44
  132. package/test/smart_contract/ordinal_transfer.js +0 -71
  133. package/test/smart_contract/preimage.js +0 -98
  134. package/test/smart_contract/sighash_marketplace.js +0 -98
  135. package/test/smart_contract/token_generalized.js +0 -175
  136. package/test/spv/headerchain.js +0 -86
  137. package/test/spv/merkleproof.js +0 -133
  138. package/test/statuslist/failclosed.js +0 -78
  139. package/test/transaction/deserialize.js +0 -33
  140. package/test/transaction/input/input.js +0 -92
  141. package/test/transaction/input/multisig.js +0 -174
  142. package/test/transaction/input/multisigscripthash.js +0 -111
  143. package/test/transaction/input/publickey.js +0 -68
  144. package/test/transaction/input/publickeyhash.js +0 -59
  145. package/test/transaction/output.js +0 -185
  146. package/test/transaction/sighash.js +0 -91
  147. package/test/transaction/signature.js +0 -127
  148. package/test/transaction/transaction.js +0 -1299
  149. package/test/transaction/unspentoutput.js +0 -97
  150. package/test/types/dts_drift.js +0 -124
  151. package/test/types/surface_honesty.js +0 -102
  152. package/test/util/id.js +0 -72
  153. package/test/util/js.js +0 -76
  154. package/test/util/preconditions.js +0 -79
  155. package/test/vcjwt/interop.js +0 -126
@@ -1,1299 +0,0 @@
1
- 'use strict'
2
-
3
- var should = require('chai').should()
4
- var expect = require('chai').expect
5
- var sinon = require('sinon')
6
-
7
- var bsv = require('../..')
8
- var _ = bsv.deps._
9
- var BN = bsv.crypto.BN
10
- var Transaction = bsv.Transaction
11
- var Input = bsv.Transaction.Input
12
- var Output = bsv.Transaction.Output
13
- var PrivateKey = bsv.PrivateKey
14
- var Script = bsv.Script
15
- var Address = bsv.Address
16
- var Opcode = bsv.Opcode
17
- var errors = bsv.errors
18
-
19
- var transactionVector = require('../data/tx_creation')
20
-
21
- describe('Transaction', function () {
22
- it('should be able to add two outputs with short addresses', function () {
23
- var errors = 0
24
- try {
25
- var tx = new Transaction()
26
- tx.to('1DpLHif3FBFnckw7Fj653VCr5wYQa3Fiow', 10000)
27
- tx.to('1ArnPQhtRU3voDbLcTRRzBuJtiCPHnKuN', 123445)
28
- tx.to('1111111111111111111114oLvT2', 123445)
29
- } catch (err) {
30
- errors++
31
- }
32
- errors.should.equal(0)
33
- })
34
-
35
- it('should serialize and deserialize correctly a given transaction', function () {
36
- var transaction = new Transaction(tx1hex)
37
- transaction.uncheckedSerialize().should.equal(tx1hex)
38
- })
39
-
40
- it('should parse the version as a signed integer', function () {
41
- var transaction = Transaction('ffffffff0000ffffffff')
42
- transaction.version.should.equal(-1)
43
- transaction.nLockTime.should.equal(0xffffffff)
44
- })
45
-
46
- it('fails if an invalid parameter is passed to constructor', function () {
47
- expect(function () {
48
- return new Transaction(1)
49
- }).to.throw(errors.InvalidArgument)
50
- })
51
-
52
- var testScript = 'OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG'
53
- var testScriptHex = '76a91488d9931ea73d60eaf7e5671efc0552b912911f2a88ac'
54
- var testPrevTx = 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458'
55
- var testAmount = 1020000
56
- var testTransaction = new Transaction()
57
- .from({
58
- 'txId': testPrevTx,
59
- 'outputIndex': 0,
60
- 'script': testScript,
61
- 'satoshis': testAmount
62
- })
63
- .to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', testAmount - 10000)
64
-
65
- it('can serialize to a plain javascript object', function () {
66
- var object = testTransaction.toObject()
67
- object.inputs[0].output.satoshis.should.equal(testAmount)
68
- object.inputs[0].output.script.should.equal(testScriptHex)
69
- object.inputs[0].prevTxId.should.equal(testPrevTx)
70
- object.inputs[0].outputIndex.should.equal(0)
71
- object.outputs[0].satoshis.should.equal(testAmount - 10000)
72
- })
73
-
74
- it('will not accept NaN as an amount', function () {
75
- (function () {
76
- new Transaction().to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', NaN) //eslint-disable-line
77
- }).should.throw('Amount is expected to be a positive integer')
78
- })
79
-
80
- it('returns the fee correctly', function () {
81
- testTransaction.getFee().should.equal(10000)
82
- })
83
-
84
- it('will return zero as the fee for a coinbase', function () {
85
- // block #2: 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098
86
- var coinbaseTransaction = new Transaction('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000')
87
- coinbaseTransaction.getFee().should.equal(0)
88
- })
89
-
90
- it('serialize to Object roundtrip', function () {
91
- var a = testTransaction.toObject()
92
- var newTransaction = new Transaction(a)
93
- var b = newTransaction.toObject()
94
- a.should.deep.equal(b)
95
- })
96
-
97
- it('toObject/fromObject with signatures and custom fee', function () {
98
- var tx = new Transaction()
99
- .from(simpleUtxoWith100000Satoshis)
100
- .to([{
101
- address: toAddress,
102
- satoshis: 50000
103
- }])
104
- .fee(15000)
105
- .change(changeAddress)
106
- .sign(privateKey)
107
-
108
- var txData = JSON.stringify(tx)
109
- var tx2 = new Transaction(JSON.parse(txData))
110
- var txData2 = JSON.stringify(tx2)
111
- txData.should.equal(txData2)
112
- })
113
-
114
- it('toObject/fromObject with p2sh signatures and custom fee', function () {
115
- var tx = new Transaction()
116
- .from(p2shUtxoWith1BSV, [p2shPublicKey1, p2shPublicKey2, p2shPublicKey3], 2)
117
- .to([{
118
- address: toAddress,
119
- satoshis: 50000
120
- }])
121
- .fee(15000)
122
- .change(changeAddress)
123
- .sign(p2shPrivateKey1)
124
- .sign(p2shPrivateKey2)
125
-
126
- var txData = JSON.stringify(tx)
127
- var tx2 = new Transaction(JSON.parse(txData))
128
- var tx2Data = JSON.stringify(tx2)
129
- txData.should.equal(tx2Data)
130
- })
131
-
132
- it('fromObject with pay-to-public-key previous outputs', function () {
133
- var tx = bsv.Transaction({
134
- hash: '132856bf03d6415562a556437d22ac63c37a4595fd986c796eb8e02dc031aa25',
135
- version: 1,
136
- inputs: [{
137
- prevTxId: 'e30ac3db24ef28500f023775d8eb06ad8a26241690080260308208a4020012a4',
138
- outputIndex: 0,
139
- sequenceNumber: 4294967294,
140
- script: '473044022024dbcf41ccd4f3fe325bebb7a87d0bf359eefa03826482008e0fe7795586ad440220676f5f211ebbc311cfa631f14a8223a343cbadc6fa97d6d17f8d2531308b533201',
141
- scriptString: '71 0x3044022024dbcf41ccd4f3fe325bebb7a87d0bf359eefa03826482008e0fe7795586ad440220676f5f211ebbc311cfa631f14a8223a343cbadc6fa97d6d17f8d2531308b533201',
142
- output: {
143
- satoshis: 5000000000,
144
- script: '2103b1c65d65f1ff3fe145a4ede692460ae0606671d04e8449e99dd11c66ab55a7feac'
145
- }
146
- }],
147
- outputs: [{
148
- satoshis: 3999999040,
149
- script: '76a914fa1e0abfb8d26e494375f47e04b4883c44dd44d988ac'
150
- }, {
151
- satoshis: 1000000000,
152
- script: '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
153
- }],
154
- nLockTime: 139
155
- })
156
- tx.inputs[0].should.be.instanceof(bsv.Transaction.Input.PublicKey)
157
- tx.inputs[0].output.satoshis.should.equal(5000000000)
158
- tx.inputs[0].output.script.toHex().should.equal('2103b1c65d65f1ff3fe145a4ede692460ae0606671d04e8449e99dd11c66ab55a7feac')
159
- })
160
-
161
- it('constructor returns a shallow copy of another transaction', function () {
162
- var transaction = new Transaction(tx1hex)
163
- var copy = new Transaction(transaction)
164
- copy.uncheckedSerialize().should.equal(transaction.uncheckedSerialize())
165
- })
166
-
167
- it('should display correctly in console', function () {
168
- var transaction = new Transaction(tx1hex)
169
- transaction.inspect().should.equal('<Transaction: ' + tx1hex + '>')
170
- })
171
-
172
- it('standard hash of transaction should be decoded correctly', function () {
173
- var transaction = new Transaction(tx1hex)
174
- transaction.id.should.equal(tx1id)
175
- })
176
-
177
- it('serializes an empty transaction', function () {
178
- var transaction = new Transaction()
179
- transaction.uncheckedSerialize().should.equal(txEmptyHex)
180
- })
181
-
182
- it('serializes and deserializes correctly', function () {
183
- var transaction = new Transaction(tx1hex)
184
- transaction.uncheckedSerialize().should.equal(tx1hex)
185
- })
186
-
187
- describe('transaction creation test vector', function () {
188
- this.timeout(5000)
189
- var index = 0
190
- transactionVector.forEach(function (vector) {
191
- index++
192
- it('case ' + index, function () {
193
- var i = 0
194
- var transaction = new Transaction()
195
- transaction.feePerKb(100000)
196
- while (i < vector.length) {
197
- var command = vector[i]
198
- var args = vector[i + 1]
199
- if (command === 'serialize') {
200
- transaction.serialize().should.equal(args)
201
- } else {
202
- transaction[command].apply(transaction, args)
203
- }
204
- i += 2
205
- }
206
- })
207
- })
208
- })
209
-
210
- // TODO: Migrate this into a test for inputs
211
-
212
- var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1'
213
- var simpleUtxoWith100000Satoshis = {
214
- address: fromAddress,
215
- txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
216
- outputIndex: 0,
217
- script: Script.buildPublicKeyHashOut(fromAddress).toString(),
218
- satoshis: 100000
219
- }
220
-
221
- var simpleUtxoWith1000000Satoshis = {
222
- address: fromAddress,
223
- txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
224
- outputIndex: 0,
225
- script: Script.buildPublicKeyHashOut(fromAddress).toString(),
226
- satoshis: 1000000
227
- }
228
- var anyoneCanSpendUTXO = JSON.parse(JSON.stringify(simpleUtxoWith100000Satoshis))
229
- anyoneCanSpendUTXO.script = new Script().add('OP_TRUE')
230
- var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc'
231
- var changeAddress = 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up'
232
- var changeAddressP2SH = '2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf'
233
- var privateKey = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY'
234
- var private1 = '6ce7e97e317d2af16c33db0b9270ec047a91bff3eff8558afb5014afb2bb5976'
235
- var private2 = 'c9b26b0f771a0d2dad88a44de90f05f416b3b385ff1d989343005546a0032890'
236
- var public1 = new PrivateKey(private1).publicKey
237
- var public2 = new PrivateKey(private2).publicKey
238
-
239
- var simpleUtxoWith1BSV = {
240
- address: fromAddress,
241
- txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
242
- outputIndex: 1,
243
- script: Script.buildPublicKeyHashOut(fromAddress).toString(),
244
- satoshis: 1e8
245
- }
246
-
247
- var tenth = 1e7
248
- var fourth = 25e6
249
- var half = 5e7
250
-
251
- var p2shPrivateKey1 = PrivateKey.fromWIF('cNuW8LX2oeQXfKKCGxajGvqwhCgBtacwTQqiCGHzzKfmpHGY4TE9')
252
- var p2shPublicKey1 = p2shPrivateKey1.toPublicKey()
253
- var p2shPrivateKey2 = PrivateKey.fromWIF('cTtLHt4mv6zuJytSnM7Vd6NLxyNauYLMxD818sBC8PJ1UPiVTRSs')
254
- var p2shPublicKey2 = p2shPrivateKey2.toPublicKey()
255
- var p2shPrivateKey3 = PrivateKey.fromWIF('cQFMZ5gP9CJtUZPc9X3yFae89qaiQLspnftyxxLGvVNvM6tS6mYY')
256
- var p2shPublicKey3 = p2shPrivateKey3.toPublicKey()
257
-
258
- var p2shAddress = Address.createMultisig([
259
- p2shPublicKey1,
260
- p2shPublicKey2,
261
- p2shPublicKey3
262
- ], 2, 'testnet')
263
- var p2shUtxoWith1BSV = {
264
- address: p2shAddress.toString(),
265
- txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
266
- outputIndex: 0,
267
- script: Script(p2shAddress).toString(),
268
- satoshis: 1e8
269
- }
270
-
271
- describe('adding inputs', function () {
272
- it('adds just once one utxo', function () {
273
- var tx = new Transaction()
274
- tx.from(simpleUtxoWith1BSV)
275
- tx.from(simpleUtxoWith1BSV)
276
- tx.inputs.length.should.equal(1)
277
- })
278
-
279
- it('rejects unsupported script type when given multisig pubkeys', function () {
280
- var tx = new Transaction()
281
- expect(function () {
282
- tx.from(simpleUtxoWith1BSV, [p2shPublicKey1, p2shPublicKey2, p2shPublicKey3], 2)
283
- }).to.throw(errors.Transaction.Input.UnsupportedScript)
284
- })
285
-
286
- it('adds OP_FALSE in front of OP_RETURN', function () {
287
- var transaction = new Transaction()
288
- .from(simpleUtxoWith100000Satoshis)
289
- .addSafeData('genesis is coming')
290
- .change(changeAddress)
291
- .sign(privateKey)
292
-
293
- transaction.serialize().should.equal('01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006b4830450221009342991af752bf19493c3fad4fc7cf42a536b665d2c72ccd5ffccd5074cff8ae022012494eba7f401e91fe365403f65afd4226acc53dd46f9680244562433b6ea4a941210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff02000000000000000014006a1167656e6573697320697320636f6d696e6731860100000000001976a914073b7eae2823efa349e3b9155b8a735526463a0f88ac00000000')
294
- })
295
-
296
- describe('isFullySigned', function () {
297
- it('works for normal p2pkh', function () {
298
- var transaction = new Transaction()
299
- .from(simpleUtxoWith100000Satoshis)
300
- .to([{
301
- address: toAddress,
302
- satoshis: 50000
303
- }])
304
- .change(changeAddress)
305
- .sign(privateKey)
306
- transaction.isFullySigned().should.equal(true)
307
- })
308
- it('fails when Inputs are not subclassed and isFullySigned is called', function () {
309
- var tx = new Transaction(tx1hex)
310
- expect(function () {
311
- return tx.isFullySigned()
312
- }).to.throw(errors.Transaction.UnableToVerifySignature)
313
- })
314
- it('fails when Inputs are not subclassed and verifySignature is called', function () {
315
- var tx = new Transaction(tx1hex)
316
- expect(function () {
317
- return tx.isValidSignature({
318
- inputIndex: 0
319
- })
320
- }).to.throw(errors.Transaction.UnableToVerifySignature)
321
- })
322
- it('passes result of input.isValidSignature', function () {
323
- var tx = new Transaction(tx1hex)
324
- tx.from(simpleUtxoWith1BSV)
325
- tx.inputs[0].isValidSignature = sinon.stub().returns(true)
326
- var sig = {
327
- inputIndex: 0
328
- }
329
- tx.isValidSignature(sig).should.equal(true)
330
- })
331
- })
332
-
333
- describe('_clearSignatures with custom-script inputs', function () {
334
- it('does not throw AbstractMethodInvoked for inputs using the base Input class', function () {
335
- var tx = new Transaction(tx1hex)
336
- expect(function () {
337
- tx._clearSignatures()
338
- }).to.not.throw()
339
- })
340
- it('still invokes clearSignatures on typed subclass inputs', function () {
341
- var tx = new Transaction()
342
- .from(simpleUtxoWith100000Satoshis)
343
- .to([{ address: toAddress, satoshis: 50000 }])
344
- .change(changeAddress)
345
- .sign(privateKey)
346
- var clearSpy = sinon.spy(tx.inputs[0], 'clearSignatures')
347
- tx._clearSignatures()
348
- clearSpy.called.should.equal(true)
349
- })
350
- })
351
-
352
- describe('P2PKH-prefixed outputs (1Sat Ordinals, MAP+BAP, etc.)', function () {
353
- // Build a real-shape 1Sat ordinal locking script: P2PKH followed by
354
- // an OP_FALSE OP_IF "ord" envelope. The script is NOT canonical
355
- // P2PKH (length > 5 chunks) but the spendable portion is identical;
356
- // Transaction.from() must dispatch it to PublicKeyHashInput so the
357
- // high-level sign() path works.
358
- function buildOrdinalScript (addressStr) {
359
- var Address = bsv.Address
360
- var Opcode = bsv.Opcode
361
- return bsv.Script.buildPublicKeyHashOut(Address.fromString(addressStr))
362
- .add(Opcode.OP_FALSE)
363
- .add(Opcode.OP_IF)
364
- .add(Buffer.from('ord'))
365
- .add(Opcode.OP_1)
366
- .add(Buffer.from('image/svg+xml'))
367
- .add(Opcode.OP_0)
368
- .add(Buffer.alloc(642, 0x20))
369
- .add(Opcode.OP_ENDIF)
370
- }
371
-
372
- it('Script.isPublicKeyHashOutPrefix matches canonical P2PKH', function () {
373
- var canonical = bsv.Script.buildPublicKeyHashOut(bsv.Address.fromString(toAddress))
374
- canonical.isPublicKeyHashOutPrefix().should.equal(true)
375
- canonical.isPublicKeyHashOut().should.equal(true)
376
- })
377
-
378
- it('Script.isPublicKeyHashOutPrefix matches P2PKH + trailing data', function () {
379
- var ord = buildOrdinalScript(toAddress)
380
- ord.isPublicKeyHashOutPrefix().should.equal(true)
381
- // strict check still rejects (length > 5)
382
- ord.isPublicKeyHashOut().should.equal(false)
383
- })
384
-
385
- it('Script.isPublicKeyHashOutPrefix rejects non-P2PKH-prefixed scripts', function () {
386
- bsv.Script.empty().isPublicKeyHashOutPrefix().should.equal(false)
387
- bsv.Script.buildDataOut('hello').isPublicKeyHashOutPrefix().should.equal(false)
388
- })
389
-
390
- it('Transaction.from dispatches a 1Sat ordinal output to PublicKeyHashInput', function () {
391
- var addr = new bsv.PrivateKey(privateKey).toAddress().toString()
392
- var ordUtxo = {
393
- txid: 'a'.repeat(64),
394
- outputIndex: 0,
395
- satoshis: 100000,
396
- script: buildOrdinalScript(addr).toHex()
397
- }
398
- var tx = new Transaction().from(ordUtxo)
399
- tx.inputs[0].constructor.name.should.equal('PublicKeyHashInput')
400
- })
401
-
402
- it('full from/to/change/sign roundtrip on an ordinal-shaped UTXO', function () {
403
- var ordPriv = bsv.PrivateKey.fromRandom('livenet')
404
- var ordAddr = ordPriv.toAddress().toString()
405
- var ordUtxo = {
406
- txid: 'b'.repeat(64),
407
- outputIndex: 0,
408
- satoshis: 100000,
409
- script: buildOrdinalScript(ordAddr).toHex()
410
- }
411
-
412
- var tx = new Transaction()
413
- .from(ordUtxo)
414
- .to(toAddress, 50000)
415
- .change(changeAddress)
416
- .feePerKb(500)
417
- .sign(ordPriv)
418
-
419
- tx.inputs[0].isFullySigned().should.equal(true)
420
- tx.inputs[0].script.toBuffer().length.should.be.greaterThan(0)
421
- })
422
-
423
- it('sighash is computed against the FULL locking script (envelope included)', function () {
424
- // Regression guard: if the signer ever truncated the script to the
425
- // canonical P2PKH prefix, the signature would still pass isFullySigned
426
- // but would fail mainnet validation. We assert sighash equality
427
- // against the full script bytes — verified end-to-end via
428
- // isValidSignature, which delegates to Sighash.verify.
429
- var ordPriv = bsv.PrivateKey.fromRandom('livenet')
430
- var ordAddr = ordPriv.toAddress().toString()
431
- var ordUtxo = {
432
- txid: 'c'.repeat(64),
433
- outputIndex: 0,
434
- satoshis: 100000,
435
- script: buildOrdinalScript(ordAddr).toHex()
436
- }
437
-
438
- var tx = new Transaction()
439
- .from(ordUtxo)
440
- .to(toAddress, 50000)
441
- .change(changeAddress)
442
- .feePerKb(500)
443
- .sign(ordPriv)
444
-
445
- var Signature = bsv.crypto.Signature
446
- var verified = tx.inputs[0].isValidSignature(tx, {
447
- signature: Signature.fromTxFormat(tx.inputs[0].script.chunks[0].buf),
448
- publicKey: bsv.PublicKey.fromBuffer(tx.inputs[0].script.chunks[1].buf),
449
- sigtype: Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID,
450
- inputIndex: 0
451
- })
452
- verified.should.equal(true)
453
- })
454
-
455
- it('canonical P2PKH spends still work (no regression)', function () {
456
- var tx = new Transaction()
457
- .from(simpleUtxoWith100000Satoshis)
458
- .to(toAddress, 50000)
459
- .change(changeAddress)
460
- .sign(privateKey)
461
- tx.inputs[0].constructor.name.should.equal('PublicKeyHashInput')
462
- tx.inputs[0].isFullySigned().should.equal(true)
463
- })
464
- })
465
- })
466
-
467
- describe('change address', function () {
468
- it('can calculate simply the output amount', function () {
469
- var transaction = new Transaction()
470
- .from(simpleUtxoWith1000000Satoshis)
471
- .to(toAddress, 500000)
472
- .change(changeAddress)
473
- .sign(privateKey)
474
- .feePerKb(100000)
475
-
476
- transaction.outputs.length.should.equal(2)
477
- transaction.outputs[1].satoshis.should.equal(477400)
478
- transaction.outputs[1].script.toString()
479
- .should.equal(Script.fromAddress(changeAddress).toString())
480
- var actual = transaction.getChangeOutput().script.toString()
481
- var expected = Script.fromAddress(changeAddress).toString()
482
- actual.should.equal(expected)
483
- })
484
- it('accepts a P2SH address for change', function () {
485
- var transaction = new Transaction()
486
- .from(simpleUtxoWith1000000Satoshis)
487
- .to(toAddress, 500000)
488
- .change(changeAddressP2SH)
489
- .sign(privateKey)
490
- transaction.outputs.length.should.equal(2)
491
- transaction.outputs[1].script.isScriptHashOut().should.equal(true)
492
- })
493
- it('can recalculate the change amount', function () {
494
- var transaction = new Transaction()
495
- .from(simpleUtxoWith100000Satoshis)
496
- .to(toAddress, 50000)
497
- .change(changeAddress)
498
- .fee(0)
499
- .sign(privateKey)
500
-
501
- transaction.getChangeOutput().satoshis.should.equal(50000)
502
-
503
- transaction = transaction
504
- .to(toAddress, 20000)
505
- .sign(privateKey)
506
-
507
- transaction.outputs.length.should.equal(3)
508
- transaction.outputs[2].satoshis.should.equal(30000)
509
- transaction.outputs[2].script.toString()
510
- .should.equal(Script.fromAddress(changeAddress).toString())
511
- })
512
- it('adds no fee if no change is available', function () {
513
- var transaction = new Transaction()
514
- .from(simpleUtxoWith100000Satoshis)
515
- .to(toAddress, 99000)
516
- .sign(privateKey)
517
- transaction.outputs.length.should.equal(1)
518
- })
519
- it('adds no fee if no money is available', function () {
520
- var transaction = new Transaction()
521
- .from(simpleUtxoWith100000Satoshis)
522
- .to(toAddress, 100000)
523
- .change(changeAddress)
524
- .sign(privateKey)
525
- transaction.outputs.length.should.equal(1)
526
- })
527
- it('fee can be set up manually', function () {
528
- var transaction = new Transaction()
529
- .from(simpleUtxoWith100000Satoshis)
530
- .to(toAddress, 80000)
531
- .fee(10000)
532
- .change(changeAddress)
533
- .sign(privateKey)
534
- transaction.outputs.length.should.equal(2)
535
- transaction.outputs[1].satoshis.should.equal(10000)
536
- })
537
- it('fee per kb can be set up manually', function () {
538
- var inputs = _.map(_.range(10), function (i) {
539
- var utxo = _.clone(simpleUtxoWith100000Satoshis)
540
- utxo.outputIndex = i
541
- return utxo
542
- })
543
- var transaction = new Transaction()
544
- .from(inputs)
545
- .to(toAddress, 950000)
546
- .feePerKb(8000)
547
- .change(changeAddress)
548
- .sign(privateKey)
549
- transaction._estimateSize().should.be.within(1000, 1999)
550
- transaction.outputs.length.should.equal(2)
551
- transaction.outputs[1].satoshis.should.equal(37536)
552
- })
553
- it('if satoshis are invalid', function () {
554
- var transaction = new Transaction()
555
- .from(simpleUtxoWith100000Satoshis)
556
- .to(toAddress, 99999)
557
- .change(changeAddress)
558
- .sign(privateKey)
559
- transaction.outputs[0]._satoshis = 100
560
- transaction.outputs[0]._satoshisBN = new BN(101, 10)
561
- expect(function () {
562
- return transaction.serialize()
563
- }).to.throw(errors.Transaction.InvalidSatoshis)
564
- })
565
- it('on second call to sign, change is not recalculated', function () {
566
- var transaction = new Transaction()
567
- .from(simpleUtxoWith100000Satoshis)
568
- .to(toAddress, 100000)
569
- .change(changeAddress)
570
- .sign(privateKey)
571
- .sign(privateKey)
572
- transaction.outputs.length.should.equal(1)
573
- })
574
- it('getFee() returns the difference between inputs and outputs if no change address set', function () {
575
- var transaction = new Transaction()
576
- .from(simpleUtxoWith100000Satoshis)
577
- .to(toAddress, 1000)
578
- transaction.getFee().should.equal(99000)
579
- })
580
- })
581
-
582
- describe('serialization', function () {
583
- it('stores the change address correctly', function () {
584
- var serialized = new Transaction()
585
- .change(changeAddress)
586
- .toObject()
587
- var deserialized = new Transaction(serialized)
588
- expect(deserialized._changeScript.toString()).to.equal(Script.fromAddress(changeAddress).toString())
589
- expect(deserialized.getChangeOutput()).to.equal(null)
590
- })
591
- it('can avoid checked serialize', function () {
592
- var transaction = new Transaction()
593
- .from(simpleUtxoWith1BSV)
594
- .to(fromAddress, 1)
595
- expect(function () {
596
- return transaction.serialize()
597
- }).to.throw()
598
- expect(function () {
599
- return transaction.serialize(true)
600
- }).to.not.throw()
601
- })
602
- it('stores the fee set by the user', function () {
603
- var fee = 1000000
604
- var serialized = new Transaction()
605
- .fee(fee)
606
- .toObject()
607
- var deserialized = new Transaction(serialized)
608
- expect(deserialized._fee).to.equal(fee)
609
- })
610
- })
611
-
612
- describe('checked serialize', function () {
613
- it('fails if no change address was set', function () {
614
- var transaction = new Transaction()
615
- .from(simpleUtxoWith1BSV)
616
- .to(toAddress, 1)
617
- expect(function () {
618
- return transaction.serialize()
619
- }).to.throw(errors.Transaction.ChangeAddressMissing)
620
- })
621
- it('fails if a high fee was set', function () {
622
- var transaction = new Transaction()
623
- .from(simpleUtxoWith1BSV)
624
- .change(changeAddress)
625
- .fee(50000000)
626
- .to(toAddress, 40000000)
627
- expect(function () {
628
- return transaction.serialize()
629
- }).to.throw(errors.Transaction.FeeError.TooLarge)
630
- })
631
- it('fails if a dust output is created', function () {
632
- var transaction = new Transaction()
633
- .from(simpleUtxoWith1BSV)
634
- .to(toAddress, 545)
635
- .change(changeAddress)
636
- .sign(privateKey)
637
- expect(function () {
638
- return transaction.serialize()
639
- }).to.throw(errors.Transaction.DustOutputs)
640
- })
641
- it('doesn\'t fail if a dust output is not dust', function () {
642
- var transaction = new Transaction()
643
- .from(simpleUtxoWith1BSV)
644
- .to(toAddress, 546)
645
- .change(changeAddress)
646
- .sign(privateKey)
647
- expect(function () {
648
- return transaction.serialize()
649
- }).to.not.throw(errors.Transaction.DustOutputs)
650
- })
651
- it('doesn\'t fail if a dust output is an op_return', function () {
652
- var transaction = new Transaction()
653
- .from(simpleUtxoWith1BSV)
654
- .addData('not dust!')
655
- .change(changeAddress)
656
- .sign(privateKey)
657
- expect(function () {
658
- return transaction.serialize()
659
- }).to.not.throw(errors.Transaction.DustOutputs)
660
- })
661
- it('fails when outputs and fee don\'t add to total input', function () {
662
- var transaction = new Transaction()
663
- .from(simpleUtxoWith1BSV)
664
- .to(toAddress, 99900000)
665
- .fee(99999)
666
- .sign(privateKey)
667
- expect(function () {
668
- return transaction.serialize()
669
- }).to.throw(errors.Transaction.FeeError.Different)
670
- })
671
- it('checks output amount before fee errors', function () {
672
- var transaction = new Transaction()
673
- transaction.from(simpleUtxoWith1BSV)
674
- transaction
675
- .to(toAddress, 10000000000000)
676
- .change(changeAddress)
677
- .fee(5)
678
-
679
- expect(function () {
680
- return transaction.serialize()
681
- }).to.throw(errors.Transaction.InvalidOutputAmountSum)
682
- })
683
- it('will throw fee error with disableMoreOutputThanInput enabled (but not triggered)', function () {
684
- var transaction = new Transaction()
685
- transaction.from(simpleUtxoWith1BSV)
686
- transaction
687
- .to(toAddress, 84000000)
688
- .change(changeAddress)
689
- .fee(16000000)
690
-
691
- expect(function () {
692
- return transaction.serialize({
693
- disableMoreOutputThanInput: true
694
- })
695
- }).to.throw(errors.Transaction.FeeError.TooLarge)
696
- })
697
- describe('skipping checks', function () {
698
- var buildSkipTest = function (builder, check, expectedError) {
699
- return function () {
700
- var transaction = new Transaction()
701
- transaction.from(simpleUtxoWith1BSV)
702
- builder(transaction)
703
-
704
- var options = {}
705
- options[check] = true
706
-
707
- expect(function () {
708
- return transaction.serialize(options)
709
- }).not.to.throw()
710
- expect(function () {
711
- return transaction.serialize()
712
- }).to.throw(expectedError)
713
- }
714
- }
715
- it('can skip the check for too much fee', buildSkipTest(
716
- function (transaction) {
717
- return transaction
718
- .fee(50000000)
719
- .change(changeAddress)
720
- .sign(privateKey)
721
- }, 'disableLargeFees', errors.Transaction.FeeError.TooLarge
722
- ))
723
- it('can skip the check that prevents dust outputs', buildSkipTest(
724
- function (transaction) {
725
- return transaction
726
- .to(toAddress, 100)
727
- .change(changeAddress)
728
- .sign(privateKey)
729
- }, 'disableDustOutputs', errors.Transaction.DustOutputs
730
- ))
731
- it('can skip the check that prevents unsigned outputs', buildSkipTest(
732
- function (transaction) {
733
- return transaction
734
- .to(toAddress, 10000)
735
- .change(changeAddress)
736
- }, 'disableIsFullySigned', errors.Transaction.MissingSignatures
737
- ))
738
- it('can skip the check that avoids spending more bitcoins than the inputs for a transaction', buildSkipTest(
739
- function (transaction) {
740
- return transaction
741
- .to(toAddress, 10000000000000)
742
- .change(changeAddress)
743
- .sign(privateKey)
744
- }, 'disableMoreOutputThanInput', errors.Transaction.InvalidOutputAmountSum
745
- ))
746
- })
747
- })
748
-
749
- describe('#verify', function () {
750
- it('not if _satoshis and _satoshisBN have different values', function () {
751
- var tx = new Transaction()
752
- .from({
753
- 'txId': testPrevTx,
754
- 'outputIndex': 0,
755
- 'script': testScript,
756
- 'satoshis': testAmount
757
- })
758
- .to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', testAmount - 10000)
759
-
760
- tx.outputs[0]._satoshis = 100
761
- tx.outputs[0]._satoshisBN = new BN('fffffffffffffff', 16)
762
- var verify = tx.verify()
763
- verify.should.equal('transaction txout 0 satoshis is invalid')
764
- })
765
-
766
- it('not if _satoshis is negative', function () {
767
- var tx = new Transaction()
768
- .from({
769
- 'txId': testPrevTx,
770
- 'outputIndex': 0,
771
- 'script': testScript,
772
- 'satoshis': testAmount
773
- })
774
- .to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', testAmount - 10000)
775
-
776
- tx.outputs[0]._satoshis = -100
777
- tx.outputs[0]._satoshisBN = new BN(-100, 10)
778
- var verify = tx.verify()
779
- verify.should.equal('transaction txout 0 satoshis is invalid')
780
- })
781
-
782
- it('not if transaction is greater than max block size', function () {
783
- var tx = new Transaction()
784
- .from({
785
- 'txId': testPrevTx,
786
- 'outputIndex': 0,
787
- 'script': testScript,
788
- 'satoshis': testAmount
789
- })
790
- .to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', testAmount - 10000)
791
-
792
- tx.toBuffer = sinon.stub().returns({
793
- length: 10000000
794
- })
795
-
796
- var verify = tx.verify()
797
- verify.should.equal('transaction over the maximum block size')
798
- })
799
-
800
- it('not if has null input (and not coinbase)', function () {
801
- var tx = new Transaction()
802
- .from({
803
- 'txId': testPrevTx,
804
- 'outputIndex': 0,
805
- 'script': testScript,
806
- 'satoshis': testAmount
807
- })
808
- .to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', testAmount - 10000)
809
-
810
- tx.isCoinbase = sinon.stub().returns(false)
811
- tx.inputs[0].isNull = sinon.stub().returns(true)
812
- var verify = tx.verify()
813
- verify.should.equal('transaction input 0 has null input')
814
- })
815
- })
816
-
817
- describe('to and from JSON', function () {
818
- it('takes a string that is a valid JSON and deserializes from it', function () {
819
- var simple = new Transaction()
820
- expect(new Transaction(simple.toJSON()).uncheckedSerialize()).to.equal(simple.uncheckedSerialize())
821
- var complex = new Transaction()
822
- .from(simpleUtxoWith100000Satoshis)
823
- .to(toAddress, 50000)
824
- .change(changeAddress)
825
- .sign(privateKey)
826
- var cj = complex.toJSON()
827
- var ctx = new Transaction(cj)
828
- expect(ctx.uncheckedSerialize()).to.equal(complex.uncheckedSerialize())
829
- })
830
- it('serializes the `change` information', function () {
831
- var transaction = new Transaction()
832
- transaction.change(changeAddress)
833
- expect(transaction.toJSON().changeScript).to.equal(Script.fromAddress(changeAddress).toString())
834
- expect(new Transaction(transaction.toJSON()).uncheckedSerialize()).to.equal(transaction.uncheckedSerialize())
835
- })
836
- it('serializes correctly p2sh multisig signed tx', function () {
837
- var t = new Transaction(tx2hex)
838
- expect(t.toString()).to.equal(tx2hex)
839
- var r = new Transaction(t)
840
- expect(r.toString()).to.equal(tx2hex)
841
- var j = new Transaction(t.toObject())
842
- expect(j.toString()).to.equal(tx2hex)
843
- })
844
- })
845
-
846
- describe('serialization of inputs', function () {
847
- it('can serialize and deserialize a P2PKH input', function () {
848
- var transaction = new Transaction()
849
- .from(simpleUtxoWith1BSV)
850
- var deserialized = new Transaction(transaction.toObject())
851
- expect(deserialized.inputs[0] instanceof Transaction.Input.PublicKeyHash).to.equal(true)
852
- })
853
- it('can serialize and deserialize a P2SH input', function () {
854
- var transaction = new Transaction()
855
- .from({
856
- txId: '0000', // Not relevant
857
- outputIndex: 0,
858
- script: Script.buildMultisigOut([public1, public2], 2).toScriptHashOut(),
859
- satoshis: 10000
860
- }, [public1, public2], 2)
861
- var deserialized = new Transaction(transaction.toObject())
862
- expect(deserialized.inputs[0] instanceof Transaction.Input.MultiSigScriptHash).to.equal(true)
863
- })
864
- })
865
-
866
- describe('checks on adding inputs', function () {
867
- var transaction = new Transaction()
868
- it('fails if no output script is provided', function () {
869
- expect(function () {
870
- transaction.addInput(new Transaction.Input())
871
- }).to.throw(errors.Transaction.NeedMoreInfo)
872
- })
873
- it('fails if no satoshi amount is provided', function () {
874
- var input = new Transaction.Input()
875
- expect(function () {
876
- transaction.addInput(input)
877
- }).to.throw(errors.Transaction.NeedMoreInfo)
878
- expect(function () {
879
- transaction.addInput(new Transaction.Input(), Script.empty())
880
- }).to.throw(errors.Transaction.NeedMoreInfo)
881
- })
882
- it('allows output and transaction to be feed as arguments', function () {
883
- expect(function () {
884
- transaction.addInput(new Transaction.Input(), Script.empty(), 0)
885
- }).to.not.throw()
886
- })
887
- it('does not allow a threshold number greater than the amount of public keys', function () {
888
- expect(function () {
889
- transaction = new Transaction()
890
- return transaction.from({
891
- txId: '0000000000000000000000000000000000000000000000000000000000000000',
892
- outputIndex: 0,
893
- script: Script(),
894
- satoshis: 10000
895
- }, [], 1)
896
- }).to.throw('Number of required signatures must be greater than the number of public keys')
897
- })
898
- it('will add an empty script if not supplied', function () {
899
- transaction = new Transaction()
900
- var outputScriptString = 'OP_2 21 0x038282263212c609d9ea2a6e3e172de238d8c39' +
901
- 'cabd5ac1ca10646e23fd5f51508 21 0x038282263212c609d9ea2a6e3e172de23' +
902
- '8d8c39cabd5ac1ca10646e23fd5f51508 OP_2 OP_CHECKMULTISIG OP_EQUAL'
903
- transaction.addInput(new Transaction.Input({
904
- prevTxId: '0000000000000000000000000000000000000000000000000000000000000000',
905
- outputIndex: 0,
906
- script: new Script()
907
- }), outputScriptString, 10000)
908
- transaction.inputs[0].output.script.should.be.instanceof(bsv.Script)
909
- transaction.inputs[0].output.script.toString().should.equal(outputScriptString)
910
- })
911
- })
912
-
913
- describe('removeInput and removeOutput', function () {
914
- it('can remove an input by index', function () {
915
- var transaction = new Transaction()
916
- .from(simpleUtxoWith1BSV)
917
- transaction.inputs.length.should.equal(1)
918
- transaction.inputAmount.should.equal(simpleUtxoWith1BSV.satoshis)
919
- transaction.removeInput(0)
920
- transaction.inputs.length.should.equal(0)
921
- transaction.inputAmount.should.equal(0)
922
- })
923
- it('can remove an input by transaction id', function () {
924
- var transaction = new Transaction()
925
- .from(simpleUtxoWith1BSV)
926
- transaction.inputs.length.should.equal(1)
927
- transaction.inputAmount.should.equal(simpleUtxoWith1BSV.satoshis)
928
- transaction.removeInput(simpleUtxoWith1BSV.txId, simpleUtxoWith1BSV.outputIndex)
929
- transaction.inputs.length.should.equal(0)
930
- transaction.inputAmount.should.equal(0)
931
- })
932
- it('fails if the index provided is invalid', function () {
933
- var transaction = new Transaction()
934
- .from(simpleUtxoWith1BSV)
935
- expect(function () {
936
- transaction.removeInput(2)
937
- }).to.throw(errors.Transaction.InvalidIndex)
938
- })
939
- it('an output can be removed by index', function () {
940
- var transaction = new Transaction()
941
- .to([{
942
- address: toAddress,
943
- satoshis: 40000000
944
- }, {
945
- address: toAddress,
946
- satoshis: 40000000
947
- }])
948
- transaction.outputs.length.should.equal(2)
949
- transaction.outputAmount.should.equal(80000000)
950
- transaction.removeOutput(0)
951
- transaction.outputs.length.should.equal(1)
952
- transaction.outputAmount.should.equal(40000000)
953
- })
954
- })
955
-
956
- describe('handling the nLockTime', function () {
957
- var MILLIS_IN_SECOND = 1000
958
- var timestamp = 1423504946
959
- var blockHeight = 342734
960
- var date = new Date(timestamp * MILLIS_IN_SECOND)
961
- it('handles a null locktime', function () {
962
- var transaction = new Transaction()
963
- expect(transaction.getLockTime()).to.equal(null)
964
- })
965
- it('handles a simple example', function () {
966
- var future = new Date(2025, 10, 30) // Sun Nov 30 2025
967
- var transaction = new Transaction()
968
- .lockUntilDate(future)
969
- transaction.nLockTime.should.equal(future.getTime() / 1000)
970
- transaction.getLockTime().should.deep.equal(future)
971
- })
972
- it('accepts a date instance', function () {
973
- var transaction = new Transaction()
974
- .lockUntilDate(date)
975
- transaction.nLockTime.should.equal(timestamp)
976
- transaction.getLockTime().should.deep.equal(date)
977
- })
978
- it('accepts a number instance with a timestamp', function () {
979
- var transaction = new Transaction()
980
- .lockUntilDate(timestamp)
981
- transaction.nLockTime.should.equal(timestamp)
982
- transaction.getLockTime().should.deep.equal(new Date(timestamp * 1000))
983
- })
984
- it('accepts a block height', function () {
985
- var transaction = new Transaction()
986
- .lockUntilBlockHeight(blockHeight)
987
- transaction.nLockTime.should.equal(blockHeight)
988
- transaction.getLockTime().should.deep.equal(blockHeight)
989
- })
990
- it('fails if the block height is too high', function () {
991
- expect(function () {
992
- return new Transaction().lockUntilBlockHeight(5e8)
993
- }).to.throw(errors.Transaction.BlockHeightTooHigh)
994
- })
995
- it('fails if the date is too early', function () {
996
- expect(function () {
997
- return new Transaction().lockUntilDate(1)
998
- }).to.throw(errors.Transaction.LockTimeTooEarly)
999
- expect(function () {
1000
- return new Transaction().lockUntilDate(499999999)
1001
- }).to.throw(errors.Transaction.LockTimeTooEarly)
1002
- })
1003
- it('fails if the block height is negative', function () {
1004
- expect(function () {
1005
- return new Transaction().lockUntilBlockHeight(-1)
1006
- }).to.throw(errors.Transaction.NLockTimeOutOfRange)
1007
- })
1008
- it('has a non-max sequenceNumber for effective date locktime tx', function () {
1009
- var transaction = new Transaction()
1010
- .from(simpleUtxoWith1BSV)
1011
- .lockUntilDate(date)
1012
- transaction.inputs[0].sequenceNumber
1013
- .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER)
1014
- })
1015
- it('has a non-max sequenceNumber for effective blockheight locktime tx', function () {
1016
- var transaction = new Transaction()
1017
- .from(simpleUtxoWith1BSV)
1018
- .lockUntilBlockHeight(blockHeight)
1019
- transaction.inputs[0].sequenceNumber
1020
- .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER)
1021
- })
1022
- it('should serialize correctly for date locktime ', function () {
1023
- var transaction = new Transaction()
1024
- .from(simpleUtxoWith1BSV)
1025
- .lockUntilDate(date)
1026
- var serializedTx = transaction.uncheckedSerialize()
1027
- var copy = new Transaction(serializedTx)
1028
- serializedTx.should.equal(copy.uncheckedSerialize())
1029
- copy.inputs[0].sequenceNumber
1030
- .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER)
1031
- })
1032
- it('should serialize correctly for a block height locktime', function () {
1033
- var transaction = new Transaction()
1034
- .from(simpleUtxoWith1BSV)
1035
- .lockUntilBlockHeight(blockHeight)
1036
- var serializedTx = transaction.uncheckedSerialize()
1037
- var copy = new Transaction(serializedTx)
1038
- serializedTx.should.equal(copy.uncheckedSerialize())
1039
- copy.inputs[0].sequenceNumber
1040
- .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER)
1041
- })
1042
- })
1043
-
1044
- it('handles anyone-can-spend utxo', function () {
1045
- var transaction = new Transaction()
1046
- .from(anyoneCanSpendUTXO)
1047
- .to(toAddress, 50000)
1048
- should.exist(transaction)
1049
- })
1050
-
1051
- it('handles unsupported utxo in tx object', function () {
1052
- var transaction = new Transaction()
1053
- transaction.fromObject.bind(transaction, JSON.parse(unsupportedTxObj))
1054
- .should.throw('Unsupported input script type: OP_1 OP_ADD OP_2 OP_EQUAL')
1055
- })
1056
-
1057
- it('will error if object hash does not match transaction hash', function () {
1058
- var tx = new Transaction(tx1hex)
1059
- var txObj = tx.toObject()
1060
- txObj.hash = 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458';
1061
- (function () {
1062
- new Transaction(txObj) //eslint-disable-line
1063
- }).should.throw('Hash in object does not match transaction hash')
1064
- })
1065
-
1066
- describe('inputAmount + outputAmount', function () {
1067
- it('returns correct values for simple transaction', function () {
1068
- var transaction = new Transaction()
1069
- .from(simpleUtxoWith1BSV)
1070
- .to(toAddress, 40000000)
1071
- .feePerKb(100000)
1072
- transaction.inputAmount.should.equal(100000000)
1073
- transaction.outputAmount.should.equal(40000000)
1074
- })
1075
- it('returns correct values for transaction with change', function () {
1076
- var transaction = new Transaction()
1077
- .from(simpleUtxoWith1BSV)
1078
- .change(changeAddress)
1079
- .to(toAddress, 1000)
1080
- .feePerKb(100000)
1081
- transaction.inputAmount.should.equal(100000000)
1082
- transaction.outputAmount.should.equal(99977400)
1083
- })
1084
- it('returns correct values for coinjoin transaction', function () {
1085
- // see livenet tx c16467eea05f1f30d50ed6dbc06a38539d9bb15110e4b7dc6653046a3678a718
1086
- var transaction = new Transaction(txCoinJoinHex)
1087
- .feePerKb(100000)
1088
- transaction.outputAmount.should.equal(4191290961)
1089
- expect(function () {
1090
- var ia = transaction.inputAmount //eslint-disable-line
1091
- }).to.throw('No previous output information')
1092
- })
1093
- })
1094
-
1095
- describe('output ordering', function () {
1096
- var transaction, out1, out2, out3, out4
1097
-
1098
- beforeEach(function () {
1099
- transaction = new Transaction()
1100
- .from(simpleUtxoWith1BSV)
1101
- .to([{
1102
- address: toAddress,
1103
- satoshis: tenth
1104
- }, {
1105
- address: toAddress,
1106
- satoshis: fourth
1107
- }])
1108
- .to(toAddress, half)
1109
- .change(changeAddress)
1110
- out1 = transaction.outputs[0]
1111
- out2 = transaction.outputs[1]
1112
- out3 = transaction.outputs[2]
1113
- out4 = transaction.outputs[3]
1114
- })
1115
-
1116
- it('allows the user to sort outputs according to a criteria', function () {
1117
- var sorting = function (array) {
1118
- return [array[3], array[2], array[1], array[0]]
1119
- }
1120
- transaction.sortOutputs(sorting)
1121
- transaction.outputs[0].should.equal(out4)
1122
- transaction.outputs[1].should.equal(out3)
1123
- transaction.outputs[2].should.equal(out2)
1124
- transaction.outputs[3].should.equal(out1)
1125
- })
1126
-
1127
- it('allows the user to randomize the output order', function () {
1128
- var shuffle = sinon.stub(_, 'shuffle')
1129
- shuffle.onFirstCall().returns([out2, out1, out4, out3])
1130
-
1131
- transaction._changeIndex.should.equal(3)
1132
- transaction.shuffleOutputs()
1133
- transaction.outputs[0].should.equal(out2)
1134
- transaction.outputs[1].should.equal(out1)
1135
- transaction.outputs[2].should.equal(out4)
1136
- transaction.outputs[3].should.equal(out3)
1137
- transaction._changeIndex.should.equal(2)
1138
-
1139
- _.shuffle.restore()
1140
- })
1141
-
1142
- it('fails if the provided function does not work as expected', function () {
1143
- var sorting = function (array) {
1144
- return [array[0], array[1], array[2]]
1145
- }
1146
- expect(function () {
1147
- transaction.sortOutputs(sorting)
1148
- }).to.throw(errors.Transaction.InvalidSorting)
1149
- })
1150
-
1151
- it('shuffle without change', function () {
1152
- var tx = new Transaction(transaction.toObject()).to(toAddress, half)
1153
- expect(tx.getChangeOutput()).to.be.null //eslint-disable-line
1154
- expect(function () {
1155
- tx.shuffleOutputs()
1156
- }).to.not.throw(errors.Transaction.InvalidSorting)
1157
- })
1158
- })
1159
-
1160
- describe('clearOutputs', function () {
1161
- it('removes all outputs and maintains the transaction in order', function () {
1162
- var tx = new Transaction()
1163
- .from(simpleUtxoWith1BSV)
1164
- .to(toAddress, tenth)
1165
- .to([{
1166
- address: toAddress,
1167
- satoshis: fourth
1168
- }, {
1169
- address: toAddress,
1170
- satoshis: half
1171
- }])
1172
- .change(changeAddress)
1173
- .feePerKb(100000)
1174
- tx.clearOutputs()
1175
- tx.outputs.length.should.equal(1)
1176
- tx.to(toAddress, tenth)
1177
- tx.outputs.length.should.equal(2)
1178
- tx.outputs[0].satoshis.should.equal(10000000)
1179
- tx.outputs[0].script.toAddress().toString().should.equal(toAddress)
1180
- tx.outputs[1].satoshis.should.equal(89977400)
1181
- tx.outputs[1].script.toAddress().toString().should.equal(changeAddress)
1182
- })
1183
- })
1184
-
1185
- describe('BIP69 Sorting', function () {
1186
- it('sorts inputs correctly', function () {
1187
- var from1 = {
1188
- txId: '0000000000000000000000000000000000000000000000000000000000000000',
1189
- outputIndex: 0,
1190
- script: Script.buildPublicKeyHashOut(fromAddress).toString(),
1191
- satoshis: 100000
1192
- }
1193
- var from2 = {
1194
- txId: '0000000000000000000000000000000000000000000000000000000000000001',
1195
- outputIndex: 0,
1196
- script: Script.buildPublicKeyHashOut(fromAddress).toString(),
1197
- satoshis: 100000
1198
- }
1199
- var from3 = {
1200
- txId: '0000000000000000000000000000000000000000000000000000000000000001',
1201
- outputIndex: 1,
1202
- script: Script.buildPublicKeyHashOut(fromAddress).toString(),
1203
- satoshis: 100000
1204
- }
1205
- var tx = new Transaction()
1206
- .from(from3)
1207
- .from(from2)
1208
- .from(from1)
1209
- tx.sort()
1210
- tx.inputs[0].prevTxId.toString('hex').should.equal(from1.txId)
1211
- tx.inputs[1].prevTxId.toString('hex').should.equal(from2.txId)
1212
- tx.inputs[2].prevTxId.toString('hex').should.equal(from3.txId)
1213
- tx.inputs[0].outputIndex.should.equal(from1.outputIndex)
1214
- tx.inputs[1].outputIndex.should.equal(from2.outputIndex)
1215
- tx.inputs[2].outputIndex.should.equal(from3.outputIndex)
1216
- })
1217
-
1218
- it('sorts outputs correctly', function () {
1219
- var tx = new Transaction()
1220
- .addOutput(new Transaction.Output({
1221
- script: new Script().add(Opcode(0)),
1222
- satoshis: 2
1223
- }))
1224
- .addOutput(new Transaction.Output({
1225
- script: new Script().add(Opcode(1)),
1226
- satoshis: 2
1227
- }))
1228
- .addOutput(new Transaction.Output({
1229
- script: new Script().add(Opcode(0)),
1230
- satoshis: 1
1231
- }))
1232
- tx.sort()
1233
- tx.outputs[0].satoshis.should.equal(1)
1234
- tx.outputs[1].satoshis.should.equal(2)
1235
- tx.outputs[2].satoshis.should.equal(2)
1236
- tx.outputs[0].script.toString().should.equal('OP_0')
1237
- tx.outputs[1].script.toString().should.equal('OP_0')
1238
- tx.outputs[2].script.toString().should.equal('0x01')
1239
- })
1240
-
1241
- describe('bitcoinjs fixtures', function () {
1242
- var fixture = require('../data/bip69.json')
1243
-
1244
- // returns index-based order of sorted against original
1245
- var getIndexOrder = function (original, sorted) {
1246
- return sorted.map(function (value) {
1247
- return original.indexOf(value)
1248
- })
1249
- }
1250
-
1251
- fixture.inputs.forEach(function (inputSet) {
1252
- it(inputSet.description, function () {
1253
- var tx = new Transaction()
1254
- inputSet.inputs = inputSet.inputs.map(function (input) {
1255
- input = new Input({
1256
- prevTxId: input.txId,
1257
- outputIndex: input.vout,
1258
- script: new Script(),
1259
- output: new Output({
1260
- script: new Script(),
1261
- satoshis: 0
1262
- })
1263
- })
1264
- input.clearSignatures = function () {}
1265
- return input
1266
- })
1267
- tx.inputs = inputSet.inputs
1268
- tx.sort()
1269
- getIndexOrder(inputSet.inputs, tx.inputs).should.deep.equal(inputSet.expected)
1270
- })
1271
- })
1272
- fixture.outputs.forEach(function (outputSet) {
1273
- it(outputSet.description, function () {
1274
- var tx = new Transaction()
1275
- outputSet.outputs = outputSet.outputs.map(function (output) {
1276
- return new Output({
1277
- script: new Script(output.script),
1278
- satoshis: output.value
1279
- })
1280
- })
1281
- tx.outputs = outputSet.outputs
1282
- tx.sort()
1283
- getIndexOrder(outputSet.outputs, tx.outputs).should.deep.equal(outputSet.expected)
1284
- })
1285
- })
1286
- })
1287
- })
1288
- })
1289
-
1290
- var txEmptyHex = '01000000000000000000'
1291
-
1292
- var tx1hex = '01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006a473044022013fa3089327b50263029265572ae1b022a91d10ac80eb4f32f291c914533670b02200d8a5ed5f62634a7e1a0dc9188a3cc460a986267ae4d58faf50c79105431327501210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000'
1293
- var tx1id = '779a3e5b3c2c452c85333d8521f804c1a52800e60f4b7c3bbe36f4bab350b72c'
1294
-
1295
- var tx2hex = '0100000001e07d8090f4d4e6fcba6a2819e805805517eb19e669e9d2f856b41d4277953d640000000091004730440220248bc60bb309dd0215fbde830b6371e3fdc55685d11daa9a3c43828892e26ce202205f10cd4011f3a43657260a211f6c4d1fa81b6b6bdd6577263ed097cc22f4e5b50147522102fa38420cec94843ba963684b771ba3ca7ce1728dc2c7e7cade0bf298324d6b942103f948a83c20b2e7228ca9f3b71a96c2f079d9c32164cd07f08fbfdb483427d2ee52aeffffffff01180fe200000000001976a914ccee7ce8e8b91ec0bc23e1cfb6324461429e6b0488ac00000000'
1296
-
1297
- var unsupportedTxObj = '{"version":1,"inputs":[{"prevTxId":"a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458","outputIndex":0,"sequenceNumber":4294967295,"script":"OP_1","output":{"satoshis":1020000,"script":"OP_1 OP_ADD OP_2 OP_EQUAL"}}],"outputs":[{"satoshis":1010000,"script":"OP_DUP OP_HASH160 20 0x7821c0a3768aa9d1a37e16cf76002aef5373f1a8 OP_EQUALVERIFY OP_CHECKSIG"}],"nLockTime":0}'
1298
-
1299
- var txCoinJoinHex = '0100000013440a4e2471a0afd66c9db54db7d414507981eb3db35970dadf722453f08bdc8d0c0000006a47304402200098a7f838ff267969971f5d9d4b2c1db11b8e39c81eebf3c8fe22dd7bf0018302203fa16f0aa3559752462c20ddd8a601620eb176b4511507d11a361a7bb595c57c01210343ead2c0e2303d880bf72dfc04fc9c20d921fc53949c471e22b3c68c0690b828ffffffff0295eef5ad85c9b6b91a3d77bce015065dc64dab526b2f27fbe56f51149bb67f100000006b483045022100c46d6226167e6023e5a058b1ae541c5ca4baf4a69afb65adbfce2cc276535a6a022006320fdc8a438009bbfebfe4ab63e415ee231456a0137d167ee2113677f8e3130121032e38a3e15bee5ef272eaf71033a054637f7b74a51882e659b0eacb8db3e417a9ffffffffee0a35737ab56a0fdb84172c985f1597cffeb33c1d8e4adf3b3b4cc6d430d9b50a0000006b483045022100d02737479b676a35a5572bfd027ef9713b2ef34c87aabe2a2939a448d06c0569022018b262f34191dd2dcf5cbf1ecae8126b35aeb4afcb0426922e1d3dfc86e4dc970121022056d76bd198504c05350c415a80900aaf1174ad95ef42105c2c7976c7094425ffffffffee0a35737ab56a0fdb84172c985f1597cffeb33c1d8e4adf3b3b4cc6d430d9b5100000006a47304402207f541994740dd1aff3dbf633b7d7681c5251f2aa1f48735370dd4694ebdb049802205f4c92f3c9d8e3e758b462a5e0487c471cf7e58757815200c869801403c5ed57012102778e7fe0fc66a2746a058bbe25029ee32bfbed75a6853455ffab7c2bf764f1aeffffffff0295eef5ad85c9b6b91a3d77bce015065dc64dab526b2f27fbe56f51149bb67f050000006a473044022050304b69e695bdba599379c52d872410ae5d78804d3f3c60fb887fd0d95f617b02205f0e27fd566849f7be7d1965219cd63484cc0f37b77b62be6fdbf48f5887ae01012103c8ac0d519ba794b2e3fe7b85717d48b8b47f0e6f94015d0cb8b2ca84bce93e22ffffffff490673d994be7c9be1a39c2d45b3c3738fde5e4b54af91740a442e1cde947114110000006b48304502210085f6b6285d30a5ea3ee6b6f0e73c39e5919d5254bc09ff57b11a7909a9f3f6b7022023ffc24406384c3ee574b836f57446980d5e79c1cd795136a2160782544037a9012103152a37a23618dcc6c41dbb0d003c027215c4ce467bffc29821e067d97fa052e7ffffffffc1365292b95156f7d68ad6dfa031910f3284d9d2e9c267670c5cfa7d97bae482010000006b483045022100e59095f9bbb1daeb04c8105f6f0cf123fcf59c80d319a0e2012326d12bb0e02702206d67b31b24ed60b3f3866755ce122abb09200f9bb331d7be214edfd74733bb830121026db18f5b27ce4e60417364ce35571096927339c6e1e9d0a9f489be6a4bc03252ffffffff0295eef5ad85c9b6b91a3d77bce015065dc64dab526b2f27fbe56f51149bb67f0d0000006b483045022100ec5f0ef35f931fa047bb0ada3f23476fded62d8f114fa547093d3b5fbabf6dbe0220127d6d28388ffeaf2a282ec5f6a7b1b7cc2cb8e35778c2f7c3be834f160f1ff8012102b38aca3954870b28403cae22139004e0756ae325208b3e692200e9ddc6e33b54ffffffff73675af13a01c64ee60339613debf81b9e1dd8d9a3515a25f947353459d3af3c0c0000006b483045022100ff17593d4bff4874aa556c5f8f649d4135ea26b37baf355e793f30303d7bfb9102200f51704d8faccbaa22f58488cb2bebe523e00a436ce4d58179d0570e55785daa0121022a0c75b75739d182076c16d3525e83b1bc7362bfa855959c0cd48e5005140166ffffffff73675af13a01c64ee60339613debf81b9e1dd8d9a3515a25f947353459d3af3c0e0000006b483045022100c7d5a379e2870d03a0f3a5bdd4054a653b29804913f8720380a448f4e1f19865022051501eae29ba44a13ddd3780bc97ac5ec86e881462d0e08d9cc4bd2b29bcc815012103abe21a9dc0e9f995e3c58d6c60971e6d54559afe222bca04c2b331f42b38c0f3ffffffff6f70aeaa54516863e16fa2082cb5471e0f66b4c7dac25d9da4969e70532f6da00d0000006b483045022100afbeaf9fe032fd77c4e46442b178bdc37c7d6409985caad2463b7ab28befccfd0220779783a9b898d94827ff210c9183ff66bfb56223b0e0118cbba66c48090a4f700121036385f64e18f00d6e56417aa33ad3243356cc5879342865ee06f3b2c17552fe7efffffffffae31df57ccb4216853c0f3cc5af1f8ad7a99fc8de6bc6d80e7b1c81f4baf1e4140000006a473044022076c7bb674a88d9c6581e9c26eac236f6dd9cb38b5ffa2a3860d8083a1751302e022033297ccaaab0a6425c2afbfb6525b75e6f27cd0c9f23202bea28f8fa8a7996b40121031066fb64bd605b8f9d07c45d0d5c42485325b9289213921736bf7b048dec1df3ffffffff909d6efb9e08780c8b8e0fccff74f3e21c5dd12d86dcf5cbea494e18bbb9995c120000006a47304402205c945293257a266f8d575020fa409c1ba28742ff3c6d66f33059675bd6ba676a02204ca582141345a161726bd4ec5f53a6d50b2afbb1aa811acbad44fd295d01948501210316a04c4b9dc5035bc9fc3ec386896dcba281366e8a8a67b4904e4e4307820f56ffffffff90ac0c55af47a073de7c3f98ac5a59cd10409a8069806c8afb9ebbbf0c232436020000006a47304402200e05f3a9db10a3936ede2f64844ebcbdeeef069f4fd7e34b18d66b185217d5e30220479b734d591ea6412ded39665463f0ae90b0b21028905dd8586f74b4eaa9d6980121030e9ba4601ae3c95ce90e01aaa33b2d0426d39940f278325023d9383350923477ffffffff3e2f391615f885e626f70940bc7daf71bcdc0a7c6bf5a5eaece5b2e08d10317c000000006b4830450221009b675247b064079c32b8e632e9ee8bd62b11b5c89f1e0b37068fe9be16ae9653022044bff9be38966d3eae77eb9adb46c20758bc106f91cd022400999226b3cd6064012103239b99cadf5350746d675d267966e9597b7f5dd5a6f0f829b7bc6e5802152abcffffffffe1ce8f7faf221c2bcab3aa74e6b1c77a73d1a5399a9d401ddb4b45dc1bdc4636090000006b483045022100a891ee2286649763b1ff45b5a3ef66ce037e86e11b559d15270e8a61cfa0365302200c1e7aa62080af45ba18c8345b5f37a94e661f6fb1d62fd2f3917aa2897ae4af012102fa6980f47e0fdc80fb94bed1afebec70eb5734308cd30f850042cd9ddf01aebcffffffffe1ce8f7faf221c2bcab3aa74e6b1c77a73d1a5399a9d401ddb4b45dc1bdc4636010000006a4730440220296dbfacd2d3f3bd4224a40b7685dad8d60292a38be994a0804bdd1d1e84edef022000f30139285e6da863bf6821d46b8799a582d453e696589233769ad9810c9f6a01210314936e7118052ac5c4ba2b44cb5b7b577346a5e6377b97291e1207cf5dae47afffffffff0295eef5ad85c9b6b91a3d77bce015065dc64dab526b2f27fbe56f51149bb67f120000006b483045022100b21b2413eb7de91cab6416efd2504b15a12b34c11e6906f44649827f9c343b4702205691ab43b72862ea0ef60279f03b77d364aa843cb8fcb16d736368e432d44698012103f520fb1a59111b3d294861d3ac498537216d4a71d25391d1b3538ccbd8b023f6ffffffff5a7eaeadd2570dd5b9189eb825d6b1876266940789ebb05deeeac954ab520d060c0000006b483045022100949c7c91ae9addf549d828ed51e0ef42255149e29293a34fb8f81dc194c2f4b902202612d2d6251ef13ed936597f979a26b38916ed844a1c3fded0b3b0ea18b54380012103eda1fa3051306238c35d83e8ff8f97aa724d175dede4c0783926c98f106fb194ffffffff15620f5723000000001976a91406595e074efdd41ef65b0c3dba3d69dd3c6e494b88ac58a3fb03000000001976a914b037b0650a691c56c1f98e274e9752e2157d970288ac18c0f702000000001976a914b68642906bca6bb6c883772f35caaeed9f7a1b7888ac83bd5723000000001976a9148729016d0c88ac01d110e7d75006811f283f119788ace41f3823000000001976a9147acd2478d13395a64a0b8eadb62d501c2b41a90c88ac31d50000000000001976a91400d2a28bc7a4486248fab573d72ef6db46f777ea88aca09c0306000000001976a914d43c27ffb4a76590c245cd55447550ffe99f346a88ac80412005000000001976a914997efabe5dce8a24d4a1f3c0f9236bf2f6a2087588ac99bb0000000000001976a914593f550a3f8afe8e90b7bae14f0f0b2c31c4826688ace2c71500000000001976a914ee85450df9ca44a4e330fd0b7d681ec6fbad6fb488acb0eb4a00000000001976a914e7a48c6f7079d95e1505b45f8307197e6191f13888acea015723000000001976a9149537e8f15a7f8ef2d9ff9c674da57a376cf4369b88ac2002c504000000001976a9141821265cd111aafae46ac62f60eed21d1544128388acb0c94f0e000000001976a914a7aef50f0868fe30389b02af4fae7dda0ec5e2e988ac40b3d509000000001976a9140f9ac28f8890318c50cffe1ec77c05afe5bb036888ac9f9d1f00000000001976a914e70288cab4379092b2d694809d555c79ae59223688ac52e85623000000001976a914a947ce2aca9c6e654e213376d8d35db9e36398d788ac21ae0000000000001976a914ff3bc00eac7ec252cd5fb3318a87ac2a86d229e188ace0737a09000000001976a9146189be3daa18cb1b1fa86859f7ed79cc5c8f2b3388acf051a707000000001976a914453b1289f3f8a0248d8d914d7ad3200c6be0d28888acc0189708000000001976a914a5e2e6e7b740cef68eb374313d53a7fab1a8a3cd88ac00000000'