@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,730 @@
|
|
|
1
|
+
# Script - Bitcoin Script Compilation, Decompilation, and Utilities
|
|
2
|
+
|
|
3
|
+
The `script` module provides tools for working with Bitcoin Script: compiling human-readable or structured representations into raw byte buffers, decompiling buffers back into structured chunks, converting to and from ASM notation, validating public keys and signatures within scripts, and encoding/decoding script numbers and script signatures. It also re-exports the full set of Bitcoin opcodes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
| Concept | Description |
|
|
8
|
+
|---------|-------------|
|
|
9
|
+
| Chunks | An array of opcodes (`number`) and data pushes (`Uint8Array`) representing a script |
|
|
10
|
+
| Compiled script | A `Uint8Array` (branded as `Script`) containing the serialized byte-level encoding |
|
|
11
|
+
| ASM | A space-separated string of opcode names and hex-encoded data pushes |
|
|
12
|
+
| Stack | An array of `Uint8Array` elements extracted from push-only scripts |
|
|
13
|
+
| Script number | A variable-length little-endian signed integer encoding used by Bitcoin Script |
|
|
14
|
+
| Script signature | A DER-encoded ECDSA signature with an appended hash type byte |
|
|
15
|
+
|
|
16
|
+
### Import
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import * as script from '@btc-vision/bitcoin/script';
|
|
20
|
+
// or
|
|
21
|
+
import { script } from '@btc-vision/bitcoin';
|
|
22
|
+
|
|
23
|
+
// Destructured access
|
|
24
|
+
const { compile, decompile, toASM, fromASM, toStack, opcodes } = script;
|
|
25
|
+
const { encode, decode } = script.number; // script number
|
|
26
|
+
const { encode, decode } = script.signature; // script signature
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## compile()
|
|
32
|
+
|
|
33
|
+
Converts an array of chunks (opcodes and data buffers) into a single compiled `Script` buffer. If the input is already a `Uint8Array`, it is returned as-is.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
function compile(chunks: Uint8Array | Stack): Script;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Behavior
|
|
40
|
+
|
|
41
|
+
1. Each numeric element is written as a single byte (the opcode value).
|
|
42
|
+
2. Each `Uint8Array` element is written using Bitcoin's push data encoding:
|
|
43
|
+
- Data that can be represented as a minimal opcode (`OP_0`, `OP_1` through `OP_16`, `OP_1NEGATE`) is encoded as a single opcode byte per BIP 62.3 (minimal push policy).
|
|
44
|
+
- Otherwise the appropriate `OP_PUSHDATA` prefix is used followed by the raw bytes.
|
|
45
|
+
3. Throws `TypeError` if the input is not an array.
|
|
46
|
+
4. Throws `Error` if the final buffer length does not match the computed size.
|
|
47
|
+
|
|
48
|
+
### Example
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { script } from '@btc-vision/bitcoin';
|
|
52
|
+
const { compile, opcodes } = script;
|
|
53
|
+
|
|
54
|
+
// P2PKH scriptPubKey: OP_DUP OP_HASH160 <20-byte hash> OP_EQUALVERIFY OP_CHECKSIG
|
|
55
|
+
const pubKeyHash = new Uint8Array(20); // 20-byte public key hash
|
|
56
|
+
const compiled = compile([
|
|
57
|
+
opcodes.OP_DUP,
|
|
58
|
+
opcodes.OP_HASH160,
|
|
59
|
+
pubKeyHash,
|
|
60
|
+
opcodes.OP_EQUALVERIFY,
|
|
61
|
+
opcodes.OP_CHECKSIG,
|
|
62
|
+
]);
|
|
63
|
+
// compiled is a Uint8Array of length 25
|
|
64
|
+
|
|
65
|
+
// Minimal push: a 1-byte buffer containing 0x05 compiles to OP_5 (a single byte)
|
|
66
|
+
const minimal = compile([new Uint8Array([5])]);
|
|
67
|
+
// minimal[0] === 0x55 (OP_5)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## decompile()
|
|
73
|
+
|
|
74
|
+
Converts a compiled `Uint8Array` buffer back into an array of chunks. If the input is already an array, it is returned as-is.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
function decompile(buffer: Uint8Array | Stack): Array<number | Uint8Array> | null;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Throws** `TypeError` if the input is neither a `Uint8Array` nor an array. Returns `null` if the buffer is malformed (e.g., truncated push data).
|
|
81
|
+
|
|
82
|
+
### Behavior
|
|
83
|
+
|
|
84
|
+
1. Iterates through the buffer byte by byte.
|
|
85
|
+
2. Bytes in the range `0x01`..`0x4e` (`OP_PUSHDATA4`) are treated as push data instructions; the push data prefix is decoded and the corresponding number of bytes are read as a `Uint8Array` chunk.
|
|
86
|
+
3. Data that can be represented as a minimal opcode is converted to its numeric opcode form.
|
|
87
|
+
4. All other bytes are treated as opcode numbers.
|
|
88
|
+
5. Returns `null` if the buffer is malformed (e.g., truncated push data).
|
|
89
|
+
|
|
90
|
+
### Example
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { script } from '@btc-vision/bitcoin';
|
|
94
|
+
const { decompile, opcodes } = script;
|
|
95
|
+
|
|
96
|
+
const raw = new Uint8Array([0x76, 0xa9, 0x14, ...new Array(20).fill(0), 0x88, 0xac]);
|
|
97
|
+
const chunks = decompile(raw);
|
|
98
|
+
// chunks = [118(OP_DUP), 169(OP_HASH160), Uint8Array(20), 136(OP_EQUALVERIFY), 172(OP_CHECKSIG)]
|
|
99
|
+
|
|
100
|
+
if (chunks !== null) {
|
|
101
|
+
console.log(chunks[0] === opcodes.OP_DUP); // true
|
|
102
|
+
console.log(chunks[1] === opcodes.OP_HASH160); // true
|
|
103
|
+
console.log(chunks[2] instanceof Uint8Array); // true (the 20-byte hash)
|
|
104
|
+
console.log(chunks[3] === opcodes.OP_EQUALVERIFY); // true
|
|
105
|
+
console.log(chunks[4] === opcodes.OP_CHECKSIG); // true
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## toASM()
|
|
112
|
+
|
|
113
|
+
Converts chunks (or a compiled buffer) into a human-readable ASM string. Each chunk is separated by a space. Opcodes are rendered by name (e.g., `OP_DUP`), and data pushes are rendered as lowercase hex strings. Minimal data pushes are rendered as their opcode name.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
function toASM(chunks: Uint8Array | Stack): string;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Throws** `Error` if the input `Uint8Array` cannot be decompiled (e.g., truncated push data).
|
|
120
|
+
|
|
121
|
+
### Example
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { script } from '@btc-vision/bitcoin';
|
|
125
|
+
|
|
126
|
+
const asm = script.toASM(compiledScript);
|
|
127
|
+
// "OP_DUP OP_HASH160 0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## fromASM()
|
|
133
|
+
|
|
134
|
+
Parses a human-readable ASM string back into a compiled `Script` buffer. Each token is either an opcode name (e.g., `OP_CHECKSIG`) or a hex-encoded data push.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
function fromASM(asm: string): Script;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Throws** `TypeError` if the input is not a string or if any non-opcode token is not a valid hex string.
|
|
141
|
+
|
|
142
|
+
### Behavior
|
|
143
|
+
|
|
144
|
+
1. Splits the input string on spaces.
|
|
145
|
+
2. Tokens matching a known opcode name are converted to the corresponding numeric value.
|
|
146
|
+
3. All other tokens must be valid hex strings and are converted to `Uint8Array` data pushes.
|
|
147
|
+
4. The resulting array of chunks is passed through `compile()`.
|
|
148
|
+
|
|
149
|
+
### Example
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { script } from '@btc-vision/bitcoin';
|
|
153
|
+
|
|
154
|
+
const compiled = script.fromASM('OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG');
|
|
155
|
+
// compiled is a Uint8Array containing the serialized script
|
|
156
|
+
|
|
157
|
+
// Round-trip
|
|
158
|
+
const asm = script.toASM(compiled);
|
|
159
|
+
// "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## toStack()
|
|
165
|
+
|
|
166
|
+
Converts a push-only script (compiled buffer or chunk array) into an array of `Uint8Array` stack elements. This is useful for extracting witness or scriptSig data elements.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
function toStack(chunks: Uint8Array | Stack): Uint8Array[];
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Behavior
|
|
173
|
+
|
|
174
|
+
1. Decompiles the input if it is a `Uint8Array`.
|
|
175
|
+
2. Validates that the script is push-only (throws `TypeError` otherwise).
|
|
176
|
+
3. Converts each chunk:
|
|
177
|
+
- `Uint8Array` chunks are returned as-is.
|
|
178
|
+
- `OP_0` is converted to an empty `Uint8Array`.
|
|
179
|
+
- `OP_1` through `OP_16` are converted to their script number encoding (e.g., `OP_5` becomes a buffer encoding the number 5).
|
|
180
|
+
- `OP_1NEGATE` is converted to the script number encoding of -1.
|
|
181
|
+
|
|
182
|
+
### Example
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { script } from '@btc-vision/bitcoin';
|
|
186
|
+
|
|
187
|
+
// A push-only script with OP_0 and two data pushes
|
|
188
|
+
const chunks = [script.opcodes.OP_0, new Uint8Array([0xab, 0xcd]), new Uint8Array([0xef])];
|
|
189
|
+
const stack = script.toStack(chunks);
|
|
190
|
+
// stack[0] => Uint8Array(0) (empty buffer for OP_0)
|
|
191
|
+
// stack[1] => Uint8Array([0xab, 0xcd])
|
|
192
|
+
// stack[2] => Uint8Array([0xef])
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## isPushOnly()
|
|
198
|
+
|
|
199
|
+
Returns `true` if every element in the chunk array is either a `Uint8Array` data push or a numeric push opcode (`OP_0`, `OP_1`..`OP_16`, `OP_1NEGATE`).
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
function isPushOnly(value: Stack): boolean;
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Example
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import { script } from '@btc-vision/bitcoin';
|
|
209
|
+
const { opcodes } = script;
|
|
210
|
+
|
|
211
|
+
script.isPushOnly([opcodes.OP_0, new Uint8Array([1, 2, 3])]); // true
|
|
212
|
+
script.isPushOnly([opcodes.OP_DUP, new Uint8Array([1, 2, 3])]); // false (OP_DUP is not a push)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## countNonPushOnlyOPs()
|
|
218
|
+
|
|
219
|
+
Returns the number of elements in the chunk array that are NOT push-only (i.e., opcodes other than `OP_0`, `OP_1`..`OP_16`, `OP_1NEGATE`, and data buffers).
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
function countNonPushOnlyOPs(value: Stack): number;
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Example
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
import { script } from '@btc-vision/bitcoin';
|
|
229
|
+
const { opcodes } = script;
|
|
230
|
+
|
|
231
|
+
const chunks = [opcodes.OP_DUP, opcodes.OP_HASH160, new Uint8Array(20), opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG];
|
|
232
|
+
script.countNonPushOnlyOPs(chunks); // 4 (OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## isCanonicalPubKey()
|
|
238
|
+
|
|
239
|
+
Returns `true` if the buffer is a valid SEC-encoded public key (compressed 33 bytes with `0x02`/`0x03` prefix, or uncompressed 65 bytes with `0x04`/`0x06`/`0x07` prefix). Validates that x and y coordinates are non-zero and less than the secp256k1 field prime.
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
function isCanonicalPubKey(buffer: Uint8Array): boolean;
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Accepted formats
|
|
246
|
+
|
|
247
|
+
| Format | Length | Prefix byte |
|
|
248
|
+
|--------|--------|-------------|
|
|
249
|
+
| Compressed | 33 bytes | `0x02` or `0x03` |
|
|
250
|
+
| Uncompressed | 65 bytes | `0x04`, `0x06`, or `0x07` |
|
|
251
|
+
|
|
252
|
+
### Example
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { script } from '@btc-vision/bitcoin';
|
|
256
|
+
|
|
257
|
+
const compressedKey = new Uint8Array(33);
|
|
258
|
+
compressedKey[0] = 0x02;
|
|
259
|
+
compressedKey[1] = 0x01; // non-zero x coordinate
|
|
260
|
+
script.isCanonicalPubKey(compressedKey); // true (if valid point)
|
|
261
|
+
|
|
262
|
+
script.isCanonicalPubKey(new Uint8Array(20)); // false (wrong length)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## isCanonicalScriptSignature()
|
|
268
|
+
|
|
269
|
+
Returns `true` if the buffer is a valid DER-encoded script signature: a BIP 66-compliant DER signature followed by a valid hash type byte. Valid hash types are `0x01`, `0x02`, `0x03`, `0x81`, `0x82`, `0x83` (SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE, each optionally OR'd with `0x80` for SIGHASH_ANYONECANPAY).
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
function isCanonicalScriptSignature(buffer: Uint8Array): boolean;
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Example
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { script } from '@btc-vision/bitcoin';
|
|
279
|
+
|
|
280
|
+
// A properly DER-encoded signature with SIGHASH_ALL (0x01) appended
|
|
281
|
+
script.isCanonicalScriptSignature(derSignatureWithHashType); // true or false
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Script Number Module (`script.number`)
|
|
287
|
+
|
|
288
|
+
Encodes and decodes integers using Bitcoin Script's variable-length little-endian signed integer format. This encoding is used by arithmetic opcodes (`OP_ADD`, `OP_SUB`, etc.) and locktime checks.
|
|
289
|
+
|
|
290
|
+
### script.number.decode()
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number;
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
| Parameter | Default | Description |
|
|
297
|
+
|-----------|---------|-------------|
|
|
298
|
+
| `buffer` | -- | The buffer containing the encoded script number |
|
|
299
|
+
| `maxLength` | `4` | Maximum allowed byte length (set to 5 for lock times) |
|
|
300
|
+
| `minimal` | `true` | If `true`, rejects non-minimally-encoded numbers |
|
|
301
|
+
|
|
302
|
+
**Encoding rules:**
|
|
303
|
+
- An empty buffer decodes to `0`.
|
|
304
|
+
- The number is stored in little-endian byte order.
|
|
305
|
+
- The most significant bit of the last byte is the sign bit.
|
|
306
|
+
- If the value's MSB would collide with the sign bit, an extra byte is added.
|
|
307
|
+
- Supports up to 5 bytes (40-bit numbers) for locktime values.
|
|
308
|
+
|
|
309
|
+
### script.number.encode()
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
function encode(number: number): Buffer;
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Encodes a JavaScript number into a minimally-encoded script number buffer.
|
|
316
|
+
|
|
317
|
+
### Example
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { script } from '@btc-vision/bitcoin';
|
|
321
|
+
|
|
322
|
+
// Encode
|
|
323
|
+
const buf = script.number.encode(1000);
|
|
324
|
+
// buf => Buffer [0xe8, 0x03]
|
|
325
|
+
|
|
326
|
+
const negBuf = script.number.encode(-1000);
|
|
327
|
+
// negBuf => Buffer [0xe8, 0x83]
|
|
328
|
+
|
|
329
|
+
// Decode
|
|
330
|
+
script.number.decode(Buffer.from([0xe8, 0x03])); // 1000
|
|
331
|
+
script.number.decode(Buffer.from([0xe8, 0x83])); // -1000
|
|
332
|
+
script.number.decode(Buffer.from([])); // 0
|
|
333
|
+
|
|
334
|
+
// 5-byte locktime value
|
|
335
|
+
script.number.decode(Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00]), 5); // 1
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Script Signature Module (`script.signature`)
|
|
341
|
+
|
|
342
|
+
Encodes and decodes ECDSA signatures used in Bitcoin Script. A script signature consists of a DER-encoded signature (BIP 66) followed by a one-byte hash type flag (BIP 62).
|
|
343
|
+
|
|
344
|
+
### ScriptSignature Interface
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
interface ScriptSignature {
|
|
348
|
+
signature: Uint8Array; // 64 bytes: 32-byte R + 32-byte S (raw, not DER)
|
|
349
|
+
hashType: number; // one of 0x01, 0x02, 0x03, 0x81, 0x82, 0x83
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### script.signature.decode()
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
function decode(buffer: Uint8Array): ScriptSignature;
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Decodes a DER-encoded script signature (with trailing hash type byte) into a `ScriptSignature` object. The `signature` field in the result is the raw 64-byte `R || S` value (each component zero-padded to 32 bytes).
|
|
360
|
+
|
|
361
|
+
### script.signature.encode()
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
function encode(signature: Uint8Array, hashType: number): Uint8Array;
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Encodes a raw 64-byte signature and a hash type into a DER-encoded script signature buffer. The `signature` parameter must be exactly 64 bytes. The `hashType` must be a valid BIP 62 hash type.
|
|
368
|
+
|
|
369
|
+
### Hash Type Values
|
|
370
|
+
|
|
371
|
+
| Constant | Value | Description |
|
|
372
|
+
|----------|-------|-------------|
|
|
373
|
+
| SIGHASH_ALL | `0x01` | Sign all inputs and outputs |
|
|
374
|
+
| SIGHASH_NONE | `0x02` | Sign all inputs, no outputs |
|
|
375
|
+
| SIGHASH_SINGLE | `0x03` | Sign all inputs, only the output at the same index |
|
|
376
|
+
| SIGHASH_ALL \| ANYONECANPAY | `0x81` | Sign only own input, all outputs |
|
|
377
|
+
| SIGHASH_NONE \| ANYONECANPAY | `0x82` | Sign only own input, no outputs |
|
|
378
|
+
| SIGHASH_SINGLE \| ANYONECANPAY | `0x83` | Sign only own input, matching output |
|
|
379
|
+
|
|
380
|
+
### Example
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
import { script } from '@btc-vision/bitcoin';
|
|
384
|
+
|
|
385
|
+
// Decode a DER-encoded script signature
|
|
386
|
+
const decoded = script.signature.decode(derEncodedSigWithHashType);
|
|
387
|
+
console.log(decoded.signature.length); // 64 (raw R || S)
|
|
388
|
+
console.log(decoded.hashType); // e.g. 0x01
|
|
389
|
+
|
|
390
|
+
// Encode a raw signature with hash type
|
|
391
|
+
const raw64 = new Uint8Array(64); // 32-byte R + 32-byte S
|
|
392
|
+
const encoded = script.signature.encode(raw64, 0x01);
|
|
393
|
+
// encoded is DER-encoded with 0x01 hash type appended
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Push Data Encoding
|
|
399
|
+
|
|
400
|
+
The push data module handles the variable-length encoding used to push data onto the Bitcoin Script stack. This is used internally by `compile()` and `decompile()`.
|
|
401
|
+
|
|
402
|
+
| Data length | Encoding | Total prefix size |
|
|
403
|
+
|-------------|----------|-------------------|
|
|
404
|
+
| 0 - 75 bytes | Single byte (length = opcode) | 1 byte |
|
|
405
|
+
| 76 - 255 bytes | `OP_PUSHDATA1` + 1-byte length | 2 bytes |
|
|
406
|
+
| 256 - 65535 bytes | `OP_PUSHDATA2` + 2-byte LE length | 3 bytes |
|
|
407
|
+
| 65536+ bytes | `OP_PUSHDATA4` + 4-byte LE length | 5 bytes |
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Complete Opcodes Reference
|
|
412
|
+
|
|
413
|
+
All opcodes are available via `script.opcodes` (or imported directly from `@btc-vision/bitcoin`).
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
import { script } from '@btc-vision/bitcoin';
|
|
417
|
+
|
|
418
|
+
const { opcodes } = script;
|
|
419
|
+
opcodes.OP_CHECKSIG; // 172
|
|
420
|
+
|
|
421
|
+
// Reverse lookup: build a name-by-value map from the opcodes object
|
|
422
|
+
const reverseOps: Record<number, string> = {};
|
|
423
|
+
for (const [name, value] of Object.entries(opcodes)) {
|
|
424
|
+
reverseOps[value as number] = name;
|
|
425
|
+
}
|
|
426
|
+
reverseOps[172]; // "OP_CHECKSIG"
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
> **Note:** `getReverseOps()` is defined in `src/opcodes.ts` but is NOT re-exported from the main `@btc-vision/bitcoin` entry point. Use the manual reverse-mapping approach above, or import from the opcodes module directly.
|
|
430
|
+
|
|
431
|
+
### Constants and Push Numbers
|
|
432
|
+
|
|
433
|
+
| Opcode | Decimal | Hex | Description |
|
|
434
|
+
|--------|---------|-----|-------------|
|
|
435
|
+
| `OP_FALSE` / `OP_0` | 0 | `0x00` | Push empty byte array (false) |
|
|
436
|
+
| `OP_PUSHDATA1` | 76 | `0x4c` | Next 1 byte is data length |
|
|
437
|
+
| `OP_PUSHDATA2` | 77 | `0x4d` | Next 2 bytes (LE) are data length |
|
|
438
|
+
| `OP_PUSHDATA4` | 78 | `0x4e` | Next 4 bytes (LE) are data length |
|
|
439
|
+
| `OP_1NEGATE` | 79 | `0x4f` | Push -1 |
|
|
440
|
+
| `OP_RESERVED` | 80 | `0x50` | Reserved (causes script failure if executed) |
|
|
441
|
+
| `OP_TRUE` / `OP_1` | 81 | `0x51` | Push 1 |
|
|
442
|
+
| `OP_2` | 82 | `0x52` | Push 2 |
|
|
443
|
+
| `OP_3` | 83 | `0x53` | Push 3 |
|
|
444
|
+
| `OP_4` | 84 | `0x54` | Push 4 |
|
|
445
|
+
| `OP_5` | 85 | `0x55` | Push 5 |
|
|
446
|
+
| `OP_6` | 86 | `0x56` | Push 6 |
|
|
447
|
+
| `OP_7` | 87 | `0x57` | Push 7 |
|
|
448
|
+
| `OP_8` | 88 | `0x58` | Push 8 |
|
|
449
|
+
| `OP_9` | 89 | `0x59` | Push 9 |
|
|
450
|
+
| `OP_10` | 90 | `0x5a` | Push 10 |
|
|
451
|
+
| `OP_11` | 91 | `0x5b` | Push 11 |
|
|
452
|
+
| `OP_12` | 92 | `0x5c` | Push 12 |
|
|
453
|
+
| `OP_13` | 93 | `0x5d` | Push 13 |
|
|
454
|
+
| `OP_14` | 94 | `0x5e` | Push 14 |
|
|
455
|
+
| `OP_15` | 95 | `0x5f` | Push 15 |
|
|
456
|
+
| `OP_16` | 96 | `0x60` | Push 16 |
|
|
457
|
+
|
|
458
|
+
### Flow Control
|
|
459
|
+
|
|
460
|
+
| Opcode | Decimal | Hex | Description |
|
|
461
|
+
|--------|---------|-----|-------------|
|
|
462
|
+
| `OP_NOP` | 97 | `0x61` | No operation |
|
|
463
|
+
| `OP_VER` | 98 | `0x62` | Reserved (push protocol version, disabled) |
|
|
464
|
+
| `OP_IF` | 99 | `0x63` | Execute if top stack value is true |
|
|
465
|
+
| `OP_NOTIF` | 100 | `0x64` | Execute if top stack value is false |
|
|
466
|
+
| `OP_VERIF` | 101 | `0x65` | Reserved (always fails) |
|
|
467
|
+
| `OP_VERNOTIF` | 102 | `0x66` | Reserved (always fails) |
|
|
468
|
+
| `OP_ELSE` | 103 | `0x67` | Else branch of OP_IF/OP_NOTIF |
|
|
469
|
+
| `OP_ENDIF` | 104 | `0x68` | End of OP_IF/OP_NOTIF block |
|
|
470
|
+
| `OP_VERIFY` | 105 | `0x69` | Fail if top stack value is false |
|
|
471
|
+
| `OP_RETURN` | 106 | `0x6a` | Mark output as provably unspendable |
|
|
472
|
+
|
|
473
|
+
### Stack Operations
|
|
474
|
+
|
|
475
|
+
| Opcode | Decimal | Hex | Description |
|
|
476
|
+
|--------|---------|-----|-------------|
|
|
477
|
+
| `OP_TOALTSTACK` | 107 | `0x6b` | Move top item to alt stack |
|
|
478
|
+
| `OP_FROMALTSTACK` | 108 | `0x6c` | Move top item from alt stack |
|
|
479
|
+
| `OP_2DROP` | 109 | `0x6d` | Remove top two items |
|
|
480
|
+
| `OP_2DUP` | 110 | `0x6e` | Duplicate top two items |
|
|
481
|
+
| `OP_3DUP` | 111 | `0x6f` | Duplicate top three items |
|
|
482
|
+
| `OP_2OVER` | 112 | `0x70` | Copy 3rd and 4th items to top |
|
|
483
|
+
| `OP_2ROT` | 113 | `0x71` | Move 5th and 6th items to top |
|
|
484
|
+
| `OP_2SWAP` | 114 | `0x72` | Swap top two pairs |
|
|
485
|
+
| `OP_IFDUP` | 115 | `0x73` | Duplicate top if non-zero |
|
|
486
|
+
| `OP_DEPTH` | 116 | `0x74` | Push stack depth |
|
|
487
|
+
| `OP_DROP` | 117 | `0x75` | Remove top item |
|
|
488
|
+
| `OP_DUP` | 118 | `0x76` | Duplicate top item |
|
|
489
|
+
| `OP_NIP` | 119 | `0x77` | Remove second-to-top item |
|
|
490
|
+
| `OP_OVER` | 120 | `0x78` | Copy second-to-top item to top |
|
|
491
|
+
| `OP_PICK` | 121 | `0x79` | Copy nth item to top |
|
|
492
|
+
| `OP_ROLL` | 122 | `0x7a` | Move nth item to top |
|
|
493
|
+
| `OP_ROT` | 123 | `0x7b` | Rotate top three items |
|
|
494
|
+
| `OP_SWAP` | 124 | `0x7c` | Swap top two items |
|
|
495
|
+
| `OP_TUCK` | 125 | `0x7d` | Copy top item below second |
|
|
496
|
+
|
|
497
|
+
### Splice Operations (Disabled)
|
|
498
|
+
|
|
499
|
+
| Opcode | Decimal | Hex | Description |
|
|
500
|
+
|--------|---------|-----|-------------|
|
|
501
|
+
| `OP_CAT` | 126 | `0x7e` | Concatenate (disabled) |
|
|
502
|
+
| `OP_SUBSTR` | 127 | `0x7f` | Substring (disabled) |
|
|
503
|
+
| `OP_LEFT` | 128 | `0x80` | Left substring (disabled) |
|
|
504
|
+
| `OP_RIGHT` | 129 | `0x81` | Right substring (disabled) |
|
|
505
|
+
| `OP_SIZE` | 130 | `0x82` | Push string length |
|
|
506
|
+
|
|
507
|
+
### Bitwise Logic
|
|
508
|
+
|
|
509
|
+
| Opcode | Decimal | Hex | Description |
|
|
510
|
+
|--------|---------|-----|-------------|
|
|
511
|
+
| `OP_INVERT` | 131 | `0x83` | Bitwise NOT (disabled) |
|
|
512
|
+
| `OP_AND` | 132 | `0x84` | Bitwise AND (disabled) |
|
|
513
|
+
| `OP_OR` | 133 | `0x85` | Bitwise OR (disabled) |
|
|
514
|
+
| `OP_XOR` | 134 | `0x86` | Bitwise XOR (disabled) |
|
|
515
|
+
| `OP_EQUAL` | 135 | `0x87` | Push 1 if top two are byte-for-byte equal |
|
|
516
|
+
| `OP_EQUALVERIFY` | 136 | `0x88` | OP_EQUAL then OP_VERIFY |
|
|
517
|
+
| `OP_RESERVED1` | 137 | `0x89` | Reserved (fails if executed) |
|
|
518
|
+
| `OP_RESERVED2` | 138 | `0x8a` | Reserved (fails if executed) |
|
|
519
|
+
|
|
520
|
+
### Arithmetic
|
|
521
|
+
|
|
522
|
+
| Opcode | Decimal | Hex | Description |
|
|
523
|
+
|--------|---------|-----|-------------|
|
|
524
|
+
| `OP_1ADD` | 139 | `0x8b` | Add 1 |
|
|
525
|
+
| `OP_1SUB` | 140 | `0x8c` | Subtract 1 |
|
|
526
|
+
| `OP_2MUL` | 141 | `0x8d` | Multiply by 2 (disabled) |
|
|
527
|
+
| `OP_2DIV` | 142 | `0x8e` | Divide by 2 (disabled) |
|
|
528
|
+
| `OP_NEGATE` | 143 | `0x8f` | Negate sign |
|
|
529
|
+
| `OP_ABS` | 144 | `0x90` | Absolute value |
|
|
530
|
+
| `OP_NOT` | 145 | `0x91` | Logical NOT (0 becomes 1, else 0) |
|
|
531
|
+
| `OP_0NOTEQUAL` | 146 | `0x92` | Push 0 if input is 0, else 1 |
|
|
532
|
+
| `OP_ADD` | 147 | `0x93` | Add top two items |
|
|
533
|
+
| `OP_SUB` | 148 | `0x94` | Subtract top from second |
|
|
534
|
+
| `OP_MUL` | 149 | `0x95` | Multiply (disabled) |
|
|
535
|
+
| `OP_DIV` | 150 | `0x96` | Divide (disabled) |
|
|
536
|
+
| `OP_MOD` | 151 | `0x97` | Modulo (disabled) |
|
|
537
|
+
| `OP_LSHIFT` | 152 | `0x98` | Left shift (disabled) |
|
|
538
|
+
| `OP_RSHIFT` | 153 | `0x99` | Right shift (disabled) |
|
|
539
|
+
| `OP_BOOLAND` | 154 | `0x9a` | Boolean AND |
|
|
540
|
+
| `OP_BOOLOR` | 155 | `0x9b` | Boolean OR |
|
|
541
|
+
| `OP_NUMEQUAL` | 156 | `0x9c` | Push 1 if numbers are equal |
|
|
542
|
+
| `OP_NUMEQUALVERIFY` | 157 | `0x9d` | OP_NUMEQUAL then OP_VERIFY |
|
|
543
|
+
| `OP_NUMNOTEQUAL` | 158 | `0x9e` | Push 1 if numbers are not equal |
|
|
544
|
+
| `OP_LESSTHAN` | 159 | `0x9f` | Push 1 if a < b |
|
|
545
|
+
| `OP_GREATERTHAN` | 160 | `0xa0` | Push 1 if a > b |
|
|
546
|
+
| `OP_LESSTHANOREQUAL` | 161 | `0xa1` | Push 1 if a <= b |
|
|
547
|
+
| `OP_GREATERTHANOREQUAL` | 162 | `0xa2` | Push 1 if a >= b |
|
|
548
|
+
| `OP_MIN` | 163 | `0xa3` | Push the smaller of two values |
|
|
549
|
+
| `OP_MAX` | 164 | `0xa4` | Push the larger of two values |
|
|
550
|
+
| `OP_WITHIN` | 165 | `0xa5` | Push 1 if x is within [min, max) |
|
|
551
|
+
|
|
552
|
+
### Cryptographic Operations
|
|
553
|
+
|
|
554
|
+
| Opcode | Decimal | Hex | Description |
|
|
555
|
+
|--------|---------|-----|-------------|
|
|
556
|
+
| `OP_RIPEMD160` | 166 | `0xa6` | RIPEMD-160 hash |
|
|
557
|
+
| `OP_SHA1` | 167 | `0xa7` | SHA-1 hash |
|
|
558
|
+
| `OP_SHA256` | 168 | `0xa8` | SHA-256 hash |
|
|
559
|
+
| `OP_HASH160` | 169 | `0xa9` | SHA-256 then RIPEMD-160 |
|
|
560
|
+
| `OP_HASH256` | 170 | `0xaa` | Double SHA-256 |
|
|
561
|
+
| `OP_CODESEPARATOR` | 171 | `0xab` | Mark beginning of signature-checked script |
|
|
562
|
+
| `OP_CHECKSIG` | 172 | `0xac` | Verify signature against public key |
|
|
563
|
+
| `OP_CHECKSIGVERIFY` | 173 | `0xad` | OP_CHECKSIG then OP_VERIFY |
|
|
564
|
+
| `OP_CHECKMULTISIG` | 174 | `0xae` | Verify m-of-n multisig |
|
|
565
|
+
| `OP_CHECKMULTISIGVERIFY` | 175 | `0xaf` | OP_CHECKMULTISIG then OP_VERIFY |
|
|
566
|
+
|
|
567
|
+
### Locktime and Expansion
|
|
568
|
+
|
|
569
|
+
| Opcode | Decimal | Hex | Description |
|
|
570
|
+
|--------|---------|-----|-------------|
|
|
571
|
+
| `OP_NOP1` | 176 | `0xb0` | No operation (reserved for expansion) |
|
|
572
|
+
| `OP_NOP2` / `OP_CHECKLOCKTIMEVERIFY` | 177 | `0xb1` | Verify locktime (BIP 65) |
|
|
573
|
+
| `OP_NOP3` / `OP_CHECKSEQUENCEVERIFY` | 178 | `0xb2` | Verify sequence number (BIP 112) |
|
|
574
|
+
| `OP_NOP4` | 179 | `0xb3` | No operation (reserved) |
|
|
575
|
+
| `OP_NOP5` | 180 | `0xb4` | No operation (reserved) |
|
|
576
|
+
| `OP_NOP6` | 181 | `0xb5` | No operation (reserved) |
|
|
577
|
+
| `OP_NOP7` | 182 | `0xb6` | No operation (reserved) |
|
|
578
|
+
| `OP_NOP8` | 183 | `0xb7` | No operation (reserved) |
|
|
579
|
+
| `OP_NOP9` | 184 | `0xb8` | No operation (reserved) |
|
|
580
|
+
| `OP_NOP10` | 185 | `0xb9` | No operation (reserved) |
|
|
581
|
+
|
|
582
|
+
### Tapscript
|
|
583
|
+
|
|
584
|
+
| Opcode | Decimal | Hex | Description |
|
|
585
|
+
|--------|---------|-----|-------------|
|
|
586
|
+
| `OP_CHECKSIGADD` | 186 | `0xba` | Tapscript: verify signature and increment counter (BIP 342) |
|
|
587
|
+
|
|
588
|
+
### Template Matching (Internal)
|
|
589
|
+
|
|
590
|
+
| Opcode | Decimal | Hex | Description |
|
|
591
|
+
|--------|---------|-----|-------------|
|
|
592
|
+
| `OP_PUBKEYHASH` | 253 | `0xfd` | Template placeholder for pubkey hash |
|
|
593
|
+
| `OP_PUBKEY` | 254 | `0xfe` | Template placeholder for pubkey |
|
|
594
|
+
| `OP_INVALIDOPCODE` | 255 | `0xff` | Invalid opcode marker |
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
## Code Examples
|
|
599
|
+
|
|
600
|
+
### Building a P2PKH Script
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
603
|
+
import { script } from '@btc-vision/bitcoin';
|
|
604
|
+
const { compile, opcodes } = script;
|
|
605
|
+
|
|
606
|
+
// scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
|
607
|
+
function buildP2PKH(pubKeyHash: Uint8Array): Uint8Array {
|
|
608
|
+
if (pubKeyHash.length !== 20) throw new Error('Expected 20-byte hash');
|
|
609
|
+
return compile([
|
|
610
|
+
opcodes.OP_DUP,
|
|
611
|
+
opcodes.OP_HASH160,
|
|
612
|
+
pubKeyHash,
|
|
613
|
+
opcodes.OP_EQUALVERIFY,
|
|
614
|
+
opcodes.OP_CHECKSIG,
|
|
615
|
+
]);
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Building an OP_RETURN Data Script
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
import { script } from '@btc-vision/bitcoin';
|
|
623
|
+
const { compile, opcodes } = script;
|
|
624
|
+
|
|
625
|
+
function buildOpReturn(data: Uint8Array): Uint8Array {
|
|
626
|
+
return compile([opcodes.OP_RETURN, data]);
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### Building a CLTV Timelocked Script
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
import { script } from '@btc-vision/bitcoin';
|
|
634
|
+
const { compile, opcodes, number: scriptNum } = script;
|
|
635
|
+
|
|
636
|
+
function buildTimelocked(locktime: number, pubKeyHash: Uint8Array): Uint8Array {
|
|
637
|
+
return compile([
|
|
638
|
+
scriptNum.encode(locktime),
|
|
639
|
+
opcodes.OP_CHECKLOCKTIMEVERIFY,
|
|
640
|
+
opcodes.OP_DROP,
|
|
641
|
+
opcodes.OP_DUP,
|
|
642
|
+
opcodes.OP_HASH160,
|
|
643
|
+
pubKeyHash,
|
|
644
|
+
opcodes.OP_EQUALVERIFY,
|
|
645
|
+
opcodes.OP_CHECKSIG,
|
|
646
|
+
]);
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Parsing and Inspecting a Script
|
|
651
|
+
|
|
652
|
+
```typescript
|
|
653
|
+
import { script } from '@btc-vision/bitcoin';
|
|
654
|
+
const { decompile, toASM, isPushOnly, countNonPushOnlyOPs, opcodes } = script;
|
|
655
|
+
|
|
656
|
+
function inspectScript(raw: Uint8Array): void {
|
|
657
|
+
// Human-readable form
|
|
658
|
+
console.log('ASM:', toASM(raw));
|
|
659
|
+
|
|
660
|
+
// Structured form
|
|
661
|
+
const chunks = decompile(raw);
|
|
662
|
+
if (!chunks) {
|
|
663
|
+
console.log('Invalid script');
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
console.log('Chunk count:', chunks.length);
|
|
668
|
+
console.log('Push-only:', isPushOnly(chunks));
|
|
669
|
+
console.log('Non-push opcodes:', countNonPushOnlyOPs(chunks));
|
|
670
|
+
|
|
671
|
+
// Check for specific patterns
|
|
672
|
+
if (chunks[0] === opcodes.OP_DUP && chunks[1] === opcodes.OP_HASH160) {
|
|
673
|
+
console.log('Looks like a P2PKH script');
|
|
674
|
+
}
|
|
675
|
+
if (chunks[0] === opcodes.OP_RETURN) {
|
|
676
|
+
console.log('This is an OP_RETURN output');
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Round-trip: ASM to Buffer and Back
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
import { script } from '@btc-vision/bitcoin';
|
|
685
|
+
|
|
686
|
+
const original = 'OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_2 OP_CHECKMULTISIG';
|
|
687
|
+
|
|
688
|
+
const compiled = script.fromASM(original);
|
|
689
|
+
const restored = script.toASM(compiled);
|
|
690
|
+
console.log(original === restored); // true
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
### Validating a Script Signature
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
import { script } from '@btc-vision/bitcoin';
|
|
697
|
+
|
|
698
|
+
function validateScriptSig(sigBuffer: Uint8Array): boolean {
|
|
699
|
+
if (!script.isCanonicalScriptSignature(sigBuffer)) {
|
|
700
|
+
console.log('Invalid DER signature or hash type');
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const { signature, hashType } = script.signature.decode(sigBuffer);
|
|
705
|
+
console.log('Raw signature (64 bytes):', signature);
|
|
706
|
+
console.log('Hash type:', hashType);
|
|
707
|
+
return true;
|
|
708
|
+
}
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### Working with Script Numbers
|
|
712
|
+
|
|
713
|
+
```typescript
|
|
714
|
+
import { script } from '@btc-vision/bitcoin';
|
|
715
|
+
|
|
716
|
+
// Encode various values
|
|
717
|
+
script.number.encode(0); // Buffer(0) - empty buffer
|
|
718
|
+
script.number.encode(1); // Buffer [0x01]
|
|
719
|
+
script.number.encode(127); // Buffer [0x7f]
|
|
720
|
+
script.number.encode(128); // Buffer [0x80, 0x00] (extra byte to avoid sign-bit collision)
|
|
721
|
+
script.number.encode(-1); // Buffer [0x81]
|
|
722
|
+
script.number.encode(-128); // Buffer [0x80, 0x80]
|
|
723
|
+
|
|
724
|
+
// Decode with strict minimal encoding (default)
|
|
725
|
+
script.number.decode(Buffer.from([0x7f])); // 127
|
|
726
|
+
script.number.decode(Buffer.from([0x80, 0x00])); // 128
|
|
727
|
+
|
|
728
|
+
// Decode with relaxed minimal check
|
|
729
|
+
script.number.decode(Buffer.from([0x00]), 4, false); // 0 (would throw with minimal=true)
|
|
730
|
+
```
|