@opcat-labs/opcat 1.0.1 → 1.0.3

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 (293) hide show
  1. package/.cjs2esm.json +18 -0
  2. package/.mocharc.yaml +1 -1
  3. package/CHANGELOG.md +12 -0
  4. package/README.md +6 -0
  5. package/{lib/address.js → cjs/address.cjs} +77 -72
  6. package/cjs/block/block.cjs +332 -0
  7. package/{lib/block/blockheader.js → cjs/block/blockheader.cjs} +8 -7
  8. package/cjs/block/index.cjs +2 -0
  9. package/{lib/block/merkleblock.js → cjs/block/merkleblock.cjs} +23 -15
  10. package/cjs/bn.cjs +3411 -0
  11. package/{lib/crypto/bn.js → cjs/crypto/bn.cjs} +3 -3
  12. package/{lib/crypto/ecdsa.js → cjs/crypto/ecdsa.cjs} +150 -14
  13. package/{lib/crypto/hash.node.js → cjs/crypto/hash.cjs} +13 -2
  14. package/cjs/crypto/index.cjs +16 -0
  15. package/{lib/crypto/point.js → cjs/crypto/point.cjs} +11 -4
  16. package/cjs/crypto/random.cjs +18 -0
  17. package/{lib/crypto/signature.js → cjs/crypto/signature.cjs} +158 -8
  18. package/{lib/encoding/base58.js → cjs/encoding/base58.cjs} +58 -2
  19. package/cjs/encoding/base58check.cjs +192 -0
  20. package/cjs/encoding/bufferreader.cjs +333 -0
  21. package/cjs/encoding/bufferwriter.cjs +244 -0
  22. package/{lib/encoding/decode-asm.js → cjs/encoding/decode-asm.cjs} +4 -4
  23. package/{lib/encoding/decode-hex.js → cjs/encoding/decode-hex.cjs} +1 -1
  24. package/cjs/encoding/index.cjs +14 -0
  25. package/cjs/encoding/varint.cjs +116 -0
  26. package/{lib/errors/index.js → cjs/errors/index.cjs} +9 -9
  27. package/{lib/errors/spec.js → cjs/errors/spec.cjs} +2 -2
  28. package/cjs/hash-cache.cjs +98 -0
  29. package/{lib/hdprivatekey.js → cjs/hdprivatekey.cjs} +232 -140
  30. package/{lib/hdpublickey.js → cjs/hdpublickey.cjs} +120 -93
  31. package/cjs/index.cjs +94 -0
  32. package/cjs/interpreter/index.cjs +2 -0
  33. package/cjs/interpreter/interpreter.cjs +1988 -0
  34. package/{lib/script/stack.js → cjs/interpreter/stack.cjs} +9 -2
  35. package/{lib/message/message.js → cjs/message/message.cjs} +62 -25
  36. package/cjs/mnemonic/index.cjs +3 -0
  37. package/{lib/mnemonic/mnemonic.js → cjs/mnemonic/mnemonic.cjs} +44 -13
  38. package/{lib/mnemonic/pbkdf2.node.js → cjs/mnemonic/pbkdf2.cjs} +9 -2
  39. package/cjs/mnemonic/words/index.cjs +66 -0
  40. package/cjs/network.cjs +13 -0
  41. package/cjs/networks.cjs +321 -0
  42. package/{lib/opcode.js → cjs/opcode.cjs} +69 -5
  43. package/cjs/privatekey.cjs +422 -0
  44. package/{lib/publickey.js → cjs/publickey.cjs} +14 -16
  45. package/cjs/script/index.cjs +2 -0
  46. package/{lib/script/script.js → cjs/script/script.cjs} +322 -67
  47. package/cjs/transaction/index.cjs +5 -0
  48. package/cjs/transaction/input/index.cjs +34 -0
  49. package/cjs/transaction/input/input.cjs +396 -0
  50. package/{lib/transaction/input/multisig.js → cjs/transaction/input/multisig.cjs} +112 -18
  51. package/{lib/transaction/input/publickey.js → cjs/transaction/input/publickey.cjs} +29 -19
  52. package/{lib/transaction/input/publickeyhash.js → cjs/transaction/input/publickeyhash.cjs} +25 -17
  53. package/{lib/transaction/output.js → cjs/transaction/output.cjs} +100 -15
  54. package/cjs/transaction/sighash.cjs +187 -0
  55. package/{lib/transaction/signature.js → cjs/transaction/signature.cjs} +30 -6
  56. package/cjs/transaction/transaction.cjs +2000 -0
  57. package/{lib/transaction/unspentoutput.js → cjs/transaction/unspentoutput.cjs} +5 -5
  58. package/cjs/util/derivation.cjs +53 -0
  59. package/cjs/util/index.cjs +11 -0
  60. package/cjs/util/js.cjs +95 -0
  61. package/{lib/util/preconditions.js → cjs/util/preconditions.cjs} +2 -2
  62. package/esm/address.js +483 -0
  63. package/{lib → esm}/block/block.js +82 -27
  64. package/esm/block/blockheader.js +296 -0
  65. package/esm/block/index.js +2 -0
  66. package/esm/block/merkleblock.js +331 -0
  67. package/esm/bn.js +3411 -0
  68. package/esm/crypto/bn.js +278 -0
  69. package/esm/crypto/ecdsa.js +475 -0
  70. package/{lib/crypto/hash.browser.js → esm/crypto/hash.js} +18 -7
  71. package/esm/crypto/index.js +16 -0
  72. package/esm/crypto/point.js +228 -0
  73. package/esm/crypto/random.js +18 -0
  74. package/esm/crypto/signature.js +475 -0
  75. package/esm/encoding/base58.js +167 -0
  76. package/esm/encoding/base58check.js +192 -0
  77. package/esm/encoding/bufferreader.js +333 -0
  78. package/esm/encoding/bufferwriter.js +243 -0
  79. package/esm/encoding/decode-asm.js +24 -0
  80. package/esm/encoding/decode-hex.js +32 -0
  81. package/esm/encoding/decode-script-chunks.js +43 -0
  82. package/esm/encoding/encode-hex.js +284 -0
  83. package/esm/encoding/index.js +14 -0
  84. package/esm/encoding/is-hex.js +7 -0
  85. package/esm/encoding/varint.js +116 -0
  86. package/esm/errors/index.js +54 -0
  87. package/esm/errors/spec.js +314 -0
  88. package/esm/hash-cache.js +98 -0
  89. package/esm/hdprivatekey.js +768 -0
  90. package/esm/hdpublickey.js +549 -0
  91. package/esm/index.js +66 -0
  92. package/esm/interpreter/index.js +2 -0
  93. package/{lib/script → esm/interpreter}/interpreter.js +219 -66
  94. package/esm/interpreter/stack.js +116 -0
  95. package/esm/message/message.js +228 -0
  96. package/esm/mnemonic/index.js +3 -0
  97. package/esm/mnemonic/mnemonic.js +332 -0
  98. package/{lib/mnemonic/pbkdf2.browser.js → esm/mnemonic/pbkdf2.js} +13 -6
  99. package/esm/mnemonic/words/chinese.js +2054 -0
  100. package/esm/mnemonic/words/english.js +2054 -0
  101. package/esm/mnemonic/words/french.js +2054 -0
  102. package/esm/mnemonic/words/index.js +66 -0
  103. package/esm/mnemonic/words/italian.js +2054 -0
  104. package/esm/mnemonic/words/japanese.js +2054 -0
  105. package/esm/mnemonic/words/spanish.js +2054 -0
  106. package/esm/network.js +13 -0
  107. package/{lib → esm}/networks.js +61 -120
  108. package/esm/opcode.js +319 -0
  109. package/{lib → esm}/privatekey.js +76 -28
  110. package/esm/publickey.js +384 -0
  111. package/esm/script/index.js +2 -0
  112. package/esm/script/script.js +1329 -0
  113. package/esm/script/write-i32-le.js +17 -0
  114. package/esm/script/write-push-data.js +35 -0
  115. package/esm/script/write-u16-le.js +12 -0
  116. package/esm/script/write-u32-le.js +16 -0
  117. package/esm/script/write-u64-le.js +24 -0
  118. package/esm/script/write-u8-le.js +8 -0
  119. package/esm/script/write-varint.js +46 -0
  120. package/esm/transaction/index.js +5 -0
  121. package/esm/transaction/input/index.js +33 -0
  122. package/{lib → esm}/transaction/input/input.js +132 -90
  123. package/esm/transaction/input/multisig.js +335 -0
  124. package/esm/transaction/input/publickey.js +108 -0
  125. package/esm/transaction/input/publickeyhash.js +124 -0
  126. package/esm/transaction/output.js +316 -0
  127. package/{lib → esm}/transaction/sighash.js +42 -22
  128. package/esm/transaction/signature.js +120 -0
  129. package/{lib → esm}/transaction/transaction.js +522 -163
  130. package/esm/transaction/unspentoutput.js +112 -0
  131. package/esm/util/_.js +47 -0
  132. package/esm/util/derivation.js +53 -0
  133. package/esm/util/index.js +12 -0
  134. package/esm/util/js.js +95 -0
  135. package/esm/util/preconditions.js +33 -0
  136. package/fixup.cjs +17 -0
  137. package/package.json +18 -4
  138. package/test/{address.js → address.cjs} +14 -43
  139. package/test/block/{block.js → block.cjs} +3 -5
  140. package/test/block/{blockheader.js → blockheader.cjs} +2 -2
  141. package/test/block/{merklebloack.js → merklebloack.cjs} +2 -2
  142. package/test/crypto/{ecdsa.js → ecdsa.cjs} +9 -9
  143. package/test/crypto/{hash.browser.js → hash.browser.cjs} +2 -1
  144. package/test/crypto/{signature.js → signature.cjs} +2 -2
  145. package/test/data/bitcoind/script_tests.json +5 -5
  146. package/test/{hashCache.js → hashCache.cjs} +2 -1
  147. package/test/{hdkeys.js → hdkeys.cjs} +4 -2
  148. package/test/{hdprivatekey.js → hdprivatekey.cjs} +7 -6
  149. package/test/{hdpublickey.js → hdpublickey.cjs} +2 -7
  150. package/test/mnemonic/{pbkdf2.test.js → pbkdf2.test.cjs} +2 -2
  151. package/test/{networks.js → networks.cjs} +12 -31
  152. package/test/{publickey.js → publickey.cjs} +2 -2
  153. package/test/script/{interpreter.js → interpreter.cjs} +5 -5
  154. package/test/script/{script.js → script.cjs} +8 -2
  155. package/test/transaction/{deserialize.js → deserialize.cjs} +2 -2
  156. package/test/transaction/input/{input.js → input.cjs} +1 -1
  157. package/test/transaction/input/{multisig.js → multisig.cjs} +2 -1
  158. package/test/transaction/input/{publickeyhash.js → publickeyhash.cjs} +1 -1
  159. package/test/transaction/{sighash.js → sighash.cjs} +1 -1
  160. package/test/transaction/{transaction.js → transaction.cjs} +2 -2
  161. package/tsconfig.json +13 -0
  162. package/types/address.d.cts +252 -0
  163. package/types/block/block.d.cts +139 -0
  164. package/types/block/blockheader.d.cts +125 -0
  165. package/types/block/index.d.cts +2 -0
  166. package/types/block/merkleblock.d.cts +95 -0
  167. package/types/bn.d.cts +202 -0
  168. package/types/crypto/bn.d.cts +2 -0
  169. package/types/crypto/ecdsa.d.cts +187 -0
  170. package/types/crypto/hash.d.cts +118 -0
  171. package/types/crypto/index.d.cts +7 -0
  172. package/types/crypto/point.d.cts +134 -0
  173. package/types/crypto/random.d.cts +13 -0
  174. package/types/crypto/signature.d.cts +160 -0
  175. package/types/encoding/base58.d.cts +106 -0
  176. package/types/encoding/base58check.d.cts +107 -0
  177. package/types/encoding/bufferreader.d.cts +164 -0
  178. package/types/encoding/bufferwriter.d.cts +126 -0
  179. package/types/encoding/decode-asm.d.cts +2 -0
  180. package/types/encoding/decode-hex.d.cts +2 -0
  181. package/types/encoding/decode-script-chunks.d.cts +14 -0
  182. package/types/encoding/encode-hex.d.cts +2 -0
  183. package/types/encoding/index.d.cts +6 -0
  184. package/types/encoding/is-hex.d.cts +2 -0
  185. package/types/encoding/varint.d.cts +66 -0
  186. package/types/errors/index.d.cts +4 -0
  187. package/types/errors/spec.d.cts +22 -0
  188. package/types/hash-cache.d.cts +65 -0
  189. package/types/hdprivatekey.d.cts +281 -0
  190. package/types/hdpublickey.d.cts +240 -0
  191. package/types/index.d.cts +26 -0
  192. package/types/interpreter/index.d.cts +2 -0
  193. package/types/interpreter/interpreter.d.cts +228 -0
  194. package/types/interpreter/stack.d.cts +35 -0
  195. package/types/message/message.d.cts +110 -0
  196. package/types/mnemonic/index.d.cts +2 -0
  197. package/types/mnemonic/mnemonic.d.cts +171 -0
  198. package/types/mnemonic/pbkdf2.d.cts +14 -0
  199. package/types/mnemonic/words/chinese.d.cts +2 -0
  200. package/types/mnemonic/words/english.d.cts +2 -0
  201. package/types/mnemonic/words/french.d.cts +2 -0
  202. package/types/mnemonic/words/index.d.cts +22 -0
  203. package/types/mnemonic/words/italian.d.cts +2 -0
  204. package/types/mnemonic/words/japanese.d.cts +2 -0
  205. package/types/mnemonic/words/spanish.d.cts +2 -0
  206. package/types/network.d.cts +11 -0
  207. package/types/networks.d.cts +76 -0
  208. package/types/opcode.d.cts +93 -0
  209. package/types/privatekey.d.cts +169 -0
  210. package/types/publickey.d.cts +202 -0
  211. package/types/script/index.d.cts +2 -0
  212. package/types/script/script.d.cts +449 -0
  213. package/types/script/write-i32-le.d.cts +2 -0
  214. package/types/script/write-push-data.d.cts +2 -0
  215. package/types/script/write-u16-le.d.cts +2 -0
  216. package/types/script/write-u32-le.d.cts +2 -0
  217. package/types/script/write-u64-le.d.cts +2 -0
  218. package/types/script/write-u8-le.d.cts +2 -0
  219. package/types/script/write-varint.d.cts +2 -0
  220. package/types/transaction/index.d.cts +2 -0
  221. package/types/transaction/input/index.d.cts +2 -0
  222. package/types/transaction/input/input.d.cts +178 -0
  223. package/types/transaction/input/multisig.d.cts +127 -0
  224. package/types/transaction/input/publickey.d.cts +44 -0
  225. package/types/transaction/input/publickeyhash.d.cts +45 -0
  226. package/types/transaction/output.d.cts +118 -0
  227. package/types/transaction/sighash.d.cts +61 -0
  228. package/types/transaction/signature.d.cts +43 -0
  229. package/types/transaction/transaction.d.cts +716 -0
  230. package/types/transaction/unspentoutput.d.cts +83 -0
  231. package/types/util/_.d.cts +26 -0
  232. package/types/util/derivation.d.cts +21 -0
  233. package/types/util/index.d.cts +5 -0
  234. package/types/util/js.d.cts +50 -0
  235. package/types/util/preconditions.d.cts +3 -0
  236. package/index.d.ts +0 -1541
  237. package/index.js +0 -74
  238. package/lib/block/index.js +0 -4
  239. package/lib/bn.js +0 -3423
  240. package/lib/crypto/hash.js +0 -2
  241. package/lib/crypto/random.browser.js +0 -28
  242. package/lib/crypto/random.js +0 -2
  243. package/lib/crypto/random.node.js +0 -11
  244. package/lib/encoding/base58check.js +0 -121
  245. package/lib/encoding/bufferreader.js +0 -212
  246. package/lib/encoding/bufferwriter.js +0 -140
  247. package/lib/encoding/varint.js +0 -75
  248. package/lib/hash-cache.js +0 -50
  249. package/lib/mnemonic/pbkdf2.js +0 -2
  250. package/lib/mnemonic/words/index.js +0 -8
  251. package/lib/script/index.js +0 -5
  252. package/lib/transaction/index.js +0 -7
  253. package/lib/transaction/input/index.js +0 -5
  254. package/lib/util/js.js +0 -90
  255. /package/{lib/encoding/decode-script-chunks.js → cjs/encoding/decode-script-chunks.cjs} +0 -0
  256. /package/{lib/encoding/encode-hex.js → cjs/encoding/encode-hex.cjs} +0 -0
  257. /package/{lib/encoding/is-hex.js → cjs/encoding/is-hex.cjs} +0 -0
  258. /package/{lib/mnemonic/words/chinese.js → cjs/mnemonic/words/chinese.cjs} +0 -0
  259. /package/{lib/mnemonic/words/english.js → cjs/mnemonic/words/english.cjs} +0 -0
  260. /package/{lib/mnemonic/words/french.js → cjs/mnemonic/words/french.cjs} +0 -0
  261. /package/{lib/mnemonic/words/italian.js → cjs/mnemonic/words/italian.cjs} +0 -0
  262. /package/{lib/mnemonic/words/japanese.js → cjs/mnemonic/words/japanese.cjs} +0 -0
  263. /package/{lib/mnemonic/words/spanish.js → cjs/mnemonic/words/spanish.cjs} +0 -0
  264. /package/{lib/script/write-i32-le.js → cjs/script/write-i32-le.cjs} +0 -0
  265. /package/{lib/script/write-push-data.js → cjs/script/write-push-data.cjs} +0 -0
  266. /package/{lib/script/write-u16-le.js → cjs/script/write-u16-le.cjs} +0 -0
  267. /package/{lib/script/write-u32-le.js → cjs/script/write-u32-le.cjs} +0 -0
  268. /package/{lib/script/write-u64-le.js → cjs/script/write-u64-le.cjs} +0 -0
  269. /package/{lib/script/write-u8-le.js → cjs/script/write-u8-le.cjs} +0 -0
  270. /package/{lib/script/write-varint.js → cjs/script/write-varint.cjs} +0 -0
  271. /package/{lib/util/_.js → cjs/util/_.cjs} +0 -0
  272. /package/test/crypto/{bn.js → bn.cjs} +0 -0
  273. /package/test/crypto/{hash.js → hash.cjs} +0 -0
  274. /package/test/crypto/{point.js → point.cjs} +0 -0
  275. /package/test/crypto/{random.js → random.cjs} +0 -0
  276. /package/test/data/{blk86756-testnet.js → blk86756-testnet.cjs} +0 -0
  277. /package/test/data/{merkleblocks.js → merkleblocks.cjs} +0 -0
  278. /package/test/encoding/{base58.js → base58.cjs} +0 -0
  279. /package/test/encoding/{base58check.js → base58check.cjs} +0 -0
  280. /package/test/encoding/{bufferreader.js → bufferreader.cjs} +0 -0
  281. /package/test/encoding/{bufferwriter.js → bufferwriter.cjs} +0 -0
  282. /package/test/encoding/{varint.js → varint.cjs} +0 -0
  283. /package/test/{index.js → index.cjs} +0 -0
  284. /package/test/message/{message.js → message.cjs} +0 -0
  285. /package/test/mnemonic/{mnemonic.js → mnemonic.cjs} +0 -0
  286. /package/test/{opcode.js → opcode.cjs} +0 -0
  287. /package/test/{privatekey.js → privatekey.cjs} +0 -0
  288. /package/test/transaction/input/{publickey.js → publickey.cjs} +0 -0
  289. /package/test/transaction/{output.js → output.cjs} +0 -0
  290. /package/test/transaction/{signature.js → signature.cjs} +0 -0
  291. /package/test/transaction/{unspentoutput.js → unspentoutput.cjs} +0 -0
  292. /package/test/util/{js.js → js.cjs} +0 -0
  293. /package/test/util/{preconditions.js → preconditions.cjs} +0 -0
