xpi-ts 0.2.0

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 (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +516 -0
  3. package/dist/index.d.ts +9 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +8 -0
  6. package/dist/lib/bitcore/address.d.ts +66 -0
  7. package/dist/lib/bitcore/address.d.ts.map +1 -0
  8. package/dist/lib/bitcore/address.js +407 -0
  9. package/dist/lib/bitcore/block/block.d.ts +57 -0
  10. package/dist/lib/bitcore/block/block.d.ts.map +1 -0
  11. package/dist/lib/bitcore/block/block.js +233 -0
  12. package/dist/lib/bitcore/block/blockheader.d.ts +82 -0
  13. package/dist/lib/bitcore/block/blockheader.d.ts.map +1 -0
  14. package/dist/lib/bitcore/block/blockheader.js +323 -0
  15. package/dist/lib/bitcore/block/index.d.ts +5 -0
  16. package/dist/lib/bitcore/block/index.d.ts.map +1 -0
  17. package/dist/lib/bitcore/block/index.js +2 -0
  18. package/dist/lib/bitcore/chunk.d.ts +22 -0
  19. package/dist/lib/bitcore/chunk.d.ts.map +1 -0
  20. package/dist/lib/bitcore/chunk.js +46 -0
  21. package/dist/lib/bitcore/crypto/bn.d.ts +53 -0
  22. package/dist/lib/bitcore/crypto/bn.d.ts.map +1 -0
  23. package/dist/lib/bitcore/crypto/bn.js +238 -0
  24. package/dist/lib/bitcore/crypto/ecdsa.d.ts +46 -0
  25. package/dist/lib/bitcore/crypto/ecdsa.d.ts.map +1 -0
  26. package/dist/lib/bitcore/crypto/ecdsa.js +247 -0
  27. package/dist/lib/bitcore/crypto/hash.d.ts +16 -0
  28. package/dist/lib/bitcore/crypto/hash.d.ts.map +1 -0
  29. package/dist/lib/bitcore/crypto/hash.js +87 -0
  30. package/dist/lib/bitcore/crypto/index.d.ts +9 -0
  31. package/dist/lib/bitcore/crypto/index.d.ts.map +1 -0
  32. package/dist/lib/bitcore/crypto/index.js +8 -0
  33. package/dist/lib/bitcore/crypto/musig2.d.ts +40 -0
  34. package/dist/lib/bitcore/crypto/musig2.d.ts.map +1 -0
  35. package/dist/lib/bitcore/crypto/musig2.js +236 -0
  36. package/dist/lib/bitcore/crypto/point.d.ts +20 -0
  37. package/dist/lib/bitcore/crypto/point.d.ts.map +1 -0
  38. package/dist/lib/bitcore/crypto/point.js +133 -0
  39. package/dist/lib/bitcore/crypto/random.d.ts +7 -0
  40. package/dist/lib/bitcore/crypto/random.d.ts.map +1 -0
  41. package/dist/lib/bitcore/crypto/random.js +30 -0
  42. package/dist/lib/bitcore/crypto/schnorr.d.ts +40 -0
  43. package/dist/lib/bitcore/crypto/schnorr.d.ts.map +1 -0
  44. package/dist/lib/bitcore/crypto/schnorr.js +185 -0
  45. package/dist/lib/bitcore/crypto/signature.d.ts +53 -0
  46. package/dist/lib/bitcore/crypto/signature.d.ts.map +1 -0
  47. package/dist/lib/bitcore/crypto/signature.js +300 -0
  48. package/dist/lib/bitcore/crypto/sigtype.d.ts +5 -0
  49. package/dist/lib/bitcore/crypto/sigtype.d.ts.map +1 -0
  50. package/dist/lib/bitcore/crypto/sigtype.js +18 -0
  51. package/dist/lib/bitcore/encoding/base58.d.ts +16 -0
  52. package/dist/lib/bitcore/encoding/base58.d.ts.map +1 -0
  53. package/dist/lib/bitcore/encoding/base58.js +55 -0
  54. package/dist/lib/bitcore/encoding/base58check.d.ts +9 -0
  55. package/dist/lib/bitcore/encoding/base58check.d.ts.map +1 -0
  56. package/dist/lib/bitcore/encoding/base58check.js +82 -0
  57. package/dist/lib/bitcore/encoding/bufferreader.d.ts +34 -0
  58. package/dist/lib/bitcore/encoding/bufferreader.d.ts.map +1 -0
  59. package/dist/lib/bitcore/encoding/bufferreader.js +198 -0
  60. package/dist/lib/bitcore/encoding/bufferwriter.d.ts +36 -0
  61. package/dist/lib/bitcore/encoding/bufferwriter.d.ts.map +1 -0
  62. package/dist/lib/bitcore/encoding/bufferwriter.js +189 -0
  63. package/dist/lib/bitcore/encoding/varint.d.ts +20 -0
  64. package/dist/lib/bitcore/encoding/varint.d.ts.map +1 -0
  65. package/dist/lib/bitcore/encoding/varint.js +61 -0
  66. package/dist/lib/bitcore/errors.d.ts +28 -0
  67. package/dist/lib/bitcore/errors.d.ts.map +1 -0
  68. package/dist/lib/bitcore/errors.js +325 -0
  69. package/dist/lib/bitcore/hdprivatekey.d.ts +78 -0
  70. package/dist/lib/bitcore/hdprivatekey.d.ts.map +1 -0
  71. package/dist/lib/bitcore/hdprivatekey.js +381 -0
  72. package/dist/lib/bitcore/hdpublickey.d.ts +98 -0
  73. package/dist/lib/bitcore/hdpublickey.d.ts.map +1 -0
  74. package/dist/lib/bitcore/hdpublickey.js +416 -0
  75. package/dist/lib/bitcore/index.d.ts +60 -0
  76. package/dist/lib/bitcore/index.d.ts.map +1 -0
  77. package/dist/lib/bitcore/index.js +44 -0
  78. package/dist/lib/bitcore/message.d.ts +23 -0
  79. package/dist/lib/bitcore/message.d.ts.map +1 -0
  80. package/dist/lib/bitcore/message.js +112 -0
  81. package/dist/lib/bitcore/mnemonic/errors.d.ts +7 -0
  82. package/dist/lib/bitcore/mnemonic/errors.d.ts.map +1 -0
  83. package/dist/lib/bitcore/mnemonic/errors.js +20 -0
  84. package/dist/lib/bitcore/mnemonic/index.d.ts +5 -0
  85. package/dist/lib/bitcore/mnemonic/index.d.ts.map +1 -0
  86. package/dist/lib/bitcore/mnemonic/index.js +4 -0
  87. package/dist/lib/bitcore/mnemonic/mnemonic.d.ts +23 -0
  88. package/dist/lib/bitcore/mnemonic/mnemonic.d.ts.map +1 -0
  89. package/dist/lib/bitcore/mnemonic/mnemonic.js +164 -0
  90. package/dist/lib/bitcore/mnemonic/pbkdf2.d.ts +2 -0
  91. package/dist/lib/bitcore/mnemonic/pbkdf2.d.ts.map +1 -0
  92. package/dist/lib/bitcore/mnemonic/pbkdf2.js +25 -0
  93. package/dist/lib/bitcore/mnemonic/words/english.d.ts +2 -0
  94. package/dist/lib/bitcore/mnemonic/words/english.d.ts.map +1 -0
  95. package/dist/lib/bitcore/mnemonic/words/english.js +2050 -0
  96. package/dist/lib/bitcore/mnemonic/words/index.d.ts +4 -0
  97. package/dist/lib/bitcore/mnemonic/words/index.d.ts.map +1 -0
  98. package/dist/lib/bitcore/mnemonic/words/index.js +4 -0
  99. package/dist/lib/bitcore/musig2/index.d.ts +3 -0
  100. package/dist/lib/bitcore/musig2/index.d.ts.map +1 -0
  101. package/dist/lib/bitcore/musig2/index.js +2 -0
  102. package/dist/lib/bitcore/musig2/session.d.ts +79 -0
  103. package/dist/lib/bitcore/musig2/session.d.ts.map +1 -0
  104. package/dist/lib/bitcore/musig2/session.js +346 -0
  105. package/dist/lib/bitcore/musig2/signer.d.ts +61 -0
  106. package/dist/lib/bitcore/musig2/signer.d.ts.map +1 -0
  107. package/dist/lib/bitcore/musig2/signer.js +146 -0
  108. package/dist/lib/bitcore/networks.d.ts +53 -0
  109. package/dist/lib/bitcore/networks.d.ts.map +1 -0
  110. package/dist/lib/bitcore/networks.js +150 -0
  111. package/dist/lib/bitcore/opcode.d.ts +250 -0
  112. package/dist/lib/bitcore/opcode.d.ts.map +1 -0
  113. package/dist/lib/bitcore/opcode.js +270 -0
  114. package/dist/lib/bitcore/privatekey.d.ts +56 -0
  115. package/dist/lib/bitcore/privatekey.d.ts.map +1 -0
  116. package/dist/lib/bitcore/privatekey.js +237 -0
  117. package/dist/lib/bitcore/publickey.d.ts +59 -0
  118. package/dist/lib/bitcore/publickey.d.ts.map +1 -0
  119. package/dist/lib/bitcore/publickey.js +263 -0
  120. package/dist/lib/bitcore/script/interpreter.d.ts +98 -0
  121. package/dist/lib/bitcore/script/interpreter.d.ts.map +1 -0
  122. package/dist/lib/bitcore/script/interpreter.js +1704 -0
  123. package/dist/lib/bitcore/script.d.ts +111 -0
  124. package/dist/lib/bitcore/script.d.ts.map +1 -0
  125. package/dist/lib/bitcore/script.js +1112 -0
  126. package/dist/lib/bitcore/taproot/musig2.d.ts +29 -0
  127. package/dist/lib/bitcore/taproot/musig2.d.ts.map +1 -0
  128. package/dist/lib/bitcore/taproot/musig2.js +104 -0
  129. package/dist/lib/bitcore/taproot/nft.d.ts +164 -0
  130. package/dist/lib/bitcore/taproot/nft.d.ts.map +1 -0
  131. package/dist/lib/bitcore/taproot/nft.js +407 -0
  132. package/dist/lib/bitcore/taproot.d.ts +65 -0
  133. package/dist/lib/bitcore/taproot.d.ts.map +1 -0
  134. package/dist/lib/bitcore/taproot.js +288 -0
  135. package/dist/lib/bitcore/transaction/index.d.ts +12 -0
  136. package/dist/lib/bitcore/transaction/index.d.ts.map +1 -0
  137. package/dist/lib/bitcore/transaction/index.js +6 -0
  138. package/dist/lib/bitcore/transaction/input.d.ts +202 -0
  139. package/dist/lib/bitcore/transaction/input.d.ts.map +1 -0
  140. package/dist/lib/bitcore/transaction/input.js +911 -0
  141. package/dist/lib/bitcore/transaction/output.d.ts +48 -0
  142. package/dist/lib/bitcore/transaction/output.d.ts.map +1 -0
  143. package/dist/lib/bitcore/transaction/output.js +231 -0
  144. package/dist/lib/bitcore/transaction/sighash.d.ts +32 -0
  145. package/dist/lib/bitcore/transaction/sighash.d.ts.map +1 -0
  146. package/dist/lib/bitcore/transaction/sighash.js +335 -0
  147. package/dist/lib/bitcore/transaction/signature.d.ts +36 -0
  148. package/dist/lib/bitcore/transaction/signature.d.ts.map +1 -0
  149. package/dist/lib/bitcore/transaction/signature.js +130 -0
  150. package/dist/lib/bitcore/transaction/transaction.d.ts +164 -0
  151. package/dist/lib/bitcore/transaction/transaction.d.ts.map +1 -0
  152. package/dist/lib/bitcore/transaction/transaction.js +1016 -0
  153. package/dist/lib/bitcore/transaction/unspentoutput.d.ts +58 -0
  154. package/dist/lib/bitcore/transaction/unspentoutput.d.ts.map +1 -0
  155. package/dist/lib/bitcore/transaction/unspentoutput.js +167 -0
  156. package/dist/lib/bitcore/unit.d.ts +44 -0
  157. package/dist/lib/bitcore/unit.d.ts.map +1 -0
  158. package/dist/lib/bitcore/unit.js +106 -0
  159. package/dist/lib/bitcore/uri.d.ts +29 -0
  160. package/dist/lib/bitcore/uri.d.ts.map +1 -0
  161. package/dist/lib/bitcore/uri.js +163 -0
  162. package/dist/lib/bitcore/util/base32.d.ts +5 -0
  163. package/dist/lib/bitcore/util/base32.d.ts.map +1 -0
  164. package/dist/lib/bitcore/util/base32.js +58 -0
  165. package/dist/lib/bitcore/util/buffer.d.ts +18 -0
  166. package/dist/lib/bitcore/util/buffer.d.ts.map +1 -0
  167. package/dist/lib/bitcore/util/buffer.js +76 -0
  168. package/dist/lib/bitcore/util/convertBits.d.ts +2 -0
  169. package/dist/lib/bitcore/util/convertBits.d.ts.map +1 -0
  170. package/dist/lib/bitcore/util/convertBits.js +26 -0
  171. package/dist/lib/bitcore/util/js.d.ts +9 -0
  172. package/dist/lib/bitcore/util/js.d.ts.map +1 -0
  173. package/dist/lib/bitcore/util/js.js +45 -0
  174. package/dist/lib/bitcore/util/preconditions.d.ts +6 -0
  175. package/dist/lib/bitcore/util/preconditions.d.ts.map +1 -0
  176. package/dist/lib/bitcore/util/preconditions.js +31 -0
  177. package/dist/lib/bitcore/util.d.ts +14 -0
  178. package/dist/lib/bitcore/util.d.ts.map +1 -0
  179. package/dist/lib/bitcore/util.js +13 -0
  180. package/dist/lib/bitcore/xaddress.d.ts +45 -0
  181. package/dist/lib/bitcore/xaddress.d.ts.map +1 -0
  182. package/dist/lib/bitcore/xaddress.js +279 -0
  183. package/dist/lib/rank/api.d.ts +75 -0
  184. package/dist/lib/rank/api.d.ts.map +1 -0
  185. package/dist/lib/rank/api.js +4 -0
  186. package/dist/lib/rank/index.d.ts +127 -0
  187. package/dist/lib/rank/index.d.ts.map +1 -0
  188. package/dist/lib/rank/index.js +421 -0
  189. package/dist/lib/rank/opcode.d.ts +23 -0
  190. package/dist/lib/rank/opcode.d.ts.map +1 -0
  191. package/dist/lib/rank/opcode.js +23 -0
  192. package/dist/lib/rank/script.d.ts +2 -0
  193. package/dist/lib/rank/script.d.ts.map +1 -0
  194. package/dist/lib/rank/script.js +7 -0
  195. package/dist/lib/rank/transaction.d.ts +3 -0
  196. package/dist/lib/rank/transaction.d.ts.map +1 -0
  197. package/dist/lib/rank/transaction.js +12 -0
  198. package/dist/lib/rpc.d.ts +136 -0
  199. package/dist/lib/rpc.d.ts.map +1 -0
  200. package/dist/lib/rpc.js +62 -0
  201. package/dist/utils/constants.d.ts +18 -0
  202. package/dist/utils/constants.d.ts.map +1 -0
  203. package/dist/utils/constants.js +20 -0
  204. package/dist/utils/env.d.ts +3 -0
  205. package/dist/utils/env.d.ts.map +1 -0
  206. package/dist/utils/env.js +8 -0
  207. package/dist/utils/string.d.ts +11 -0
  208. package/dist/utils/string.d.ts.map +1 -0
  209. package/dist/utils/string.js +47 -0
  210. package/dist/utils/types.d.ts +2 -0
  211. package/dist/utils/types.d.ts.map +1 -0
  212. package/dist/utils/types.js +1 -0
  213. package/dist/utils/wallet.d.ts +12 -0
  214. package/dist/utils/wallet.d.ts.map +1 -0
  215. package/dist/utils/wallet.js +28 -0
  216. package/package.json +91 -0
@@ -0,0 +1,1016 @@
1
+ import { Preconditions } from '../util/preconditions.js';
2
+ import { JSUtil } from '../util/js.js';
3
+ import { BufferReader } from '../encoding/bufferreader.js';
4
+ import { BufferWriter } from '../encoding/bufferwriter.js';
5
+ import { Hash } from '../crypto/hash.js';
6
+ import { Signature } from '../crypto/signature.js';
7
+ import { verify } from './sighash.js';
8
+ import { BitcoreError } from '../errors.js';
9
+ import { Address } from '../address.js';
10
+ import { UnspentOutput } from './unspentoutput.js';
11
+ import { Input, MultisigInput, MultisigScriptHashInput, PublicKeyInput, PublicKeyHashInput, TaprootInput, MuSigTaprootInput, } from './input.js';
12
+ import { Output } from './output.js';
13
+ import { Script } from '../script.js';
14
+ import { PrivateKey } from '../privatekey.js';
15
+ import { BN } from '../crypto/bn.js';
16
+ import { sighash as computeSighash } from './sighash.js';
17
+ import { Interpreter } from '../script/interpreter.js';
18
+ const CURRENT_VERSION = 2;
19
+ const DEFAULT_NLOCKTIME = 0;
20
+ const MAX_BLOCK_SIZE = 32_000_000;
21
+ const DUST_AMOUNT = 546;
22
+ const FEE_SECURITY_MARGIN = 150;
23
+ const MAX_MONEY = 2_100_000_000_000_000;
24
+ const NLOCKTIME_BLOCKHEIGHT_LIMIT = 5e8;
25
+ const NLOCKTIME_MAX_VALUE = 4294967295;
26
+ const FEE_PER_KB = 1_000;
27
+ const CHANGE_OUTPUT_MAX_SIZE = 20 + 4 + 34 + 4;
28
+ const MAXIMUM_EXTRA_SIZE = 4 + 9 + 9 + 4;
29
+ const NULL_HASH = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex');
30
+ export class Transaction {
31
+ static DUST_AMOUNT = DUST_AMOUNT;
32
+ static FEE_SECURITY_MARGIN = FEE_SECURITY_MARGIN;
33
+ static NLOCKTIME_BLOCKHEIGHT_LIMIT = NLOCKTIME_BLOCKHEIGHT_LIMIT;
34
+ static NLOCKTIME_MAX_VALUE = NLOCKTIME_MAX_VALUE;
35
+ static FEE_PER_KB = FEE_PER_KB;
36
+ static CHANGE_OUTPUT_MAX_SIZE = CHANGE_OUTPUT_MAX_SIZE;
37
+ static MAXIMUM_EXTRA_SIZE = MAXIMUM_EXTRA_SIZE;
38
+ static NULL_HASH = NULL_HASH;
39
+ inputs = [];
40
+ outputs = [];
41
+ _version = CURRENT_VERSION;
42
+ nLockTime = DEFAULT_NLOCKTIME;
43
+ _inputAmount;
44
+ _outputAmount;
45
+ _changeScript;
46
+ _changeIndex;
47
+ _fee;
48
+ _feePerKb;
49
+ _feePerByte;
50
+ _hash;
51
+ _txid;
52
+ get spentOutputs() {
53
+ if (!this.inputs.every(input => input.output)) {
54
+ return undefined;
55
+ }
56
+ return this.inputs.map(input => input.output);
57
+ }
58
+ constructor(serialized) {
59
+ if (serialized instanceof Transaction) {
60
+ return Transaction.shallowCopy(serialized);
61
+ }
62
+ else if (typeof serialized === 'string' && JSUtil.isHexa(serialized)) {
63
+ this.fromString(serialized);
64
+ }
65
+ else if (Buffer.isBuffer(serialized)) {
66
+ this.fromBuffer(serialized);
67
+ }
68
+ else if (serialized && typeof serialized === 'object') {
69
+ this.fromObject(serialized);
70
+ }
71
+ else {
72
+ this._newTransaction();
73
+ }
74
+ }
75
+ static create(serialized) {
76
+ return new Transaction(serialized);
77
+ }
78
+ static shallowCopy(transaction) {
79
+ const copy = new Transaction(transaction.toBuffer());
80
+ return copy;
81
+ }
82
+ static fromBuffer(buffer) {
83
+ return new Transaction(buffer);
84
+ }
85
+ static fromBufferReader(reader) {
86
+ return new Transaction().fromBufferReader(reader);
87
+ }
88
+ static fromObject(arg) {
89
+ return new Transaction(arg);
90
+ }
91
+ static fromString(str) {
92
+ return new Transaction(str);
93
+ }
94
+ get hash() {
95
+ if (!this._hash) {
96
+ const hashBuffer = this._getHash();
97
+ const reader = new BufferReader(hashBuffer);
98
+ this._hash = reader.readReverse(32).toString('hex');
99
+ }
100
+ return this._hash;
101
+ }
102
+ get id() {
103
+ return this.txid;
104
+ }
105
+ get txid() {
106
+ if (!this._txid) {
107
+ const txidBuffer = this._getTxid();
108
+ const reader = new BufferReader(txidBuffer);
109
+ this._txid = reader.readReverse(32).toString('hex');
110
+ }
111
+ return this._txid;
112
+ }
113
+ get inputAmount() {
114
+ return this._getInputAmount();
115
+ }
116
+ get outputAmount() {
117
+ return this._getOutputAmount();
118
+ }
119
+ get version() {
120
+ return this._version;
121
+ }
122
+ feePerByte(feePerByte) {
123
+ this._feePerByte = feePerByte;
124
+ this._updateChangeOutput();
125
+ }
126
+ fee(amount) {
127
+ this._fee = amount;
128
+ this._updateChangeOutput();
129
+ }
130
+ feePerKb(amount) {
131
+ this._feePerKb = amount;
132
+ this._updateChangeOutput();
133
+ }
134
+ set version(version) {
135
+ this._version = version;
136
+ }
137
+ _getHash() {
138
+ return Hash.sha256sha256(this.toBuffer());
139
+ }
140
+ _getTxid() {
141
+ const writer = new BufferWriter();
142
+ writer.writeInt32LE(this.version);
143
+ const inputHashes = this._getTxInputHashes();
144
+ const outputHashes = this._getTxOutputHashes();
145
+ const inputMerkleRootAndHeight = this._computeMerkleRoot(inputHashes);
146
+ const outputMerkleRootAndHeight = this._computeMerkleRoot(outputHashes);
147
+ writer.write(inputMerkleRootAndHeight.root);
148
+ writer.writeUInt8(inputMerkleRootAndHeight.height);
149
+ writer.write(outputMerkleRootAndHeight.root);
150
+ writer.writeUInt8(outputMerkleRootAndHeight.height);
151
+ writer.writeUInt32LE(this.nLockTime);
152
+ return Hash.sha256sha256(writer.toBuffer());
153
+ }
154
+ _getTxInputHashes() {
155
+ const hashes = [];
156
+ if (this.inputs.length === 0) {
157
+ return [Transaction.NULL_HASH];
158
+ }
159
+ for (let i = 0; i < this.inputs.length; i++) {
160
+ const input = this.inputs[i];
161
+ const writer = new BufferWriter();
162
+ writer.writeReverse(input.prevTxId);
163
+ writer.writeUInt32LE(input.outputIndex);
164
+ writer.writeUInt32LE(Number(input.sequenceNumber));
165
+ const hash = Hash.sha256sha256(writer.toBuffer());
166
+ hashes.push(hash);
167
+ }
168
+ return hashes;
169
+ }
170
+ _getTxOutputHashes() {
171
+ const hashes = [];
172
+ if (this.outputs.length === 0) {
173
+ return [Transaction.NULL_HASH];
174
+ }
175
+ for (let i = 0; i < this.outputs.length; i++) {
176
+ const output = this.outputs[i];
177
+ const writer = new BufferWriter();
178
+ writer.writeUInt64LEBN(new BN(output.satoshis));
179
+ writer.writeVarLengthBuffer(output.scriptBuffer);
180
+ const hash = Hash.sha256sha256(writer.toBuffer());
181
+ hashes.push(hash);
182
+ }
183
+ return hashes;
184
+ }
185
+ _computeMerkleRoot(hashes) {
186
+ if (hashes.length === 0) {
187
+ return {
188
+ root: Transaction.NULL_HASH,
189
+ height: 0,
190
+ };
191
+ }
192
+ let j = 0;
193
+ let height = 1;
194
+ for (let size = hashes.length; size > 1; size = Math.floor(size / 2)) {
195
+ height += 1;
196
+ if (size % 2 === 1) {
197
+ hashes.push(Transaction.NULL_HASH);
198
+ size += 1;
199
+ }
200
+ for (let i = 0; i < size; i += 2) {
201
+ const buf = Buffer.concat([hashes[j + i], hashes[j + i + 1]]);
202
+ hashes.push(Hash.sha256sha256(buf));
203
+ }
204
+ j += size;
205
+ }
206
+ return {
207
+ root: hashes[hashes.length - 1],
208
+ height: height,
209
+ };
210
+ }
211
+ _getInputAmount() {
212
+ if (this._inputAmount !== undefined) {
213
+ return this._inputAmount;
214
+ }
215
+ let total = 0;
216
+ for (const input of this.inputs) {
217
+ if (input.output && input.output.satoshis) {
218
+ total += input.output.satoshis;
219
+ }
220
+ }
221
+ this._inputAmount = total;
222
+ return total;
223
+ }
224
+ _getOutputAmount() {
225
+ if (this._outputAmount !== undefined) {
226
+ return this._outputAmount;
227
+ }
228
+ let total = 0;
229
+ for (const output of this.outputs) {
230
+ total += output.satoshis;
231
+ }
232
+ this._outputAmount = total;
233
+ return total;
234
+ }
235
+ _newTransaction() {
236
+ this.version = CURRENT_VERSION;
237
+ this.nLockTime = DEFAULT_NLOCKTIME;
238
+ }
239
+ serialize(unsafe) {
240
+ if (unsafe === true || (unsafe && unsafe.disableAll)) {
241
+ return this.uncheckedSerialize();
242
+ }
243
+ else {
244
+ return this.checkedSerialize(unsafe);
245
+ }
246
+ }
247
+ uncheckedSerialize() {
248
+ return this.toBuffer().toString('hex');
249
+ }
250
+ checkedSerialize(opts) {
251
+ const serializationError = this.getSerializationError(opts);
252
+ if (serializationError) {
253
+ serializationError.message +=
254
+ ' - For more information please see: ' +
255
+ 'https://bitcore.io/api/lib/transaction#serialization-checks';
256
+ throw serializationError;
257
+ }
258
+ return this.uncheckedSerialize();
259
+ }
260
+ getSerializationError(opts) {
261
+ const dustError = this._hasDustOutputs(opts);
262
+ if (dustError)
263
+ return dustError;
264
+ const sigError = this._isMissingSignatures(opts);
265
+ if (sigError)
266
+ return sigError;
267
+ if (this._hasInvalidSatoshis()) {
268
+ return new BitcoreError('Invalid satoshis in outputs');
269
+ }
270
+ return null;
271
+ }
272
+ _hasDustOutputs(opts) {
273
+ if (opts && opts.disableDustOutputs) {
274
+ return null;
275
+ }
276
+ for (const output of this.outputs) {
277
+ if (output.satoshis < Transaction.DUST_AMOUNT && !output.isOpReturn()) {
278
+ return new BitcoreError('Dust outputs not allowed');
279
+ }
280
+ }
281
+ return null;
282
+ }
283
+ _isMissingSignatures(opts) {
284
+ if (opts && opts.disableIsFullySigned) {
285
+ return null;
286
+ }
287
+ if (!this.isFullySigned()) {
288
+ return new BitcoreError('Transaction is not fully signed');
289
+ }
290
+ return null;
291
+ }
292
+ _hasInvalidSatoshis() {
293
+ for (const output of this.outputs) {
294
+ if (output.satoshis < 0) {
295
+ return true;
296
+ }
297
+ }
298
+ return false;
299
+ }
300
+ isFullySigned() {
301
+ for (const input of this.inputs) {
302
+ if (!input.script || input.script.chunks.length === 0) {
303
+ return false;
304
+ }
305
+ }
306
+ return true;
307
+ }
308
+ toBuffer() {
309
+ const writer = new BufferWriter();
310
+ return this.toBufferWriter(writer).toBuffer();
311
+ }
312
+ toBufferWriter(writer) {
313
+ if (!writer) {
314
+ writer = new BufferWriter();
315
+ }
316
+ writer.writeInt32LE(this.version);
317
+ writer.writeVarintNum(this.inputs.length);
318
+ for (const input of this.inputs) {
319
+ input.toBufferWriter(writer);
320
+ }
321
+ writer.writeVarintNum(this.outputs.length);
322
+ for (const output of this.outputs) {
323
+ writer.writeUInt64LEBN(new BN(output.satoshis));
324
+ writer.writeVarLengthBuffer(output.scriptBuffer);
325
+ }
326
+ writer.writeUInt32LE(this.nLockTime);
327
+ return writer;
328
+ }
329
+ fromBuffer(buffer) {
330
+ const reader = new BufferReader(buffer);
331
+ return this.fromBufferReader(reader);
332
+ }
333
+ fromBufferReader(reader) {
334
+ Preconditions.checkArgument(!reader.finished(), 'No transaction data received');
335
+ this.version = reader.readInt32LE();
336
+ const sizeTxIns = reader.readVarintNum();
337
+ for (let i = 0; i < sizeTxIns; i++) {
338
+ const input = Input.fromBufferReader(reader);
339
+ this.inputs.push(input);
340
+ }
341
+ const sizeTxOuts = reader.readVarintNum();
342
+ for (let i = 0; i < sizeTxOuts; i++) {
343
+ const output = Output.fromBufferReader(reader);
344
+ this.outputs.push(output);
345
+ }
346
+ this.nLockTime = reader.readUInt32LE();
347
+ return this;
348
+ }
349
+ fromString(str) {
350
+ return this.fromBuffer(Buffer.from(str, 'hex'));
351
+ }
352
+ toObject() {
353
+ const inputs = this.inputs.map(input => input.toObject());
354
+ const outputs = this.outputs.map(output => output.toObject());
355
+ const obj = {
356
+ txid: this.txid,
357
+ hash: this.hash,
358
+ version: this.version,
359
+ inputs: inputs,
360
+ outputs: outputs,
361
+ nLockTime: this.nLockTime,
362
+ };
363
+ if (this._changeScript) {
364
+ obj.changeScript = this._changeScript.toString();
365
+ obj.changeAsm = this._changeScript.toASM();
366
+ }
367
+ if (this._changeIndex !== undefined) {
368
+ obj.changeIndex = this._changeIndex;
369
+ }
370
+ if (this._fee !== undefined) {
371
+ obj.fee = this._fee;
372
+ }
373
+ return obj;
374
+ }
375
+ toJSON = this.toObject;
376
+ fromObject(arg) {
377
+ Preconditions.checkArgument(typeof arg === 'object' && arg !== null, 'Must provide an object to deserialize a transaction');
378
+ let transaction;
379
+ if (arg instanceof Transaction) {
380
+ const obj = arg.toObject();
381
+ transaction = {
382
+ version: obj.version,
383
+ nLockTime: obj.nLockTime,
384
+ inputs: obj.inputs,
385
+ outputs: obj.outputs,
386
+ changeScript: obj.changeScript,
387
+ changeIndex: obj.changeIndex,
388
+ fee: obj.fee,
389
+ };
390
+ }
391
+ else {
392
+ transaction = arg;
393
+ }
394
+ this.inputs = [];
395
+ this.outputs = [];
396
+ this.version = transaction.version || CURRENT_VERSION;
397
+ this.nLockTime = transaction.nLockTime || DEFAULT_NLOCKTIME;
398
+ if (transaction.inputs) {
399
+ for (const inputData of transaction.inputs) {
400
+ const input = new Input({
401
+ prevTxId: inputData.prevTxId,
402
+ outputIndex: inputData.outputIndex,
403
+ sequenceNumber: inputData.sequenceNumber,
404
+ script: inputData.script || undefined,
405
+ scriptBuffer: inputData.scriptBuffer,
406
+ output: inputData.output,
407
+ });
408
+ this.inputs.push(input);
409
+ }
410
+ }
411
+ if (transaction.outputs) {
412
+ for (const outputData of transaction.outputs) {
413
+ const output = new Output({
414
+ satoshis: outputData.satoshis,
415
+ script: outputData.script,
416
+ });
417
+ this.outputs.push(output);
418
+ }
419
+ }
420
+ if (transaction.changeScript) {
421
+ this._changeScript =
422
+ typeof transaction.changeScript === 'string'
423
+ ? Script.fromString(transaction.changeScript)
424
+ : transaction.changeScript;
425
+ }
426
+ if (transaction.changeIndex !== undefined) {
427
+ this._changeIndex = transaction.changeIndex;
428
+ }
429
+ if (transaction.fee !== undefined) {
430
+ this._fee = transaction.fee;
431
+ }
432
+ return this;
433
+ }
434
+ addInput(input) {
435
+ this.inputs.push(input);
436
+ this._inputAmount = undefined;
437
+ return this;
438
+ }
439
+ addOutput(output) {
440
+ this._addOutput(output);
441
+ this._updateChangeOutput();
442
+ return this;
443
+ }
444
+ clone() {
445
+ return Transaction.shallowCopy(this);
446
+ }
447
+ toString() {
448
+ return this.uncheckedSerialize();
449
+ }
450
+ inspect() {
451
+ return '<Transaction: ' + this.uncheckedSerialize() + '>';
452
+ }
453
+ from(utxos, pubkeys, threshold, opts) {
454
+ if (Array.isArray(utxos)) {
455
+ for (const utxo of utxos) {
456
+ this.from(utxo, pubkeys, threshold, opts);
457
+ }
458
+ return this;
459
+ }
460
+ const exists = this.inputs.some(input => input.prevTxId.toString('hex') === utxos.txId &&
461
+ input.outputIndex === utxos.outputIndex);
462
+ if (exists) {
463
+ return this;
464
+ }
465
+ const utxo = utxos instanceof UnspentOutput ? utxos : new UnspentOutput(utxos);
466
+ if (pubkeys && threshold) {
467
+ this._fromMultisigUtxo(utxo, pubkeys, threshold, opts);
468
+ }
469
+ else {
470
+ this._fromNonP2SH(utxo);
471
+ }
472
+ return this;
473
+ }
474
+ change(address) {
475
+ this._changeScript = Script.fromAddress(address);
476
+ this._updateChangeOutput();
477
+ return this;
478
+ }
479
+ to(address, amount) {
480
+ if (Array.isArray(address)) {
481
+ for (const to of address) {
482
+ this.to(to.address, to.satoshis);
483
+ }
484
+ return this;
485
+ }
486
+ Preconditions.checkArgument(JSUtil.isNaturalNumber(amount), 'Amount is expected to be a positive integer');
487
+ this.addOutput(new Output({
488
+ script: Script.fromAddress(new Address(address)),
489
+ satoshis: amount,
490
+ }));
491
+ return this;
492
+ }
493
+ sign(privateKey, sigtype, signingMethod) {
494
+ const privKeys = Array.isArray(privateKey) ? privateKey : [privateKey];
495
+ const sigtypeDefault = sigtype || Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID;
496
+ for (const privKey of privKeys) {
497
+ const signatures = this.getSignatures(privKey, sigtypeDefault, signingMethod);
498
+ for (const signature of signatures) {
499
+ this.applySignature(signature, signingMethod);
500
+ }
501
+ }
502
+ return this;
503
+ }
504
+ signSchnorr(privateKey) {
505
+ return this.sign(privateKey, Signature.SIGHASH_ALL | Signature.SIGHASH_LOTUS, 'schnorr');
506
+ }
507
+ getMuSig2Inputs() {
508
+ return this.inputs.filter(input => input instanceof MuSigTaprootInput);
509
+ }
510
+ getMuSig2Sighash(inputIndex) {
511
+ const input = this.inputs[inputIndex];
512
+ if (!(input instanceof MuSigTaprootInput)) {
513
+ throw new Error(`Input ${inputIndex} is not a MuSigTaprootInput`);
514
+ }
515
+ if (!input.output) {
516
+ throw new Error(`Input ${inputIndex} is missing output information`);
517
+ }
518
+ const sigtype = Signature.SIGHASH_ALL | Signature.SIGHASH_LOTUS;
519
+ return computeSighash(this, sigtype, inputIndex, input.output.script, new BN(input.output.satoshis));
520
+ }
521
+ addMuSig2Nonce(inputIndex, signerIndex, nonce) {
522
+ const input = this.inputs[inputIndex];
523
+ if (!(input instanceof MuSigTaprootInput)) {
524
+ throw new Error(`Input ${inputIndex} is not a MuSigTaprootInput`);
525
+ }
526
+ input.addPublicNonce(signerIndex, nonce);
527
+ return this;
528
+ }
529
+ addMuSig2PartialSignature(inputIndex, signerIndex, partialSig) {
530
+ const input = this.inputs[inputIndex];
531
+ if (!(input instanceof MuSigTaprootInput)) {
532
+ throw new Error(`Input ${inputIndex} is not a MuSigTaprootInput`);
533
+ }
534
+ input.addPartialSignature(signerIndex, partialSig);
535
+ return this;
536
+ }
537
+ finalizeMuSig2Signatures() {
538
+ const musigInputs = this.getMuSig2Inputs();
539
+ for (let i = 0; i < this.inputs.length; i++) {
540
+ const input = this.inputs[i];
541
+ if (input instanceof MuSigTaprootInput) {
542
+ if (!input.hasAllPartialSignatures()) {
543
+ throw new Error(`MuSig2 input ${i} is missing partial signatures. ` +
544
+ `Has ${input.partialSignatures?.size || 0} of ${input.keyAggContext?.pubkeys.length || 0}`);
545
+ }
546
+ const sighash = this.getMuSig2Sighash(i);
547
+ input.finalizeMuSigSignature(this, sighash);
548
+ }
549
+ }
550
+ return this;
551
+ }
552
+ getSignatures(privKey, sigtype, signingMethod) {
553
+ const privateKey = new PrivateKey(privKey);
554
+ const sigtypeDefault = sigtype || Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID;
555
+ const results = [];
556
+ const hashData = Hash.sha256ripemd160(privateKey.publicKey.toBuffer());
557
+ for (let index = 0; index < this.inputs.length; index++) {
558
+ const input = this.inputs[index];
559
+ const signatures = input.getSignatures(this, privateKey, index, sigtypeDefault, hashData, signingMethod);
560
+ for (const signature of signatures) {
561
+ results.push(signature);
562
+ }
563
+ }
564
+ return results;
565
+ }
566
+ applySignature(signature, signingMethod) {
567
+ this.inputs[signature.inputIndex].addSignature(this, signature, signingMethod);
568
+ return this;
569
+ }
570
+ isValidSignature(sig) {
571
+ const input = this.inputs[sig.inputIndex];
572
+ return input.isValidSignature(this, sig);
573
+ }
574
+ verifySignature(sig, pubkey, nin, subscript, satoshisBN, flags, signingMethod) {
575
+ return verify(this, sig, pubkey, nin, subscript, satoshisBN, flags, signingMethod);
576
+ }
577
+ lockUntilDate(time) {
578
+ Preconditions.checkArgument(!!time, 'time is required');
579
+ if (typeof time === 'number' &&
580
+ time < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
581
+ throw new Error('Lock time too early');
582
+ }
583
+ if (time instanceof Date) {
584
+ time = time.getTime() / 1000;
585
+ }
586
+ for (let i = 0; i < this.inputs.length; i++) {
587
+ if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER) {
588
+ this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER;
589
+ }
590
+ }
591
+ this.nLockTime = time;
592
+ return this;
593
+ }
594
+ lockUntilBlockHeight(height) {
595
+ Preconditions.checkArgument(typeof height === 'number', 'height must be a number');
596
+ if (height >= Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
597
+ throw new Error('Block height too high');
598
+ }
599
+ if (height < 0) {
600
+ throw new Error('NLockTime out of range');
601
+ }
602
+ for (let i = 0; i < this.inputs.length; i++) {
603
+ if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER) {
604
+ this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER;
605
+ }
606
+ }
607
+ this.nLockTime = height;
608
+ return this;
609
+ }
610
+ getLockTime() {
611
+ if (!this.nLockTime) {
612
+ return null;
613
+ }
614
+ if (this.nLockTime < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
615
+ return this.nLockTime;
616
+ }
617
+ return new Date(1000 * this.nLockTime);
618
+ }
619
+ hasAllUtxoInfo() {
620
+ return this.inputs.every(input => !!input.output);
621
+ }
622
+ addData(value) {
623
+ this.addOutput(new Output({
624
+ script: Script.buildDataOut(value),
625
+ satoshis: 0,
626
+ }));
627
+ return this;
628
+ }
629
+ clearOutputs() {
630
+ this.outputs = [];
631
+ this._clearSignatures();
632
+ this._outputAmount = undefined;
633
+ this._changeIndex = undefined;
634
+ this._updateChangeOutput();
635
+ return this;
636
+ }
637
+ removeOutput(index) {
638
+ this._removeOutput(index);
639
+ this._updateChangeOutput();
640
+ }
641
+ sort() {
642
+ this.sortInputs(inputs => {
643
+ const copy = [...inputs];
644
+ let i = 0;
645
+ copy.forEach(x => {
646
+ ;
647
+ x.i = i++;
648
+ });
649
+ copy.sort((first, second) => {
650
+ const prevTxIdCompare = Buffer.compare(first.prevTxId, second.prevTxId);
651
+ if (prevTxIdCompare !== 0)
652
+ return prevTxIdCompare;
653
+ const outputIndexCompare = first.outputIndex - second.outputIndex;
654
+ if (outputIndexCompare !== 0)
655
+ return outputIndexCompare;
656
+ return (first.i -
657
+ second.i);
658
+ });
659
+ return copy;
660
+ });
661
+ this.sortOutputs(outputs => {
662
+ const copy = [...outputs];
663
+ let i = 0;
664
+ copy.forEach(x => {
665
+ ;
666
+ x.i = i++;
667
+ });
668
+ copy.sort((first, second) => {
669
+ const satoshisCompare = first.satoshis - second.satoshis;
670
+ if (satoshisCompare !== 0)
671
+ return satoshisCompare;
672
+ const scriptCompare = Buffer.compare(first.scriptBuffer, second.scriptBuffer);
673
+ if (scriptCompare !== 0)
674
+ return scriptCompare;
675
+ return (first.i -
676
+ second.i);
677
+ });
678
+ return copy;
679
+ });
680
+ return this;
681
+ }
682
+ sortInputs(sortingFunction) {
683
+ this.inputs = sortingFunction(this.inputs);
684
+ return this;
685
+ }
686
+ sortOutputs(sortingFunction) {
687
+ const sortedOutputs = sortingFunction(this.outputs);
688
+ return this._newOutputOrder(sortedOutputs);
689
+ }
690
+ shuffleOutputs() {
691
+ return this.sortOutputs(outputs => {
692
+ const shuffled = [...outputs];
693
+ for (let i = shuffled.length - 1; i > 0; i--) {
694
+ const j = Math.floor(Math.random() * (i + 1));
695
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
696
+ }
697
+ return shuffled;
698
+ });
699
+ }
700
+ removeInput(index) {
701
+ this.inputs.splice(index, 1);
702
+ this._inputAmount = undefined;
703
+ }
704
+ getFee() {
705
+ if (this.isCoinbase()) {
706
+ return 0;
707
+ }
708
+ if (this._fee !== undefined) {
709
+ return this._fee;
710
+ }
711
+ if (!this._changeScript) {
712
+ return this._getUnspentValue();
713
+ }
714
+ return this._estimateFee();
715
+ }
716
+ getChangeOutput() {
717
+ if (this._changeIndex !== undefined) {
718
+ return this.outputs[this._changeIndex];
719
+ }
720
+ return null;
721
+ }
722
+ verify() {
723
+ if (this.inputs.length === 0) {
724
+ return 'transaction inputs empty';
725
+ }
726
+ if (this.outputs.length === 0) {
727
+ return 'transaction outputs empty';
728
+ }
729
+ if (this.toBuffer().length > MAX_BLOCK_SIZE) {
730
+ return 'transaction over the maximum block size';
731
+ }
732
+ let totalOutput = 0;
733
+ for (let i = 0; i < this.outputs.length; i++) {
734
+ const output = this.outputs[i];
735
+ if (output.satoshis < 0) {
736
+ return 'transaction output ' + i + ' satoshis is negative';
737
+ }
738
+ if (output.satoshis > MAX_MONEY) {
739
+ return 'transaction output ' + i + ' greater than MAX_MONEY';
740
+ }
741
+ totalOutput += output.satoshis;
742
+ if (totalOutput > MAX_MONEY) {
743
+ return ('transaction output ' + i + ' total output greater than MAX_MONEY');
744
+ }
745
+ }
746
+ if (this.isCoinbase()) {
747
+ const coinbaseScript = this.inputs[0].scriptBuffer;
748
+ if (!coinbaseScript ||
749
+ coinbaseScript.length < 2 ||
750
+ coinbaseScript.length > 100) {
751
+ return 'coinbase transaction script size invalid';
752
+ }
753
+ return true;
754
+ }
755
+ if (!this.hasAllUtxoInfo()) {
756
+ return 'Missing previous output information';
757
+ }
758
+ if (this.inputAmount < this.outputAmount) {
759
+ return 'transaction input amount is less than output amount';
760
+ }
761
+ const actualFee = this.inputAmount - this.outputAmount;
762
+ const txSize = this.toBuffer().length;
763
+ const feeRatePerByte = Transaction.FEE_PER_KB / 1000;
764
+ const minRequiredFee = Math.ceil(txSize * feeRatePerByte);
765
+ if (actualFee < minRequiredFee) {
766
+ return `transaction fee too low: ${actualFee} < ${minRequiredFee} (minimum ${feeRatePerByte} satoshi/byte)`;
767
+ }
768
+ const inputSet = new Set();
769
+ for (let i = 0; i < this.inputs.length; i++) {
770
+ const input = this.inputs[i];
771
+ if (input.prevTxId.equals(Transaction.NULL_HASH)) {
772
+ return 'transaction input ' + i + ' has null input';
773
+ }
774
+ const inputId = input.prevTxId.toString('hex') + ':' + input.outputIndex.toString();
775
+ if (inputSet.has(inputId)) {
776
+ return 'transaction input ' + i + ' duplicate input';
777
+ }
778
+ inputSet.add(inputId);
779
+ }
780
+ const scriptVerification = this._verifyScripts();
781
+ if (!scriptVerification.success) {
782
+ return scriptVerification.error || 'Script verification failed';
783
+ }
784
+ return true;
785
+ }
786
+ _verifyScripts(flags) {
787
+ if (this.isCoinbase()) {
788
+ return { success: true };
789
+ }
790
+ if (!this.hasAllUtxoInfo()) {
791
+ return {
792
+ success: false,
793
+ error: 'Missing UTXO (output) information for script verification',
794
+ };
795
+ }
796
+ for (let i = 0; i < this.inputs.length; i++) {
797
+ const input = this.inputs[i];
798
+ if (!input.script || !input.output?.script) {
799
+ return {
800
+ success: false,
801
+ error: `Input ${i} script verification failed: missing script`,
802
+ };
803
+ }
804
+ try {
805
+ const verifyFlags = flags !== undefined
806
+ ? flags
807
+ : Interpreter.SCRIPT_VERIFY_P2SH |
808
+ Interpreter.SCRIPT_VERIFY_STRICTENC |
809
+ Interpreter.SCRIPT_VERIFY_DERSIG |
810
+ Interpreter.SCRIPT_VERIFY_LOW_S |
811
+ Interpreter.SCRIPT_VERIFY_NULLFAIL |
812
+ Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID |
813
+ Interpreter.SCRIPT_ENABLE_SCHNORR_MULTISIG;
814
+ const interpreter = new Interpreter();
815
+ const isValid = interpreter.verify(input.script, input.output.script, this, i, verifyFlags, BigInt(input.output.satoshis));
816
+ if (!isValid) {
817
+ return {
818
+ success: false,
819
+ error: `Input ${i} script verification failed: ${interpreter.errstr}`,
820
+ };
821
+ }
822
+ }
823
+ catch (error) {
824
+ return {
825
+ success: false,
826
+ error: `Input ${i} script verification error: ${error instanceof Error ? error.message : String(error)}`,
827
+ };
828
+ }
829
+ }
830
+ return { success: true };
831
+ }
832
+ isCoinbase() {
833
+ return (this.inputs.length === 1 &&
834
+ this.inputs[0].prevTxId.equals(Transaction.NULL_HASH) &&
835
+ this.inputs[0].outputIndex === 0xffffffff);
836
+ }
837
+ uncheckedAddInput(input) {
838
+ Preconditions.checkArgument(input instanceof Input, 'input must be an Input');
839
+ this.inputs.push(input);
840
+ this._inputAmount = undefined;
841
+ this._updateChangeOutput();
842
+ return this;
843
+ }
844
+ _newOutputOrder(newOutputs) {
845
+ const isInvalidSorting = this.outputs.length !== newOutputs.length ||
846
+ this.outputs.some((output, index) => output !== newOutputs[index]);
847
+ if (isInvalidSorting) {
848
+ throw new BitcoreError('Invalid sorting: outputs must contain the same elements');
849
+ }
850
+ if (this._changeIndex !== undefined) {
851
+ const changeOutput = this.outputs[this._changeIndex];
852
+ this._changeIndex = newOutputs.findIndex(output => output === changeOutput);
853
+ }
854
+ this.outputs = newOutputs;
855
+ return this;
856
+ }
857
+ _fromNonP2SH(utxo) {
858
+ let clazz;
859
+ const unspentOutput = new UnspentOutput(utxo);
860
+ if (unspentOutput.script.isPayToTaproot()) {
861
+ if (unspentOutput.keyAggContext &&
862
+ unspentOutput.mySignerIndex !== undefined) {
863
+ clazz = MuSigTaprootInput;
864
+ const input = new MuSigTaprootInput({
865
+ output: new Output({
866
+ script: unspentOutput.script,
867
+ satoshis: unspentOutput.satoshis,
868
+ }),
869
+ prevTxId: unspentOutput.txId,
870
+ outputIndex: unspentOutput.outputIndex,
871
+ script: new Script(),
872
+ keyAggContext: unspentOutput.keyAggContext,
873
+ mySignerIndex: unspentOutput.mySignerIndex,
874
+ });
875
+ this.addInput(input);
876
+ return;
877
+ }
878
+ clazz = TaprootInput;
879
+ const taprootInput = new TaprootInput({
880
+ output: new Output({
881
+ script: unspentOutput.script,
882
+ satoshis: unspentOutput.satoshis,
883
+ }),
884
+ prevTxId: unspentOutput.txId,
885
+ outputIndex: unspentOutput.outputIndex,
886
+ script: new Script(),
887
+ internalPubKey: unspentOutput.internalPubKey,
888
+ merkleRoot: unspentOutput.merkleRoot,
889
+ });
890
+ this.addInput(taprootInput);
891
+ return;
892
+ }
893
+ else if (unspentOutput.script.isPayToPublicKeyHash()) {
894
+ clazz = PublicKeyHashInput;
895
+ }
896
+ else if (unspentOutput.script.isPublicKeyOut()) {
897
+ clazz = PublicKeyInput;
898
+ }
899
+ else {
900
+ clazz = Input;
901
+ }
902
+ this.addInput(new clazz({
903
+ output: new Output({
904
+ script: unspentOutput.script,
905
+ satoshis: unspentOutput.satoshis,
906
+ }),
907
+ prevTxId: unspentOutput.txId,
908
+ outputIndex: unspentOutput.outputIndex,
909
+ script: new Script(),
910
+ }));
911
+ }
912
+ _fromMultisigUtxo(utxo, pubkeys, threshold, opts) {
913
+ Preconditions.checkArgument(threshold <= pubkeys.length, 'Number of required signatures must be greater than the number of public keys');
914
+ const unspentOutput = new UnspentOutput(utxo);
915
+ if (unspentOutput.script.isMultisigOut()) {
916
+ this.addInput(new MultisigInput(new Input({
917
+ output: new Output({
918
+ script: unspentOutput.script,
919
+ satoshis: unspentOutput.satoshis,
920
+ }),
921
+ prevTxId: unspentOutput.txId,
922
+ outputIndex: unspentOutput.outputIndex,
923
+ script: new Script(),
924
+ }), pubkeys, threshold, undefined, opts));
925
+ }
926
+ else if (unspentOutput.script.isPayToScriptHash()) {
927
+ this.addInput(new MultisigScriptHashInput(new Input({
928
+ output: new Output({
929
+ script: unspentOutput.script,
930
+ satoshis: unspentOutput.satoshis,
931
+ }),
932
+ prevTxId: unspentOutput.txId,
933
+ outputIndex: unspentOutput.outputIndex,
934
+ script: new Script(),
935
+ }), pubkeys, threshold, undefined, opts));
936
+ }
937
+ else {
938
+ throw new Error('Unsupported script type');
939
+ }
940
+ }
941
+ _updateChangeOutput() {
942
+ if (!this._changeScript) {
943
+ return;
944
+ }
945
+ this._clearSignatures();
946
+ if (this._changeIndex !== undefined) {
947
+ this._removeOutput(this._changeIndex);
948
+ }
949
+ const available = this._getUnspentValue();
950
+ const fee = this.getFee();
951
+ const changeAmount = available - fee;
952
+ if (changeAmount >= Transaction.DUST_AMOUNT) {
953
+ this._changeIndex = this.outputs.length;
954
+ this._addOutput(new Output({
955
+ script: this._changeScript,
956
+ satoshis: changeAmount,
957
+ }));
958
+ }
959
+ else {
960
+ this._changeIndex = undefined;
961
+ }
962
+ }
963
+ _getUnspentValue() {
964
+ return this._getInputAmount() - this._getOutputAmount();
965
+ }
966
+ _clearSignatures() {
967
+ for (const input of this.inputs) {
968
+ input.clearSignatures();
969
+ }
970
+ }
971
+ _estimateFee() {
972
+ const estimatedSize = this._estimateSize();
973
+ const available = this._getUnspentValue();
974
+ const feeRate = this._feePerByte || (this._feePerKb || Transaction.FEE_PER_KB) / 1000;
975
+ const getFee = (size) => size * feeRate;
976
+ const fee = Math.ceil(getFee(estimatedSize));
977
+ const feeWithChange = Math.ceil(getFee(estimatedSize) + getFee(Transaction.CHANGE_OUTPUT_MAX_SIZE));
978
+ if (!this._changeScript || available <= feeWithChange) {
979
+ return fee;
980
+ }
981
+ return feeWithChange;
982
+ }
983
+ static _getVarintSize(n) {
984
+ if (n < 253)
985
+ return 1;
986
+ if (n < 0x10000)
987
+ return 3;
988
+ if (n < 0x100000000)
989
+ return 5;
990
+ return 9;
991
+ }
992
+ _estimateSize() {
993
+ let result = 4;
994
+ result += Transaction._getVarintSize(this.inputs.length);
995
+ for (const input of this.inputs) {
996
+ result += 40;
997
+ const scriptSigLen = input._estimateSize();
998
+ result += Transaction._getVarintSize(scriptSigLen);
999
+ result += scriptSigLen;
1000
+ }
1001
+ result += Transaction._getVarintSize(this.outputs.length);
1002
+ for (const output of this.outputs) {
1003
+ result += output.getSize();
1004
+ }
1005
+ result += 4;
1006
+ return result;
1007
+ }
1008
+ _removeOutput(index) {
1009
+ this.outputs.splice(index, 1);
1010
+ this._outputAmount = undefined;
1011
+ }
1012
+ _addOutput(output) {
1013
+ this.outputs.push(output);
1014
+ this._outputAmount = undefined;
1015
+ }
1016
+ }