@btc-vision/bitcoin 7.0.0-beta.0 → 7.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -13
- package/benchmark-compare/BENCHMARK.md +74 -59
- package/benchmark-compare/compare.bench.ts +249 -96
- package/benchmark-compare/harness.ts +23 -25
- package/benchmark-compare/package.json +1 -0
- package/browser/address.d.ts +4 -4
- package/browser/address.d.ts.map +1 -1
- package/browser/chunks/{psbt-parallel-B-dfm5GZ.js → psbt-parallel-jZ6QcCnM.js} +3128 -2731
- package/browser/index.d.ts +1 -1
- package/browser/index.d.ts.map +1 -1
- package/browser/index.js +603 -585
- package/browser/io/base58check.d.ts +1 -25
- package/browser/io/base58check.d.ts.map +1 -1
- package/browser/io/base64.d.ts.map +1 -1
- package/browser/networks.d.ts +1 -0
- package/browser/networks.d.ts.map +1 -1
- package/browser/payments/bip341.d.ts +17 -0
- package/browser/payments/bip341.d.ts.map +1 -1
- package/browser/payments/index.d.ts +3 -2
- package/browser/payments/index.d.ts.map +1 -1
- package/browser/payments/p2mr.d.ts +169 -0
- package/browser/payments/p2mr.d.ts.map +1 -0
- package/browser/payments/types.d.ts +11 -1
- package/browser/payments/types.d.ts.map +1 -1
- package/browser/psbt/bip371.d.ts +30 -0
- package/browser/psbt/bip371.d.ts.map +1 -1
- package/browser/psbt/psbtutils.d.ts +1 -0
- package/browser/psbt/psbtutils.d.ts.map +1 -1
- package/browser/psbt.d.ts.map +1 -1
- package/browser/workers/index.js +9 -9
- package/build/address.d.ts +4 -4
- package/build/address.d.ts.map +1 -1
- package/build/address.js +11 -1
- package/build/address.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/io/base58check.d.ts +1 -25
- package/build/io/base58check.d.ts.map +1 -1
- package/build/io/base58check.js +1 -31
- package/build/io/base58check.js.map +1 -1
- package/build/io/base64.d.ts.map +1 -1
- package/build/io/base64.js +3 -0
- package/build/io/base64.js.map +1 -1
- package/build/networks.d.ts +1 -0
- package/build/networks.d.ts.map +1 -1
- package/build/networks.js +12 -0
- package/build/networks.js.map +1 -1
- package/build/payments/bip341.d.ts +17 -0
- package/build/payments/bip341.d.ts.map +1 -1
- package/build/payments/bip341.js +32 -1
- package/build/payments/bip341.js.map +1 -1
- package/build/payments/index.d.ts +3 -2
- package/build/payments/index.d.ts.map +1 -1
- package/build/payments/index.js +2 -1
- package/build/payments/index.js.map +1 -1
- package/build/payments/p2mr.d.ts +178 -0
- package/build/payments/p2mr.d.ts.map +1 -0
- package/build/payments/p2mr.js +555 -0
- package/build/payments/p2mr.js.map +1 -0
- package/build/payments/types.d.ts +11 -1
- package/build/payments/types.d.ts.map +1 -1
- package/build/payments/types.js +1 -0
- package/build/payments/types.js.map +1 -1
- package/build/psbt/bip371.d.ts +30 -0
- package/build/psbt/bip371.d.ts.map +1 -1
- package/build/psbt/bip371.js +80 -15
- package/build/psbt/bip371.js.map +1 -1
- package/build/psbt/psbtutils.d.ts +1 -0
- package/build/psbt/psbtutils.d.ts.map +1 -1
- package/build/psbt/psbtutils.js +2 -0
- package/build/psbt/psbtutils.js.map +1 -1
- package/build/psbt.d.ts.map +1 -1
- package/build/psbt.js +3 -2
- package/build/psbt.js.map +1 -1
- package/build/pubkey.js +1 -1
- package/build/pubkey.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/documentation/README.md +122 -0
- package/documentation/address.md +820 -0
- package/documentation/block.md +679 -0
- package/documentation/crypto.md +461 -0
- package/documentation/ecc.md +584 -0
- package/documentation/errors.md +656 -0
- package/documentation/io.md +942 -0
- package/documentation/networks.md +625 -0
- package/documentation/p2mr.md +380 -0
- package/documentation/payments.md +1485 -0
- package/documentation/psbt.md +1400 -0
- package/documentation/script.md +730 -0
- package/documentation/taproot.md +670 -0
- package/documentation/transaction.md +943 -0
- package/documentation/types.md +587 -0
- package/documentation/workers.md +1007 -0
- package/eslint.config.js +3 -0
- package/package.json +17 -14
- package/src/address.ts +22 -10
- package/src/index.ts +1 -0
- package/src/io/base58check.ts +1 -35
- package/src/io/base64.ts +5 -0
- package/src/networks.ts +13 -0
- package/src/payments/bip341.ts +36 -1
- package/src/payments/index.ts +4 -0
- package/src/payments/p2mr.ts +660 -0
- package/src/payments/types.ts +12 -0
- package/src/psbt/bip371.ts +84 -13
- package/src/psbt/psbtutils.ts +2 -0
- package/src/psbt.ts +4 -2
- package/src/pubkey.ts +1 -1
- package/test/bitcoin.core.spec.ts +1 -1
- package/test/fixtures/p2mr.json +270 -0
- package/test/integration/taproot.spec.ts +7 -3
- package/test/opnetTestnet.spec.ts +302 -0
- package/test/payments.spec.ts +3 -1
- package/test/psbt.spec.ts +297 -2
- package/test/tsconfig.json +2 -2
|
@@ -0,0 +1,943 @@
|
|
|
1
|
+
# Transaction
|
|
2
|
+
|
|
3
|
+
The `Transaction` class represents a Bitcoin transaction. It handles parsing, serialization, cloning, and producing the various sighash digests needed for legacy, SegWit v0, and Taproot (SegWit v1) signing.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
| Property | Description |
|
|
8
|
+
|----------|-------------|
|
|
9
|
+
| Module | `@btc-vision/bitcoin` |
|
|
10
|
+
| Export | `Transaction` |
|
|
11
|
+
| Witness support | Yes (BIP 141 serialization) |
|
|
12
|
+
| Signing support | Legacy (`hashForSignature`), SegWit v0 (`hashForWitnessV0`), Taproot (`hashForWitnessV1`) |
|
|
13
|
+
| TRUC support | Version 3 transactions (Topologically Restricted Until Confirmation) |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Static Constants
|
|
18
|
+
|
|
19
|
+
### Sighash Types
|
|
20
|
+
|
|
21
|
+
| Constant | Value | Description |
|
|
22
|
+
|----------|-------|-------------|
|
|
23
|
+
| `SIGHASH_DEFAULT` | `0x00` | Taproot-only default, semantically equivalent to `SIGHASH_ALL` |
|
|
24
|
+
| `SIGHASH_ALL` | `0x01` | Sign all inputs and outputs |
|
|
25
|
+
| `SIGHASH_NONE` | `0x02` | Sign all inputs, no outputs (wildcard payee) |
|
|
26
|
+
| `SIGHASH_SINGLE` | `0x03` | Sign all inputs, only the output at the same index |
|
|
27
|
+
| `SIGHASH_ANYONECANPAY` | `0x80` | Combined with the above via bitwise OR; sign only the current input |
|
|
28
|
+
| `SIGHASH_OUTPUT_MASK` | `0x03` | Bitmask to extract the output sighash type |
|
|
29
|
+
| `SIGHASH_INPUT_MASK` | `0x80` | Bitmask to extract the input sighash type |
|
|
30
|
+
|
|
31
|
+
### Sequence and Serialization
|
|
32
|
+
|
|
33
|
+
| Constant | Value | Description |
|
|
34
|
+
|----------|-------|-------------|
|
|
35
|
+
| `DEFAULT_SEQUENCE` | `0xffffffff` | Default sequence number (no RBF, no relative timelock) |
|
|
36
|
+
| `ADVANCED_TRANSACTION_MARKER` | `0x00` | SegWit marker byte in serialized transactions |
|
|
37
|
+
| `ADVANCED_TRANSACTION_FLAG` | `0x01` | SegWit flag byte in serialized transactions |
|
|
38
|
+
|
|
39
|
+
### TRUC (Topologically Restricted Until Confirmation)
|
|
40
|
+
|
|
41
|
+
| Constant | Value | Description |
|
|
42
|
+
|----------|-------|-------------|
|
|
43
|
+
| `TRUC_VERSION` | `3` | Transaction version for TRUC transactions |
|
|
44
|
+
| `TRUC_MAX_VSIZE` | `10000` | Maximum virtual size in vbytes for a TRUC parent transaction |
|
|
45
|
+
| `TRUC_CHILD_MAX_VSIZE` | `1000` | Maximum virtual size in vbytes for a TRUC child transaction |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Interfaces
|
|
50
|
+
|
|
51
|
+
### Input
|
|
52
|
+
|
|
53
|
+
Represents a transaction input (a reference to a previous output being spent).
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface Input {
|
|
57
|
+
readonly hash: Bytes32; // 32-byte hash of the previous transaction
|
|
58
|
+
readonly index: number; // Output index in the previous transaction
|
|
59
|
+
script: Script; // Input script (scriptSig)
|
|
60
|
+
sequence: number; // Sequence number
|
|
61
|
+
witness: Uint8Array[]; // Witness data stack
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Output
|
|
66
|
+
|
|
67
|
+
Represents a transaction output (a locking script with an associated value).
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
interface Output {
|
|
71
|
+
readonly script: Script; // Output script (scriptPubKey / locking script)
|
|
72
|
+
readonly value: Satoshi; // Value in satoshis (bigint)
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### TaprootHashCache
|
|
77
|
+
|
|
78
|
+
Cache for Taproot sighash intermediate values. These are identical for all inputs when using `SIGHASH_ALL`, so they can be computed once and reused across inputs.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
interface TaprootHashCache {
|
|
82
|
+
readonly hashPrevouts: Bytes32;
|
|
83
|
+
readonly hashAmounts: Bytes32;
|
|
84
|
+
readonly hashScriptPubKeys: Bytes32;
|
|
85
|
+
readonly hashSequences: Bytes32;
|
|
86
|
+
readonly hashOutputs: Bytes32;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Instance Properties
|
|
93
|
+
|
|
94
|
+
| Property | Type | Default | Description |
|
|
95
|
+
|----------|------|---------|-------------|
|
|
96
|
+
| `version` | `number` | `1` | Transaction version |
|
|
97
|
+
| `locktime` | `number` | `0` | Transaction locktime |
|
|
98
|
+
| `ins` | `Input[]` | `[]` | Array of transaction inputs |
|
|
99
|
+
| `outs` | `Output[]` | `[]` | Array of transaction outputs |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Static Methods
|
|
104
|
+
|
|
105
|
+
### fromBuffer
|
|
106
|
+
|
|
107
|
+
Parse a transaction from a raw `Uint8Array` buffer.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
static fromBuffer(buffer: Uint8Array, _NO_STRICT?: boolean): Transaction
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| Parameter | Type | Required | Description |
|
|
114
|
+
|-----------|------|----------|-------------|
|
|
115
|
+
| `buffer` | `Uint8Array` | Yes | The raw transaction bytes |
|
|
116
|
+
| `_NO_STRICT` | `boolean` | No | If `true`, allow extra trailing data after the transaction |
|
|
117
|
+
|
|
118
|
+
Returns a fully parsed `Transaction` instance. Automatically detects SegWit transactions by checking for the marker and flag bytes. Throws if the buffer contains superfluous witness data or unexpected trailing bytes (unless `_NO_STRICT` is set).
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { Transaction, fromHex } from '@btc-vision/bitcoin';
|
|
122
|
+
|
|
123
|
+
const rawTx = fromHex('0200000001abcdef...');
|
|
124
|
+
const tx = Transaction.fromBuffer(rawTx);
|
|
125
|
+
console.log(tx.version); // 2
|
|
126
|
+
console.log(tx.ins.length);
|
|
127
|
+
console.log(tx.outs.length);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### fromHex
|
|
133
|
+
|
|
134
|
+
Parse a transaction from a hex string. A convenience wrapper around `fromBuffer`.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
static fromHex(hex: string): Transaction
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
| Parameter | Type | Required | Description |
|
|
141
|
+
|-----------|------|----------|-------------|
|
|
142
|
+
| `hex` | `string` | Yes | The transaction as a hex-encoded string |
|
|
143
|
+
|
|
144
|
+
Returns a fully parsed `Transaction` instance.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
148
|
+
|
|
149
|
+
const tx = Transaction.fromHex('0200000001abcdef...');
|
|
150
|
+
console.log(tx.getId());
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### isCoinbaseHash
|
|
156
|
+
|
|
157
|
+
Check if a 32-byte hash is a coinbase hash (all zeros).
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
static isCoinbaseHash(hash: Bytes32): boolean
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
| Parameter | Type | Required | Description |
|
|
164
|
+
|-----------|------|----------|-------------|
|
|
165
|
+
| `hash` | `Bytes32` | Yes | 32-byte hash to check |
|
|
166
|
+
|
|
167
|
+
Returns `true` if every byte is `0x00`. Throws `TypeError` if the hash is not exactly 32 bytes.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Instance Methods
|
|
172
|
+
|
|
173
|
+
### addInput
|
|
174
|
+
|
|
175
|
+
Add an input to the transaction.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
addInput(hash: Bytes32, index: number, sequence?: number, scriptSig?: Script): number
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
| Parameter | Type | Required | Description |
|
|
182
|
+
|-----------|------|----------|-------------|
|
|
183
|
+
| `hash` | `Bytes32` | Yes | 32-byte hash of the previous transaction |
|
|
184
|
+
| `index` | `number` | Yes | Output index in the previous transaction (uint32) |
|
|
185
|
+
| `sequence` | `number` | No | Sequence number (defaults to `0xffffffff`) |
|
|
186
|
+
| `scriptSig` | `Script` | No | Input script (defaults to empty) |
|
|
187
|
+
|
|
188
|
+
Returns the index of the newly added input. The witness field is initialized to an empty array.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { Transaction, fromHex } from '@btc-vision/bitcoin';
|
|
192
|
+
import type { Bytes32, Script } from '@btc-vision/bitcoin';
|
|
193
|
+
|
|
194
|
+
const tx = new Transaction();
|
|
195
|
+
|
|
196
|
+
// Previous transaction hash (in internal byte order)
|
|
197
|
+
const prevTxHash = fromHex(
|
|
198
|
+
'a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2'
|
|
199
|
+
) as Bytes32;
|
|
200
|
+
|
|
201
|
+
const inputIndex = tx.addInput(prevTxHash, 0);
|
|
202
|
+
console.log(inputIndex); // 0
|
|
203
|
+
|
|
204
|
+
// With custom sequence (e.g. for RBF)
|
|
205
|
+
tx.addInput(prevTxHash, 1, 0xfffffffd);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### addOutput
|
|
211
|
+
|
|
212
|
+
Add an output to the transaction.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
addOutput(scriptPubKey: Script, value: Satoshi): number
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
| Parameter | Type | Required | Description |
|
|
219
|
+
|-----------|------|----------|-------------|
|
|
220
|
+
| `scriptPubKey` | `Script` | Yes | Output script (locking script) |
|
|
221
|
+
| `value` | `Satoshi` | Yes | Output value in satoshis (`bigint`, range `0` to `2^63 - 1`) |
|
|
222
|
+
|
|
223
|
+
Returns the index of the newly added output.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
import { Transaction, address } from '@btc-vision/bitcoin';
|
|
227
|
+
import type { Satoshi } from '@btc-vision/bitcoin';
|
|
228
|
+
|
|
229
|
+
const tx = new Transaction();
|
|
230
|
+
const scriptPubKey = address.toOutputScript('bc1qexampleaddress...');
|
|
231
|
+
const outputIndex = tx.addOutput(scriptPubKey, 50000n as Satoshi);
|
|
232
|
+
console.log(outputIndex); // 0
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### clone
|
|
238
|
+
|
|
239
|
+
Create a deep copy of the transaction. All inputs and outputs are duplicated.
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
clone(): Transaction
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Returns a new `Transaction` instance with identical version, locktime, inputs, and outputs.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const original = Transaction.fromHex('0200000001...');
|
|
249
|
+
const copy = original.clone();
|
|
250
|
+
|
|
251
|
+
// Modifying the copy does not affect the original
|
|
252
|
+
copy.locktime = 800000;
|
|
253
|
+
console.log(original.locktime); // unchanged
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### toBuffer
|
|
259
|
+
|
|
260
|
+
Serialize the transaction to a `Uint8Array` buffer. Includes witness data if present.
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
toBuffer(buffer?: Uint8Array, initialOffset?: number): Uint8Array
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
| Parameter | Type | Required | Description |
|
|
267
|
+
|-----------|------|----------|-------------|
|
|
268
|
+
| `buffer` | `Uint8Array` | No | Pre-allocated buffer (auto-allocated if omitted) |
|
|
269
|
+
| `initialOffset` | `number` | No | Starting offset within the buffer |
|
|
270
|
+
|
|
271
|
+
Returns the serialized transaction bytes. If witness data is present, the output uses the BIP 141 serialization format with marker and flag bytes.
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
const tx = new Transaction();
|
|
275
|
+
// ... add inputs and outputs ...
|
|
276
|
+
const raw = tx.toBuffer();
|
|
277
|
+
console.log(raw.length); // byte length of the serialized transaction
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### toHex
|
|
283
|
+
|
|
284
|
+
Serialize the transaction to a hex string. A convenience wrapper around `toBuffer`.
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
toHex(): string
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Returns the full transaction as a hex-encoded string.
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
const tx = new Transaction();
|
|
294
|
+
// ... add inputs and outputs ...
|
|
295
|
+
const hex = tx.toHex();
|
|
296
|
+
console.log(hex); // "0200000001..."
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
### getHash
|
|
302
|
+
|
|
303
|
+
Compute the transaction hash (double SHA-256 of the serialized data).
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
getHash(forWitness?: boolean): Bytes32
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
| Parameter | Type | Required | Description |
|
|
310
|
+
|-----------|------|----------|-------------|
|
|
311
|
+
| `forWitness` | `boolean` | No | If `true`, include witness data to produce the wtxid |
|
|
312
|
+
|
|
313
|
+
Returns a 32-byte hash. When `forWitness` is `false` or omitted, witness data is excluded from the hash (producing the txid). When `forWitness` is `true`, witness data is included (producing the wtxid). For coinbase transactions with `forWitness = true`, always returns 32 zero bytes.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
### getId
|
|
318
|
+
|
|
319
|
+
Get the transaction ID (txid) as a hex string in the conventional display order (reversed).
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
getId(): string
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Returns the txid as a 64-character hex string. Bitcoin transaction IDs are displayed in reversed byte order relative to the internal hash.
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
const tx = Transaction.fromHex('0200000001...');
|
|
329
|
+
console.log(tx.getId()); // "d4e5f6a1b2c3..."
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
### weight
|
|
335
|
+
|
|
336
|
+
Calculate the transaction weight as defined by BIP 141.
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
weight(): number
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Returns the weight in weight units. The formula is `base_size * 3 + total_size`, where `base_size` is the serialized size without witness data and `total_size` includes witness data.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
### virtualSize
|
|
347
|
+
|
|
348
|
+
Calculate the virtual size (vsize) of the transaction in virtual bytes.
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
virtualSize(): number
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Returns `Math.ceil(weight() / 4)`. This is the value used for fee rate calculations.
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
const tx = Transaction.fromHex('0200000001...');
|
|
358
|
+
console.log(tx.virtualSize()); // e.g. 141
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
### byteLength
|
|
364
|
+
|
|
365
|
+
Calculate the serialized byte length of the transaction.
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
byteLength(_ALLOW_WITNESS?: boolean): number
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
| Parameter | Type | Required | Description |
|
|
372
|
+
|-----------|------|----------|-------------|
|
|
373
|
+
| `_ALLOW_WITNESS` | `boolean` | No | If `true` (default), include witness data in the calculation |
|
|
374
|
+
|
|
375
|
+
Returns the byte count. When `_ALLOW_WITNESS` is `true` and the transaction has witness data, the count includes the marker, flag, and all witness stacks.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
### isCoinbase
|
|
380
|
+
|
|
381
|
+
Check if this transaction is a coinbase transaction.
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
isCoinbase(): boolean
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Returns `true` if the transaction has exactly one input and that input's hash is all zeros (the defining characteristic of a coinbase transaction).
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
const tx = Transaction.fromHex('0100000001000000000000000000000000...');
|
|
391
|
+
console.log(tx.isCoinbase()); // true
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
### hasWitnesses
|
|
397
|
+
|
|
398
|
+
Check if any input in the transaction has witness data.
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
hasWitnesses(): boolean
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Returns `true` if at least one input has a non-empty witness stack.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
### setInputScript
|
|
409
|
+
|
|
410
|
+
Set the scriptSig for a specific input.
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
setInputScript(index: number, scriptSig: Script): void
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
| Parameter | Type | Required | Description |
|
|
417
|
+
|-----------|------|----------|-------------|
|
|
418
|
+
| `index` | `number` | Yes | Input index |
|
|
419
|
+
| `scriptSig` | `Script` | Yes | The script to set |
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
### setWitness
|
|
424
|
+
|
|
425
|
+
Set the witness data for a specific input.
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
setWitness(index: number, witness: Uint8Array[]): void
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
| Parameter | Type | Required | Description |
|
|
432
|
+
|-----------|------|----------|-------------|
|
|
433
|
+
| `index` | `number` | Yes | Input index |
|
|
434
|
+
| `witness` | `Uint8Array[]` | Yes | Array of witness stack elements |
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Signing Methods
|
|
439
|
+
|
|
440
|
+
### hashForSignature
|
|
441
|
+
|
|
442
|
+
Produce the sighash digest for signing a legacy (pre-SegWit) input. This method clones the transaction, modifies it according to the sighash type, serializes it with the hash type appended, and returns the double SHA-256 hash.
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
hashForSignature(inIndex: number, prevOutScript: Script, hashType: number): MessageHash
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
| Parameter | Type | Required | Description |
|
|
449
|
+
|-----------|------|----------|-------------|
|
|
450
|
+
| `inIndex` | `number` | Yes | Index of the input being signed |
|
|
451
|
+
| `prevOutScript` | `Script` | Yes | The scriptPubKey of the output being spent |
|
|
452
|
+
| `hashType` | `number` | Yes | Sighash type (combination of `SIGHASH_*` constants) |
|
|
453
|
+
|
|
454
|
+
Returns a 32-byte `MessageHash`. In two specific cases, the method returns the constant `ONE` (32-byte value `0x0000...0001`) instead of computing a normal sighash:
|
|
455
|
+
|
|
456
|
+
1. **`inIndex >= ins.length`**: The input index is out of range (any sighash type).
|
|
457
|
+
2. **`SIGHASH_SINGLE` with `inIndex >= outs.length`**: The output at the matching index does not exist.
|
|
458
|
+
|
|
459
|
+
Both cases are well-known Bitcoin consensus quirks — the method returns the literal 32-byte value `0x0000000000000000000000000000000000000000000000000000000000000001`, **not** a hash of `0x01`.
|
|
460
|
+
|
|
461
|
+
The method automatically strips `OP_CODESEPARATOR` from the previous output script.
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
465
|
+
|
|
466
|
+
const tx = Transaction.fromHex('0200000001...');
|
|
467
|
+
const sighash = tx.hashForSignature(
|
|
468
|
+
0, // input index
|
|
469
|
+
prevOutScript, // scriptPubKey of the UTXO
|
|
470
|
+
Transaction.SIGHASH_ALL, // sighash type
|
|
471
|
+
);
|
|
472
|
+
// Sign `sighash` with your private key
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
### hashForWitnessV0
|
|
478
|
+
|
|
479
|
+
Produce the sighash digest for signing a SegWit v0 input (P2WPKH or P2WSH), as defined by BIP 143.
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
hashForWitnessV0(
|
|
483
|
+
inIndex: number,
|
|
484
|
+
prevOutScript: Script,
|
|
485
|
+
value: Satoshi,
|
|
486
|
+
hashType: number,
|
|
487
|
+
): MessageHash
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
| Parameter | Type | Required | Description |
|
|
491
|
+
|-----------|------|----------|-------------|
|
|
492
|
+
| `inIndex` | `number` | Yes | Index of the input being signed |
|
|
493
|
+
| `prevOutScript` | `Script` | Yes | The scriptCode of the output being spent |
|
|
494
|
+
| `value` | `Satoshi` | Yes | Value of the output being spent (bigint satoshis) |
|
|
495
|
+
| `hashType` | `number` | Yes | Sighash type (combination of `SIGHASH_*` constants) |
|
|
496
|
+
|
|
497
|
+
Returns a 32-byte `MessageHash`. Unlike legacy signing, the BIP 143 algorithm commits to the value of the input being spent, which prevents certain fee-related attacks.
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
501
|
+
import type { Satoshi, Script } from '@btc-vision/bitcoin';
|
|
502
|
+
|
|
503
|
+
const tx = new Transaction();
|
|
504
|
+
tx.version = 2;
|
|
505
|
+
// ... add inputs and outputs ...
|
|
506
|
+
|
|
507
|
+
const sighash = tx.hashForWitnessV0(
|
|
508
|
+
0, // input index
|
|
509
|
+
prevOutScript as Script, // scriptCode of the UTXO
|
|
510
|
+
100000n as Satoshi, // value of the UTXO in satoshis
|
|
511
|
+
Transaction.SIGHASH_ALL, // sighash type
|
|
512
|
+
);
|
|
513
|
+
// Sign `sighash` with your private key
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
### hashForWitnessV1
|
|
519
|
+
|
|
520
|
+
Produce the sighash digest for signing a Taproot (SegWit v1) input, as defined by BIP 341 and BIP 342.
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
hashForWitnessV1(
|
|
524
|
+
inIndex: number,
|
|
525
|
+
prevOutScripts: readonly Script[],
|
|
526
|
+
values: readonly Satoshi[],
|
|
527
|
+
hashType: number,
|
|
528
|
+
leafHash?: Bytes32,
|
|
529
|
+
annex?: Uint8Array,
|
|
530
|
+
taprootCache?: TaprootHashCache,
|
|
531
|
+
): MessageHash
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
| Parameter | Type | Required | Description |
|
|
535
|
+
|-----------|------|----------|-------------|
|
|
536
|
+
| `inIndex` | `number` | Yes | Index of the input being signed |
|
|
537
|
+
| `prevOutScripts` | `readonly Script[]` | Yes | Scripts of ALL inputs being spent |
|
|
538
|
+
| `values` | `readonly Satoshi[]` | Yes | Values of ALL inputs being spent |
|
|
539
|
+
| `hashType` | `number` | Yes | Sighash type (`SIGHASH_DEFAULT`, or combination of `SIGHASH_*` constants) |
|
|
540
|
+
| `leafHash` | `Bytes32` | No | Leaf hash for script-path spending (BIP 342) |
|
|
541
|
+
| `annex` | `Uint8Array` | No | Optional annex data |
|
|
542
|
+
| `taprootCache` | `TaprootHashCache` | No | Pre-computed intermediate hashes (from `getTaprootHashCache`) |
|
|
543
|
+
|
|
544
|
+
Returns a 32-byte `MessageHash`. The Taproot sighash algorithm commits to the scripts and values of ALL inputs (not just the one being signed), providing stronger security guarantees. The hash is produced using the `TapSighash` tagged hash.
|
|
545
|
+
|
|
546
|
+
For key-path spending, omit `leafHash`. For script-path spending (BIP 342), pass the `leafHash` of the tapleaf being executed.
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
550
|
+
import type { Satoshi, Script } from '@btc-vision/bitcoin';
|
|
551
|
+
|
|
552
|
+
const tx = new Transaction();
|
|
553
|
+
tx.version = 2;
|
|
554
|
+
// ... add inputs and outputs ...
|
|
555
|
+
|
|
556
|
+
const prevOutScripts: Script[] = [scriptPubKey0, scriptPubKey1];
|
|
557
|
+
const values: Satoshi[] = [50000n as Satoshi, 75000n as Satoshi];
|
|
558
|
+
|
|
559
|
+
// Key-path spending
|
|
560
|
+
const sighash = tx.hashForWitnessV1(
|
|
561
|
+
0, // input index
|
|
562
|
+
prevOutScripts, // scripts of ALL inputs
|
|
563
|
+
values, // values of ALL inputs
|
|
564
|
+
Transaction.SIGHASH_DEFAULT, // sighash type
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
// Script-path spending (with leaf hash)
|
|
568
|
+
const scriptPathHash = tx.hashForWitnessV1(
|
|
569
|
+
0,
|
|
570
|
+
prevOutScripts,
|
|
571
|
+
values,
|
|
572
|
+
Transaction.SIGHASH_DEFAULT,
|
|
573
|
+
leafHash, // 32-byte tapleaf hash
|
|
574
|
+
);
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
### getTaprootHashCache
|
|
580
|
+
|
|
581
|
+
Pre-compute the intermediate hash values used during Taproot signing. When signing multiple inputs in the same transaction, calling this once and passing the result to each `hashForWitnessV1` call avoids redundant O(n) hashing per input, reducing overall complexity from O(n^2) to O(n).
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
getTaprootHashCache(
|
|
585
|
+
prevOutScripts: readonly Script[],
|
|
586
|
+
values: readonly Satoshi[],
|
|
587
|
+
): TaprootHashCache
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
| Parameter | Type | Required | Description |
|
|
591
|
+
|-----------|------|----------|-------------|
|
|
592
|
+
| `prevOutScripts` | `readonly Script[]` | Yes | Array of previous output scripts for all inputs |
|
|
593
|
+
| `values` | `readonly Satoshi[]` | Yes | Array of previous output values for all inputs |
|
|
594
|
+
|
|
595
|
+
Returns a `TaprootHashCache` object containing five 32-byte intermediate hashes.
|
|
596
|
+
|
|
597
|
+
```typescript
|
|
598
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
599
|
+
import type { Satoshi, Script } from '@btc-vision/bitcoin';
|
|
600
|
+
|
|
601
|
+
const tx = new Transaction();
|
|
602
|
+
tx.version = 2;
|
|
603
|
+
// ... add multiple inputs and outputs ...
|
|
604
|
+
|
|
605
|
+
const prevOutScripts: Script[] = [script0, script1, script2];
|
|
606
|
+
const values: Satoshi[] = [10000n as Satoshi, 20000n as Satoshi, 30000n as Satoshi];
|
|
607
|
+
|
|
608
|
+
// Compute cache once
|
|
609
|
+
const cache = tx.getTaprootHashCache(prevOutScripts, values);
|
|
610
|
+
|
|
611
|
+
// Sign each input using the cache
|
|
612
|
+
for (let i = 0; i < tx.ins.length; i++) {
|
|
613
|
+
const sighash = tx.hashForWitnessV1(
|
|
614
|
+
i,
|
|
615
|
+
prevOutScripts,
|
|
616
|
+
values,
|
|
617
|
+
Transaction.SIGHASH_DEFAULT,
|
|
618
|
+
undefined, // no leafHash (key-path spend)
|
|
619
|
+
undefined, // no annex
|
|
620
|
+
cache, // reuse pre-computed hashes
|
|
621
|
+
);
|
|
622
|
+
// Sign sighash with the private key for input i
|
|
623
|
+
}
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
## Sighash Types Explained
|
|
629
|
+
|
|
630
|
+
The sighash type controls which parts of the transaction are covered by the signature. It is a single byte composed of an output mode (lower bits) and an optional input modifier (upper bit).
|
|
631
|
+
|
|
632
|
+
### Output Modes
|
|
633
|
+
|
|
634
|
+
| Type | Value | Inputs Signed | Outputs Signed |
|
|
635
|
+
|------|-------|---------------|----------------|
|
|
636
|
+
| `SIGHASH_ALL` | `0x01` | All | All |
|
|
637
|
+
| `SIGHASH_NONE` | `0x02` | All | None |
|
|
638
|
+
| `SIGHASH_SINGLE` | `0x03` | All | Only the output at the same index as the signed input |
|
|
639
|
+
|
|
640
|
+
### Input Modifier
|
|
641
|
+
|
|
642
|
+
| Modifier | Value | Effect |
|
|
643
|
+
|----------|-------|--------|
|
|
644
|
+
| `SIGHASH_ANYONECANPAY` | `0x80` | Only sign the current input (others may be added/removed) |
|
|
645
|
+
|
|
646
|
+
### Taproot-Specific
|
|
647
|
+
|
|
648
|
+
| Type | Value | Description |
|
|
649
|
+
|------|-------|-------------|
|
|
650
|
+
| `SIGHASH_DEFAULT` | `0x00` | Taproot only. Semantically identical to `SIGHASH_ALL` but produces a different byte in the signature serialization. A 64-byte Schnorr signature (without appended sighash byte) implicitly means `SIGHASH_DEFAULT`. |
|
|
651
|
+
|
|
652
|
+
### Combining Modifiers
|
|
653
|
+
|
|
654
|
+
Combine an output mode with the input modifier using bitwise OR:
|
|
655
|
+
|
|
656
|
+
```typescript
|
|
657
|
+
// Sign only this input, and only the matching output
|
|
658
|
+
const hashType = Transaction.SIGHASH_SINGLE | Transaction.SIGHASH_ANYONECANPAY;
|
|
659
|
+
// hashType === 0x83
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### All Valid Combinations
|
|
663
|
+
|
|
664
|
+
| Combination | Value | Description |
|
|
665
|
+
|-------------|-------|-------------|
|
|
666
|
+
| `SIGHASH_ALL` | `0x01` | All inputs, all outputs |
|
|
667
|
+
| `SIGHASH_NONE` | `0x02` | All inputs, no outputs |
|
|
668
|
+
| `SIGHASH_SINGLE` | `0x03` | All inputs, matching output |
|
|
669
|
+
| `SIGHASH_ALL \| SIGHASH_ANYONECANPAY` | `0x81` | This input only, all outputs |
|
|
670
|
+
| `SIGHASH_NONE \| SIGHASH_ANYONECANPAY` | `0x82` | This input only, no outputs |
|
|
671
|
+
| `SIGHASH_SINGLE \| SIGHASH_ANYONECANPAY` | `0x83` | This input only, matching output |
|
|
672
|
+
|
|
673
|
+
---
|
|
674
|
+
|
|
675
|
+
## Complete Examples
|
|
676
|
+
|
|
677
|
+
### Creating a Transaction from Scratch
|
|
678
|
+
|
|
679
|
+
```typescript
|
|
680
|
+
import { Transaction, address, fromHex } from '@btc-vision/bitcoin';
|
|
681
|
+
import type { Bytes32, Satoshi, Script } from '@btc-vision/bitcoin';
|
|
682
|
+
|
|
683
|
+
// Create a new transaction
|
|
684
|
+
const tx = new Transaction();
|
|
685
|
+
tx.version = 2;
|
|
686
|
+
|
|
687
|
+
// Add an input referencing a previous transaction output
|
|
688
|
+
const prevTxHash = fromHex(
|
|
689
|
+
'a1b2c3d4e5f6071829304a5b6c7d8e9f0011223344556677a1b2c3d4e5f60718'
|
|
690
|
+
) as Bytes32;
|
|
691
|
+
tx.addInput(prevTxHash, 0);
|
|
692
|
+
|
|
693
|
+
// Optionally set a custom sequence for RBF (replace-by-fee)
|
|
694
|
+
tx.addInput(prevTxHash, 1, 0xfffffffd);
|
|
695
|
+
|
|
696
|
+
// Add outputs
|
|
697
|
+
const outputScript = address.toOutputScript('bc1qexampleaddress...');
|
|
698
|
+
tx.addOutput(outputScript, 49000n as Satoshi);
|
|
699
|
+
|
|
700
|
+
// Set locktime (optional)
|
|
701
|
+
tx.locktime = 800000;
|
|
702
|
+
|
|
703
|
+
console.log(tx.ins.length); // 2
|
|
704
|
+
console.log(tx.outs.length); // 1
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### Serializing and Deserializing
|
|
708
|
+
|
|
709
|
+
```typescript
|
|
710
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
711
|
+
|
|
712
|
+
// Serialize to hex
|
|
713
|
+
const tx = new Transaction();
|
|
714
|
+
tx.version = 2;
|
|
715
|
+
// ... add inputs and outputs ...
|
|
716
|
+
const hex = tx.toHex();
|
|
717
|
+
|
|
718
|
+
// Deserialize from hex
|
|
719
|
+
const parsed = Transaction.fromHex(hex);
|
|
720
|
+
console.log(parsed.version); // 2
|
|
721
|
+
console.log(parsed.getId()); // txid as hex string
|
|
722
|
+
|
|
723
|
+
// Serialize to buffer
|
|
724
|
+
const buffer = tx.toBuffer();
|
|
725
|
+
|
|
726
|
+
// Deserialize from buffer
|
|
727
|
+
const parsed2 = Transaction.fromBuffer(buffer);
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### Cloning a Transaction
|
|
731
|
+
|
|
732
|
+
```typescript
|
|
733
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
734
|
+
|
|
735
|
+
const original = Transaction.fromHex('0200000001...');
|
|
736
|
+
const clone = original.clone();
|
|
737
|
+
|
|
738
|
+
// The clone is independent of the original
|
|
739
|
+
clone.locktime = 900000;
|
|
740
|
+
console.log(original.locktime !== clone.locktime); // true
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
### Computing Transaction Size and Weight
|
|
744
|
+
|
|
745
|
+
```typescript
|
|
746
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
747
|
+
|
|
748
|
+
const tx = Transaction.fromHex('0200000001...');
|
|
749
|
+
|
|
750
|
+
// Size without witness data
|
|
751
|
+
const baseSize = tx.byteLength(false);
|
|
752
|
+
|
|
753
|
+
// Size with witness data (if present)
|
|
754
|
+
const totalSize = tx.byteLength(true);
|
|
755
|
+
|
|
756
|
+
// BIP 141 weight
|
|
757
|
+
const weight = tx.weight();
|
|
758
|
+
|
|
759
|
+
// Virtual size for fee calculation
|
|
760
|
+
const vsize = tx.virtualSize();
|
|
761
|
+
|
|
762
|
+
console.log(`Base size: ${baseSize} bytes`);
|
|
763
|
+
console.log(`Total size: ${totalSize} bytes`);
|
|
764
|
+
console.log(`Weight: ${weight} WU`);
|
|
765
|
+
console.log(`Virtual size: ${vsize} vbytes`);
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
### Legacy Input Signing
|
|
769
|
+
|
|
770
|
+
```typescript
|
|
771
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
772
|
+
import type { Script } from '@btc-vision/bitcoin';
|
|
773
|
+
|
|
774
|
+
const tx = new Transaction();
|
|
775
|
+
tx.version = 1;
|
|
776
|
+
// ... add inputs and outputs ...
|
|
777
|
+
|
|
778
|
+
// Produce the sighash for legacy signing
|
|
779
|
+
const sighash = tx.hashForSignature(
|
|
780
|
+
0, // input index
|
|
781
|
+
prevOutScript as Script, // the scriptPubKey of the UTXO being spent
|
|
782
|
+
Transaction.SIGHASH_ALL,
|
|
783
|
+
);
|
|
784
|
+
|
|
785
|
+
// Sign the sighash with an ECDSA private key
|
|
786
|
+
// const signature = ecpair.sign(sighash);
|
|
787
|
+
|
|
788
|
+
// Set the scriptSig with the signature and public key
|
|
789
|
+
// tx.setInputScript(0, scriptSig);
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
### SegWit v0 Input Signing
|
|
793
|
+
|
|
794
|
+
```typescript
|
|
795
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
796
|
+
import type { Satoshi, Script } from '@btc-vision/bitcoin';
|
|
797
|
+
|
|
798
|
+
const tx = new Transaction();
|
|
799
|
+
tx.version = 2;
|
|
800
|
+
// ... add inputs and outputs ...
|
|
801
|
+
|
|
802
|
+
// BIP 143 sighash commits to the input value
|
|
803
|
+
const sighash = tx.hashForWitnessV0(
|
|
804
|
+
0, // input index
|
|
805
|
+
prevOutScript as Script, // scriptCode for this input
|
|
806
|
+
100000n as Satoshi, // value of the UTXO being spent
|
|
807
|
+
Transaction.SIGHASH_ALL,
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
// Sign and set witness
|
|
811
|
+
// const signature = ecpair.sign(sighash);
|
|
812
|
+
// tx.setWitness(0, [signature, publicKey]);
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
### Taproot Key-Path Signing
|
|
816
|
+
|
|
817
|
+
```typescript
|
|
818
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
819
|
+
import type { Satoshi, Script } from '@btc-vision/bitcoin';
|
|
820
|
+
|
|
821
|
+
const tx = new Transaction();
|
|
822
|
+
tx.version = 2;
|
|
823
|
+
// ... add inputs and outputs ...
|
|
824
|
+
|
|
825
|
+
// Taproot sighash requires scripts and values for ALL inputs
|
|
826
|
+
const prevOutScripts: Script[] = [utxo0ScriptPubKey, utxo1ScriptPubKey];
|
|
827
|
+
const values: Satoshi[] = [50000n as Satoshi, 75000n as Satoshi];
|
|
828
|
+
|
|
829
|
+
// Key-path spend: no leafHash
|
|
830
|
+
const sighash = tx.hashForWitnessV1(
|
|
831
|
+
0, // input index
|
|
832
|
+
prevOutScripts,
|
|
833
|
+
values,
|
|
834
|
+
Transaction.SIGHASH_DEFAULT, // 0x00 for default key-path
|
|
835
|
+
);
|
|
836
|
+
|
|
837
|
+
// Sign with Schnorr signature
|
|
838
|
+
// const schnorrSig = tweakedKeypair.signSchnorr(sighash);
|
|
839
|
+
// tx.setWitness(0, [schnorrSig]);
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
### Taproot Script-Path Signing with Cache
|
|
843
|
+
|
|
844
|
+
```typescript
|
|
845
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
846
|
+
import type { Bytes32, Satoshi, Script } from '@btc-vision/bitcoin';
|
|
847
|
+
|
|
848
|
+
const tx = new Transaction();
|
|
849
|
+
tx.version = 2;
|
|
850
|
+
// ... add inputs and outputs ...
|
|
851
|
+
|
|
852
|
+
const prevOutScripts: Script[] = [script0, script1, script2];
|
|
853
|
+
const values: Satoshi[] = [10000n as Satoshi, 20000n as Satoshi, 30000n as Satoshi];
|
|
854
|
+
|
|
855
|
+
// Pre-compute intermediate hashes once
|
|
856
|
+
const cache = tx.getTaprootHashCache(prevOutScripts, values);
|
|
857
|
+
|
|
858
|
+
// Sign each input with the cache for O(n) total performance
|
|
859
|
+
for (let i = 0; i < tx.ins.length; i++) {
|
|
860
|
+
const sighash = tx.hashForWitnessV1(
|
|
861
|
+
i,
|
|
862
|
+
prevOutScripts,
|
|
863
|
+
values,
|
|
864
|
+
Transaction.SIGHASH_DEFAULT,
|
|
865
|
+
leafHash as Bytes32, // tapleaf hash for script-path spend
|
|
866
|
+
undefined, // no annex
|
|
867
|
+
cache, // reuse pre-computed hashes
|
|
868
|
+
);
|
|
869
|
+
// Sign sighash and set witness for input i
|
|
870
|
+
}
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
### Checking for Coinbase Transactions
|
|
874
|
+
|
|
875
|
+
```typescript
|
|
876
|
+
import { Transaction } from '@btc-vision/bitcoin';
|
|
877
|
+
|
|
878
|
+
const tx = Transaction.fromHex('0100000001000000000000000000000000...');
|
|
879
|
+
|
|
880
|
+
if (tx.isCoinbase()) {
|
|
881
|
+
console.log('This is a coinbase transaction (block reward)');
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Static method to check a hash directly
|
|
885
|
+
import type { Bytes32 } from '@btc-vision/bitcoin';
|
|
886
|
+
const hash = new Uint8Array(32) as Bytes32; // all zeros
|
|
887
|
+
console.log(Transaction.isCoinbaseHash(hash)); // true
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
### Setting Witness Data
|
|
891
|
+
|
|
892
|
+
```typescript
|
|
893
|
+
import { Transaction, fromHex } from '@btc-vision/bitcoin';
|
|
894
|
+
|
|
895
|
+
const tx = Transaction.fromHex('0200000001...');
|
|
896
|
+
|
|
897
|
+
// Set witness for a P2WPKH input
|
|
898
|
+
tx.setWitness(0, [
|
|
899
|
+
fromHex('3045022100...'), // DER-encoded signature
|
|
900
|
+
fromHex('02abcdef...'), // compressed public key
|
|
901
|
+
]);
|
|
902
|
+
|
|
903
|
+
// Verify witness is set
|
|
904
|
+
console.log(tx.hasWitnesses()); // true
|
|
905
|
+
console.log(tx.ins[0].witness.length); // 2
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
---
|
|
909
|
+
|
|
910
|
+
## Transaction Serialization Format
|
|
911
|
+
|
|
912
|
+
### Legacy Format
|
|
913
|
+
|
|
914
|
+
```
|
|
915
|
+
[version: 4 bytes]
|
|
916
|
+
[input count: varint]
|
|
917
|
+
[prev tx hash: 32 bytes][prev output index: 4 bytes][scriptSig: varint + bytes][sequence: 4 bytes]
|
|
918
|
+
...
|
|
919
|
+
[output count: varint]
|
|
920
|
+
[value: 8 bytes][scriptPubKey: varint + bytes]
|
|
921
|
+
...
|
|
922
|
+
[locktime: 4 bytes]
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
### SegWit Format (BIP 141)
|
|
926
|
+
|
|
927
|
+
```
|
|
928
|
+
[version: 4 bytes]
|
|
929
|
+
[marker: 0x00][flag: 0x01]
|
|
930
|
+
[input count: varint]
|
|
931
|
+
[prev tx hash: 32 bytes][prev output index: 4 bytes][scriptSig: varint + bytes][sequence: 4 bytes]
|
|
932
|
+
...
|
|
933
|
+
[output count: varint]
|
|
934
|
+
[value: 8 bytes][scriptPubKey: varint + bytes]
|
|
935
|
+
...
|
|
936
|
+
[witness data]
|
|
937
|
+
[witness stack for input 0: varint count + varint-length items]
|
|
938
|
+
[witness stack for input 1: ...]
|
|
939
|
+
...
|
|
940
|
+
[locktime: 4 bytes]
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
The `marker` (`0x00`) and `flag` (`0x01`) bytes distinguish SegWit transactions from legacy ones during parsing. The `Transaction` class handles this automatically in both `fromBuffer` and `toBuffer`.
|