@vbyte/btc-dev 1.1.8 → 2.0.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.
- package/CHANGELOG.md +94 -0
- package/README.md +260 -3
- package/dist/const.d.ts +3 -0
- package/dist/const.js +23 -22
- package/dist/index.d.ts +11 -11
- package/dist/index.js +10 -10
- package/dist/lib/address/api.d.ts +2 -2
- package/dist/lib/address/api.js +12 -12
- package/dist/lib/address/encode.d.ts +1 -1
- package/dist/lib/address/encode.js +24 -24
- package/dist/lib/address/index.d.ts +6 -6
- package/dist/lib/address/index.js +6 -6
- package/dist/lib/address/p2pkh.d.ts +2 -2
- package/dist/lib/address/p2pkh.js +14 -14
- package/dist/lib/address/p2sh.d.ts +2 -2
- package/dist/lib/address/p2sh.js +13 -13
- package/dist/lib/address/p2tr.d.ts +2 -2
- package/dist/lib/address/p2tr.js +13 -13
- package/dist/lib/address/p2wpkh.d.ts +2 -2
- package/dist/lib/address/p2wpkh.js +14 -14
- package/dist/lib/address/p2wsh.d.ts +2 -2
- package/dist/lib/address/p2wsh.js +13 -13
- package/dist/lib/address/script.d.ts +1 -1
- package/dist/lib/address/script.js +16 -16
- package/dist/lib/address/util.d.ts +1 -1
- package/dist/lib/address/util.js +22 -22
- package/dist/lib/meta/index.d.ts +4 -4
- package/dist/lib/meta/index.js +4 -4
- package/dist/lib/meta/locktime.d.ts +1 -1
- package/dist/lib/meta/locktime.js +12 -12
- package/dist/lib/meta/ref.js +9 -6
- package/dist/lib/meta/scribe.d.ts +2 -2
- package/dist/lib/meta/scribe.js +48 -53
- package/dist/lib/meta/sequence.d.ts +1 -1
- package/dist/lib/meta/sequence.js +16 -15
- package/dist/lib/script/decode.d.ts +2 -2
- package/dist/lib/script/decode.js +50 -15
- package/dist/lib/script/encode.d.ts +1 -1
- package/dist/lib/script/encode.js +20 -16
- package/dist/lib/script/index.d.ts +5 -13
- package/dist/lib/script/index.js +5 -14
- package/dist/lib/script/lock.d.ts +2 -2
- package/dist/lib/script/lock.js +15 -12
- package/dist/lib/script/util.js +4 -4
- package/dist/lib/script/words.js +129 -129
- package/dist/lib/sighash/index.d.ts +3 -3
- package/dist/lib/sighash/index.js +3 -3
- package/dist/lib/sighash/segwit.d.ts +2 -2
- package/dist/lib/sighash/segwit.js +15 -14
- package/dist/lib/sighash/taproot.d.ts +2 -2
- package/dist/lib/sighash/taproot.js +24 -23
- package/dist/lib/sighash/util.d.ts +2 -2
- package/dist/lib/sighash/util.js +7 -7
- package/dist/lib/signer/index.d.ts +2 -2
- package/dist/lib/signer/index.js +2 -2
- package/dist/lib/signer/sign.d.ts +1 -1
- package/dist/lib/signer/sign.js +42 -7
- package/dist/lib/signer/verify.d.ts +17 -3
- package/dist/lib/signer/verify.js +233 -3
- package/dist/lib/taproot/cblock.d.ts +1 -1
- package/dist/lib/taproot/cblock.js +14 -16
- package/dist/lib/taproot/encode.d.ts +1 -1
- package/dist/lib/taproot/encode.js +7 -7
- package/dist/lib/taproot/index.d.ts +4 -4
- package/dist/lib/taproot/index.js +4 -4
- package/dist/lib/taproot/parse.d.ts +1 -1
- package/dist/lib/taproot/parse.js +12 -14
- package/dist/lib/taproot/tree.d.ts +2 -2
- package/dist/lib/taproot/tree.js +11 -7
- package/dist/lib/tx/create.d.ts +1 -1
- package/dist/lib/tx/create.js +28 -12
- package/dist/lib/tx/decode.d.ts +2 -2
- package/dist/lib/tx/decode.js +50 -17
- package/dist/lib/tx/encode.d.ts +2 -2
- package/dist/lib/tx/encode.js +13 -16
- package/dist/lib/tx/index.d.ts +7 -7
- package/dist/lib/tx/index.js +7 -7
- package/dist/lib/tx/parse.d.ts +1 -1
- package/dist/lib/tx/parse.js +9 -9
- package/dist/lib/tx/size.d.ts +2 -2
- package/dist/lib/tx/size.js +9 -9
- package/dist/lib/tx/util.d.ts +2 -2
- package/dist/lib/tx/util.js +23 -20
- package/dist/lib/tx/validate.d.ts +1 -1
- package/dist/lib/tx/validate.js +3 -3
- package/dist/lib/witness/index.d.ts +2 -2
- package/dist/lib/witness/index.js +2 -2
- package/dist/lib/witness/parse.d.ts +2 -2
- package/dist/lib/witness/parse.js +24 -23
- package/dist/lib/witness/util.d.ts +2 -2
- package/dist/lib/witness/util.js +5 -5
- package/dist/main.cjs +2308 -1005
- package/dist/main.cjs.map +1 -1
- package/dist/module.mjs +2308 -1005
- package/dist/module.mjs.map +1 -1
- package/dist/package.json +20 -17
- package/dist/schema/base.d.ts +1 -1
- package/dist/schema/base.js +17 -13
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.js +2 -2
- package/dist/schema/taproot.d.ts +1 -1
- package/dist/schema/taproot.js +2 -2
- package/dist/schema/tx.d.ts +1 -1
- package/dist/schema/tx.js +4 -4
- package/dist/script.js +8 -8
- package/dist/script.js.map +1 -1
- package/dist/types/address.d.ts +4 -4
- package/dist/types/index.d.ts +8 -8
- package/dist/types/index.js +8 -8
- package/dist/types/meta.d.ts +4 -4
- package/dist/types/psbt.d.ts +2 -2
- package/dist/types/script.d.ts +2 -2
- package/dist/types/sighash.d.ts +2 -2
- package/dist/types/witness.d.ts +5 -5
- package/package.json +20 -17
- package/src/const.ts +0 -61
- package/src/index.ts +0 -13
- package/src/lib/address/api.ts +0 -50
- package/src/lib/address/encode.ts +0 -183
- package/src/lib/address/index.ts +0 -7
- package/src/lib/address/p2pkh.ts +0 -94
- package/src/lib/address/p2sh.ts +0 -96
- package/src/lib/address/p2tr.ts +0 -91
- package/src/lib/address/p2wpkh.ts +0 -94
- package/src/lib/address/p2wsh.ts +0 -92
- package/src/lib/address/script.ts +0 -63
- package/src/lib/address/util.ts +0 -87
- package/src/lib/meta/index.ts +0 -4
- package/src/lib/meta/locktime.ts +0 -57
- package/src/lib/meta/ref.ts +0 -107
- package/src/lib/meta/scribe.ts +0 -256
- package/src/lib/meta/sequence.ts +0 -146
- package/src/lib/script/decode.ts +0 -85
- package/src/lib/script/encode.ts +0 -129
- package/src/lib/script/index.ts +0 -20
- package/src/lib/script/lock.ts +0 -73
- package/src/lib/script/util.ts +0 -78
- package/src/lib/script/words.ts +0 -182
- package/src/lib/sighash/index.ts +0 -3
- package/src/lib/sighash/segwit.ts +0 -152
- package/src/lib/sighash/taproot.ts +0 -206
- package/src/lib/sighash/util.ts +0 -51
- package/src/lib/signer/index.ts +0 -2
- package/src/lib/signer/sign.ts +0 -39
- package/src/lib/signer/verify.ts +0 -88
- package/src/lib/taproot/cblock.ts +0 -96
- package/src/lib/taproot/encode.ts +0 -49
- package/src/lib/taproot/index.ts +0 -4
- package/src/lib/taproot/parse.ts +0 -65
- package/src/lib/taproot/tree.ts +0 -94
- package/src/lib/tx/create.ts +0 -90
- package/src/lib/tx/decode.ts +0 -123
- package/src/lib/tx/encode.ts +0 -155
- package/src/lib/tx/index.ts +0 -7
- package/src/lib/tx/parse.ts +0 -69
- package/src/lib/tx/size.ts +0 -68
- package/src/lib/tx/util.ts +0 -111
- package/src/lib/tx/validate.ts +0 -49
- package/src/lib/witness/index.ts +0 -2
- package/src/lib/witness/parse.ts +0 -127
- package/src/lib/witness/util.ts +0 -18
- package/src/schema/base.ts +0 -57
- package/src/schema/index.ts +0 -2
- package/src/schema/taproot.ts +0 -12
- package/src/schema/tx.ts +0 -48
- package/src/types/address.ts +0 -35
- package/src/types/index.ts +0 -8
- package/src/types/meta.ts +0 -48
- package/src/types/psbt.ts +0 -15
- package/src/types/script.ts +0 -18
- package/src/types/sighash.ts +0 -16
- package/src/types/taproot.ts +0 -41
- package/src/types/txdata.ts +0 -85
- package/src/types/witness.ts +0 -42
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
## [2.0.0] - 2026-01-23
|
|
4
|
+
|
|
5
|
+
### Security Fixes
|
|
6
|
+
|
|
7
|
+
- **Fixed witness parsing bug**: Added missing `break` statements in switch block in `src/lib/witness/parse.ts` that could cause incorrect script extraction for p2ts and p2wsh witness types.
|
|
8
|
+
- **Implemented `verify_tx()` function**: Full signature verification for segwit (ECDSA) and taproot (Schnorr) transactions, supporting all sighash types.
|
|
9
|
+
- **Added input validation to sign functions**: Secret key format validation in `sign_segwit_tx()` and `sign_taproot_tx()` to prevent invalid key errors.
|
|
10
|
+
- **Added transaction size limits**: Maximum transaction size (4MB), varint size (10MB), and element count (100k) limits in decoder to prevent memory exhaustion attacks.
|
|
11
|
+
- **Added taproot tree depth limits**: Maximum depth of 128 levels in merkle tree construction to prevent stack overflow from deeply nested trees.
|
|
12
|
+
- **Sanitized error messages**: Removed sensitive data from error messages in address and transaction modules.
|
|
13
|
+
- **Fixed taproot verification null check**: Added proper null check for `prevout` in taproot input verification to prevent runtime errors.
|
|
14
|
+
|
|
15
|
+
### New Features
|
|
16
|
+
|
|
17
|
+
- **Full signature verification**: `verify_tx()` now returns detailed verification results including per-input status and error messages.
|
|
18
|
+
- **Enhanced witness parsing**: Improved annex detection and control block parsing for taproot witnesses.
|
|
19
|
+
|
|
20
|
+
### Code Quality
|
|
21
|
+
|
|
22
|
+
- **Biome linting compliance**: Applied comprehensive linting fixes across all 59 source files in `src/`
|
|
23
|
+
- Converted string concatenation to template literals
|
|
24
|
+
- Added explicit radix parameter to all `parseInt()` calls
|
|
25
|
+
- Converted `import` statements to `import type` where appropriate
|
|
26
|
+
- Replaced `isNaN()` with `Number.isNaN()` for type safety
|
|
27
|
+
- Simplified computed property access to literal keys
|
|
28
|
+
- Standardized code formatting (quotes, semicolons, indentation)
|
|
29
|
+
- **Improved control block construction**: Replaced `forEach` with spread operator in taproot control block building
|
|
30
|
+
|
|
31
|
+
### Testing
|
|
32
|
+
|
|
33
|
+
- Added 843+ new tests (total: 1063 tests passing)
|
|
34
|
+
- **SIGNER module tests**: Essential signing function tests, transaction scenarios, and sighash coverage
|
|
35
|
+
- **WITNESS module tests**: Full witness parsing coverage (p2wpkh, p2wsh, p2tr, p2ts, annex) plus edge cases
|
|
36
|
+
- **SCRIPT module tests**: Lock script detection, decode/encode roundtrips, malformed script handling, size limits
|
|
37
|
+
- **SIGHASH module tests**: Bounds checking and edge cases
|
|
38
|
+
- **META module tests**: BIP-65 locktime, BIP-68 sequence, and reference pointer encoding/decoding
|
|
39
|
+
- **TX module tests**: Size calculation, essential operations, create functions, encoding functions, error handling
|
|
40
|
+
- **TAPROOT module tests**: Parse operations coverage
|
|
41
|
+
- **Integration tests**: End-to-end workflows for address creation, transaction building, and signing
|
|
42
|
+
|
|
43
|
+
### Documentation
|
|
44
|
+
|
|
45
|
+
- **README.md**: Expanded with installation instructions, quick start guide, module overview, and API examples
|
|
46
|
+
- **SECURITY.md**: New security guidelines document covering private key handling, input validation, and best practices
|
|
47
|
+
- **EXAMPLES.md**: New examples document with practical code for common Bitcoin development tasks
|
|
48
|
+
- **CONVENTIONS.md**: Added project coding conventions documentation
|
|
49
|
+
- **JSDoc**: Added comprehensive documentation to exported functions with @param, @returns, @throws, and @example
|
|
50
|
+
- **Type definitions**: Documented all interfaces in `src/types/`
|
|
51
|
+
- **Schemas**: Added inline documentation for validation schemas
|
|
52
|
+
|
|
53
|
+
### Breaking Changes
|
|
54
|
+
|
|
55
|
+
- `verify_tx()` now returns a `VerifyResult` object instead of a boolean. Access the `.valid` property for boolean result.
|
|
56
|
+
|
|
57
|
+
## [1.1.8]
|
|
58
|
+
|
|
59
|
+
- Removed excess logging.
|
|
60
|
+
|
|
61
|
+
## [1.1.7]
|
|
62
|
+
|
|
63
|
+
- Removed schema dependency.
|
|
64
|
+
- Fixed an issue with the transaction encoder.
|
|
65
|
+
|
|
66
|
+
## [1.1.6]
|
|
67
|
+
|
|
68
|
+
- Changed `create_address` to `get_address`, fixed issues with interface.
|
|
69
|
+
|
|
70
|
+
## [1.1.5]
|
|
71
|
+
|
|
72
|
+
- Updated exports for Script module.
|
|
73
|
+
|
|
74
|
+
## [1.1.4]
|
|
75
|
+
|
|
76
|
+
- Updates to API for Address module.
|
|
77
|
+
- Updates to API for Script module.
|
|
78
|
+
- Updates to API for TX module.
|
|
79
|
+
|
|
80
|
+
## [1.1.3]
|
|
81
|
+
|
|
82
|
+
- Updated transaction utils to have a better input interface.
|
|
83
|
+
|
|
84
|
+
## [1.1.2]
|
|
85
|
+
|
|
86
|
+
- Methods `get_tx_output_type` and `get_tx_output_version` have been updated and replaced with `get_script_pk_type` and `get_script_pk_version`.
|
|
87
|
+
|
|
88
|
+
## [1.1.1]
|
|
89
|
+
|
|
90
|
+
- Updated `encode_script`
|
|
91
|
+
|
|
92
|
+
## [1.1.0]
|
|
93
|
+
|
|
94
|
+
- Public release.
|
package/README.md
CHANGED
|
@@ -1,5 +1,262 @@
|
|
|
1
|
-
# btc-dev
|
|
1
|
+
# @vbyte/btc-dev
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A batteries-included TypeScript toolset for Bitcoin development. Create, sign, and verify Bitcoin transactions with full support for segwit and taproot.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Full Address Support**: P2PKH, P2SH, P2WPKH, P2WSH, P2TR (taproot)
|
|
8
|
+
- **Transaction Building**: Create, encode, decode, and parse Bitcoin transactions
|
|
9
|
+
- **Signature Hashing**: BIP-143 (segwit) and BIP-341 (taproot) sighash calculation
|
|
10
|
+
- **Signing & Verification**: ECDSA (segwit) and Schnorr (taproot) signatures
|
|
11
|
+
- **Taproot Scripts**: Merkle tree construction, control blocks, and script-path spends
|
|
12
|
+
- **Script Handling**: Encode/decode Bitcoin scripts, lock script detection
|
|
13
|
+
- **Metadata Utilities**: Locktime, sequence (BIP-68), outpoints, rune IDs, inscription IDs
|
|
14
|
+
- **Type Safety**: Full TypeScript support with strict types
|
|
15
|
+
- **Tree-shakeable**: Import only what you need
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @vbyte/btc-dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { ADDRESS, TX, SIGNER } from '@vbyte/btc-dev'
|
|
27
|
+
|
|
28
|
+
// Create a P2WPKH address from a public key
|
|
29
|
+
const address = ADDRESS.p2wpkh(pubkey, 'main')
|
|
30
|
+
console.log(address.data) // bc1q...
|
|
31
|
+
|
|
32
|
+
// Parse a raw transaction
|
|
33
|
+
const tx = TX.parse(txhex)
|
|
34
|
+
console.log(tx.vin.length, 'inputs')
|
|
35
|
+
console.log(tx.vout.length, 'outputs')
|
|
36
|
+
|
|
37
|
+
// Sign a segwit transaction
|
|
38
|
+
const signature = SIGNER.sign_segwit_tx(secretKey, txdata, {
|
|
39
|
+
txindex: 0,
|
|
40
|
+
pubkey: publicKey,
|
|
41
|
+
sigflag: 0x01 // SIGHASH_ALL
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Module Overview
|
|
46
|
+
|
|
47
|
+
| Module | Description |
|
|
48
|
+
|--------|-------------|
|
|
49
|
+
| `ADDRESS` | Create and parse Bitcoin addresses (P2PKH, P2SH, P2WPKH, P2WSH, P2TR) |
|
|
50
|
+
| `TX` | Transaction creation, encoding, decoding, parsing, and validation |
|
|
51
|
+
| `SCRIPT` | Bitcoin script encoding, decoding, and lock script detection |
|
|
52
|
+
| `SIGHASH` | Signature hash calculation for segwit (BIP-143) and taproot (BIP-341) |
|
|
53
|
+
| `SIGNER` | Sign and verify transactions using ECDSA and Schnorr |
|
|
54
|
+
| `TAPROOT` | Taproot tree construction, control blocks, and tweaking |
|
|
55
|
+
| `WITNESS` | Parse and analyze witness data |
|
|
56
|
+
| `META` | Locktime, sequence, outpoints, and reference IDs |
|
|
57
|
+
|
|
58
|
+
## Import Patterns
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Import all namespaces
|
|
62
|
+
import { ADDRESS, TX, SCRIPT, SIGHASH, SIGNER, TAPROOT, WITNESS, META } from '@vbyte/btc-dev'
|
|
63
|
+
|
|
64
|
+
// Tree-shaking: import specific modules
|
|
65
|
+
import { p2wpkh, p2tr } from '@vbyte/btc-dev/address'
|
|
66
|
+
import { parse_tx, encode_tx } from '@vbyte/btc-dev/tx'
|
|
67
|
+
import { sign_segwit_tx, sign_taproot_tx, verify_tx } from '@vbyte/btc-dev/signer'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API Highlights
|
|
71
|
+
|
|
72
|
+
### Address Creation
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { ADDRESS } from '@vbyte/btc-dev'
|
|
76
|
+
|
|
77
|
+
// P2PKH (legacy)
|
|
78
|
+
const p2pkh = ADDRESS.p2pkh(pubkey, 'main')
|
|
79
|
+
|
|
80
|
+
// P2WPKH (native segwit)
|
|
81
|
+
const p2wpkh = ADDRESS.p2wpkh(pubkey, 'main')
|
|
82
|
+
|
|
83
|
+
// P2WSH (segwit script hash)
|
|
84
|
+
const p2wsh = ADDRESS.p2wsh(redeemScript, 'main')
|
|
85
|
+
|
|
86
|
+
// P2TR (taproot)
|
|
87
|
+
const p2tr = ADDRESS.p2tr(xOnlyPubkey, 'main')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Transaction Parsing
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { TX } from '@vbyte/btc-dev'
|
|
94
|
+
|
|
95
|
+
// Parse raw transaction hex
|
|
96
|
+
const tx = TX.parse(rawTxHex)
|
|
97
|
+
|
|
98
|
+
// Access transaction data
|
|
99
|
+
console.log(tx.version) // Transaction version
|
|
100
|
+
console.log(tx.vin) // Inputs array
|
|
101
|
+
console.log(tx.vout) // Outputs array
|
|
102
|
+
console.log(tx.locktime) // Locktime
|
|
103
|
+
|
|
104
|
+
// Encode transaction back to hex
|
|
105
|
+
const encoded = TX.encode(tx)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Signing Transactions
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { SIGNER } from '@vbyte/btc-dev'
|
|
112
|
+
|
|
113
|
+
// Sign segwit (v0) transaction input
|
|
114
|
+
const segwitSig = SIGNER.sign_segwit_tx(secretKey, txdata, {
|
|
115
|
+
txindex: 0, // Input index to sign
|
|
116
|
+
pubkey: compressedPubkey, // For P2WPKH
|
|
117
|
+
sigflag: 0x01 // SIGHASH_ALL
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Sign taproot (v1) transaction input
|
|
121
|
+
const taprootSig = SIGNER.sign_taproot_tx(secretKey, txdata, {
|
|
122
|
+
txindex: 0,
|
|
123
|
+
sigflag: 0x00 // SIGHASH_DEFAULT (taproot)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
// Verify all signatures in a transaction
|
|
127
|
+
const result = SIGNER.verify_tx(txdata)
|
|
128
|
+
if (result.valid) {
|
|
129
|
+
console.log('All signatures valid')
|
|
130
|
+
} else {
|
|
131
|
+
console.log('Verification failed:', result.error)
|
|
132
|
+
result.inputs.forEach(input => {
|
|
133
|
+
if (!input.valid) console.log(`Input ${input.index}: ${input.error}`)
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Taproot Scripts
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { TAPROOT } from '@vbyte/btc-dev'
|
|
142
|
+
|
|
143
|
+
// Create a taproot output with scripts
|
|
144
|
+
const taprootCtx = TAPROOT.create({
|
|
145
|
+
pubkey: internalPubkey,
|
|
146
|
+
leaves: [tapleaf1, tapleaf2] // Script leaves
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
console.log(taprootCtx.tapkey) // Tweaked public key
|
|
150
|
+
console.log(taprootCtx.cblock) // Control block for script-path
|
|
151
|
+
console.log(taprootCtx.taptweak) // Tweak value
|
|
152
|
+
|
|
153
|
+
// Verify control block
|
|
154
|
+
const isValid = TAPROOT.verify(tapkey, target, cblock)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Script Detection
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { SCRIPT } from '@vbyte/btc-dev'
|
|
161
|
+
|
|
162
|
+
// Detect lock script type
|
|
163
|
+
const type = SCRIPT.get_lock_script_type(scriptPubKey)
|
|
164
|
+
// Returns: 'p2pkh' | 'p2sh' | 'p2wpkh' | 'p2wsh' | 'p2tr' | 'opreturn' | null
|
|
165
|
+
|
|
166
|
+
// Check specific types
|
|
167
|
+
SCRIPT.is_p2wpkh_script(script) // true/false
|
|
168
|
+
SCRIPT.is_p2tr_script(script) // true/false
|
|
169
|
+
|
|
170
|
+
// Get witness version
|
|
171
|
+
const version = SCRIPT.get_lock_script_version(script)
|
|
172
|
+
// Returns: 0 (segwit v0), 1 (taproot), or null (legacy)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Witness Parsing
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import { WITNESS } from '@vbyte/btc-dev'
|
|
179
|
+
|
|
180
|
+
// Parse witness data from transaction input
|
|
181
|
+
const witnessData = WITNESS.parse(witness)
|
|
182
|
+
|
|
183
|
+
console.log(witnessData.type) // 'p2wpkh' | 'p2wsh' | 'p2tr' | 'p2ts' | null
|
|
184
|
+
console.log(witnessData.version) // 0 | 1 | null
|
|
185
|
+
console.log(witnessData.params) // Signature and other params
|
|
186
|
+
console.log(witnessData.script) // Witness script (if p2wsh/p2ts)
|
|
187
|
+
console.log(witnessData.cblock) // Control block (if p2ts)
|
|
188
|
+
console.log(witnessData.annex) // Annex data (if present)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Metadata Utilities
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { META } from '@vbyte/btc-dev'
|
|
195
|
+
|
|
196
|
+
// Encode/decode locktime (BIP-65)
|
|
197
|
+
const locktime = META.encode_locktime({ type: 'heightlock', height: 800000 })
|
|
198
|
+
const decoded = META.decode_locktime(locktime)
|
|
199
|
+
|
|
200
|
+
// Encode/decode sequence (BIP-68)
|
|
201
|
+
const sequence = META.encode_sequence({ mode: 'height', height: 144 }) // ~24 hours
|
|
202
|
+
const decodedSeq = META.decode_sequence(sequence)
|
|
203
|
+
|
|
204
|
+
// Reference pointers
|
|
205
|
+
const outpoint = META.RefPointer.outpoint.encode(txid, vout)
|
|
206
|
+
const inscriptionId = META.RefPointer.record_id.encode(txid, 0)
|
|
207
|
+
const runeId = META.RefPointer.rune_id.encode(840000, 15)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Security Considerations
|
|
211
|
+
|
|
212
|
+
- Always validate inputs before signing transactions
|
|
213
|
+
- Never log or expose secret keys
|
|
214
|
+
- Use secure random number generation for key generation
|
|
215
|
+
- Verify signatures after signing to ensure correctness
|
|
216
|
+
- Be aware of sighash flag implications (ANYONECANPAY, SINGLE, NONE)
|
|
217
|
+
|
|
218
|
+
See [SECURITY.md](./docs/SECURITY.md) for detailed security guidelines.
|
|
219
|
+
|
|
220
|
+
## Type Definitions
|
|
221
|
+
|
|
222
|
+
All types are exported from the main module:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import type {
|
|
226
|
+
TxData,
|
|
227
|
+
TxInput,
|
|
228
|
+
TxOutput,
|
|
229
|
+
SigHashOptions,
|
|
230
|
+
AddressData,
|
|
231
|
+
WitnessData,
|
|
232
|
+
TaprootContext
|
|
233
|
+
} from '@vbyte/btc-dev'
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Dependencies
|
|
237
|
+
|
|
238
|
+
- `@noble/curves` - Elliptic curve cryptography
|
|
239
|
+
- `@noble/hashes` - Cryptographic hash functions
|
|
240
|
+
- `@scure/btc-signer` - Bitcoin signing utilities
|
|
241
|
+
- `@vbyte/buff` - Buffer manipulation utilities
|
|
242
|
+
- `zod` - Runtime validation schemas
|
|
243
|
+
|
|
244
|
+
## Development
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
# Run tests
|
|
248
|
+
npm test
|
|
249
|
+
|
|
250
|
+
# Run specific test file
|
|
251
|
+
npm run script test/path/to/file.ts
|
|
252
|
+
|
|
253
|
+
# Build the package
|
|
254
|
+
npm run build
|
|
255
|
+
|
|
256
|
+
# Build and test
|
|
257
|
+
npm run package
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
CC-BY-1.0
|
package/dist/const.d.ts
CHANGED
|
@@ -36,3 +36,6 @@ export declare const TX_SIZE: {
|
|
|
36
36
|
export declare const SIGHASH_DEFAULT = 1;
|
|
37
37
|
export declare const SIGHASH_SEGWIT: number[];
|
|
38
38
|
export declare const SIGHASH_TAPROOT: number[];
|
|
39
|
+
export declare const MAX_SCRIPT_SIZE = 10000;
|
|
40
|
+
export declare const MAX_VARINT_SIZE = 520000;
|
|
41
|
+
export declare const OP_1_OFFSET = 80;
|
package/dist/const.js
CHANGED
|
@@ -1,36 +1,34 @@
|
|
|
1
1
|
export const COINBASE = {
|
|
2
|
-
TXID:
|
|
3
|
-
VOUT:
|
|
2
|
+
TXID: "00".repeat(32),
|
|
3
|
+
VOUT: 0xffffffff,
|
|
4
4
|
};
|
|
5
5
|
export const DEFAULT = {
|
|
6
6
|
LOCKTIME: 0,
|
|
7
|
-
SEQUENCE:
|
|
7
|
+
SEQUENCE: 0xffffffff,
|
|
8
8
|
VERSION: 2,
|
|
9
9
|
};
|
|
10
10
|
export const TAPLEAF_VERSIONS = [
|
|
11
|
-
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
0x66, 0x7e, 0x80, 0x84, 0x96, 0x98, 0xba, 0xbc,
|
|
16
|
-
0xbe
|
|
11
|
+
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8,
|
|
12
|
+
0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2,
|
|
13
|
+
0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x66, 0x7e, 0x80, 0x84, 0x96, 0x98, 0xba,
|
|
14
|
+
0xbc, 0xbe,
|
|
17
15
|
];
|
|
18
16
|
export const TAPLEAF_DEFAULT_VERSION = 0xc0;
|
|
19
17
|
export const LOCK_SCRIPT_TYPE = {
|
|
20
|
-
P2PKH:
|
|
21
|
-
P2SH:
|
|
22
|
-
P2WPKH:
|
|
23
|
-
P2WSH:
|
|
24
|
-
P2TR:
|
|
25
|
-
OPRETURN:
|
|
18
|
+
P2PKH: "p2pkh",
|
|
19
|
+
P2SH: "p2sh",
|
|
20
|
+
P2WPKH: "p2wpkh",
|
|
21
|
+
P2WSH: "p2wsh",
|
|
22
|
+
P2TR: "p2tr",
|
|
23
|
+
OPRETURN: "opreturn",
|
|
26
24
|
};
|
|
27
25
|
export const SPEND_SCRIPT_TYPE = {
|
|
28
|
-
P2PKH:
|
|
29
|
-
P2SH:
|
|
30
|
-
P2WPKH:
|
|
31
|
-
P2WSH:
|
|
32
|
-
P2TR:
|
|
33
|
-
P2TS:
|
|
26
|
+
P2PKH: "p2pkh",
|
|
27
|
+
P2SH: "p2sh",
|
|
28
|
+
P2WPKH: "p2wpkh",
|
|
29
|
+
P2WSH: "p2wsh",
|
|
30
|
+
P2TR: "p2tr",
|
|
31
|
+
P2TS: "p2ts",
|
|
34
32
|
};
|
|
35
33
|
export const LOCK_SCRIPT_REGEX = {
|
|
36
34
|
[LOCK_SCRIPT_TYPE.P2PKH]: /^76a914[0-9a-f]{40}88ac$/i,
|
|
@@ -40,7 +38,7 @@ export const LOCK_SCRIPT_REGEX = {
|
|
|
40
38
|
[LOCK_SCRIPT_TYPE.P2TR]: /^5120[0-9a-f]{64}$/i,
|
|
41
39
|
[LOCK_SCRIPT_TYPE.OPRETURN]: /^6a[0-9a-f]{2,}$/i,
|
|
42
40
|
};
|
|
43
|
-
export const SCRIPT_INT_KEY =
|
|
41
|
+
export const SCRIPT_INT_KEY = "";
|
|
44
42
|
export const TX_SIZE = {
|
|
45
43
|
GLOBAL_BASE: 8,
|
|
46
44
|
GLOBAL_WIT: 10,
|
|
@@ -50,3 +48,6 @@ export const TX_SIZE = {
|
|
|
50
48
|
export const SIGHASH_DEFAULT = 0x01;
|
|
51
49
|
export const SIGHASH_SEGWIT = [0x01, 0x02, 0x03, 0x81, 0x82, 0x83];
|
|
52
50
|
export const SIGHASH_TAPROOT = [0x00, ...SIGHASH_SEGWIT];
|
|
51
|
+
export const MAX_SCRIPT_SIZE = 10_000;
|
|
52
|
+
export const MAX_VARINT_SIZE = 520_000;
|
|
53
|
+
export const OP_1_OFFSET = 0x50;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export * as
|
|
2
|
-
export * as
|
|
3
|
-
export * as
|
|
4
|
-
export * as
|
|
5
|
-
export * as
|
|
6
|
-
export * as
|
|
7
|
-
export * as
|
|
8
|
-
export * as
|
|
9
|
-
export * as
|
|
10
|
-
export * as SCHEMA from
|
|
11
|
-
export type * from
|
|
1
|
+
export * as CONST from "./const.js";
|
|
2
|
+
export * as ADDRESS from "./lib/address/index.js";
|
|
3
|
+
export * as META from "./lib/meta/index.js";
|
|
4
|
+
export * as SCRIPT from "./lib/script/index.js";
|
|
5
|
+
export * as SIGHASH from "./lib/sighash/index.js";
|
|
6
|
+
export * as SIGNER from "./lib/signer/index.js";
|
|
7
|
+
export * as TAPROOT from "./lib/taproot/index.js";
|
|
8
|
+
export * as TX from "./lib/tx/index.js";
|
|
9
|
+
export * as WITNESS from "./lib/witness/index.js";
|
|
10
|
+
export * as SCHEMA from "./schema/index.js";
|
|
11
|
+
export type * from "./types/index.js";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export * as
|
|
2
|
-
export * as
|
|
3
|
-
export * as
|
|
4
|
-
export * as
|
|
5
|
-
export * as
|
|
6
|
-
export * as
|
|
7
|
-
export * as
|
|
8
|
-
export * as
|
|
9
|
-
export * as
|
|
10
|
-
export * as SCHEMA from
|
|
1
|
+
export * as CONST from "./const.js";
|
|
2
|
+
export * as ADDRESS from "./lib/address/index.js";
|
|
3
|
+
export * as META from "./lib/meta/index.js";
|
|
4
|
+
export * as SCRIPT from "./lib/script/index.js";
|
|
5
|
+
export * as SIGHASH from "./lib/sighash/index.js";
|
|
6
|
+
export * as SIGNER from "./lib/signer/index.js";
|
|
7
|
+
export * as TAPROOT from "./lib/taproot/index.js";
|
|
8
|
+
export * as TX from "./lib/tx/index.js";
|
|
9
|
+
export * as WITNESS from "./lib/witness/index.js";
|
|
10
|
+
export * as SCHEMA from "./schema/index.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bytes } from
|
|
2
|
-
import type { AddressInfo, ChainNetwork } from
|
|
1
|
+
import { type Bytes } from "@vbyte/buff";
|
|
2
|
+
import type { AddressInfo, ChainNetwork } from "../../types/index.js";
|
|
3
3
|
export declare function get_address(script: Bytes, network?: ChainNetwork): string;
|
|
4
4
|
export declare function parse_address(address: string): AddressInfo;
|
package/dist/lib/address/api.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { Buff } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
export function get_address(script, network =
|
|
1
|
+
import { Buff } from "@vbyte/buff";
|
|
2
|
+
import { LOCK_SCRIPT_TYPE } from "../../const.js";
|
|
3
|
+
import { get_lock_script_type } from "../../lib/script/lock.js";
|
|
4
|
+
import { P2PKH } from "./p2pkh.js";
|
|
5
|
+
import { P2SH } from "./p2sh.js";
|
|
6
|
+
import { P2TR } from "./p2tr.js";
|
|
7
|
+
import { P2WPKH } from "./p2wpkh.js";
|
|
8
|
+
import { P2WSH } from "./p2wsh.js";
|
|
9
|
+
import { get_address_info } from "./util.js";
|
|
10
|
+
export function get_address(script, network = "main") {
|
|
11
11
|
const bytes = Buff.bytes(script);
|
|
12
12
|
const type = get_lock_script_type(bytes);
|
|
13
13
|
if (type === null)
|
|
14
|
-
throw new Error(
|
|
14
|
+
throw new Error("Unknown or unsupported locking script type");
|
|
15
15
|
switch (type) {
|
|
16
16
|
case LOCK_SCRIPT_TYPE.P2PKH:
|
|
17
17
|
return P2PKH.encode_address(script, network);
|
|
@@ -24,7 +24,7 @@ export function get_address(script, network = 'main') {
|
|
|
24
24
|
case LOCK_SCRIPT_TYPE.P2TR:
|
|
25
25
|
return P2TR.encode_address(script, network);
|
|
26
26
|
default:
|
|
27
|
-
throw new Error(
|
|
27
|
+
throw new Error(`unknown script type: ${type}`);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
export function parse_address(address) {
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import { Buff } from
|
|
2
|
-
import { Assert, B58chk, Bech32, Bech32m } from
|
|
1
|
+
import { Buff } from "@vbyte/buff";
|
|
2
|
+
import { Assert, B58chk, Bech32, Bech32m } from "@vbyte/micro-lib";
|
|
3
3
|
const ENCODING_REGEX = {
|
|
4
4
|
base58: /^[13mn2][a-km-zA-HJ-NP-Z1-9]{25,34}$/,
|
|
5
5
|
bech32: /^(bc|tb|bcrt)1q[ac-hj-np-z02-9]{6,87}$/,
|
|
6
|
-
bech32m: /^(bc|tb|bcrt)1p[ac-hj-np-z02-9]{6,87}
|
|
6
|
+
bech32m: /^(bc|tb|bcrt)1p[ac-hj-np-z02-9]{6,87}$/,
|
|
7
7
|
};
|
|
8
8
|
const VERSION = {
|
|
9
9
|
bech32: 0,
|
|
10
|
-
bech32m: 1
|
|
10
|
+
bech32m: 1,
|
|
11
11
|
};
|
|
12
12
|
export function decode_address(address) {
|
|
13
13
|
const format = get_address_format(address);
|
|
14
14
|
if (format === null)
|
|
15
|
-
throw new Error(
|
|
16
|
-
if (format ===
|
|
15
|
+
throw new Error(`unrecognized address format: ${address}`);
|
|
16
|
+
if (format === "base58")
|
|
17
17
|
return base58_decode(address);
|
|
18
|
-
if (format ===
|
|
18
|
+
if (format === "bech32")
|
|
19
19
|
return bech32_decode(address);
|
|
20
|
-
if (format ===
|
|
20
|
+
if (format === "bech32m")
|
|
21
21
|
return bech32m_decode(address);
|
|
22
|
-
throw new Error(
|
|
22
|
+
throw new Error("unable to find a matching address configuration");
|
|
23
23
|
}
|
|
24
24
|
export function encode_address(config) {
|
|
25
|
-
if (config.format ===
|
|
25
|
+
if (config.format === "base58")
|
|
26
26
|
return base58_encode(config);
|
|
27
|
-
if (config.format ===
|
|
27
|
+
if (config.format === "bech32")
|
|
28
28
|
return bech32_encode(config);
|
|
29
|
-
if (config.format ===
|
|
29
|
+
if (config.format === "bech32m")
|
|
30
30
|
return bech32m_encode(config);
|
|
31
|
-
throw new Error(
|
|
31
|
+
throw new Error(`unrecognized encoding format: ${config.format}`);
|
|
32
32
|
}
|
|
33
33
|
function get_address_format(address) {
|
|
34
34
|
for (const [format, regex] of Object.entries(ENCODING_REGEX)) {
|
|
@@ -38,8 +38,8 @@ function get_address_format(address) {
|
|
|
38
38
|
return null;
|
|
39
39
|
}
|
|
40
40
|
function base58_encode(config) {
|
|
41
|
-
Assert.ok(config.format ===
|
|
42
|
-
Assert.exists(config.version,
|
|
41
|
+
Assert.ok(config.format === "base58", "encoding mismatch");
|
|
42
|
+
Assert.exists(config.version, "must specify a version");
|
|
43
43
|
const bytes = Buff.join([config.version, config.data]);
|
|
44
44
|
return B58chk.encode(bytes);
|
|
45
45
|
}
|
|
@@ -47,11 +47,11 @@ function base58_decode(encoded) {
|
|
|
47
47
|
const bytes = B58chk.decode(encoded);
|
|
48
48
|
const data = bytes.slice(1);
|
|
49
49
|
const version = bytes[0];
|
|
50
|
-
return { data, format:
|
|
50
|
+
return { data, format: "base58", version };
|
|
51
51
|
}
|
|
52
52
|
function bech32_encode(config) {
|
|
53
|
-
Assert.ok(config.format ===
|
|
54
|
-
Assert.exists(config.prefix,
|
|
53
|
+
Assert.ok(config.format === "bech32", "encoding mismatch");
|
|
54
|
+
Assert.exists(config.prefix, "prefix is required");
|
|
55
55
|
const bytes = Buff.bytes(config.data);
|
|
56
56
|
const words = Bech32.to_words(bytes);
|
|
57
57
|
return Bech32.encode(config.prefix, [VERSION.bech32, ...words]);
|
|
@@ -59,13 +59,13 @@ function bech32_encode(config) {
|
|
|
59
59
|
function bech32_decode(encoded) {
|
|
60
60
|
const { prefix, words } = Bech32.decode(encoded);
|
|
61
61
|
const [version, ...rest] = words;
|
|
62
|
-
Assert.ok(version === VERSION.bech32,
|
|
62
|
+
Assert.ok(version === VERSION.bech32, "bech32 version mismatch");
|
|
63
63
|
const data = Bech32.to_bytes(rest);
|
|
64
|
-
return { data, format:
|
|
64
|
+
return { data, format: "bech32", prefix, version };
|
|
65
65
|
}
|
|
66
66
|
function bech32m_encode(config) {
|
|
67
|
-
Assert.ok(config.format ===
|
|
68
|
-
Assert.exists(config.prefix,
|
|
67
|
+
Assert.ok(config.format === "bech32m", "encoding mismatch");
|
|
68
|
+
Assert.exists(config.prefix, "prefix is required");
|
|
69
69
|
const bytes = Buff.bytes(config.data);
|
|
70
70
|
const words = Bech32m.to_words(bytes);
|
|
71
71
|
return Bech32m.encode(config.prefix, [VERSION.bech32m, ...words]);
|
|
@@ -73,7 +73,7 @@ function bech32m_encode(config) {
|
|
|
73
73
|
function bech32m_decode(encoded) {
|
|
74
74
|
const { prefix, words } = Bech32m.decode(encoded);
|
|
75
75
|
const [version, ...rest] = words;
|
|
76
|
-
Assert.ok(version === VERSION.bech32m,
|
|
76
|
+
Assert.ok(version === VERSION.bech32m, "bech32m version mismatch");
|
|
77
77
|
const data = Bech32m.to_bytes(rest);
|
|
78
|
-
return { data, format:
|
|
78
|
+
return { data, format: "bech32m", prefix, version };
|
|
79
79
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export
|
|
1
|
+
export * from "./api.js";
|
|
2
|
+
export { P2PKH } from "./p2pkh.js";
|
|
3
|
+
export { P2SH } from "./p2sh.js";
|
|
4
|
+
export { P2TR } from "./p2tr.js";
|
|
5
|
+
export { P2WPKH } from "./p2wpkh.js";
|
|
6
|
+
export { P2WSH } from "./p2wsh.js";
|