@@ -0,0 +1,2000 @@
1
+ 'use strict';
2
+
3
+ var _ = require('../util/_.cjs');
4
+ var $ = require('../util/preconditions.cjs');
5
+
6
+ var errors = require('../errors/index.cjs');
7
+ var JSUtil = require('../util/js.cjs');
8
+ var BufferReader = require('../encoding/bufferreader.cjs');
9
+ var BufferWriter = require('../encoding/bufferwriter.cjs');
10
+ var Varint = require('../encoding/varint.cjs');
11
+ var Hash = require('../crypto/hash.cjs');
12
+ var Signature = require('../crypto/signature.cjs');
13
+ var TransactionSignature = require('./signature.cjs');
14
+ var Sighash = require('./sighash.cjs');
15
+
16
+ var Address = require('../address.cjs');
17
+ var UnspentOutput = require('./unspentoutput.cjs');
18
+ var Input = require('./input/index.cjs');
19
+ var PublicKeyHashInput = Input.PublicKeyHash;
20
+ var PublicKeyInput = Input.PublicKey;
21
+ var Output = require('./output.cjs');
22
+ var Script = require('../script/index.cjs');
23
+ var PrivateKey = require('../privatekey.cjs');
24
+ var BN = require('../crypto/bn.cjs');
25
+
26
+ /**
27
+ * Represents a transaction, a set of inputs and outputs to change ownership of tokens
28
+ * @constructor
29
+ * @param {string|Buffer|Object|Transaction} [serialized] - Optional serialized data to initialize the transaction.
30
+ * Can be a hex string, Buffer, plain object, or another Transaction instance.
31
+ * @throws {errors.InvalidArgument} If invalid serialization format is provided.
32
+ * @property {Array} inputs - Transaction input objects.
33
+ * @property {Array} outputs - Transaction output objects.
34
+ * @property {boolean} sealed - Indicates if transaction is finalized.
35
+ */
36
+ function Transaction(serialized) {
37
+ if (!(this instanceof Transaction)) {
38
+ return new Transaction(serialized);
39
+ }
40
+ this.inputs = [];
41
+ this.outputs = [];
42
+ this._inputAmount = undefined;
43
+ this._outputAmount = undefined;
44
+ this._inputsMap = new Map();
45
+ this._outputsMap = new Map();
46
+ this._privateKey = undefined;
47
+ this._sigType = undefined;
48
+ this.sealed = false;
49
+ if (serialized) {
50
+ if (serialized instanceof Transaction) {
51
+ return Transaction.shallowCopy(serialized);
52
+ } else if (JSUtil.isHexa(serialized)) {
53
+ this.fromString(serialized);
54
+ } else if (Buffer.isBuffer(serialized)) {
55
+ this.fromBuffer(serialized);
56
+ } else if (_.isObject(serialized)) {
57
+ this.fromObject(serialized);
58
+ } else {
59
+ throw new errors.InvalidArgument(
60
+ 'Must provide an object or string to deserialize a transaction',
61
+ );
62
+ }
63
+ } else {
64
+ this._newTransaction();
65
+ }
66
+ }
67
+
68
+ var CURRENT_VERSION = 1;
69
+ var DEFAULT_NLOCKTIME = 0;
70
+
71
+
72
+ /**
73
+ * The minimum amount (in satoshis) considered non-dust in a transaction.
74
+ * @type {number}
75
+ * @default 1
76
+ */
77
+ Transaction.DUST_AMOUNT = 1;
78
+
79
+
80
+ /**
81
+ * Margin of error to allow fees in the vecinity of the expected value but doesn't allow a big difference
82
+ * @type {number}
83
+ * @default 150
84
+ */
85
+ Transaction.FEE_SECURITY_MARGIN = 150;
86
+
87
+ // max amount of satoshis in circulation
88
+ /**
89
+ * The maximum amount of money (in satoshis) that can be transacted in a single transaction.
90
+ * This follows Bitcoin's 21 million coin limit (21000000 * 1e8 satoshis).
91
+ * @type {number}
92
+ * @default 2100000000000000
93
+ */
94
+ Transaction.MAX_MONEY = 21000000 * 1e8;
95
+
96
+ /**
97
+ * The maximum block height value allowed for nLockTime in a transaction.
98
+ * Transactions with nLockTime above this value are interpreted as timestamp-based.
99
+ * @type {number}
100
+ * @default 500000000
101
+ */
102
+ Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT = 5e8;
103
+
104
+
105
+ /**
106
+ * The maximum value allowed for the nLockTime field in a transaction (2^32 - 1).
107
+ * @type {number}
108
+ * @default 4294967295
109
+ */
110
+ Transaction.NLOCKTIME_MAX_VALUE = 4294967295;
111
+
112
+ /**
113
+ * The fee per kilobyte (KB) for transactions, in satoshis.
114
+ * @type {number}
115
+ * @default 1
116
+ */
117
+ Transaction.FEE_PER_KB = 1;
118
+
119
+
120
+
121
+ /**
122
+ * a dummy privatekey
123
+ * @type {PrivateKey}
124
+ */
125
+ Transaction.DUMMY_PRIVATEKEY = PrivateKey.fromWIF(
126
+ 'cQ3nCBQB9RsFSyjNQM15NQLVpXXMtWh9PUyeFz5KxLJCHsuRH2Su',
127
+ );
128
+
129
+
130
+ /**
131
+ * Creates a Transaction instance from a raw hexadecimal string.
132
+ * @param {string} rawHex - The hexadecimal string representation of the transaction.
133
+ * @returns {Transaction} A new Transaction instance populated from the input string.
134
+ */
135
+ Transaction.fromString = function (rawHex) {
136
+ return new Transaction().fromString(rawHex)
137
+ }
138
+ /**
139
+ * Creates a Transaction instance from a buffer.
140
+ * @param {Buffer} buffer - The input buffer containing transaction data.
141
+ * @returns {Transaction} A new Transaction instance populated from the buffer.
142
+ */
143
+ Transaction.fromBuffer = function (buffer) {
144
+ return new Transaction().fromBuffer(buffer)
145
+ }
146
+ /**
147
+ * Creates a Transaction instance from a plain object.
148
+ * @param {Object} obj - The plain object to convert to a Transaction.
149
+ * @returns {Transaction} A new Transaction instance populated from the object.
150
+ */
151
+ Transaction.fromObject = function (obj) {
152
+ return new Transaction().fromObject(obj)
153
+ }
154
+
155
+
156
+ /**
157
+ * Create a 'shallow' copy of the transaction, by serializing and deserializing
158
+ * it dropping any additional information that inputs and outputs may have hold
159
+ * @param {Transaction} transaction - The transaction to copy.
160
+ * @returns {Transaction} A new Transaction instance with the same data.
161
+ */
162
+ Transaction.shallowCopy = function (transaction) {
163
+ var copy = new Transaction(transaction.toBuffer());
164
+ return copy;
165
+ };
166
+
167
+ var hashProperty = {
168
+ configurable: false,
169
+ enumerable: true,
170
+ get: function () {
171
+ this._hash = new BufferReader(this._getHash()).readReverse().toString('hex');
172
+ return this._hash;
173
+ },
174
+ };
175
+ /**
176
+ * The unique identifier hash of the transaction.
177
+ * @name Transaction.prototype.hash
178
+ * @memberof Transaction
179
+ * @instance
180
+ * @type {string}
181
+ */
182
+ Object.defineProperty(Transaction.prototype, 'hash', hashProperty);
183
+ /**
184
+ * The unique identifier hash of the transaction.
185
+ * @name Transaction.prototype.id
186
+ * @memberof Transaction
187
+ * @instance
188
+ * @type {string}
189
+ */
190
+ Object.defineProperty(Transaction.prototype, 'id', hashProperty);
191
+
192
+ /**
193
+ * Gets the inputs amount for the transaction.
194
+ * @name Transaction.prototype.inputAmount
195
+ * @memberof Transaction
196
+ * @type {number}
197
+ */
198
+ Object.defineProperty(Transaction.prototype, 'inputAmount', {
199
+ configurable: false,
200
+ enumerable: true,
201
+ get: function () {
202
+ return this._getInputAmount();
203
+ },
204
+ });
205
+
206
+ /**
207
+ * Gets the outputs amount for the transaction.
208
+ * @name Transaction.prototype.outputAmount
209
+ * @memberof Transaction
210
+ * @type {number}
211
+ */
212
+ Object.defineProperty(Transaction.prototype, 'outputAmount', {
213
+ configurable: false,
214
+ enumerable: true,
215
+ get: function () {
216
+ return this._getOutputAmount();
217
+ },
218
+ });
219
+
220
+ /**
221
+ * Retrieve the little endian hash of the transaction (used for serialization)
222
+ * @return {Buffer}
223
+ * @private
224
+ */
225
+ Transaction.prototype._getHash = function () {
226
+ return Hash.sha256sha256(this.toBufferWriter(true).toBuffer());
227
+ };
228
+
229
+ /**
230
+ * Retrieve a hexa string that can be used with bitcoind's CLI interface
231
+ * (decoderawtransaction, sendrawtransaction)
232
+ *
233
+ * @param {Object|boolean=} unsafe if true, skip all tests. if it's an object,
234
+ * it's expected to contain a set of flags to skip certain tests:
235
+ * * `disableAll`: disable all checks
236
+ * * `disableLargeFees`: disable checking for fees that are too large
237
+ * * `disableIsFullySigned`: disable checking if all inputs are fully signed
238
+ * * `disableDustOutputs`: disable checking if there are no outputs that are dust amounts
239
+ * * `disableMoreOutputThanInput`: disable checking if the transaction spends more bitcoins than the sum of the input amounts
240
+ * @return {string}
241
+ */
242
+ Transaction.prototype.serialize = function (unsafe) {
243
+ if (unsafe === true || (unsafe && unsafe.disableAll)) {
244
+ return this.uncheckedSerialize();
245
+ } else {
246
+ return this.checkedSerialize(unsafe);
247
+ }
248
+ };
249
+
250
+ /**
251
+ * Creates a deep clone of the Transaction instance.
252
+ * @returns {Transaction} A new Transaction instance with cloned inputs.
253
+ */
254
+ Transaction.prototype.clone = function () {
255
+ const tx = Transaction.fromString(this.uncheckedSerialize());
256
+ this.inputs.forEach((input, index) => {
257
+ if(input.output) {
258
+ tx.inputs[index].output = input.output.clone();
259
+ }
260
+ });
261
+ return tx;
262
+ };
263
+
264
+ /**
265
+ * Serializes the transaction to a hexadecimal string.
266
+ * This method is aliased as `toString()` and `toHex()` for convenience.
267
+ * @returns {string} Hexadecimal representation of the transaction.
268
+ */
269
+ Transaction.prototype.uncheckedSerialize = Transaction.prototype.toString = Transaction.prototype.toHex = function () {
270
+ return this.toBuffer().toString('hex');
271
+ };
272
+
273
+ /**
274
+ * Retrieve a hexa string that can be used with bitcoind's CLI interface
275
+ * (decoderawtransaction, sendrawtransaction)
276
+ *
277
+ * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize}
278
+ * @return {string}
279
+ */
280
+ Transaction.prototype.checkedSerialize = function (opts) {
281
+ var serializationError = this.getSerializationError(opts);
282
+ if (serializationError) {
283
+ serializationError.message +=
284
+ ' - For more information please see: ' + 'https://github.com/OPCAT-Labs/ts-tools';
285
+ throw serializationError;
286
+ }
287
+ return this.uncheckedSerialize();
288
+ };
289
+
290
+ /**
291
+ * Checks if any output in the transaction has invalid satoshis.
292
+ * @returns {boolean} True if at least one output has invalid satoshis, false otherwise.
293
+ */
294
+ Transaction.prototype.invalidSatoshis = function () {
295
+ var invalid = false;
296
+ for (var i = 0; i < this.outputs.length; i++) {
297
+ if (this.outputs[i].invalidSatoshis()) {
298
+ invalid = true;
299
+ }
300
+ }
301
+ return invalid;
302
+ };
303
+
304
+ /**
305
+ * Retrieve a possible error that could appear when trying to serialize and
306
+ * broadcast this transaction.
307
+ *
308
+ * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize}
309
+ * @return {opcat.Error}
310
+ */
311
+ Transaction.prototype.getSerializationError = function (opts) {
312
+ opts = opts || {};
313
+
314
+ if (this.invalidSatoshis()) {
315
+ return new errors.Transaction.InvalidSatoshis();
316
+ }
317
+
318
+ var unspent = this.getUnspentValue();
319
+ var unspentError;
320
+ if (unspent < 0) {
321
+ if (!opts.disableMoreOutputThanInput) {
322
+ unspentError = new errors.Transaction.InvalidOutputAmountSum();
323
+ }
324
+ } else {
325
+ unspentError = this._hasFeeError(opts, unspent);
326
+ }
327
+
328
+ return unspentError || this._hasDustOutputs(opts) || this._isMissingSignatures(opts);
329
+ };
330
+
331
+ /**
332
+ * Checks for fee-related errors in a transaction.
333
+ *
334
+ * @param {Object} opts - Transaction options
335
+ * @param {number} unspent - The unspent amount to be used as fee
336
+ * @returns {errors.Transaction.FeeError.Different|errors.Transaction.ChangeAddressMissing|errors.Transaction.FeeError.TooLarge|undefined}
337
+ * Returns a fee error if:
338
+ * - Specified fee doesn't match unspent amount
339
+ * - Fee is too large and no change address is provided (when large fees are enabled)
340
+ * - Fee exceeds security margin (when large fees are enabled)
341
+ * Otherwise returns undefined if no errors are found.
342
+ * @private
343
+ */
344
+ Transaction.prototype._hasFeeError = function (opts, unspent) {
345
+ if (!_.isUndefined(this._fee) && this._fee !== unspent) {
346
+ return new errors.Transaction.FeeError.Different(
347
+ 'Unspent value is ' + unspent + ' but specified fee is ' + this._fee,
348
+ );
349
+ }
350
+
351
+ if (!opts.disableLargeFees) {
352
+ var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee());
353
+ if (unspent > maximumFee) {
354
+ if (this._missingChange()) {
355
+ return new errors.Transaction.ChangeAddressMissing(
356
+ 'Fee is too large and no change address was provided',
357
+ );
358
+ }
359
+ return new errors.Transaction.FeeError.TooLarge(
360
+ 'expected less than ' + maximumFee + ' but got ' + unspent,
361
+ );
362
+ }
363
+ }
364
+ };
365
+
366
+ /**
367
+ * Checks if the transaction is missing a change script.
368
+ * @returns {boolean} True if change script is missing, false otherwise.
369
+ * @private
370
+ */
371
+ Transaction.prototype._missingChange = function () {
372
+ return !this._changeScript;
373
+ };
374
+
375
+ /**
376
+ * Checks if the transaction contains any dust outputs (outputs below the dust limit).
377
+ * @param {Object} opts - Options object.
378
+ * @param {boolean} [opts.disableDustOutputs] - If true, skips dust output checking.
379
+ * @returns {errors.Transaction.DustOutputs|undefined} Returns DustOutputs error if dust outputs are found, otherwise undefined.
380
+ * @private
381
+ */
382
+ Transaction.prototype._hasDustOutputs = function (opts) {
383
+ if (opts.disableDustOutputs) {
384
+ return;
385
+ }
386
+ var index, output;
387
+ for (index in this.outputs) {
388
+ output = this.outputs[index];
389
+ if (
390
+ output.satoshis < Transaction.DUST_AMOUNT &&
391
+ !output.script.isDataOut() &&
392
+ !output.script.isSafeDataOut()
393
+ ) {
394
+ return new errors.Transaction.DustOutputs();
395
+ }
396
+ }
397
+ };
398
+
399
+ /**
400
+ * Checks if the transaction is missing signatures.
401
+ * @param {Object} opts - Options object.
402
+ * @param {boolean} [opts.disableIsFullySigned] - If true, skips the check.
403
+ * @returns {errors.Transaction.MissingSignatures|undefined} Returns MissingSignatures error if not fully signed, otherwise undefined.
404
+ */
405
+ Transaction.prototype._isMissingSignatures = function (opts) {
406
+ if (opts.disableIsFullySigned) {
407
+ return;
408
+ }
409
+ if (!this.isFullySigned()) {
410
+ return new errors.Transaction.MissingSignatures();
411
+ }
412
+ };
413
+
414
+ /**
415
+ * Returns a string representation of the Transaction object for debugging/inspection.
416
+ * The format is: '<Transaction: [serializedData]>' where serializedData comes from uncheckedSerialize().
417
+ * @returns {string} Formatted transaction inspection string.
418
+ */
419
+ Transaction.prototype.inspect = function () {
420
+ return '<Transaction: ' + this.uncheckedSerialize() + '>';
421
+ };
422
+
423
+ /**
424
+ * Converts the transaction to a Buffer.
425
+ * @returns {Buffer} The serialized transaction as a Buffer.
426
+ */
427
+ Transaction.prototype.toBuffer = function () {
428
+ var writer = new BufferWriter();
429
+ return this.toBufferWriter(false, writer).toBuffer();
430
+ };
431
+
432
+
433
+ /**
434
+ * Calculates the double SHA-256 hash of the transaction preimage for signature verification.
435
+ * The resulting hash is returned in reverse byte order (little-endian).
436
+ *
437
+ * @param {number} inputIndex - Index of the input being signed
438
+ * @param {number} hashType - SIGHASH type flag
439
+ * @returns {Buffer} The hash result in little-endian format
440
+ */
441
+ Transaction.prototype.hashForSignature = function (inputIndex, hashType) {
442
+ var preimage = this.getPreimage(inputIndex, hashType);
443
+ var ret = Hash.sha256sha256(preimage)
444
+ return new BufferReader(ret).readReverse()
445
+ }
446
+
447
+ /**
448
+ * Converts the transaction to a hash preimage by serializing it into a buffer.
449
+ * @returns {Buffer} The serialized transaction data as a buffer.
450
+ */
451
+ Transaction.prototype.toTxHashPreimage = function () {
452
+ var writer = new BufferWriter();
453
+ return this.toBufferWriter(true, writer).toBuffer();
454
+ }
455
+
456
+
457
+ /**
458
+ * Serializes the transaction to a BufferWriter.
459
+ * @param {boolean} forTxHash - Whether to serialize for transaction hash calculation (excludes some fields)
460
+ * @param {BufferWriter} [writer] - Optional BufferWriter instance to write to
461
+ * @returns {BufferWriter} The BufferWriter containing serialized transaction data
462
+ */
463
+ Transaction.prototype.toBufferWriter = function (forTxHash, writer) {
464
+ $.checkArgument(typeof forTxHash === 'boolean', 'forTxHash parameter must be a boolean');
465
+ writer = writer || new BufferWriter();
466
+ writer.writeUInt32LE(this.version);
467
+ writer.writeVarintNum(this.inputs.length);
468
+ _.each(this.inputs, function (input) {
469
+ input.toBufferWriter(forTxHash, writer);
470
+ });
471
+ writer.writeVarintNum(this.outputs.length);
472
+ _.each(this.outputs, function (output) {
473
+ output.toBufferWriter(forTxHash, writer);
474
+ });
475
+ writer.writeUInt32LE(this.nLockTime);
476
+ return writer;
477
+ };
478
+
479
+ /**
480
+ * Initializes the transaction from a buffer.
481
+ * @param {Buffer} buffer - The buffer containing transaction data.
482
+ * @returns {Transaction} The transaction instance.
483
+ */
484
+ Transaction.prototype.fromBuffer = function (buffer) {
485
+ var reader = new BufferReader(buffer);
486
+ return this.fromBufferReader(reader);
487
+ };
488
+
489
+ /**
490
+ * Reads transaction data from a buffer reader and populates the transaction instance.
491
+ * @param {BufferReader} reader - The buffer reader containing transaction data.
492
+ * @returns {Transaction} The transaction instance with populated data.
493
+ * @throws {Error} If no transaction data is received (reader is finished).
494
+ */
495
+ Transaction.prototype.fromBufferReader = function (reader) {
496
+ $.checkArgument(!reader.finished(), 'No transaction data received');
497
+ var i, sizeTxIns, sizeTxOuts;
498
+
499
+ this.version = reader.readInt32LE();
500
+ sizeTxIns = reader.readVarintNum();
501
+ for (i = 0; i < sizeTxIns; i++) {
502
+ var input = Input.fromBufferReader(reader);
503
+ this.inputs.push(input);
504
+ }
505
+ sizeTxOuts = reader.readVarintNum();
506
+ for (i = 0; i < sizeTxOuts; i++) {
507
+ this.outputs.push(Output.fromBufferReader(reader));
508
+ }
509
+ this.nLockTime = reader.readUInt32LE();
510
+ return this;
511
+ };
512
+
513
+ /**
514
+ * Converts the Transaction object to a plain JavaScript object (POJO) for serialization.
515
+ * Includes transaction details like hash, version, inputs, outputs, and lock time.
516
+ * Optionally includes change script, change address, change index, and fee if they are defined.
517
+ * @returns {Object} A plain object representation of the transaction.
518
+ */
519
+ Transaction.prototype.toObject = Transaction.prototype.toJSON = function toObject() {
520
+ var inputs = [];
521
+ this.inputs.forEach(function (input) {
522
+ inputs.push(input.toObject());
523
+ });
524
+ var outputs = [];
525
+ this.outputs.forEach(function (output) {
526
+ outputs.push(output.toObject());
527
+ });
528
+ var obj = {
529
+ hash: this.hash,
530
+ version: this.version,
531
+ inputs: inputs,
532
+ outputs: outputs,
533
+ nLockTime: this.nLockTime,
534
+ };
535
+ if (this._changeScript) {
536
+ obj.changeScript = this._changeScript.toString();
537
+ }
538
+
539
+ if (this._changeScript) {
540
+ obj.changeAddress = this._changeAddress.toString();
541
+ }
542
+
543
+ if (!_.isUndefined(this._changeIndex)) {
544
+ obj.changeIndex = this._changeIndex;
545
+ }
546
+ if (!_.isUndefined(this._fee)) {
547
+ obj.fee = this._fee;
548
+ }
549
+ return obj;
550
+ };
551
+
552
+ /**
553
+ * Creates a Transaction instance from a plain object or another Transaction.
554
+ * Handles conversion of inputs/outputs and other transaction properties.
555
+ *
556
+ * @param {Object|Transaction} arg - Either a transaction object or Transaction instance
557
+ * @returns {Transaction} The populated Transaction instance
558
+ * @throws {Error} If argument is not an object or Transaction instance
559
+ */
560
+ Transaction.prototype.fromObject = function fromObject(arg) {
561
+ $.checkArgument(_.isObject(arg) || arg instanceof Transaction);
562
+ var self = this;
563
+ var transaction;
564
+ if (arg instanceof Transaction) {
565
+ transaction = transaction.toObject();
566
+ } else {
567
+ transaction = arg;
568
+ }
569
+ _.each(transaction.inputs, function (input) {
570
+ if (!input.output || !input.output.script) {
571
+ self.uncheckedAddInput(new Input(input));
572
+ return;
573
+ }
574
+ var script = new Script(input.output.script);
575
+ var txin;
576
+ if (script.isPublicKeyHashOut()) {
577
+ txin = new Input.PublicKeyHash(input);
578
+ } else if (script.isPublicKeyOut()) {
579
+ txin = new Input.PublicKey(input);
580
+ } else {
581
+ txin = new Input(input)
582
+ }
583
+ self.addInput(txin);
584
+ });
585
+ _.each(transaction.outputs, function (output) {
586
+ self.addOutput(new Output(output));
587
+ });
588
+ if (transaction.changeIndex) {
589
+ this._changeIndex = transaction.changeIndex;
590
+ }
591
+ if (transaction.changeScript) {
592
+ this._changeScript = new Script(transaction.changeScript);
593
+ }
594
+ if (transaction.changeAddress) {
595
+ this._changeAddress = Address.fromString(transaction.changeAddress);
596
+ }
597
+ if (transaction.changeData) {
598
+ this._changeData = transaction.changeData;
599
+ }
600
+ if (transaction.fee) {
601
+ this._fee = transaction.fee;
602
+ }
603
+ this.nLockTime = transaction.nLockTime;
604
+ this.version = transaction.version;
605
+ this._checkConsistency(arg);
606
+ return this;
607
+ };
608
+
609
+ /**
610
+ * Checks transaction consistency by validating:
611
+ * - Change output script and address (if change index is set)
612
+ * - Transaction hash (if provided in arg)
613
+ * @param {Object} [arg] - Optional argument containing expected hash
614
+ * @throws {Error} If any consistency check fails
615
+ * @private
616
+ */
617
+ Transaction.prototype._checkConsistency = function (arg) {
618
+ if (!_.isUndefined(this._changeIndex)) {
619
+ $.checkState(this._changeScript, 'Change script is expected.');
620
+ $.checkState(this._changeAddress, 'Change address is expected.');
621
+ $.checkState(this.outputs[this._changeIndex], 'Change index points to undefined output.');
622
+ $.checkState(
623
+ this.outputs[this._changeIndex].script.toString() === this._changeScript.toString(),
624
+ 'Change output has an unexpected script.',
625
+ );
626
+ }
627
+ if (arg && arg.hash) {
628
+ $.checkState(arg.hash === this.hash, 'Hash in object does not match transaction hash.');
629
+ }
630
+ };
631
+
632
+
633
+ /**
634
+ * Sets nLockTime so that transaction is not valid until the desired date(a
635
+ * timestamp in seconds since UNIX epoch is also accepted)
636
+ * @param {number|Date} time - The lock time as a timestamp (number) or Date object.
637
+ * @throws {Transaction.LockTimeTooEarly} If the time is a number below NLOCKTIME_BLOCKHEIGHT_LIMIT.
638
+ * @returns {Transaction} The transaction instance for chaining.
639
+ */
640
+ Transaction.prototype.lockUntilDate = function (time) {
641
+ $.checkArgument(time);
642
+ if (_.isNumber(time) && time < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
643
+ throw new errors.Transaction.LockTimeTooEarly();
644
+ }
645
+ if (_.isDate(time)) {
646
+ time = time.getTime() / 1000;
647
+ }
648
+
649
+ for (var i = 0; i < this.inputs.length; i++) {
650
+ if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER) {
651
+ this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER;
652
+ }
653
+ }
654
+
655
+ this.nLockTime = time;
656
+ return this;
657
+ };
658
+
659
+
660
+ /**
661
+ * Sets the transaction's lock time to a specific block height.
662
+ * Validates the height is within allowed bounds (0 <= height < NLOCKTIME_BLOCKHEIGHT_LIMIT).
663
+ * Updates sequence numbers of inputs to enable lock time if using default sequence.
664
+ * @param {number} height - The block height to lock until (must be non-negative and below limit)
665
+ * @returns {Transaction} Returns the transaction instance for chaining
666
+ * @throws {Transaction.BlockHeightTooHigh} If height exceeds block height limit
667
+ * @throws {Transaction.NLockTimeOutOfRange} If height is negative
668
+ */
669
+ Transaction.prototype.lockUntilBlockHeight = function (height) {
670
+ $.checkArgument(_.isNumber(height));
671
+ if (height >= Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
672
+ throw new errors.Transaction.BlockHeightTooHigh();
673
+ }
674
+ if (height < 0) {
675
+ throw new errors.Transaction.NLockTimeOutOfRange();
676
+ }
677
+
678
+ for (var i = 0; i < this.inputs.length; i++) {
679
+ if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER) {
680
+ this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER;
681
+ }
682
+ }
683
+
684
+ this.nLockTime = height;
685
+ return this;
686
+ };
687
+
688
+ /**
689
+ * Returns a semantic version of the transaction's nLockTime.
690
+ * @return {Number|Date}
691
+ * If nLockTime is 0, it returns null,
692
+ * if it is < 500000000, it returns a block height (number)
693
+ * else it returns a Date object.
694
+ */
695
+ Transaction.prototype.getLockTime = function () {
696
+ if (!this.nLockTime) {
697
+ return null;
698
+ }
699
+ if (this.nLockTime < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
700
+ return this.nLockTime;
701
+ }
702
+ return new Date(1000 * this.nLockTime);
703
+ };
704
+
705
+ /**
706
+ * Converts a hex string into a transaction buffer and initializes the transaction.
707
+ * @param {string} string - Hex string representation of the transaction data.
708
+ * @returns {Transaction} The transaction instance initialized from the hex string.
709
+ */
710
+ Transaction.prototype.fromString = function (string) {
711
+ return this.fromBuffer(Buffer.from(string, 'hex'));
712
+ };
713
+
714
+ /**
715
+ * Initializes a new transaction with default values.
716
+ * Sets the version to CURRENT_VERSION and nLockTime to DEFAULT_NLOCKTIME.
717
+ * @private
718
+ */
719
+ Transaction.prototype._newTransaction = function () {
720
+ this.version = CURRENT_VERSION;
721
+ this.nLockTime = DEFAULT_NLOCKTIME;
722
+ };
723
+
724
+ /* Transaction creation interface */
725
+
726
+ /**
727
+ * @typedef {Object} Transaction~fromObject
728
+ * @property {string} prevTxId
729
+ * @property {number} outputIndex
730
+ * @property {(Buffer|string|Script)} script
731
+ * @property {number} satoshis
732
+ */
733
+
734
+ /**
735
+ * Add an input to this transaction. This is a high level interface
736
+ * to add an input, for more control, use @{link Transaction#addInput}.
737
+ *
738
+ * Can receive, as output information, the output of bitcoind's `listunspent` command,
739
+ * and a slightly fancier format recognized by opcat:
740
+ *
741
+ * ```
742
+ * {
743
+ * address: 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1',
744
+ * txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
745
+ * outputIndex: 0,
746
+ * script: Script.empty(),
747
+ * satoshis: 1020000
748
+ * }
749
+ * ```
750
+ * Where `address` can be either a string or a opcat Address object. The
751
+ * same is true for `script`, which can be a string or a opcat Script.
752
+ *
753
+ * Beware that this resets all the signatures for inputs (in further versions,
754
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
755
+ *
756
+ * @example
757
+ * ```javascript
758
+ * var transaction = new Transaction();
759
+ *
760
+ * // From a pay to public key hash output from bitcoind's listunspent
761
+ * transaction.from({'txid': '0000...', vout: 0, amount: 0.1, scriptPubKey: 'OP_DUP ...'});
762
+ *
763
+ * // From a pay to public key hash output
764
+ * transaction.from({'txId': '0000...', outputIndex: 0, satoshis: 1000, script: 'OP_DUP ...'});
765
+ *
766
+ * ```
767
+ *
768
+ * @param {(Array.<Transaction~fromObject>|Transaction~fromObject)} utxo
769
+ * @param {Array=} pubkeys
770
+ * @param {number=} threshold
771
+ * @returns {Transaction} The transaction instance for chaining.
772
+ */
773
+ Transaction.prototype.from = function (utxo) {
774
+ if (_.isArray(utxo)) {
775
+ var self = this;
776
+ _.each(utxo, function (utxo) {
777
+ self.from(utxo);
778
+ });
779
+ return this;
780
+ }
781
+ var exists = _.some(this.inputs, function (input) {
782
+ // TODO: Maybe prevTxId should be a string? Or defined as read only property?
783
+ return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex;
784
+ });
785
+ if (exists) {
786
+ return this;
787
+ }
788
+ this._fromUTXO(utxo);
789
+ return this;
790
+ };
791
+
792
+ /**
793
+ * Adds an input to the transaction from a UTXO (Unspent Transaction Output).
794
+ * Determines the appropriate input type (PublicKeyHashInput, PublicKeyInput, or generic Input)
795
+ * based on the UTXO's script type.
796
+ * @param {Object} utxo - The UTXO to create input from
797
+ * @param {Script} utxo.script - The output script
798
+ * @param {number} utxo.satoshis - The output amount in satoshis
799
+ * @param {Buffer} [utxo.data] - Optional output data
800
+ * @param {string} utxo.txId - The previous transaction ID
801
+ * @param {number} utxo.outputIndex - The output index in previous transaction
802
+ * @private
803
+ */
804
+ Transaction.prototype._fromUTXO = function (utxo) {
805
+ var Clazz;
806
+ utxo = new UnspentOutput(utxo);
807
+ if (utxo.script.isPublicKeyHashOut()) {
808
+ Clazz = PublicKeyHashInput;
809
+ } else if (utxo.script.isPublicKeyOut()) {
810
+ Clazz = PublicKeyInput;
811
+ } else {
812
+ Clazz = Input;
813
+ }
814
+ this.addInput(
815
+ new Clazz({
816
+ output: new Output({
817
+ script: utxo.script,
818
+ satoshis: utxo.satoshis,
819
+ data: utxo.data || Buffer.from([]),
820
+ }),
821
+ prevTxId: utxo.txId,
822
+ outputIndex: utxo.outputIndex,
823
+ script: Script.empty(),
824
+ }),
825
+ );
826
+ };
827
+
828
+
829
+ /**
830
+ * Add an input to this transaction. The input must be an instance of the `Input` class.
831
+ * It should have information about the Output that it's spending, but if it's not already
832
+ * set, three additional parameters, `outputScript`, `satoshis` and `data` can be provided.
833
+ * @param {Input} input - The input to add
834
+ * @param {Script|string} [outputScript] - The output script (required if input doesn't have output)
835
+ * @param {number} [satoshis] - The satoshis amount (required if input doesn't have output)
836
+ * @param {Buffer|string} [data] - Additional data for the output
837
+ * @returns {Transaction} The transaction instance for chaining
838
+ * @throws {errors.Transaction.NeedMoreInfo} If input has no output and missing required params
839
+ */
840
+ Transaction.prototype.addInput = function (input, outputScript, satoshis, data) {
841
+ $.checkArgumentType(input, Input, 'input');
842
+ if (!input.output && (_.isUndefined(outputScript) || _.isUndefined(satoshis))) {
843
+ throw new errors.Transaction.NeedMoreInfo(
844
+ 'Need information about the UTXO script and satoshis',
845
+ );
846
+ }
847
+ if (!input.output && outputScript && !_.isUndefined(satoshis)) {
848
+ outputScript = outputScript instanceof Script ? outputScript : new Script(outputScript);
849
+ $.checkArgumentType(satoshis, 'number', 'satoshis');
850
+
851
+ input.output = new Output({
852
+ script: outputScript,
853
+ satoshis: satoshis,
854
+ data: data,
855
+ });
856
+ }
857
+ return this.uncheckedAddInput(input);
858
+ };
859
+
860
+ /**
861
+ * Add an input to this transaction, without checking that the input has information about
862
+ * the output that it's spending.
863
+ *
864
+ * @param {Input} input
865
+ * @return Transaction this, for chaining
866
+ */
867
+ Transaction.prototype.uncheckedAddInput = function (input) {
868
+ $.checkArgumentType(input, Input, 'input');
869
+ this.inputs.push(input);
870
+ this._inputAmount = undefined;
871
+ this._updateChangeOutput();
872
+ return this;
873
+ };
874
+
875
+ /**
876
+ * Returns true if the transaction has enough info on all inputs to be correctly validated
877
+ *
878
+ * @return {boolean}
879
+ */
880
+ Transaction.prototype.hasAllUtxoInfo = function () {
881
+ return _.every(
882
+ this.inputs.map(function (input) {
883
+ return !!input.output;
884
+ }),
885
+ );
886
+ };
887
+
888
+ /**
889
+ * Manually set the fee for this transaction. Beware that this resets all the signatures
890
+ * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not
891
+ * be reset).
892
+ *
893
+ * @param {number} amount satoshis to be sent
894
+ * @return {Transaction} this, for chaining
895
+ */
896
+ Transaction.prototype.fee = function (amount) {
897
+ $.checkArgument(_.isNumber(amount), 'amount must be a number');
898
+ this._fee = amount;
899
+ this._updateChangeOutput();
900
+ return this;
901
+ };
902
+
903
+ /**
904
+ * Manually set the fee per KB for this transaction. Beware that this resets all the signatures
905
+ * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not
906
+ * be reset).
907
+ *
908
+ * @param {number} amount satoshis per KB to be sent
909
+ * @return {Transaction} this, for chaining
910
+ */
911
+ Transaction.prototype.feePerKb = function (amount) {
912
+ $.checkArgument(_.isNumber(amount), 'amount must be a number');
913
+ this._feePerKb = amount;
914
+ this._updateChangeOutput();
915
+ return this;
916
+ };
917
+
918
+ /* Output management */
919
+
920
+ /**
921
+ * Set the change address for this transaction
922
+ *
923
+ * Beware that this resets all the signatures for inputs (in further versions,
924
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
925
+ *
926
+ * @param {Address} address An address for change to be sent to.
927
+ * @param {Buffer|string} data The data to be stored in the change output.
928
+ * @return {Transaction} this, for chaining
929
+ */
930
+ Transaction.prototype.change = function (address, data) {
931
+ $.checkArgument(address, 'address is required');
932
+ this._changeScript = Script.fromAddress(address);
933
+ this._changeAddress = Address(address);
934
+ if (data) {
935
+ this._changeData = data
936
+ }
937
+ this._updateChangeOutput();
938
+ return this;
939
+ };
940
+
941
+
942
+ /**
943
+ * Gets the change output from the transaction outputs.
944
+ * @returns {Output|null} The change output object if defined, otherwise null.
945
+ */
946
+ Transaction.prototype.getChangeOutput = function () {
947
+ if (!_.isUndefined(this._changeIndex)) {
948
+ return this.outputs[this._changeIndex];
949
+ }
950
+ return null;
951
+ };
952
+
953
+
954
+ /**
955
+ * Gets the change address for this transaction.
956
+ * @returns {Address|null} The change address if set, otherwise null.
957
+ */
958
+ Transaction.prototype.getChangeAddress = function () {
959
+ return this._changeAddress ? this._changeAddress : null;
960
+ };
961
+
962
+
963
+
964
+ /**
965
+ * Add an output to the transaction.
966
+ *
967
+ * Beware that this resets all the signatures for inputs (in further versions,
968
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
969
+ *
970
+ * @param {(string|Address|Array<Address>)} address
971
+ * @param {number} amount in satoshis
972
+ * @return {Transaction} this, for chaining
973
+ */
974
+ Transaction.prototype.to = function (address, amount) {
975
+ if (_.isArray(address)) {
976
+ var self = this;
977
+ _.each(address, function (to) {
978
+ self.to(to.address, to.satoshis);
979
+ });
980
+ return this;
981
+ }
982
+
983
+ $.checkArgument(JSUtil.isNaturalNumber(amount), 'Amount is expected to be a positive integer');
984
+ this.addOutput(
985
+ new Output({
986
+ script: Script(new Address(address)),
987
+ satoshis: amount,
988
+ }),
989
+ );
990
+ return this;
991
+ };
992
+
993
+ /**
994
+ * Add an OP_RETURN output to the transaction.
995
+ *
996
+ * Beware that this resets all the signatures for inputs (in further versions,
997
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
998
+ *
999
+ * @param {Buffer|string} value the data to be stored in the OP_RETURN output.
1000
+ * In case of a string, the UTF-8 representation will be stored
1001
+ * @return {Transaction} this, for chaining
1002
+ */
1003
+ Transaction.prototype.addData = function (value) {
1004
+ this.addOutput(
1005
+ new Output({
1006
+ script: Script.buildDataOut(value),
1007
+ satoshis: 0,
1008
+ }),
1009
+ );
1010
+ return this;
1011
+ };
1012
+
1013
+ /**
1014
+ * Add an OP_FALSE | OP_RETURN output to the transaction.
1015
+ *
1016
+ * Beware that this resets all the signatures for inputs (in further versions,
1017
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
1018
+ *
1019
+ * @param {Buffer|string} value the data to be stored in the OP_RETURN output.
1020
+ * In case of a string, the UTF-8 representation will be stored
1021
+ * @return {Transaction} this, for chaining
1022
+ */
1023
+ Transaction.prototype.addSafeData = function (value) {
1024
+ this.addOutput(
1025
+ new Output({
1026
+ script: Script.buildSafeDataOut(value),
1027
+ satoshis: 0,
1028
+ }),
1029
+ );
1030
+ return this;
1031
+ };
1032
+
1033
+ /**
1034
+ * Add an output to the transaction.
1035
+ *
1036
+ * @param {Output} output the output to add.
1037
+ * @return {Transaction} this, for chaining
1038
+ */
1039
+ Transaction.prototype.addOutput = function (output) {
1040
+ $.checkArgumentType(output, Output, 'output');
1041
+ this._addOutput(output);
1042
+ this._updateChangeOutput();
1043
+ return this;
1044
+ };
1045
+
1046
+ /**
1047
+ * Remove all outputs from the transaction.
1048
+ *
1049
+ * @return {Transaction} this, for chaining
1050
+ */
1051
+ Transaction.prototype.clearOutputs = function () {
1052
+ this.outputs = [];
1053
+ this._clearSignatures();
1054
+ this._outputAmount = undefined;
1055
+ this._changeIndex = undefined;
1056
+ this._updateChangeOutput();
1057
+ return this;
1058
+ };
1059
+
1060
+ /**
1061
+ * Adds an output to the transaction.
1062
+ * @param {Output} output - The output to add to the transaction.
1063
+ * @private
1064
+ */
1065
+ Transaction.prototype._addOutput = function (output) {
1066
+ this.outputs.push(output);
1067
+ this._outputAmount = undefined;
1068
+ };
1069
+
1070
+ /**
1071
+ * Calculates or gets the total output amount in satoshis
1072
+ *
1073
+ * @return {Number} the transaction total output amount
1074
+ * @private
1075
+ */
1076
+ Transaction.prototype._getOutputAmount = function () {
1077
+ if (_.isUndefined(this._outputAmount)) {
1078
+ var self = this;
1079
+ this._outputAmount = 0;
1080
+ _.each(this.outputs, function (output) {
1081
+ self._outputAmount += output.satoshis;
1082
+ });
1083
+ }
1084
+ return this._outputAmount;
1085
+ };
1086
+
1087
+ /**
1088
+ * Calculates or gets the total input amount in satoshis
1089
+ *
1090
+ * @return {Number} the transaction total input amount
1091
+ * @private
1092
+ */
1093
+ Transaction.prototype._getInputAmount = function () {
1094
+ if (_.isUndefined(this._inputAmount)) {
1095
+ var self = this;
1096
+ this._inputAmount = 0;
1097
+ _.each(this.inputs, function (input) {
1098
+ if (_.isUndefined(input.output)) {
1099
+ throw new errors.Transaction.Input.MissingPreviousOutput();
1100
+ }
1101
+ self._inputAmount += input.output.satoshis;
1102
+ });
1103
+ }
1104
+ return this._inputAmount;
1105
+ };
1106
+
1107
+ /**
1108
+ * Updates the change output of the transaction.
1109
+ * - Removes existing change output if present.
1110
+ * - Calculates available change amount after fee.
1111
+ * - Adds new change output if amount is above dust threshold.
1112
+ * - Clears any existing signatures.
1113
+ * @throws {TransactionAlreadySealed} If transaction is already sealed.
1114
+ * @private
1115
+ */
1116
+ Transaction.prototype._updateChangeOutput = function () {
1117
+ if (this.sealed) {
1118
+ throw new errors.Transaction.TransactionAlreadySealed();
1119
+ }
1120
+
1121
+ if (!this._changeScript) {
1122
+ return;
1123
+ }
1124
+ if (!_.isUndefined(this._changeIndex)) {
1125
+ this._removeOutput(this._changeIndex);
1126
+ }
1127
+ this._changeIndex = this.outputs.length;
1128
+ this._addOutput(
1129
+ new Output({
1130
+ script: this._changeScript,
1131
+ satoshis: 0,
1132
+ data: this._changeData || ''
1133
+ }),
1134
+ );
1135
+ var available = this.getUnspentValue();
1136
+ var fee = this.getFee();
1137
+ var changeAmount = available - fee;
1138
+ this._removeOutput(this._changeIndex);
1139
+ this._changeIndex = undefined;
1140
+ if (changeAmount >= Transaction.DUST_AMOUNT) {
1141
+ this._changeIndex = this.outputs.length;
1142
+ this._addOutput(
1143
+ new Output({
1144
+ script: this._changeScript,
1145
+ satoshis: changeAmount,
1146
+ data: this._changeData || ''
1147
+ }),
1148
+ );
1149
+ }
1150
+ this._clearSignatures();
1151
+ };
1152
+ /**
1153
+ * Calculates the fee of the transaction.
1154
+ *
1155
+ * If there's a fixed fee set, return that.
1156
+ *
1157
+ * If there is no change output set, the fee is the
1158
+ * total value of the outputs minus inputs. Note that
1159
+ * a serialized transaction only specifies the value
1160
+ * of its outputs. (The value of inputs are recorded
1161
+ * in the previous transaction outputs being spent.)
1162
+ * This method therefore raises a "MissingPreviousOutput"
1163
+ * error when called on a serialized transaction.
1164
+ *
1165
+ * If there's no fee set and no change address,
1166
+ * estimate the fee based on size.
1167
+ *
1168
+ * @return {Number} fee of this transaction in satoshis
1169
+ */
1170
+ Transaction.prototype.getFee = function () {
1171
+ if (this.isCoinbase()) {
1172
+ return 0;
1173
+ }
1174
+ if (!_.isUndefined(this._fee)) {
1175
+ return this._fee;
1176
+ }
1177
+ // if no change output is set, fees should equal all the unspent amount
1178
+ if (!this._changeScript) {
1179
+ return this.getUnspentValue();
1180
+ }
1181
+ return this._estimateFee();
1182
+ };
1183
+
1184
+ /**
1185
+ * Estimates fee from serialized transaction size in bytes.
1186
+ * @private
1187
+ */
1188
+ Transaction.prototype._estimateFee = function () {
1189
+ var estimatedSize = this._estimateSize();
1190
+ return Math.ceil((estimatedSize / 1000) * (this._feePerKb || Transaction.FEE_PER_KB));
1191
+ };
1192
+
1193
+ /**
1194
+ * Calculates the unspent value (difference between input and output amounts) of the transaction.
1195
+ * @returns {number} The unspent value (input amount minus output amount).
1196
+ */
1197
+ Transaction.prototype.getUnspentValue = function () {
1198
+ return this._getInputAmount() - this._getOutputAmount();
1199
+ };
1200
+
1201
+ /**
1202
+ * Clears all signatures from the transaction inputs.
1203
+ * @private
1204
+ */
1205
+ Transaction.prototype._clearSignatures = function () {
1206
+ _.each(this.inputs, function (input) {
1207
+ input.clearSignatures();
1208
+ });
1209
+ };
1210
+
1211
+ // 4 version
1212
+ // ??? num inputs (VARINT)
1213
+ // --- input list ---
1214
+ //
1215
+ // ??? num outputs (VARINT)
1216
+ // --- output list ---
1217
+ // 8 value
1218
+ // ??? script size (VARINT)
1219
+ // ??? script
1220
+ //
1221
+ // 4 locktime
1222
+ /**
1223
+ * Gets the estimated size of the transaction.
1224
+ * @returns {number} The estimated size in bytes.
1225
+ */
1226
+ Transaction.prototype.getEstimateSize = function () {
1227
+ return this._estimateSize();
1228
+ };
1229
+
1230
+ /**
1231
+ * Estimates the total size of the transaction in bytes.
1232
+ * Calculates the sum of:
1233
+ * - Fixed header size (version + locktime)
1234
+ * - Varint-encoded input/output counts
1235
+ * - Each input's estimated size
1236
+ * - Each output's fixed size
1237
+ * @returns {number} The estimated transaction size in bytes
1238
+ * @private
1239
+ */
1240
+ Transaction.prototype._estimateSize = function () {
1241
+ var result = 4 + 4; // size of version + size of locktime
1242
+ result += Varint(this.inputs.length).toBuffer().length;
1243
+ result += Varint(this.outputs.length).toBuffer().length;
1244
+ _.each(this.inputs, function (input) {
1245
+ result += input._estimateSize();
1246
+ });
1247
+ _.each(this.outputs, function (output) {
1248
+ result += output.getSize();
1249
+ });
1250
+ return result;
1251
+ };
1252
+
1253
+ /**
1254
+ * Removes an output from the transaction by index.
1255
+ * @param {number} index - The index of the output to remove.
1256
+ * @private
1257
+ */
1258
+ Transaction.prototype._removeOutput = function (index) {
1259
+ var output = this.outputs[index];
1260
+ this.outputs = _.without(this.outputs, output);
1261
+ this._outputAmount = undefined;
1262
+ };
1263
+
1264
+ /**
1265
+ * Removes an output from the transaction at the specified index and updates the change output.
1266
+ * @param {number} index - The index of the output to remove.
1267
+ */
1268
+ Transaction.prototype.removeOutput = function (index) {
1269
+ this._removeOutput(index);
1270
+ this._updateChangeOutput();
1271
+ };
1272
+
1273
+ /**
1274
+ * Sort a transaction's inputs and outputs according to BIP69
1275
+ *
1276
+ * @see {https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki}
1277
+ * @return {Transaction} this
1278
+ */
1279
+ Transaction.prototype.sort = function () {
1280
+ this.sortInputs(function (inputs) {
1281
+ var copy = Array.prototype.concat.apply([], inputs);
1282
+ copy.sort(function (first, second) {
1283
+ return first.prevTxId.compare(second.prevTxId) || first.outputIndex - second.outputIndex;
1284
+ });
1285
+ return copy;
1286
+ });
1287
+ this.sortOutputs(function (outputs) {
1288
+ var copy = Array.prototype.concat.apply([], outputs);
1289
+ copy.sort(function (first, second) {
1290
+ return (
1291
+ first.satoshis - second.satoshis ||
1292
+ first.script.toBuffer().compare(second.script.toBuffer())
1293
+ );
1294
+ });
1295
+ return copy;
1296
+ });
1297
+ return this;
1298
+ };
1299
+
1300
+ /**
1301
+ * Randomize this transaction's outputs ordering. The shuffling algorithm is a
1302
+ * version of the Fisher-Yates shuffle.
1303
+ *
1304
+ * @return {Transaction} this
1305
+ */
1306
+ Transaction.prototype.shuffleOutputs = function () {
1307
+ return this.sortOutputs(_.shuffle);
1308
+ };
1309
+
1310
+ /**
1311
+ * Sort this transaction's outputs, according to a given sorting function that
1312
+ * takes an array as argument and returns a new array, with the same elements
1313
+ * but with a different order. The argument function MUST NOT modify the order
1314
+ * of the original array
1315
+ *
1316
+ * @param {Function} sortingFunction
1317
+ * @return {Transaction} this
1318
+ */
1319
+ Transaction.prototype.sortOutputs = function (sortingFunction) {
1320
+ var outs = sortingFunction(this.outputs);
1321
+ return this._newOutputOrder(outs);
1322
+ };
1323
+
1324
+ /**
1325
+ * Sort this transaction's inputs, according to a given sorting function that
1326
+ * takes an array as argument and returns a new array, with the same elements
1327
+ * but with a different order.
1328
+ *
1329
+ * @param {Function} sortingFunction
1330
+ * @return {Transaction} this
1331
+ */
1332
+ Transaction.prototype.sortInputs = function (sortingFunction) {
1333
+ this.inputs = sortingFunction(this.inputs);
1334
+ this._clearSignatures();
1335
+ return this;
1336
+ };
1337
+
1338
+ /**
1339
+ * Updates the order of transaction outputs while maintaining consistency.
1340
+ * Validates that new outputs match original outputs before applying the change.
1341
+ * Adjusts the change output index if it exists.
1342
+ *
1343
+ * @param {Array} newOutputs - The new ordered outputs array
1344
+ * @returns {Transaction} Returns the transaction instance for chaining
1345
+ * @throws {Transaction.InvalidSorting} If output arrays don't match
1346
+ * @private
1347
+ */
1348
+ Transaction.prototype._newOutputOrder = function (newOutputs) {
1349
+ var isInvalidSorting =
1350
+ this.outputs.length !== newOutputs.length ||
1351
+ _.difference(this.outputs, newOutputs).length !== 0;
1352
+ if (isInvalidSorting) {
1353
+ throw new errors.Transaction.InvalidSorting();
1354
+ }
1355
+
1356
+ if (!_.isUndefined(this._changeIndex)) {
1357
+ var changeOutput = this.outputs[this._changeIndex];
1358
+ this._changeIndex = newOutputs.indexOf(changeOutput);
1359
+ }
1360
+
1361
+ this.outputs = newOutputs;
1362
+ return this;
1363
+ };
1364
+
1365
+ /**
1366
+ * Removes an input from the transaction by either its index or txId/outputIndex pair.
1367
+ * @param {string|number} txId - Transaction ID (as hex string) or input index if outputIndex is omitted.
1368
+ * @param {number} [outputIndex] - Output index of the input to remove (required if txId is string).
1369
+ * @throws {Transaction.InvalidIndex} If input index is out of bounds.
1370
+ */
1371
+ Transaction.prototype.removeInput = function (txId, outputIndex) {
1372
+ var index;
1373
+ if (!outputIndex && _.isNumber(txId)) {
1374
+ index = txId;
1375
+ } else {
1376
+ index = _.findIndex(this.inputs, function (input) {
1377
+ return input.prevTxId.toString('hex') === txId && input.outputIndex === outputIndex;
1378
+ });
1379
+ }
1380
+ if (index < 0 || index >= this.inputs.length) {
1381
+ throw new errors.Transaction.InvalidIndex(index, this.inputs.length);
1382
+ }
1383
+ var input = this.inputs[index];
1384
+ this.inputs = _.without(this.inputs, input);
1385
+ this._inputAmount = undefined;
1386
+ this._updateChangeOutput();
1387
+ };
1388
+
1389
+
1390
+ /**
1391
+ * Sign the transaction using one or more private keys.
1392
+ *
1393
+ * It tries to sign each input, verifying that the signature will be valid
1394
+ * (matches a public key).
1395
+ * @param {Buffer|Array<Buffer>} privateKey - Private key(s) to sign the transaction with.
1396
+ * @param {number} [sigtype] - Optional signature type.
1397
+ * @returns {Transaction} Returns the transaction instance for chaining.
1398
+ * @throws {Error} Throws if not all UTXO information is available.
1399
+ */
1400
+ Transaction.prototype.sign = function (privateKey, sigtype) {
1401
+ $.checkState(
1402
+ this.hasAllUtxoInfo(),
1403
+ 'Not all utxo information is available to sign the transaction.',
1404
+ );
1405
+ var self = this;
1406
+ if (_.isArray(privateKey)) {
1407
+ _.each(privateKey, function (privateKey) {
1408
+ self.sign(privateKey, sigtype);
1409
+ });
1410
+ return this;
1411
+ }
1412
+ _.each(this.getSignatures(privateKey, sigtype), function (signature) {
1413
+ self.applySignature(signature);
1414
+ });
1415
+
1416
+ this._privateKey = privateKey;
1417
+ this._sigType = sigtype;
1418
+ return this;
1419
+ };
1420
+
1421
+ /**
1422
+ * Generates signatures for all inputs in the transaction using the provided private key.
1423
+ * @param {string|PrivateKey} privKey - The private key to sign with (can be string or PrivateKey instance).
1424
+ * @param {number} [sigtype=Signature.SIGHASH_ALL] - The signature hash type (defaults to SIGHASH_ALL).
1425
+ * @returns {Array} Array of generated signatures for the transaction inputs.
1426
+ */
1427
+ Transaction.prototype.getSignatures = function (privKey, sigtype) {
1428
+ privKey = new PrivateKey(privKey);
1429
+ // By default, signs using SIGHASH_ALL
1430
+ sigtype = sigtype || Signature.SIGHASH_ALL;
1431
+ var transaction = this;
1432
+ var results = [];
1433
+ var hashData = Hash.sha256ripemd160(privKey.publicKey.toBuffer());
1434
+ _.each(this.inputs, function forEachInput(input, index) {
1435
+ _.each(
1436
+ input.getSignatures(transaction, privKey, index, sigtype, hashData),
1437
+ function (signature) {
1438
+ results.push(signature);
1439
+ },
1440
+ );
1441
+ });
1442
+ return results;
1443
+ };
1444
+
1445
+ /**
1446
+ * Add a signature to the transaction
1447
+ *
1448
+ * @param {Object} signature
1449
+ * @param {number} signature.inputIndex
1450
+ * @param {number} signature.sigtype
1451
+ * @param {PublicKey} signature.publicKey
1452
+ * @param {Signature} signature.signature
1453
+ * @return {Transaction} this, for chaining
1454
+ */
1455
+ Transaction.prototype.applySignature = function (signature) {
1456
+ this.inputs[signature.inputIndex].addSignature(this, signature);
1457
+ return this;
1458
+ };
1459
+
1460
+ /**
1461
+ * Checks if all inputs in the transaction are fully signed.
1462
+ * @returns {boolean} True if all inputs have valid signatures, false otherwise.
1463
+ * @throws {errors.Transaction.UnableToVerifySignature} If any input has an unrecognized script kind
1464
+ * or insufficient information to verify signatures (common when deserializing transactions).
1465
+ */
1466
+ Transaction.prototype.isFullySigned = function () {
1467
+ _.each(this.inputs, function (input) {
1468
+ if (input.isFullySigned === Input.prototype.isFullySigned) {
1469
+ throw new errors.Transaction.UnableToVerifySignature(
1470
+ 'Unrecognized script kind, or not enough information to execute script.' +
1471
+ 'This usually happens when creating a transaction from a serialized transaction',
1472
+ );
1473
+ }
1474
+ });
1475
+ return _.every(
1476
+ _.map(this.inputs, function (input) {
1477
+ return input.isFullySigned();
1478
+ }),
1479
+ );
1480
+ };
1481
+
1482
+ /**
1483
+ * Validates a signature for a transaction input.
1484
+ * @param {Object} signature - The signature object to validate.
1485
+ * @throws {errors.Transaction.UnableToVerifySignature} If the input script is unrecognized or lacks execution info.
1486
+ * @returns {boolean} True if the signature is valid for the specified input.
1487
+ */
1488
+ Transaction.prototype.isValidSignature = function (signature) {
1489
+ var self = this;
1490
+ if (this.inputs[signature.inputIndex].isValidSignature === Input.prototype.isValidSignature) {
1491
+ throw new errors.Transaction.UnableToVerifySignature(
1492
+ 'Unrecognized script kind, or not enough information to execute script.' +
1493
+ 'This usually happens when creating a transaction from a serialized transaction',
1494
+ );
1495
+ }
1496
+ return this.inputs[signature.inputIndex].isValidSignature(self, signature);
1497
+ };
1498
+
1499
+
1500
+ /**
1501
+ * Verifies a signature for this transaction.
1502
+ * @param {Buffer} sig - The signature to verify.
1503
+ * @param {Buffer} pubkey - The public key corresponding to the signature.
1504
+ * @param {number} nin - The input index being signed.
1505
+ * @returns {boolean} True if the signature is valid, false otherwise.
1506
+ */
1507
+ Transaction.prototype.verifySignature = function (sig, pubkey, nin) {
1508
+ return Sighash.verify(this, sig, pubkey, nin);
1509
+ };
1510
+
1511
+
1512
+ /**
1513
+ * Check that a transaction passes basic sanity tests. If not, return a string
1514
+ * describing the error. This function contains the same logic as
1515
+ * CheckTransaction in bitcoin core.
1516
+ *
1517
+ * Checks include:
1518
+ * - Non-empty inputs and outputs
1519
+ * - Valid output satoshis (non-negative, not exceeding MAX_MONEY)
1520
+ * - No duplicate inputs
1521
+ * - Coinbase script size validation (if coinbase)
1522
+ * - Input null checks and verification (if not coinbase and notVerifyInput is false)
1523
+ *
1524
+ * @param {boolean} [notVerifyInput=false] - Whether to skip input verification
1525
+ * @returns {true|string} Returns true if valid, or an error message string if invalid
1526
+ */
1527
+ Transaction.prototype.verify = function (notVerifyInput) {
1528
+ // Basic checks that don't depend on any context
1529
+ if (this.inputs.length === 0) {
1530
+ return 'transaction txins empty';
1531
+ }
1532
+
1533
+ if (this.outputs.length === 0) {
1534
+ return 'transaction txouts empty';
1535
+ }
1536
+
1537
+ // Check for negative or overflow output values
1538
+ var valueoutbn = new BN(0);
1539
+ for (var i = 0; i < this.outputs.length; i++) {
1540
+ var txout = this.outputs[i];
1541
+
1542
+ if (txout.invalidSatoshis()) {
1543
+ return 'transaction txout ' + i + ' satoshis is invalid';
1544
+ }
1545
+ if (txout._satoshisBN.gt(new BN(Transaction.MAX_MONEY, 10))) {
1546
+ return 'transaction txout ' + i + ' greater than MAX_MONEY';
1547
+ }
1548
+ valueoutbn = valueoutbn.add(txout._satoshisBN);
1549
+ if (valueoutbn.gt(new BN(Transaction.MAX_MONEY))) {
1550
+ return 'transaction txout ' + i + ' total output greater than MAX_MONEY';
1551
+ }
1552
+ }
1553
+
1554
+ // Check for duplicate inputs
1555
+ var txinmap = {};
1556
+ for (i = 0; i < this.inputs.length; i++) {
1557
+ var txin = this.inputs[i];
1558
+
1559
+ var inputid = txin.prevTxId + ':' + txin.outputIndex;
1560
+ if (!_.isUndefined(txinmap[inputid])) {
1561
+ return 'transaction input ' + i + ' duplicate input';
1562
+ }
1563
+ txinmap[inputid] = true;
1564
+ }
1565
+
1566
+ var isCoinbase = this.isCoinbase();
1567
+ if (isCoinbase) {
1568
+ var buf = this.inputs[0]._scriptBuffer;
1569
+ if (buf.length < 2 || buf.length > 100) {
1570
+ return 'coinbase transaction script size invalid';
1571
+ }
1572
+ } else {
1573
+ for (i = 0; i < this.inputs.length; i++) {
1574
+ if (this.inputs[i].isNull()) {
1575
+ return 'transaction input ' + i + ' has null input';
1576
+ }
1577
+
1578
+ if (!notVerifyInput) {
1579
+ var res = this.inputs[i].verify(this, i);
1580
+ if (!res.success) {
1581
+ return 'transaction input ' + i + ' VerifyError: ' + res.error;
1582
+ }
1583
+ }
1584
+ }
1585
+ }
1586
+ return true;
1587
+ };
1588
+
1589
+
1590
+ /**
1591
+ * Checks if the transaction is a coinbase transaction.
1592
+ * A coinbase transaction has exactly one input and that input is null.
1593
+ * @returns {boolean} True if the transaction is a coinbase, false otherwise.
1594
+ */
1595
+ Transaction.prototype.isCoinbase = function () {
1596
+ return this.inputs.length === 1 && this.inputs[0].isNull();
1597
+ };
1598
+
1599
+
1600
+ /**
1601
+ * Sets the input script for a transaction input.
1602
+ * @param {number|Object} options - Either an input index number or an options object
1603
+ * @param {number} [options.inputIndex=0] - Input index if options is an object
1604
+ * @param {string} [options.privateKey] - Private key for signing
1605
+ * @param {number} [options.sigtype=Signature.SIGHASH_ALL] - Signature hash type
1606
+ * @param {boolean} [options.isLowS=false] - Whether to use low-S signatures
1607
+ * @param {Function|Script} unlockScriptOrCallback - Either a script or callback function that returns a script
1608
+ * @returns {Transaction} Returns the transaction instance for chaining
1609
+ */
1610
+ Transaction.prototype.setInputScript = function (options, unlockScriptOrCallback) {
1611
+ var inputIndex = 0;
1612
+ var privateKey;
1613
+ var sigtype;
1614
+ var isLowS = false;
1615
+ if (typeof options === 'number') {
1616
+ inputIndex = options;
1617
+ sigtype = Signature.SIGHASH_ALL;
1618
+ } else {
1619
+ inputIndex = options.inputIndex || 0;
1620
+ privateKey = options.privateKey;
1621
+ sigtype = options.sigtype || Signature.SIGHASH_ALL;
1622
+ isLowS = options.isLowS || false;
1623
+ }
1624
+
1625
+ if (unlockScriptOrCallback instanceof Function) {
1626
+ var outputInPrevTx = this.inputs[inputIndex].output;
1627
+ this._inputsMap.set(inputIndex, {
1628
+ sigtype,
1629
+ privateKey,
1630
+ isLowS,
1631
+ callback: unlockScriptOrCallback,
1632
+ });
1633
+ var unlockScript = unlockScriptOrCallback(this, outputInPrevTx);
1634
+ this.inputs[inputIndex].setScript(unlockScript);
1635
+ } else {
1636
+ this.inputs[inputIndex].setScript(unlockScriptOrCallback);
1637
+ }
1638
+
1639
+ return this;
1640
+ };
1641
+
1642
+
1643
+ /**
1644
+ * Sets the sequence number for a specific transaction input.
1645
+ * @param {number} inputIndex - The index of the input to update.
1646
+ * @param {number} sequence - The sequence number to set.
1647
+ * @returns {Transaction} Returns the transaction instance for chaining.
1648
+ */
1649
+ Transaction.prototype.setInputSequence = function (inputIndex, sequence) {
1650
+ this.inputs[inputIndex].sequenceNumber = sequence;
1651
+ return this;
1652
+ };
1653
+
1654
+
1655
+ /**
1656
+ * Sets an output at the specified index, either directly or via a callback function.
1657
+ * If a callback is provided, it will be invoked with the transaction instance to generate the output value.
1658
+ * Automatically updates the change output after setting.
1659
+ * @param {number} outputIndex - The index of the output to set
1660
+ * @param {any|Function} outputOrcb - The output value or a callback function that returns the output value
1661
+ * @returns {Transaction} Returns the transaction instance for chaining
1662
+ */
1663
+ Transaction.prototype.setOutput = function (outputIndex, outputOrcb) {
1664
+ if (outputOrcb instanceof Function) {
1665
+ this._outputsMap.set(outputIndex, outputOrcb);
1666
+ this.outputs[outputIndex] = outputOrcb(this);
1667
+ } else {
1668
+ this.outputs[outputIndex] = outputOrcb;
1669
+ }
1670
+
1671
+ this._updateChangeOutput();
1672
+ return this;
1673
+ };
1674
+
1675
+
1676
+ /**
1677
+ * Seals the transaction by processing all outputs and inputs.
1678
+ * - For each output, executes the registered callback to generate the final output.
1679
+ * - Updates the change output if applicable.
1680
+ * - For each input, generates and sets the unlock script using the registered callback.
1681
+ * - If a private key is provided, signs the transaction.
1682
+ * - Marks the transaction as sealed and returns the instance.
1683
+ * @returns {Transaction} The sealed transaction instance.
1684
+ */
1685
+ Transaction.prototype.seal = function () {
1686
+ var self = this;
1687
+
1688
+ this._outputsMap.forEach(function (callback, key) {
1689
+ self.outputs[key] = callback(self);
1690
+ });
1691
+
1692
+ this._updateChangeOutput();
1693
+
1694
+ this._inputsMap.forEach(function (options, key) {
1695
+ var outputInPrevTx = self.inputs[key].output;
1696
+ var unlockScript = options.callback(self, outputInPrevTx);
1697
+ self.inputs[key].setScript(unlockScript);
1698
+ });
1699
+
1700
+ if (this._privateKey) {
1701
+ this.sign(this._privateKey, this._sigType);
1702
+ }
1703
+
1704
+ this.sealed = true;
1705
+
1706
+ return this;
1707
+ };
1708
+
1709
+
1710
+ /**
1711
+ * Sets the lock time for the transaction.
1712
+ * @param {number} nLockTime - The lock time to set.
1713
+ * @returns {Transaction} Returns the transaction instance for chaining.
1714
+ */
1715
+ Transaction.prototype.setLockTime = function (nLockTime) {
1716
+ this.nLockTime = nLockTime;
1717
+ return this;
1718
+ };
1719
+
1720
+
1721
+ /**
1722
+ * Gets the amount of change (in satoshis) for this transaction.
1723
+ * @returns {number} The change amount in satoshis, or 0 if no change exists.
1724
+ */
1725
+ Transaction.prototype.getChangeAmount = function () {
1726
+ if (_.isUndefined(this._changeIndex)) {
1727
+ return 0;
1728
+ }
1729
+
1730
+ return this.outputs[this._changeIndex].satoshis;
1731
+ };
1732
+
1733
+
1734
+ /**
1735
+ * Gets the estimated fee for the transaction.
1736
+ * @returns {number} The estimated fee value.
1737
+ */
1738
+ Transaction.prototype.getEstimateFee = function () {
1739
+ return this._estimateFee();
1740
+ };
1741
+
1742
+
1743
+ /**
1744
+ * Checks if the transaction's fee rate meets or exceeds the expected rate.
1745
+ * @param {number} [feePerKb] - Optional fee per KB (in satoshis). Falls back to instance or default fee.
1746
+ * @returns {boolean} True if actual fee rate (fee/size) >= expected rate.
1747
+ */
1748
+ Transaction.prototype.checkFeeRate = function (feePerKb) {
1749
+ var fee = this.getUnspentValue();
1750
+
1751
+ var estimatedSize = this._estimateSize();
1752
+ var expectedRate = (feePerKb || this._feePerKb || Transaction.FEE_PER_KB) / 1000;
1753
+ var realFeeRate = fee / estimatedSize;
1754
+ return realFeeRate >= expectedRate;
1755
+ };
1756
+
1757
+
1758
+ /**
1759
+ * Serializes the transaction's inputs (prevTxId and outputIndex) into a hex string.
1760
+ * @returns {string} Hex-encoded serialized input data.
1761
+ */
1762
+ Transaction.prototype.prevouts = function () {
1763
+ var writer = new BufferWriter();
1764
+
1765
+ _.each(this.inputs, function (input) {
1766
+ writer.writeReverse(input.prevTxId);
1767
+ writer.writeUInt32LE(input.outputIndex);
1768
+ });
1769
+
1770
+ var buf = writer.toBuffer();
1771
+ return buf.toString('hex');
1772
+ };
1773
+
1774
+
1775
+ /**
1776
+ * Checks if the transaction is sealed.
1777
+ * @returns {boolean} True if the transaction is sealed, false otherwise.
1778
+ */
1779
+ Transaction.prototype.isSealed = function () {
1780
+ return this.sealed;
1781
+ };
1782
+
1783
+ /**
1784
+ * Gets the preimage for a transaction input.
1785
+ * @param {number} inputIndex - The index of the input to get the preimage for.
1786
+ * @param {number} [sigtype=Signature.SIGHASH_ALL] - The signature hash type.
1787
+ * @param {boolean} [isLowS=false] - Whether to use low-S signatures.
1788
+ * @returns {*} The preimage for the specified input.
1789
+ */
1790
+ Transaction.prototype.getPreimage = function (inputIndex, sigtype, isLowS) {
1791
+ $.checkArgumentType(inputIndex, 'number', 'inputIndex');
1792
+ sigtype = sigtype || Signature.SIGHASH_ALL;
1793
+ isLowS = isLowS || false;
1794
+ inputIndex = inputIndex || 0;
1795
+ return this.inputs[inputIndex].getPreimage(this, inputIndex, sigtype, isLowS);
1796
+ };
1797
+
1798
+ /**
1799
+ * Gets the signature(s) for a transaction input.
1800
+ * @param {number} inputIndex - Index of the input to sign.
1801
+ * @param {Array|Buffer|string} [privateKeys] - Private key(s) to sign with. Defaults to input's privateKey or transaction's _privateKey.
1802
+ * @param {number} [sigtypes] - Signature hash type. Defaults to SIGHASH_ALL.
1803
+ * @returns {string|Array} - Single signature hex string or array of signatures. Returns empty array if no privateKeys provided.
1804
+ */
1805
+ Transaction.prototype.getSignature = function (inputIndex, privateKeys, sigtypes) {
1806
+ $.checkArgumentType(inputIndex, 'number', 'inputIndex');
1807
+ var results = [];
1808
+ var inputOpt = (this._inputsMap || new Map()).get(inputIndex);
1809
+
1810
+ privateKeys = privateKeys || (inputOpt ? inputOpt.privateKey : this._privateKey);
1811
+
1812
+ if (privateKeys) {
1813
+ sigtypes = sigtypes || Signature.SIGHASH_ALL;
1814
+ var sigs = this.inputs[inputIndex].getSignatures(this, privateKeys, inputIndex, sigtypes);
1815
+
1816
+ _.each(sigs, function (sig) {
1817
+ results.push(sig.signature.toTxFormat().toString('hex'));
1818
+ });
1819
+
1820
+ if (results.length === 1) {
1821
+ return results[0];
1822
+ }
1823
+
1824
+ return results;
1825
+ }
1826
+
1827
+ return [];
1828
+ };
1829
+
1830
+ /**
1831
+ * Adds an input to the transaction from a previous transaction's output.
1832
+ * @param {Transaction} prevTx - The previous transaction containing the output to spend.
1833
+ * @param {number} [outputIndex=0] - The index of the output in the previous transaction.
1834
+ * @returns {Transaction} The transaction instance for chaining.
1835
+ * @throws {Error} If prevTx is not a valid Transaction.
1836
+ */
1837
+ Transaction.prototype.addInputFromPrevTx = function (prevTx, outputIndex) {
1838
+ $.checkArgumentType(prevTx, Transaction, 'prevTx');
1839
+
1840
+ var outputIdx = outputIndex || 0;
1841
+
1842
+ const output = prevTx.outputs[outputIdx];
1843
+
1844
+ if (output.script.isPublicKeyHashOut()) {
1845
+ return this.addInput(
1846
+ new PublicKeyHashInput({
1847
+ prevTxId: prevTx.id,
1848
+ outputIndex: outputIdx,
1849
+ script: new Script(''), // placeholder
1850
+ output: output,
1851
+ }),
1852
+ );
1853
+ } else {
1854
+ return this.addInput(
1855
+ new Input({
1856
+ prevTxId: prevTx.id,
1857
+ outputIndex: outputIdx,
1858
+ script: new Script(''), // placeholder
1859
+ output: output,
1860
+ }),
1861
+ );
1862
+ }
1863
+ };
1864
+
1865
+ /**
1866
+ * Adds a dummy input to the transaction with the specified script and satoshis.
1867
+ * The dummy input uses a placeholder script and a fixed previous transaction ID.
1868
+ *
1869
+ * @param {Script} script - The script to use for the output of the dummy input.
1870
+ * @param {number} satoshis - The amount in satoshis for the output of the dummy input.
1871
+ * @returns {Transaction} The transaction instance for chaining.
1872
+ */
1873
+ Transaction.prototype.addDummyInput = function (script, satoshis) {
1874
+ $.checkArgumentType(script, Script, 'script');
1875
+ $.checkArgumentType(satoshis, 'number', 'satoshis');
1876
+
1877
+ return this.addInput(
1878
+ new Input({
1879
+ prevTxId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
1880
+ outputIndex: 0,
1881
+ script: new Script(''), // placeholder
1882
+ output: new Output({
1883
+ script: script,
1884
+ satoshis: satoshis,
1885
+ }),
1886
+ }),
1887
+ );
1888
+ };
1889
+
1890
+ /**
1891
+ * Same as change(addresss), but using the address of Transaction.DUMMY_PRIVATEKEY as default change address
1892
+ *
1893
+ * Beware that this resets all the signatures for inputs (in further versions,
1894
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
1895
+ *
1896
+ * @return {Transaction} this, for chaining
1897
+ */
1898
+ Transaction.prototype.dummyChange = function () {
1899
+ return this.change(Transaction.DUMMY_PRIVATEKEY.toAddress());
1900
+ };
1901
+
1902
+ /**
1903
+ * Verifies the script for a specific transaction input.
1904
+ * @param {number} inputIndex - Index of the input to verify.
1905
+ * @throws {errors.Transaction.Input.MissingInput} If input at given index doesn't exist.
1906
+ * @returns {boolean} True if the script verification passes.
1907
+ */
1908
+ Transaction.prototype.verifyScript = function (inputIndex) {
1909
+ $.checkArgumentType(inputIndex, 'number', 'inputIndex');
1910
+
1911
+ if (!this.inputs[inputIndex]) {
1912
+ throw new errors.Transaction.Input.MissingInput();
1913
+ }
1914
+
1915
+ return this.inputs[inputIndex].verify(this, inputIndex);
1916
+ };
1917
+
1918
+
1919
+ /**
1920
+ * Verifies the input script for a specific input index in the transaction.
1921
+ * @param {number} inputIndex - The index of the input to verify.
1922
+ * @returns {boolean} True if the input script is valid, false otherwise.
1923
+ */
1924
+ Transaction.prototype.verifyInputScript = function (inputIndex) {
1925
+ return this.verifyScript(inputIndex);
1926
+ };
1927
+
1928
+ /**
1929
+ * Gets the amount of satoshis for a specific transaction input.
1930
+ * @param {number} inputIndex - The index of the input to query.
1931
+ * @returns {number} The satoshis amount of the specified input.
1932
+ * @throws {errors.Transaction.Input.MissingInput} If the input at the specified index doesn't exist.
1933
+ */
1934
+ Transaction.prototype.getInputAmount = function (inputIndex) {
1935
+ $.checkArgumentType(inputIndex, 'number', 'inputIndex');
1936
+
1937
+ if (!this.inputs[inputIndex]) {
1938
+ throw new errors.Transaction.Input.MissingInput();
1939
+ }
1940
+
1941
+ return this.inputs[inputIndex].output.satoshis;
1942
+ };
1943
+
1944
+ /**
1945
+ * Gets the output amount in satoshis for the specified output index.
1946
+ * @param {number} outputIndex - The index of the output to retrieve.
1947
+ * @returns {number} The output amount in satoshis.
1948
+ * @throws {errors.Transaction.MissingOutput} If the output index is invalid.
1949
+ */
1950
+ Transaction.prototype.getOutputAmount = function (outputIndex) {
1951
+ $.checkArgumentType(outputIndex, 'number', 'outputIndex');
1952
+
1953
+ if (!this.outputs[outputIndex]) {
1954
+ throw new errors.Transaction.MissingOutput();
1955
+ }
1956
+
1957
+ return this.outputs[outputIndex].satoshis;
1958
+ };
1959
+
1960
+
1961
+ /**
1962
+ * Assigns the Input class to the Transaction namespace.
1963
+ * @memberof Transaction
1964
+ * @name Input
1965
+ * @alias Input
1966
+ */
1967
+ Transaction.Input = Input;
1968
+ /**
1969
+ * Assigns the Output class to Transaction.Output property.
1970
+ * @memberof Transaction
1971
+ * @name Output
1972
+ * @alias Output
1973
+ */
1974
+ Transaction.Output = Output;
1975
+
1976
+ /**
1977
+ * Attaches the Sighash module to the Transaction class.
1978
+ * @memberof Transaction
1979
+ * @name Sighash
1980
+ * @alias Sighash
1981
+ */
1982
+ Transaction.Sighash = Sighash;
1983
+ /**
1984
+ * Attaches the UnspentOutput class to the Transaction namespace.
1985
+ * @memberof Transaction
1986
+ * @name UnspentOutput
1987
+ * @alias UnspentOutput
1988
+ */
1989
+ Transaction.UnspentOutput = UnspentOutput;
1990
+
1991
+ /**
1992
+ * Attaches the TransactionSignature class to the Transaction namespace.
1993
+ * @memberof Transaction
1994
+ * @name Signature
1995
+ * @alias TransactionSignature
1996
+ */
1997
+ Transaction.Signature = TransactionSignature;
1998
+
1999
+
2000
+ module.exports = Transaction;