@opcat-labs/opcat 1.0.1 → 1.0.2

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 +6 -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,1329 @@
1
+ 'use strict';
2
+
3
+ import Address from '../address.js';
4
+ import BufferWriter from '../encoding/bufferwriter.js';
5
+ import Hash from '../crypto/hash.js';
6
+ import Opcode from '../opcode.js';
7
+ import PublicKey from '../publickey.js';
8
+ import Signature from '../crypto/signature.js';
9
+ import Networks from '../networks.js';
10
+ import $ from '../util/preconditions.js';
11
+ import _ from '../util/_.js';
12
+ import errors from '../errors/index.js';
13
+ import JSUtil from '../util/js.js';
14
+ import decodeScriptChunks from '../encoding/decode-script-chunks.js';
15
+ import decodeASM from '../encoding/decode-asm.js';
16
+ import encodeHex from '../encoding/encode-hex.js';
17
+
18
+ // These WeakMap caches allow the objects themselves to maintain their immutability
19
+ const SCRIPT_TO_CHUNKS_CACHE = new WeakMap();
20
+
21
+ /**
22
+ * A bitcoin transaction script. Each transaction's inputs and outputs
23
+ * has a script that is evaluated to validate it's spending.
24
+ *
25
+ * See https://en.bitcoin.it/wiki/Script
26
+ *
27
+ * @constructor
28
+ * @param {Object|string|Buffer} [from] optional data to populate script
29
+ */
30
+ function Script(from) {
31
+ if (!(this instanceof Script)) {
32
+ return new Script(from);
33
+ }
34
+ this.buffer = Buffer.from([]);
35
+
36
+ if (Buffer.isBuffer(from)) {
37
+ return Script.fromBuffer(from);
38
+ } else if (from instanceof Address) {
39
+ return Script.fromAddress(from);
40
+ } else if (from instanceof Script) {
41
+ return Script.fromBuffer(from.toBuffer());
42
+ } else if (_.isString(from)) {
43
+ return Script.fromString(from);
44
+ } else if (_.isObject(from) && _.isArray(from.chunks)) {
45
+ return Script.fromChunks(from.chunks);
46
+ } else if (_.isObject(from) && Buffer.isBuffer(from.buffer)) {
47
+ return Script.fromBuffer(from.buffer);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Sets the script content from an object.
53
+ * @param {Object} obj - The source object containing either chunks array or buffer.
54
+ * @param {Array} [obj.chunks] - Optional array of chunks to create script from.
55
+ * @param {Buffer} [obj.buffer] - Optional buffer containing script data.
56
+ * @returns {Script} Returns the script instance for chaining.
57
+ * @throws Will throw if argument is invalid (not object or missing required buffer).
58
+ */
59
+ Script.prototype.set = function (obj) {
60
+ $.checkArgument(_.isObject(obj));
61
+ if (obj.chunks && _.isArray(obj.chunks)) {
62
+ var s = Script.fromChunks(obj.chunks);
63
+ this.buffer = s.buffer;
64
+ return this;
65
+ }
66
+
67
+ $.checkArgument(Buffer.isBuffer(obj.buffer));
68
+ this.buffer = obj.buffer;
69
+ return this;
70
+ };
71
+
72
+ /**
73
+ * Creates a Script instance from a Buffer.
74
+ * @param {Buffer} buffer - The buffer containing the script data.
75
+ * @returns {Script} A new Script instance with the provided buffer.
76
+ * @throws {Error} Throws if the input is not a Buffer.
77
+ */
78
+ Script.fromBuffer = function (buffer) {
79
+ $.checkArgument(Buffer.isBuffer(buffer));
80
+ var script = new Script();
81
+ script.buffer = buffer;
82
+ return script;
83
+ };
84
+
85
+ /**
86
+ * Creates a Script instance from an array of opcode chunks.
87
+ * Handles different pushdata opcodes (OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4)
88
+ * by writing appropriate length prefixes before the buffer data.
89
+ * @param {Array} chunks - Array of opcode chunks containing opcodenum and optional buf/len
90
+ * @returns {Script} A new Script instance with compiled buffer
91
+ */
92
+ Script.fromChunks = function (chunks) {
93
+ var script = new Script();
94
+
95
+ const bw = new BufferWriter();
96
+
97
+ for (let index = 0; index < chunks.length; index++) {
98
+ const chunk = chunks[index];
99
+ bw.writeUInt8(chunk.opcodenum);
100
+ if (chunk.buf) {
101
+ if (chunk.opcodenum < Opcode.OP_PUSHDATA1) {
102
+ bw.write(chunk.buf);
103
+ } else if (chunk.opcodenum === Opcode.OP_PUSHDATA1) {
104
+ bw.writeUInt8(chunk.len);
105
+ bw.write(chunk.buf);
106
+ } else if (chunk.opcodenum === Opcode.OP_PUSHDATA2) {
107
+ bw.writeUInt16LE(chunk.len);
108
+ bw.write(chunk.buf);
109
+ } else if (chunk.opcodenum === Opcode.OP_PUSHDATA4) {
110
+ bw.writeUInt32LE(chunk.len);
111
+ bw.write(chunk.buf);
112
+ }
113
+ }
114
+ }
115
+
116
+ script.buffer = bw.toBuffer();
117
+ return script;
118
+ };
119
+
120
+ /**
121
+ * Returns the underlying buffer of the script.
122
+ * @returns {Buffer} The script's buffer data.
123
+ */
124
+ Script.prototype.toBuffer = function () {
125
+ return this.buffer;
126
+ };
127
+
128
+ /**
129
+ * Creates a Script instance from ASM (Assembly) formatted string.
130
+ * @param {string} str - ASM formatted string to decode
131
+ * @returns {Script} Script instance created from decoded ASM
132
+ */
133
+ Script.fromASM = function (str) {
134
+ return Script.fromBuffer(decodeASM(str));
135
+ };
136
+
137
+ /**
138
+ * Creates a Script instance from a hex string.
139
+ * @param {string} str - Hex string to convert to Script.
140
+ * @returns {Script} New Script instance created from the hex string.
141
+ */
142
+ Script.fromHex = function (str) {
143
+ return new Script(Buffer.from(str, 'hex'));
144
+ };
145
+
146
+ /**
147
+ * Converts a string representation of a script into a Script object.
148
+ * Handles hex strings, empty strings, and space-separated opcode tokens.
149
+ * For pushdata operations (OP_PUSHDATA1/2/4), validates format and length.
150
+ * Throws errors for invalid script formats or data lengths.
151
+ * @param {string} str - The script string to parse (hex or opcode tokens)
152
+ * @returns {Script} The constructed Script object
153
+ * @throws {Error} When script format is invalid or data lengths don't match
154
+ */
155
+ Script.fromString = function (str) {
156
+ if (JSUtil.isHexa(str) || str.length === 0) {
157
+ return new Script(Buffer.from(str, 'hex'));
158
+ }
159
+
160
+ var chunks = [];
161
+
162
+ var tokens = str.split(' ');
163
+ var i = 0;
164
+ while (i < tokens.length) {
165
+ var token = tokens[i];
166
+ var opcode = Opcode(token);
167
+ var opcodenum = opcode.toNumber();
168
+
169
+ if (_.isUndefined(opcodenum)) {
170
+ opcodenum = parseInt(token);
171
+ if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) {
172
+ var buf = Buffer.from(tokens[i + 1].slice(2), 'hex');
173
+ if (buf.length !== opcodenum) {
174
+ throw new Error('Invalid script buf len: ' + JSON.stringify(str));
175
+ }
176
+ chunks.push({
177
+ buf: Buffer.from(tokens[i + 1].slice(2), 'hex'),
178
+ len: opcodenum,
179
+ opcodenum: opcodenum,
180
+ });
181
+ i = i + 2;
182
+ } else {
183
+ throw new Error('Invalid script: ' + JSON.stringify(str));
184
+ }
185
+ } else if (
186
+ opcodenum === Opcode.OP_PUSHDATA1 ||
187
+ opcodenum === Opcode.OP_PUSHDATA2 ||
188
+ opcodenum === Opcode.OP_PUSHDATA4
189
+ ) {
190
+ if (tokens[i + 2].slice(0, 2) !== '0x') {
191
+ throw new Error('Pushdata data must start with 0x');
192
+ }
193
+ chunks.push({
194
+ buf: Buffer.from(tokens[i + 2].slice(2), 'hex'),
195
+ len: parseInt(tokens[i + 1]),
196
+ opcodenum: opcodenum,
197
+ });
198
+ i = i + 3;
199
+ } else {
200
+ chunks.push({
201
+ opcodenum: opcodenum,
202
+ });
203
+ i = i + 1;
204
+ }
205
+ }
206
+ return Script.fromChunks(chunks);
207
+ };
208
+
209
+ /**
210
+ * Gets a portion of the script's buffer as a new buffer.
211
+ * @param {number} [start] - The beginning index of the specified portion of the buffer.
212
+ * @param {number} [end] - The end index of the specified portion of the buffer.
213
+ * @returns {Buffer} A new Buffer that contains the specified portion of the original buffer.
214
+ */
215
+ Script.prototype.slice = function (start, end) {
216
+ return this.buffer.slice(start, end);
217
+ };
218
+
219
+ /**
220
+ * Gets the chunks associated with the Script instance.
221
+ * @memberof Script.prototype
222
+ * @name chunks
223
+ * @type {Array}
224
+ */
225
+ Object.defineProperty(Script.prototype, 'chunks', {
226
+ get() {
227
+ if (SCRIPT_TO_CHUNKS_CACHE.has(this)) return SCRIPT_TO_CHUNKS_CACHE.get(this);
228
+ const chunks = decodeScriptChunks(this.buffer);
229
+ SCRIPT_TO_CHUNKS_CACHE.set(this, chunks);
230
+ return chunks;
231
+ },
232
+ });
233
+
234
+ /**
235
+ * Gets the length of the script in bytes.
236
+ * @memberof Script.prototype
237
+ * @name length
238
+ * @type {number}
239
+ */
240
+ Object.defineProperty(Script.prototype, 'length', {
241
+ get() {
242
+ return this.buffer.length;
243
+ },
244
+ });
245
+
246
+ /**
247
+ * Converts a script chunk to a string representation based on the given type.
248
+ * Handles both data chunks and opcode chunks, with special formatting for ASM output.
249
+ *
250
+ * @param {Object} chunk - The script chunk to convert, containing opcodenum and optional buf/len
251
+ * @param {string} type - The output type ('asm' or other)
252
+ * @returns {string} The formatted string representation of the chunk
253
+ * @private
254
+ */
255
+ Script.prototype._chunkToString = function (chunk, type) {
256
+ var opcodenum = chunk.opcodenum;
257
+ var asm = type === 'asm';
258
+ var str = '';
259
+ if (!chunk.buf) {
260
+ // no data chunk
261
+ if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') {
262
+ if (asm) {
263
+ // A few cases where the opcode name differs from reverseMap
264
+ // aside from 1 to 16 data pushes.
265
+ if (opcodenum === 0) {
266
+ // OP_0 -> 0
267
+ str = str + ' 0';
268
+ } else if (opcodenum === 79) {
269
+ // OP_1NEGATE -> 1
270
+ str = str + ' -1';
271
+ } else {
272
+ str = str + ' ' + Opcode(opcodenum).toString();
273
+ }
274
+ } else {
275
+ str = str + ' ' + Opcode(opcodenum).toString();
276
+ }
277
+ } else {
278
+ var numstr = opcodenum.toString(16);
279
+ if (numstr.length % 2 !== 0) {
280
+ numstr = '0' + numstr;
281
+ }
282
+ if (asm) {
283
+ str = str + ' ' + numstr;
284
+ } else {
285
+ str = str + ' ' + '0x' + numstr;
286
+ }
287
+ }
288
+ } else {
289
+ // data chunk
290
+ if (
291
+ !asm &&
292
+ (opcodenum === Opcode.OP_PUSHDATA1 ||
293
+ opcodenum === Opcode.OP_PUSHDATA2 ||
294
+ opcodenum === Opcode.OP_PUSHDATA4)
295
+ ) {
296
+ str = str + ' ' + Opcode(opcodenum).toString();
297
+ }
298
+ if (chunk.len > 0) {
299
+ if (asm) {
300
+ str = str + ' ' + chunk.buf.toString('hex');
301
+ } else {
302
+ str = str + ' ' + chunk.len + ' ' + '0x' + chunk.buf.toString('hex');
303
+ }
304
+ }
305
+ }
306
+ return str;
307
+ };
308
+
309
+ /**
310
+ * Converts the script chunks to ASM (Assembly) format string representation.
311
+ * Iterates through each chunk and appends its ASM string representation.
312
+ * @returns {string} The ASM formatted string (excluding the first character).
313
+ */
314
+ Script.prototype.toASM = function () {
315
+ var str = '';
316
+ var chunks = this.chunks;
317
+ for (var i = 0; i < chunks.length; i++) {
318
+ var chunk = this.chunks[i];
319
+ str += this._chunkToString(chunk, 'asm');
320
+ }
321
+
322
+ return str.substr(1);
323
+ };
324
+
325
+ /**
326
+ * Converts the script's chunks to a string representation.
327
+ * Iterates through each chunk and appends its string representation,
328
+ * then removes the leading character from the result.
329
+ * @returns {string} The concatenated string of all chunks.
330
+ */
331
+ Script.prototype.toString = function () {
332
+ var str = '';
333
+ for (var i = 0; i < this.chunks.length; i++) {
334
+ var chunk = this.chunks[i];
335
+ str += this._chunkToString(chunk);
336
+ }
337
+
338
+ return str.substr(1);
339
+ };
340
+
341
+ /**
342
+ * Converts the script's buffer to a hexadecimal string.
343
+ * @returns {string} Hex-encoded representation of the script buffer.
344
+ */
345
+ Script.prototype.toHex = function () {
346
+ return encodeHex(this.buffer);
347
+ };
348
+
349
+ /**
350
+ * Custom inspect method for Script instances.
351
+ * @returns {string} String representation of the Script object in format '<Script: [content]>'.
352
+ */
353
+ Script.prototype.inspect = function () {
354
+ return '<Script: ' + this.toString() + '>';
355
+ };
356
+
357
+ // script classification methods
358
+
359
+
360
+ /**
361
+ * Checks if the script is a standard public key hash output script (P2PKH).
362
+ * @returns {boolean} True if the script matches the P2PKH pattern:
363
+ * - OP_DUP
364
+ * - OP_HASH160
365
+ * - 20-byte hash
366
+ * - OP_EQUALVERIFY
367
+ * - OP_CHECKSIG
368
+ */
369
+ Script.prototype.isPublicKeyHashOut = function () {
370
+ return !!(
371
+ this.chunks.length === 5 &&
372
+ this.chunks[0].opcodenum === Opcode.OP_DUP &&
373
+ this.chunks[1].opcodenum === Opcode.OP_HASH160 &&
374
+ this.chunks[2].buf &&
375
+ this.chunks[2].buf.length === 20 &&
376
+ this.chunks[3].opcodenum === Opcode.OP_EQUALVERIFY &&
377
+ this.chunks[4].opcodenum === Opcode.OP_CHECKSIG
378
+ );
379
+ };
380
+
381
+
382
+ /**
383
+ * Checks if the script contains a valid public key hash.
384
+ * @returns {boolean} True if the script has exactly 2 chunks (signature and public key),
385
+ * the signature starts with 0x30, and the public key has a valid version
386
+ * and length (65 bytes for versions 0x04/0x06/0x07, 33 bytes for 0x02/0x03).
387
+ */
388
+ Script.prototype.isPublicKeyHashIn = function () {
389
+ if (this.chunks.length === 2) {
390
+ var signatureBuf = this.chunks[0].buf;
391
+ var pubkeyBuf = this.chunks[1].buf;
392
+ if (
393
+ signatureBuf &&
394
+ signatureBuf.length &&
395
+ signatureBuf[0] === 0x30 &&
396
+ pubkeyBuf &&
397
+ pubkeyBuf.length
398
+ ) {
399
+ var version = pubkeyBuf[0];
400
+ if ((version === 0x04 || version === 0x06 || version === 0x07) && pubkeyBuf.length === 65) {
401
+ return true;
402
+ } else if ((version === 0x03 || version === 0x02) && pubkeyBuf.length === 33) {
403
+ return true;
404
+ }
405
+ }
406
+ }
407
+ return false;
408
+ };
409
+
410
+ /**
411
+ * Gets the public key from a script output.
412
+ * @returns {Buffer} The public key buffer.
413
+ * @throws {Error} If the script is not a public key output.
414
+ */
415
+ Script.prototype.getPublicKey = function () {
416
+ $.checkState(this.isPublicKeyOut(), "Can't retrieve PublicKey from a non-PK output");
417
+ return this.chunks[0].buf;
418
+ };
419
+
420
+ /**
421
+ * Retrieves the PublicKeyHash from a script output.
422
+ * @returns {Buffer} The PublicKeyHash buffer.
423
+ * @throws {Error} If the script output is not a PublicKeyHash output.
424
+ */
425
+ Script.prototype.getPublicKeyHash = function () {
426
+ $.checkState(this.isPublicKeyHashOut(), "Can't retrieve PublicKeyHash from a non-PKH output");
427
+ return this.chunks[2].buf;
428
+ };
429
+
430
+
431
+ /**
432
+ * Checks if the script is a standard public key output script.
433
+ * @returns {boolean} True if the script matches the standard public key output format:
434
+ * - Contains exactly 2 chunks
435
+ * - First chunk is a valid public key buffer (65 bytes for uncompressed, 33 bytes for compressed)
436
+ * - Second chunk is OP_CHECKSIG opcode
437
+ */
438
+ Script.prototype.isPublicKeyOut = function () {
439
+ if (
440
+ this.chunks.length === 2 &&
441
+ this.chunks[0].buf &&
442
+ this.chunks[0].buf.length &&
443
+ this.chunks[1].opcodenum === Opcode.OP_CHECKSIG
444
+ ) {
445
+ var pubkeyBuf = this.chunks[0].buf;
446
+ var version = pubkeyBuf[0];
447
+ var isVersion = false;
448
+ if ((version === 0x04 || version === 0x06 || version === 0x07) && pubkeyBuf.length === 65) {
449
+ isVersion = true;
450
+ } else if ((version === 0x03 || version === 0x02) && pubkeyBuf.length === 33) {
451
+ isVersion = true;
452
+ }
453
+ if (isVersion) {
454
+ return PublicKey.isValid(pubkeyBuf);
455
+ }
456
+ }
457
+ return false;
458
+ };
459
+
460
+
461
+ /**
462
+ * Checks if the script contains a valid public key signature.
463
+ * @returns {boolean} True if the script has exactly one chunk that starts with 0x30 (DER signature marker), false otherwise.
464
+ */
465
+ Script.prototype.isPublicKeyIn = function () {
466
+ if (this.chunks.length === 1) {
467
+ var signatureBuf = this.chunks[0].buf;
468
+ if (signatureBuf && signatureBuf.length && signatureBuf[0] === 0x30) {
469
+ return true;
470
+ }
471
+ }
472
+ return false;
473
+ };
474
+
475
+
476
+ /**
477
+ * Checks if the script is a multisig output script.
478
+ * @returns {boolean} True if the script matches the multisig output pattern:
479
+ * - Has more than 3 chunks
480
+ * - First chunk is a small integer opcode
481
+ * - Middle chunks are all buffers
482
+ * - Second-to-last chunk is a small integer opcode
483
+ * - Last chunk is OP_CHECKMULTISIG
484
+ */
485
+ Script.prototype.isMultisigOut = function () {
486
+ return (
487
+ this.chunks.length > 3 &&
488
+ Opcode.isSmallIntOp(this.chunks[0].opcodenum) &&
489
+ this.chunks.slice(1, this.chunks.length - 2).every(function (obj) {
490
+ return obj.buf && Buffer.isBuffer(obj.buf);
491
+ }) &&
492
+ Opcode.isSmallIntOp(this.chunks[this.chunks.length - 2].opcodenum) &&
493
+ this.chunks[this.chunks.length - 1].opcodenum === Opcode.OP_CHECKMULTISIG
494
+ );
495
+ };
496
+
497
+
498
+ /**
499
+ * Decodes a multisig output script into its components.
500
+ * @returns {Object} An object containing:
501
+ * - m {number} The required number of signatures (m-of-n)
502
+ * - n {number} The total number of public keys
503
+ * - pubkeys {Buffer[]} Array of public keys involved in the multisig
504
+ */
505
+ Script.prototype.decodeMultisigOut = function () {
506
+ $.checkState(this.isMultisigOut(), "Can't decode a non-multisig output script");
507
+ const OP_INT_BASE = Opcode.OP_RESERVED; // OP_1 - 1
508
+ const m = this.chunks[0].opcodenum - OP_INT_BASE
509
+ const n = (this.chunks[0][this.chunks[0].length - 2]) - OP_INT_BASE;
510
+ const pubkeys = this.chunks.slice(1, -2).map((chunk) => chunk.buf);
511
+
512
+ return {
513
+ m,
514
+ n,
515
+ pubkeys
516
+ };
517
+ };
518
+
519
+
520
+ /**
521
+ * Checks if the script is a multisig input script.
522
+ * @returns {boolean} True if the script is a valid multisig input (starts with OP_0 and has valid DER signatures).
523
+ */
524
+ Script.prototype.isMultisigIn = function () {
525
+ return (
526
+ this.chunks.length >= 2 &&
527
+ this.chunks[0].opcodenum === 0 &&
528
+ this.chunks.slice(1, this.chunks.length).every(function (obj) {
529
+ return obj.buf && Buffer.isBuffer(obj.buf) && Signature.isTxDER(obj.buf);
530
+ })
531
+ );
532
+ };
533
+
534
+
535
+ /**
536
+ * Checks if the script is a data-only output script (OP_RETURN followed by push-only data).
537
+ * @returns {boolean} True if the script is a valid data-only output, false otherwise.
538
+ */
539
+ Script.prototype.isDataOut = function () {
540
+ var step1 = this.buffer.length >= 1 && this.buffer[0] === Opcode.OP_RETURN;
541
+ if (!step1) return false;
542
+ var buffer = this.buffer.slice(1);
543
+ var script2 = new Script({ buffer: buffer });
544
+ return script2.isPushOnly();
545
+ };
546
+
547
+ /**
548
+ * Checks if the script is a safe data output script.
549
+ * A safe data output script must start with OP_FALSE followed by a valid data output script.
550
+ * @returns {boolean} True if the script is a safe data output, false otherwise.
551
+ */
552
+ Script.prototype.isSafeDataOut = function () {
553
+ if (this.buffer.length < 2) {
554
+ return false;
555
+ }
556
+ if (this.buffer[0] !== Opcode.OP_FALSE) {
557
+ return false;
558
+ }
559
+ var buffer = this.buffer.slice(1);
560
+ var script2 = new Script({ buffer });
561
+ return script2.isDataOut();
562
+ };
563
+
564
+ /**
565
+ * Retrieve the associated data for this script.
566
+ * In the case of a pay to public key hash, return the hash.
567
+ * In the case of safe OP_RETURN data, return an array of buffers
568
+ * In the case of a standard deprecated OP_RETURN, return the data
569
+ * @returns {Buffer}
570
+ */
571
+ Script.prototype.getData = function () {
572
+ if (this.isSafeDataOut()) {
573
+ var chunks = this.chunks.slice(2);
574
+ var buffers = chunks.map((chunk) => chunk.buf);
575
+ return buffers;
576
+ }
577
+ if (this.isDataOut()) {
578
+ if (_.isUndefined(this.chunks[1])) {
579
+ return Buffer.alloc(0);
580
+ } else {
581
+ return Buffer.from(this.chunks[1].buf);
582
+ }
583
+ }
584
+ if (this.isPublicKeyHashOut()) {
585
+ return Buffer.from(this.chunks[2].buf);
586
+ }
587
+ throw new Error('Unrecognized script type to get data from');
588
+ };
589
+
590
+
591
+ /**
592
+ * Checks if the script consists only of push operations (OP_0 to OP_16) or data push operations (OP_PUSHDATA1/2/4).
593
+ * @returns {boolean} True if all chunks are push operations, false otherwise.
594
+ */
595
+ Script.prototype.isPushOnly = function () {
596
+ return _.every(this.chunks, function (chunk) {
597
+ return (
598
+ chunk.opcodenum <= Opcode.OP_16 ||
599
+ chunk.opcodenum === Opcode.OP_PUSHDATA1 ||
600
+ chunk.opcodenum === Opcode.OP_PUSHDATA2 ||
601
+ chunk.opcodenum === Opcode.OP_PUSHDATA4
602
+ );
603
+ });
604
+ };
605
+
606
+ /**
607
+ * Registry for script types.
608
+ * @namespace
609
+ */
610
+ Script.types = {};
611
+ /**
612
+ * Represents the 'Unknown' type constant for script types.
613
+ * @type {string}
614
+ */
615
+ Script.types.UNKNOWN = 'Unknown';
616
+ /**
617
+ * Defines the display text for the public key output script type.
618
+ * @type {string}
619
+ */
620
+ Script.types.PUBKEY_OUT = 'Pay to public key';
621
+ /**
622
+ * Script type constant for spending from a public key input.
623
+ * @type {string}
624
+ */
625
+ Script.types.PUBKEY_IN = 'Spend from public key';
626
+ /**
627
+ * Script type constant for Pay to Public Key Hash (P2PKH) output.
628
+ * @type {string}
629
+ */
630
+ Script.types.PUBKEYHASH_OUT = 'Pay to public key hash';
631
+ /**
632
+ * Constant defining the display string for public key hash input script type.
633
+ * @type {string}
634
+ */
635
+ Script.types.PUBKEYHASH_IN = 'Spend from public key hash';
636
+ /**
637
+ * Script type constant for Pay to Script Hash (P2SH) output.
638
+ * @type {string}
639
+ */
640
+ Script.types.SCRIPTHASH_OUT = 'Pay to script hash';
641
+ /**
642
+ * Constant defining the string representation for spending from a script hash input type.
643
+ * @type {string}
644
+ */
645
+ Script.types.SCRIPTHASH_IN = 'Spend from script hash';
646
+ /**
647
+ * Multisig output script type identifier.
648
+ * @type {string}
649
+ */
650
+ Script.types.MULTISIG_OUT = 'Pay to multisig';
651
+ /**
652
+ * Multisig input script type - represents spending from a multisig address.
653
+ */
654
+ Script.types.MULTISIG_IN = 'Spend from multisig';
655
+ /**
656
+ * Constant defining the type string for data output operations.
657
+ * @type {string}
658
+ */
659
+ Script.types.DATA_OUT = 'Data push';
660
+ /**
661
+ * Constant defining the type string for safe data output operations.
662
+ * @type {string}
663
+ */
664
+ Script.types.SAFE_DATA_OUT = 'Safe data push';
665
+
666
+
667
+ /**
668
+ * @returns {object} The Script type if it is a known form,
669
+ * or Script.UNKNOWN if it isn't
670
+ */
671
+ Script.prototype.classify = function () {
672
+ if (this._isInput) {
673
+ return this.classifyInput();
674
+ } else if (this._isOutput) {
675
+ return this.classifyOutput();
676
+ } else {
677
+ var outputType = this.classifyOutput();
678
+ return outputType !== Script.types.UNKNOWN ? outputType : this.classifyInput();
679
+ }
680
+ };
681
+
682
+ Script.outputIdentifiers = {};
683
+ Script.outputIdentifiers.PUBKEY_OUT = Script.prototype.isPublicKeyOut;
684
+ Script.outputIdentifiers.PUBKEYHASH_OUT = Script.prototype.isPublicKeyHashOut;
685
+ Script.outputIdentifiers.MULTISIG_OUT = Script.prototype.isMultisigOut;
686
+ Script.outputIdentifiers.DATA_OUT = Script.prototype.isDataOut;
687
+ Script.outputIdentifiers.SAFE_DATA_OUT = Script.prototype.isSafeDataOut;
688
+
689
+ /**
690
+ * @returns {object} The Script type if it is a known form,
691
+ * or Script.UNKNOWN if it isn't
692
+ */
693
+ Script.prototype.classifyOutput = function () {
694
+ for (var type in Script.outputIdentifiers) {
695
+ if (Script.outputIdentifiers[type].bind(this)()) {
696
+ return Script.types[type];
697
+ }
698
+ }
699
+ return Script.types.UNKNOWN;
700
+ };
701
+
702
+ Script.inputIdentifiers = {};
703
+ Script.inputIdentifiers.PUBKEY_IN = Script.prototype.isPublicKeyIn;
704
+ Script.inputIdentifiers.PUBKEYHASH_IN = Script.prototype.isPublicKeyHashIn;
705
+ Script.inputIdentifiers.MULTISIG_IN = Script.prototype.isMultisigIn;
706
+
707
+ /**
708
+ * @returns {object} The Script type if it is a known form,
709
+ * or Script.UNKNOWN if it isn't
710
+ */
711
+ Script.prototype.classifyInput = function () {
712
+ for (var type in Script.inputIdentifiers) {
713
+ if (Script.inputIdentifiers[type].bind(this)()) {
714
+ return Script.types[type];
715
+ }
716
+ }
717
+ return Script.types.UNKNOWN;
718
+ };
719
+
720
+ /**
721
+ * @returns {boolean} if script is one of the known types
722
+ */
723
+ Script.prototype.isStandard = function () {
724
+ // TODO: Add BIP62 compliance
725
+ return this.classify() !== Script.types.UNKNOWN;
726
+ };
727
+
728
+ // Script construction methods
729
+
730
+ /**
731
+ * Adds a script element at the start of the script.
732
+ * @param {*} obj a string, number, Opcode, Buffer, or object to add
733
+ * @returns {Script} this script instance
734
+ */
735
+ Script.prototype.prepend = function (obj) {
736
+ this._addByType(obj, true);
737
+ return this;
738
+ };
739
+
740
+
741
+ /**
742
+ * Compares this script with another script for equality.
743
+ * @param {Script} script - The script to compare with.
744
+ * @returns {boolean} True if the scripts have identical buffer contents, false otherwise.
745
+ * @throws {Error} If the provided argument is not a Script instance.
746
+ */
747
+ Script.prototype.equals = function (script) {
748
+ $.checkState(script instanceof Script, 'Must provide another script');
749
+ if (this.buffer.length !== script.buffer.length) {
750
+ return false;
751
+ }
752
+ var i;
753
+ for (i = 0; i < this.buffer.length; i++) {
754
+ if (this.buffer[i] !== script.buffer[i]) {
755
+ return false;
756
+ }
757
+ }
758
+ return true;
759
+ };
760
+
761
+
762
+ /**
763
+ * Adds a script element to the end of the script.
764
+ * @param {Object} obj - The object to add.
765
+ * @returns {Script} Returns the script instance for chaining.
766
+ */
767
+ Script.prototype.add = function (obj) {
768
+ this._addByType(obj, false);
769
+ return this;
770
+ };
771
+
772
+ /**
773
+ * Adds a script element to the script by type.
774
+ * Handles strings, numbers, Opcode instances, Buffers, Script instances, or objects.
775
+ * @param {string|number|Opcode|Buffer|Script|Object} obj - The element to add
776
+ * @param {boolean} [prepend=false] - Whether to prepend (true) or append (false)
777
+ * @throws {Error} If the input is an invalid script chunk
778
+ * @private
779
+ */
780
+ Script.prototype._addByType = function (obj, prepend) {
781
+ if (typeof obj === 'string') {
782
+ this._addOpcode(obj, prepend);
783
+ } else if (typeof obj === 'number') {
784
+ this._addOpcode(obj, prepend);
785
+ } else if (obj instanceof Opcode) {
786
+ this._addOpcode(obj, prepend);
787
+ } else if (Buffer.isBuffer(obj)) {
788
+ this._addBuffer(obj, prepend);
789
+ } else if (obj instanceof Script) {
790
+ this._insertAtPosition(obj.buffer, prepend);
791
+ } else if (typeof obj === 'object') {
792
+ var s = Script.fromChunks([obj]);
793
+ this._insertAtPosition(s.toBuffer(), prepend);
794
+ } else {
795
+ throw new Error('Invalid script chunk');
796
+ }
797
+ };
798
+
799
+ /**
800
+ * Inserts a buffer at the specified position in the script's buffer.
801
+ * @param {Buffer} buf - The buffer to insert.
802
+ * @param {boolean} prepend - If true, inserts before the existing buffer; otherwise appends after.
803
+ * @private
804
+ */
805
+ Script.prototype._insertAtPosition = function (buf, prepend) {
806
+ var bw = new BufferWriter();
807
+
808
+ if (prepend) {
809
+ bw.write(buf);
810
+ bw.write(this.buffer);
811
+ } else {
812
+ bw.write(this.buffer);
813
+ bw.write(buf);
814
+ }
815
+ this.buffer = bw.toBuffer();
816
+ };
817
+
818
+ /**
819
+ * Adds an opcode to the script.
820
+ * @param {number|Opcode|string} opcode - The opcode to add (can be a number, Opcode instance, or string).
821
+ * @param {boolean} [prepend=false] - Whether to prepend the opcode (true) or append it (false).
822
+ * @returns {Script} Returns the script instance for chaining.
823
+ * @throws {errors.Script.InvalidOpcode} Throws if the opcode value exceeds 255.
824
+ */
825
+ Script.prototype._addOpcode = function (opcode, prepend) {
826
+ var op;
827
+ if (typeof opcode === 'number') {
828
+ op = opcode;
829
+ } else if (opcode instanceof Opcode) {
830
+ op = opcode.toNumber();
831
+ } else {
832
+ op = Opcode(opcode).toNumber();
833
+ }
834
+
835
+ // OP_INVALIDOPCODE
836
+ if (op > 255) {
837
+ throw new errors.Script.InvalidOpcode(op);
838
+ }
839
+ this._insertAtPosition(
840
+ Script.fromChunks([
841
+ {
842
+ opcodenum: op,
843
+ },
844
+ ]).toBuffer(),
845
+ prepend,
846
+ );
847
+ return this;
848
+ };
849
+
850
+ /**
851
+ * Adds a buffer to the script with appropriate opcode based on buffer length.
852
+ * Handles different buffer sizes by using corresponding pushdata opcodes.
853
+ * @param {Buffer} buf - The buffer to add to the script
854
+ * @param {boolean} [prepend] - Whether to prepend the buffer (default: append)
855
+ * @returns {Script} Returns the script instance for chaining
856
+ * @throws {Error} If buffer length exceeds maximum allowed size (2^32)
857
+ */
858
+ Script.prototype._addBuffer = function (buf, prepend) {
859
+ var bw = new BufferWriter();
860
+ var opcodenum;
861
+ var len = buf.length;
862
+ if (len === 0) {
863
+ opcodenum = 0;
864
+ bw.writeUInt8(opcodenum);
865
+ } else if (len > 0 && len < Opcode.OP_PUSHDATA1) {
866
+ opcodenum = len;
867
+ bw.writeUInt8(opcodenum);
868
+ bw.write(buf);
869
+ } else if (len < Math.pow(2, 8)) {
870
+ opcodenum = Opcode.OP_PUSHDATA1;
871
+ bw.writeUInt8(opcodenum);
872
+ bw.writeUInt8(len);
873
+ bw.write(buf);
874
+ } else if (len < Math.pow(2, 16)) {
875
+ opcodenum = Opcode.OP_PUSHDATA2;
876
+ bw.writeUInt8(opcodenum);
877
+ bw.writeUInt16LE(len);
878
+ bw.write(buf);
879
+ } else if (len < Math.pow(2, 32)) {
880
+ opcodenum = Opcode.OP_PUSHDATA4;
881
+ bw.writeUInt8(opcodenum);
882
+ bw.writeUInt32LE(len);
883
+ bw.write(buf);
884
+ } else {
885
+ throw new Error("You can't push that much data");
886
+ }
887
+
888
+ this._insertAtPosition(bw.toBuffer(), prepend);
889
+ return this;
890
+ };
891
+
892
+ /**
893
+ * Creates a shallow copy of the Script instance.
894
+ * @returns {Script} A new Script instance with the same buffer content.
895
+ */
896
+ Script.prototype.clone = function () {
897
+ return Script.fromBuffer(this.buffer.slice());
898
+ };
899
+
900
+ /**
901
+ * Removes all OP_CODESEPARATOR opcodes from the script chunks.
902
+ * Updates the script buffer with the filtered chunks and clears the cache.
903
+ * @returns {Script} The modified script instance for chaining.
904
+ */
905
+ Script.prototype.removeCodeseparators = function () {
906
+ var chunks = [];
907
+ for (var i = 0; i < this.chunks.length; i++) {
908
+ if (this.chunks[i].opcodenum !== Opcode.OP_CODESEPARATOR) {
909
+ chunks.push(this.chunks[i]);
910
+ }
911
+ }
912
+ SCRIPT_TO_CHUNKS_CACHE.delete(this);
913
+
914
+ this.buffer = Script.fromChunks(chunks).toBuffer();
915
+ return this;
916
+ };
917
+
918
+ /**
919
+ * If the script does not contain any OP_CODESEPARATOR, Return all scripts
920
+ * If the script contains any OP_CODESEPARATOR, the scriptCode is the script but removing everything up to and including the last executed OP_CODESEPARATOR before the signature checking opcode being executed
921
+ * @param {n} The {n}th codeseparator in the script
922
+ *
923
+ * @returns {Script} Subset of script starting at the {n}th codeseparator
924
+ */
925
+ Script.prototype.subScript = function (n) {
926
+ var idx = 0;
927
+
928
+ for (var i = 0; i < this.chunks.length; i++) {
929
+ if (this.chunks[i].opcodenum === Opcode.OP_CODESEPARATOR) {
930
+ if (idx === n) {
931
+ return Script.fromChunks(this.chunks.slice(i + 1));
932
+ } else {
933
+ idx++;
934
+ }
935
+ }
936
+ }
937
+
938
+ return this;
939
+ };
940
+
941
+
942
+ /**
943
+ * Builds a multisig output script from given public keys and threshold.
944
+ * @param {Array} publicKeys - Array of public keys to include in the multisig
945
+ * @param {number} threshold - Minimum number of signatures required
946
+ * @param {Object} [opts] - Optional parameters
947
+ * @param {boolean} [opts.noSorting] - If true, skips sorting of public keys
948
+ * @returns {Script} The constructed multisig script
949
+ */
950
+ Script.buildMultisigOut = function (publicKeys, threshold, opts) {
951
+ $.checkArgument(
952
+ threshold <= publicKeys.length,
953
+ 'Number of required signatures must be less than or equal to the number of public keys',
954
+ );
955
+ opts = opts || {};
956
+ var script = new Script();
957
+ script.add(Opcode.smallInt(threshold));
958
+ publicKeys = _.map(publicKeys, PublicKey);
959
+ var sorted = publicKeys;
960
+ if (!opts.noSorting) {
961
+ sorted = publicKeys
962
+ .map((k) => k.toString('hex'))
963
+ .sort()
964
+ .map((k) => new PublicKey(k));
965
+ }
966
+ for (var i = 0; i < sorted.length; i++) {
967
+ var publicKey = sorted[i];
968
+ script.add(publicKey.toBuffer());
969
+ }
970
+ script.add(Opcode.smallInt(publicKeys.length));
971
+ script.add(Opcode.OP_CHECKMULTISIG);
972
+ return script;
973
+ };
974
+
975
+ /**
976
+ * A new Multisig input script for the given public keys, requiring m of those public keys to spend
977
+ *
978
+ * @param {PublicKey[]} pubkeys list of all public keys controlling the output
979
+ * @param {number} threshold amount of required signatures to spend the output
980
+ * @param {Array} signatures and array of signature buffers to append to the script
981
+ * @param {Object=} opts
982
+ * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default)
983
+ * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript
984
+ *
985
+ * @returns {Script}
986
+ */
987
+ Script.buildMultisigIn = function (pubkeys, threshold, signatures, opts) {
988
+ $.checkArgument(_.isArray(pubkeys));
989
+ $.checkArgument(_.isNumber(threshold));
990
+ $.checkArgument(_.isArray(signatures));
991
+ opts = opts || {};
992
+ var s = new Script();
993
+ s.add(Opcode.OP_0);
994
+ _.each(signatures, function (signature) {
995
+ $.checkArgument(Buffer.isBuffer(signature), 'Signatures must be an array of Buffers');
996
+ // TODO: allow signatures to be an array of Signature objects
997
+ s.add(signature);
998
+ });
999
+ return s;
1000
+ };
1001
+
1002
+
1003
+ /**
1004
+ * Builds a standard P2PKH (Pay-to-Public-Key-Hash) script for a given recipient.
1005
+ * @param {PublicKey|Address|string} to - Recipient's public key, address, or address string
1006
+ * @returns {Script} A P2PKH script with the format: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
1007
+ * @throws {Error} If 'to' argument is undefined or invalid type
1008
+ */
1009
+ Script.buildPublicKeyHashOut = function (to) {
1010
+ $.checkArgument(!_.isUndefined(to));
1011
+ $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to));
1012
+ if (to instanceof PublicKey) {
1013
+ to = to.toAddress();
1014
+ } else if (_.isString(to)) {
1015
+ to = new Address(to);
1016
+ }
1017
+ var s = new Script();
1018
+ s.add(Opcode.OP_DUP)
1019
+ .add(Opcode.OP_HASH160)
1020
+ .add(to.hashBuffer)
1021
+ .add(Opcode.OP_EQUALVERIFY)
1022
+ .add(Opcode.OP_CHECKSIG);
1023
+ s._network = to.network;
1024
+ return s;
1025
+ };
1026
+
1027
+
1028
+ /**
1029
+ * Builds a standard P2PK (Pay-to-Public-Key) script output.
1030
+ * @param {PublicKey} pubkey - The public key to create the script for
1031
+ * @returns {Script} A new script containing the public key and OP_CHECKSIG opcode
1032
+ */
1033
+ Script.buildPublicKeyOut = function (pubkey) {
1034
+ $.checkArgument(pubkey instanceof PublicKey);
1035
+ var s = new Script();
1036
+ s.add(pubkey.toBuffer()).add(Opcode.OP_CHECKSIG);
1037
+ return s;
1038
+ };
1039
+
1040
+ /**
1041
+ * @returns {Script} a new OP_RETURN script with data
1042
+ * @param {string|Buffer|Array} data - the data to embed in the output - it is a string, buffer, or array of strings or buffers
1043
+ * @param {string} encoding - the type of encoding of the string(s)
1044
+ */
1045
+ Script.buildDataOut = function (data, encoding) {
1046
+ $.checkArgument(
1047
+ _.isUndefined(data) || _.isString(data) || _.isArray(data) || Buffer.isBuffer(data),
1048
+ );
1049
+ var datas = data;
1050
+ if (!_.isArray(datas)) {
1051
+ datas = [data];
1052
+ }
1053
+ var s = new Script();
1054
+ s.add(Opcode.OP_RETURN);
1055
+ for (let data of datas) {
1056
+ $.checkArgument(_.isUndefined(data) || _.isString(data) || Buffer.isBuffer(data));
1057
+ if (_.isString(data)) {
1058
+ data = Buffer.from(data, encoding);
1059
+ }
1060
+ if (!_.isUndefined(data)) {
1061
+ s.add(data);
1062
+ }
1063
+ }
1064
+ return s;
1065
+ };
1066
+
1067
+ /**
1068
+ * @returns {Script} a new OP_RETURN script with data
1069
+ * @param {string|Buffer|Array} data - the data to embed in the output - it is a string, buffer, or array of strings or buffers
1070
+ * @param {string} encoding - the type of encoding of the string(s)
1071
+ */
1072
+ Script.buildSafeDataOut = function (data, encoding) {
1073
+ var s2 = Script.buildDataOut(data, encoding);
1074
+ var s1 = new Script();
1075
+ s1.add(Opcode.OP_FALSE);
1076
+ s1.add(s2);
1077
+ return s1;
1078
+ };
1079
+
1080
+
1081
+ /**
1082
+ * Builds a scriptSig (a script for an input) that signs a public key output script.
1083
+ *
1084
+ * @param {Signature|Buffer} signature - a Signature object, or the signature in DER canonical encoding
1085
+ * @param {number} [sigtype] - the type of the signature (defaults to SIGHASH_ALL)
1086
+ */
1087
+ Script.buildPublicKeyIn = function (signature, sigtype) {
1088
+ $.checkArgument(signature instanceof Signature || Buffer.isBuffer(signature));
1089
+ $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype));
1090
+ if (signature instanceof Signature) {
1091
+ signature = signature.toBuffer();
1092
+ }
1093
+ var script = new Script();
1094
+ script.add(Buffer.concat([signature, Buffer.from([(sigtype || Signature.SIGHASH_ALL) & 0xff])]));
1095
+ return script;
1096
+ };
1097
+
1098
+ /**
1099
+ * Builds a scriptSig (a script for an input) that signs a public key hash
1100
+ * output script.
1101
+ *
1102
+ * @param {Buffer|string|PublicKey} publicKey
1103
+ * @param {Signature|Buffer} signature - a Signature object, or the signature in DER canonical encoding
1104
+ * @param {number} [sigtype] - the type of the signature (defaults to SIGHASH_ALL)
1105
+ */
1106
+ Script.buildPublicKeyHashIn = function (publicKey, signature, sigtype) {
1107
+ $.checkArgument(signature instanceof Signature || Buffer.isBuffer(signature));
1108
+ $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype));
1109
+ if (signature instanceof Signature) {
1110
+ signature = signature.toBuffer();
1111
+ }
1112
+ var script = new Script()
1113
+ .add(Buffer.concat([signature, Buffer.from([(sigtype || Signature.SIGHASH_ALL) & 0xff])]))
1114
+ .add(new PublicKey(publicKey).toBuffer());
1115
+ return script;
1116
+ };
1117
+
1118
+
1119
+ /**
1120
+ * Creates and returns an empty Script instance.
1121
+ * @returns {Script} A new empty Script object.
1122
+ */
1123
+ Script.empty = function () {
1124
+ return new Script();
1125
+ };
1126
+
1127
+
1128
+ /**
1129
+ * Creates a Script from an address.
1130
+ * @param {Address|string} address - The address to convert to a script.
1131
+ * @returns {Script} A Pay-to-PublicKeyHash (P2PKH) script for the given address.
1132
+ * @throws {errors.Script.UnrecognizedAddress} If the address type is not supported.
1133
+ */
1134
+ Script.fromAddress = function (address) {
1135
+ address = Address(address);
1136
+ if (address.isPayToPublicKeyHash()) {
1137
+ return Script.buildPublicKeyHashOut(address);
1138
+ }
1139
+ throw new errors.Script.UnrecognizedAddress(address);
1140
+ };
1141
+
1142
+
1143
+ /**
1144
+ * Gets address information for the script.
1145
+ * For input scripts, returns input address info.
1146
+ * For output scripts, returns output address info.
1147
+ * For general scripts, tries output address info first, falls back to input if not available.
1148
+ * @returns {Object} Address information object
1149
+ */
1150
+ Script.prototype.getAddressInfo = function () {
1151
+ if (this._isInput) {
1152
+ return this._getInputAddressInfo();
1153
+ } else if (this._isOutput) {
1154
+ return this._getOutputAddressInfo();
1155
+ } else {
1156
+ var info = this._getOutputAddressInfo();
1157
+ if (!info) {
1158
+ return this._getInputAddressInfo();
1159
+ }
1160
+ return info;
1161
+ }
1162
+ };
1163
+
1164
+
1165
+ /**
1166
+ * Gets the output address information from the script.
1167
+ * @returns {Object|boolean} An object containing the hash buffer and address type if the script is a public key hash output, otherwise false.
1168
+ * @property {Buffer} info.hashBuffer - The hash buffer of the address.
1169
+ * @property {number} info.type - The type of the address (Address.PayToPublicKeyHash).
1170
+ */
1171
+ Script.prototype._getOutputAddressInfo = function () {
1172
+ var info = {};
1173
+ if (this.isPublicKeyHashOut()) {
1174
+ info.hashBuffer = this.getData();
1175
+ info.type = Address.PayToPublicKeyHash;
1176
+ } else {
1177
+ return false;
1178
+ }
1179
+ return info;
1180
+ };
1181
+
1182
+ /**
1183
+ * Will return the associated input scriptSig address information object
1184
+ * @return {Address|boolean}
1185
+ * @private
1186
+ */
1187
+ Script.prototype._getInputAddressInfo = function () {
1188
+ var info = {};
1189
+ if (this.isPublicKeyHashIn()) {
1190
+ // hash the publickey found in the scriptSig
1191
+ info.hashBuffer = Hash.sha256ripemd160(this.chunks[1].buf);
1192
+ info.type = Address.PayToPublicKeyHash;
1193
+ } else {
1194
+ return false;
1195
+ }
1196
+ return info;
1197
+ };
1198
+
1199
+
1200
+ /**
1201
+ * Converts the script to an Address object for the specified network.
1202
+ * @param {string|Network} [network] - optianal, the network name or identifier.
1203
+ * @returns {Address} The derived Address object.
1204
+ * @throws {errors.Script.CantDeriveAddress} If address information cannot be derived from the script.
1205
+ */
1206
+ Script.prototype.toAddress = function (network) {
1207
+ var info = this.getAddressInfo();
1208
+ if (!info) {
1209
+ throw new errors.Script.CantDeriveAddress(this);
1210
+ }
1211
+ info.network = Networks.get(network) || this._network || Networks.defaultNetwork;
1212
+ return new Address(info);
1213
+ };
1214
+
1215
+ /**
1216
+ * Finds and deletes a matching script chunk from the current script.
1217
+ * Analogous to bitcoind's FindAndDelete. Find and delete equivalent chunks,
1218
+ * typically used with push data chunks. Note that this will find and delete
1219
+ * not just the same data, but the same data with the same push data op as
1220
+ * produced by default. i.e., if a pushdata in a tx does not use the minimal
1221
+ * pushdata op, then when you try to remove the data it is pushing, it will not
1222
+ * be removed, because they do not use the same pushdata op.
1223
+ * @param {Script} script - The script chunk to find and delete.
1224
+ * @returns {Script} The modified script instance after deletion.
1225
+ */
1226
+ Script.prototype.findAndDelete = function (script) {
1227
+ var buf = script.toBuffer();
1228
+ var hex = buf.toString('hex');
1229
+ var chunks = this.chunks;
1230
+ for (var i = 0; i < chunks.length; i++) {
1231
+ var script2 = Script.fromChunks([chunks[i]]);
1232
+ var buf2 = script2.toBuffer();
1233
+ var hex2 = buf2.toString('hex');
1234
+ if (hex === hex2) {
1235
+ chunks.splice(i, 1);
1236
+ this.buffer = Script.fromChunks(chunks).toBuffer();
1237
+ }
1238
+ }
1239
+ return this;
1240
+ };
1241
+
1242
+
1243
+ /**
1244
+ * Checks if a script chunk uses the minimal push operation possible.
1245
+ *
1246
+ * @param {number} i - Index of the chunk to check
1247
+ * @returns {boolean} True if the chunk uses minimal push operation, false otherwise
1248
+ *
1249
+ * The function verifies if the chunk could have been represented with:
1250
+ * - OP_0 for empty buffer
1251
+ * - OP_1 to OP_16 for single-byte values 1-16
1252
+ * - OP_1NEGATE for 0x81
1253
+ * - Direct push for buffers ≤75 bytes
1254
+ * - OP_PUSHDATA1 for buffers ≤255 bytes
1255
+ * - OP_PUSHDATA2 for buffers ≤65535 bytes
1256
+ */
1257
+ Script.prototype.checkMinimalPush = function (i) {
1258
+ var chunk = this.chunks[i];
1259
+ var buf = chunk.buf;
1260
+ var opcodenum = chunk.opcodenum;
1261
+ if (!buf) {
1262
+ return true;
1263
+ }
1264
+ if (buf.length === 0) {
1265
+ // Could have used OP_0.
1266
+ return opcodenum === Opcode.OP_0;
1267
+ } else if (buf.length === 1 && buf[0] >= 1 && buf[0] <= 16) {
1268
+ // Could have used OP_1 .. OP_16.
1269
+ return opcodenum === Opcode.OP_1 + (buf[0] - 1);
1270
+ } else if (buf.length === 1 && buf[0] === 0x81) {
1271
+ // Could have used OP_1NEGATE
1272
+ return opcodenum === Opcode.OP_1NEGATE;
1273
+ } else if (buf.length <= 75) {
1274
+ // Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
1275
+ return opcodenum === buf.length;
1276
+ } else if (buf.length <= 255) {
1277
+ // Could have used OP_PUSHDATA.
1278
+ return opcodenum === Opcode.OP_PUSHDATA1;
1279
+ } else if (buf.length <= 65535) {
1280
+ // Could have used OP_PUSHDATA2.
1281
+ return opcodenum === Opcode.OP_PUSHDATA2;
1282
+ }
1283
+ return true;
1284
+ };
1285
+
1286
+ /**
1287
+ * Comes from bitcoind's script DecodeOP_N function
1288
+ * @param {number} opcode
1289
+ * @returns {number} numeric value in range of 0 to 16
1290
+ * @private
1291
+ */
1292
+ Script.prototype._decodeOP_N = function (opcode) {
1293
+ if (opcode === Opcode.OP_0) {
1294
+ return 0;
1295
+ } else if (opcode >= Opcode.OP_1 && opcode <= Opcode.OP_16) {
1296
+ return opcode - (Opcode.OP_1 - 1);
1297
+ } else {
1298
+ throw new Error('Invalid opcode: ' + JSON.stringify(opcode));
1299
+ }
1300
+ };
1301
+
1302
+
1303
+ /**
1304
+ * Counts the number of signature operations in the script.
1305
+ * @param {boolean} [accurate=true] - Whether to count accurately for OP_CHECKMULTISIG(VERIFY).
1306
+ * @returns {number} The total count of signature operations.
1307
+ */
1308
+ Script.prototype.getSignatureOperationsCount = function (accurate) {
1309
+ accurate = _.isUndefined(accurate) ? true : accurate;
1310
+ var self = this;
1311
+ var n = 0;
1312
+ var lastOpcode = Opcode.OP_INVALIDOPCODE;
1313
+ _.each(self.chunks, function getChunk(chunk) {
1314
+ var opcode = chunk.opcodenum;
1315
+ if (opcode === Opcode.OP_CHECKSIG || opcode === Opcode.OP_CHECKSIGVERIFY) {
1316
+ n++;
1317
+ } else if (opcode === Opcode.OP_CHECKMULTISIG || opcode === Opcode.OP_CHECKMULTISIGVERIFY) {
1318
+ if (accurate && lastOpcode >= Opcode.OP_1 && lastOpcode <= Opcode.OP_16) {
1319
+ n += self._decodeOP_N(lastOpcode);
1320
+ } else {
1321
+ n += 20;
1322
+ }
1323
+ }
1324
+ lastOpcode = opcode;
1325
+ });
1326
+ return n;
1327
+ };
1328
+
1329
+ export default Script;