@btc-vision/transaction
Version:
OPNet transaction library allows you to create and sign transactions for the OPNet network.
549 lines (406 loc) • 16.8 kB
Markdown
# Address Types Overview
Complete reference for all Bitcoin address types supported by the `@btc-vision/transaction` library.
## Navigation
- [Back to Documentation](../README.md#address-types-1)
- [P2OP Addresses](./P2OP.md)
- [P2WDA Addresses](./P2WDA.md)
## Supported Address Types
| Type | Prefix (Mainnet) | Witness Version | Weight Efficiency | Support | Description |
|------|-------------------|-----------------|-------------------|---------|-------------|
| P2PKH | `1...` | N/A (legacy) | 1x | Full | Pay-to-Public-Key-Hash |
| P2SH | `3...` | N/A (legacy) | 1x | Full | Pay-to-Script-Hash |
| P2WPKH | `bc1q...` (42 chars) | v0 | ~0.68x | Full | Pay-to-Witness-Public-Key-Hash |
| P2WSH | `bc1q...` (62 chars) | v0 | ~0.68x | Full | Pay-to-Witness-Script-Hash |
| P2TR | `bc1p...` | v1 | ~0.57x | Full | Pay-to-Taproot |
| P2MR | `bc1z...` | v2 | ~0.57x | Full | Pay-to-Merkle-Root (BIP 360) |
| P2OP | `bc1s...` / `bcrt1s...` | v16 | N/A | Contracts only | Pay-to-OPNet |
| P2WDA | `bc1q...` (P2WSH) | v0 | N/A | Data witness | Pay-to-Witness-Data-Authentication |
| P2A | Anchor output | N/A | Minimal | Full | Pay-to-Anchor (CPFP) |
| P2PK | Raw public key | N/A | N/A | Limited | Pay-to-Public-Key |
> **Weight Efficiency** indicates the relative cost compared to legacy P2PKH. Lower is cheaper. SegWit v0 benefits from the witness discount (1 weight unit instead of 4 for witness data). Taproot (v1) benefits further from key-path spending optimizations.
## P2PKH -- Pay-to-Public-Key-Hash
The original Bitcoin address format. Uses `OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG`.
| Property | Value |
|----------|-------|
| Prefix (mainnet) | `1` |
| Prefix (testnet) | `m` or `n` |
| Encoding | Base58Check |
| Address length | 25-34 characters |
| Witness version | N/A (pre-SegWit) |
| Enum value | `AddressTypes.P2PKH` |
### Detection
```typescript
import { AddressVerificator, AddressTypes } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
const type = AddressVerificator.detectAddressType('1A1zP1...', networks.bitcoin);
// Returns AddressTypes.P2PKH
```
### How It Works
The transaction builder automatically detects P2PKH inputs by examining the `scriptPubKey`. When a UTXO has a P2PKH script (`OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG`), the builder generates a legacy scriptSig with the ECDSA signature and compressed public key.
P2PKH UTXOs require the `nonWitnessUtxo` field (the full previous transaction) for PSBT signing:
```typescript
const utxo: UTXO = {
transactionId: 'abc...',
outputIndex: 0,
value: 10_000n,
scriptPubKey: { hex: '76a914...88ac', address: '1A1z...' },
nonWitnessUtxo: fullPreviousTxBytes,
};
```
## P2SH -- Pay-to-Script-Hash
Allows sending to a script hash. The redeemer must provide the script that hashes to the committed value, plus data to satisfy it.
| Property | Value |
|----------|-------|
| Prefix (mainnet) | `3` |
| Prefix (testnet) | `2` |
| Encoding | Base58Check |
| Address length | 34 characters |
| Witness version | N/A (pre-SegWit) |
| Enum value | `AddressTypes.P2SH_OR_P2SH_P2WPKH` |
### P2SH-P2WPKH (Nested SegWit)
The most common P2SH usage today wraps a P2WPKH script inside P2SH, providing SegWit benefits while maintaining backward compatibility with older software that only recognizes P2SH addresses.
```typescript
const utxo: UTXO = {
transactionId: 'abc...',
outputIndex: 0,
value: 10_000n,
scriptPubKey: { hex: 'a914...87', address: '3...' },
redeemScript: '0014...', // P2WPKH script inside P2SH
};
```
> **Note:** `AddressVerificator.detectAddressType()` returns `P2SH_OR_P2SH_P2WPKH` because it cannot distinguish pure P2SH from P2SH-P2WPKH by address alone. The `redeemScript` determines the actual spending path.
## P2WPKH -- Pay-to-Witness-Public-Key-Hash
Native SegWit v0 address for single-key spending. Signature and public key are moved to the witness field, benefiting from the witness discount.
| Property | Value |
|----------|-------|
| Prefix (mainnet) | `bc1q` |
| Prefix (testnet) | `tb1q` |
| Prefix (opnetTestnet) | `opt1q` |
| Prefix (regtest) | `bcrt1q` |
| Encoding | Bech32 |
| Address length | 42 characters (mainnet) |
| Data length | 20 bytes (HASH160 of public key) |
| Witness version | 0 |
| Enum value | `AddressTypes.P2WPKH` |
### Detection
```typescript
const isP2WPKH = AddressVerificator.isP2WPKHAddress('bc1q...', networks.bitcoin);
// true if version=0 and data=20 bytes
```
### Creation
The library automatically generates P2WPKH addresses when using `AddressGenerator.generatePKSH()`:
```typescript
import { AddressGenerator } from '@btc-vision/transaction';
const p2wpkhAddress = AddressGenerator.generatePKSH(sha256Hash, network);
// Returns bc1q... address
```
## P2WSH -- Pay-to-Witness-Script-Hash
Native SegWit v0 address for script-based spending. The witness script is committed via SHA256 (not HASH160 like P2SH).
| Property | Value |
|----------|-------|
| Prefix (mainnet) | `bc1q` |
| Prefix (testnet) | `tb1q` |
| Prefix (opnetTestnet) | `opt1q` |
| Prefix (regtest) | `bcrt1q` |
| Encoding | Bech32 |
| Address length | 62 characters (mainnet) |
| Data length | 32 bytes (SHA256 of witness script) |
| Witness version | 0 |
| Enum value | `AddressTypes.P2WSH` |
### Use Cases in OPNet
P2WSH is used extensively in OPNet for:
1. **Epoch challenge timelocks** -- `TimeLockGenerator` creates P2WSH outputs with CSV-locked witness scripts for miner rewards
2. **Multi-signature** -- `MultiSignTransaction` uses P2WSH for M-of-N multisig scripts
3. **Consolidated interactions (CHCT)** -- `ConsolidatedInteractionTransaction` creates P2WSH outputs with HASH160 data commitments
```typescript
// P2WSH address with witness script
const p2wsh: IP2WSHAddress = {
address: 'bc1q...', // 62-character bech32 address
witnessScript: witnessScriptBytes,
};
```
## P2TR -- Pay-to-Taproot
Taproot (SegWit v1) addresses provide the most efficient single-key spending and support complex script trees via Tapscript.
| Property | Value |
|----------|-------|
| Prefix (mainnet) | `bc1p` |
| Prefix (testnet) | `tb1p` |
| Prefix (opnetTestnet) | `opt1p` |
| Prefix (regtest) | `bcrt1p` |
| Encoding | Bech32m |
| Address length | 62 characters (mainnet) |
| Data length | 32 bytes (x-only public key) |
| Witness version | 1 |
| Enum value | `AddressTypes.P2TR` |
### Key-Path vs Script-Path
| Spending Path | Witness | Use Case |
|---------------|---------|----------|
| Key-path | Single 64-byte Schnorr signature | Standard transfers, most interactions |
| Script-path | Script + control block + witnesses | Contract deployment, interaction data embedding |
### Detection and Validation
```typescript
const isP2TR = AddressVerificator.isValidP2TRAddress('bc1p...', networks.bitcoin);
// true if version=1 and data=32 bytes
```
### Address Generation
```typescript
import { AddressGenerator } from '@btc-vision/transaction';
const p2trAddress = AddressGenerator.generateTaprootAddress(xOnlyPubKey, network);
// Returns bc1p... address (bech32m)
```
### Role in OPNet
P2TR is the **default address type** for OPNet:
- **Contract addresses** are P2TR (Taproot) addresses
- **User wallets** typically use P2TR for the best fee efficiency
- **Interaction transactions** embed data in Tapscript leaves
- **Deployment transactions** use Tapscript for bytecode embedding
> **Quantum Safety:** For quantum-resistant outputs, use **P2MR** (BIP 360) instead. All transaction builders accept `useP2MR: true` to switch from P2TR to P2MR. See the [P2MR section](#p2mr----pay-to-merkle-root-bip-360) below.
## P2MR -- Pay-to-Merkle-Root (BIP 360)
A quantum-safe SegWit version 2 output type that commits directly to a Merkle root, eliminating the quantum-vulnerable key-path spend of P2TR.
| Property | Value |
|----------|-------|
| Prefix (mainnet) | `bc1z` |
| Prefix (testnet) | `tb1z` |
| Prefix (opnetTestnet) | `opt1z` |
| Prefix (regtest) | `bcrt1z` |
| Encoding | Bech32m |
| Address length | 62 characters (mainnet) |
| Data length | 32 bytes (Merkle root) |
| Witness version | 2 |
| Output format | `OP_2 <32-byte merkle_root>` |
### Key Difference from P2TR
P2MR has **no internal public key** and therefore **no key-path spend**. All spending must go through the script-path. This eliminates the quantum attack vector where a quantum computer could derive the private key from the internal public key exposed in the output.
| Feature | P2TR | P2MR |
|---------|------|------|
| Internal pubkey | Yes (exposed in output) | No |
| Key-path spend | Yes | No |
| Script-path spend | Yes | Yes |
| Control block size | `33 + 32*m` bytes | `1 + 32*m` bytes |
| Quantum resistance | Vulnerable (key-path) | Resistant |
| Address prefix | `bc1p` | `bc1z` |
### Detection
```typescript
import { isP2MR } from '@btc-vision/bitcoin';
const isP2MROutput = isP2MR(scriptPubKey);
// true if version=2 and data=32 bytes
```
### Usage in Transactions
All transaction builders support P2MR via the `useP2MR` flag:
```typescript
const result = await factory.signInteraction({
// ... other params
useP2MR: true, // Use P2MR instead of P2TR
});
```
When `useP2MR` is `true`, the transaction builder:
- Generates P2MR outputs (no internal pubkey)
- Uses smaller control blocks (32 bytes saved per script-path input)
- Produces addresses starting with `bc1z` instead of `bc1p`
- Only supports script-path spending (no key-path)
### Multi-Signature with P2MR
```typescript
import { P2MR_MS } from '@btc-vision/transaction';
const multisigAddress = P2MR_MS.generateMultiSigAddress(
[pubkey1, pubkey2, pubkey3],
2, // 2-of-3
networks.bitcoin,
);
// Returns bc1z... address
```
### CSV Time-Locked P2MR Addresses
```typescript
const csvAddress = address.toCSVP2MR(144, networks.bitcoin);
// Returns a P2MR address with a 144-block CSV timelock
```
## P2OP -- Pay-to-OPNet
A custom OPNet-specific address type using witness version 16 for smart contract identification.
| Property | Value |
|----------|-------|
| Prefix (mainnet) | `bc1s` |
| Prefix (testnet) | `tb1s` |
| Prefix (regtest) | `bcrt1s` |
| Encoding | Bech32m |
| Data length | 21 bytes |
| Witness version | 16 |
| Enum value | `AddressTypes.P2OP` |
### Detection
```typescript
const isP2OP = AddressVerificator.isValidP2OPAddress(address, network);
// true if version=16 and data=21 bytes with correct prefix
```
### Purpose
P2OP addresses identify OPNet smart contracts on the Bitcoin network. They are derived from contract bytecode and deployment parameters, providing a unique on-chain identifier for each contract.
See [P2OP Addresses](./P2OP.md) for detailed documentation.
## P2WDA -- Pay-to-Witness-Data-Authentication
A quantum-resistant witness data authentication scheme built on P2WSH. The witness field carries both the authentication data and arbitrary payload data.
| Property | Value |
|----------|-------|
| Prefix | Same as P2WSH (`bc1q...`) |
| Encoding | Bech32 |
| Witness version | 0 (P2WSH) |
| Enum value | `AddressTypes.P2WDA` |
### Detection
P2WDA addresses look identical to P2WSH addresses. Detection requires examining the witness script:
```typescript
// From address alone (cannot distinguish from P2WSH)
const type = AddressVerificator.detectAddressType(address, network);
// Returns AddressTypes.P2WSH
// With witness script (can detect P2WDA)
const typeWithWitness = AddressVerificator.detectAddressTypeWithWitnessScript(
address,
network,
witnessScript,
);
// Returns AddressTypes.P2WDA if witness script matches pattern
// Validate P2WDA address
const validation = AddressVerificator.validateP2WDAAddress(address, network, witnessScript);
// Returns { isValid, isPotentiallyP2WDA, isDefinitelyP2WDA, publicKey?, error? }
```
### Witness Script Pattern
The P2WDA witness script follows the pattern: `(OP_2DROP * 5) <pubkey> OP_CHECKSIG`
This allows embedding 5 data slots in the witness while requiring a valid signature for spending.
See [P2WDA Addresses](./P2WDA.md) for detailed documentation.
## P2A -- Pay-to-Anchor
Minimal anchor outputs used for Child-Pays-for-Parent (CPFP) fee bumping.
| Property | Value |
|----------|-------|
| Script | `OP_1 OP_PUSHBYTES_2 4e73` |
| Value | 0 satoshis |
| Enum value | N/A (detected by script) |
### Usage
Anchor outputs are added via the `anchor` parameter:
```typescript
const params: ITransactionParameters = {
anchor: true, // Adds a P2A anchor output
// ...other parameters
};
```
Or manually:
```typescript
import { ANCHOR_SCRIPT } from '@btc-vision/transaction';
builder.addAnchor();
// Adds output: { value: 0, script: ANCHOR_SCRIPT }
```
### Detection
```typescript
import { isP2A } from '@btc-vision/bitcoin';
const isAnchor = isP2A(outputScript);
```
## P2PK -- Pay-to-Public-Key
The simplest Bitcoin output type. Pays directly to a public key without hashing.
| Property | Value |
|----------|-------|
| Encoding | Raw hex public key |
| Enum value | `AddressTypes.P2PK` |
### Detection
```typescript
const isPublicKey = AddressVerificator.isValidPublicKey(input, network);
// Supports 33-byte compressed, 65-byte uncompressed, and 32-byte x-only keys
```
> **Note:** P2PK is rarely used for new outputs but may appear in legacy UTXOs. The library supports spending P2PK inputs.
## Address Type Detection
The `AddressVerificator` class provides comprehensive address type detection:
```typescript
import { AddressVerificator, AddressTypes } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
const network = networks.bitcoin;
// Detect any address type
const type = AddressVerificator.detectAddressType(address, network);
switch (type) {
case AddressTypes.P2TR:
console.log('Taproot address');
break;
case AddressTypes.P2MR:
console.log('Pay-to-Merkle-Root address (quantum-safe)');
break;
case AddressTypes.P2WPKH:
console.log('Native SegWit address');
break;
case AddressTypes.P2WSH:
console.log('Witness Script Hash address');
break;
case AddressTypes.P2PKH:
console.log('Legacy address');
break;
case AddressTypes.P2SH_OR_P2SH_P2WPKH:
console.log('P2SH or nested SegWit');
break;
case AddressTypes.P2OP:
console.log('OPNet contract address');
break;
case AddressTypes.P2PK:
console.log('Raw public key');
break;
case null:
console.log('Unknown address type');
break;
}
```
## Network Prefixes
Address prefixes vary by network:
| Type | Mainnet | Testnet | OPNet Testnet | Regtest |
|------|---------|---------|---------------|---------|
| P2PKH | `1` | `m` / `n` | `m` / `n` | `m` / `n` |
| P2SH | `3` | `2` | `2` | `2` |
| Bech32 (v0) | `bc1q` | `tb1q` | `opt1q` | `bcrt1q` |
| Bech32m (v1, P2TR) | `bc1p` | `tb1p` | `opt1p` | `bcrt1p` |
| Bech32m (v2, P2MR) | `bc1z` | `tb1z` | `opt1z` | `bcrt1z` |
## UTXO Script Requirements
Different address types require different fields in the `UTXO` interface:
| Address Type | `scriptPubKey` | `redeemScript` | `witnessScript` | `nonWitnessUtxo` |
|-------------|----------------|----------------|-----------------|-------------------|
| P2PKH | Required | -- | -- | Required |
| P2SH | Required | Required | -- | -- |
| P2SH-P2WPKH | Required | Required | -- | -- |
| P2WPKH | Required | -- | -- | -- |
| P2WSH | Required | -- | Required | -- |
| P2TR | Required | -- | -- | -- |
| P2MR | Required | -- | -- | -- |
| P2WDA | Required | -- | Required | -- |
```typescript
// P2TR UTXO (simplest)
const p2trUtxo: UTXO = {
transactionId: 'abc...',
outputIndex: 0,
value: 50_000n,
scriptPubKey: { hex: '5120...', address: 'bc1p...' },
};
// P2PKH UTXO (needs full previous tx)
const p2pkhUtxo: UTXO = {
transactionId: 'def...',
outputIndex: 1,
value: 30_000n,
scriptPubKey: { hex: '76a914...88ac', address: '1...' },
nonWitnessUtxo: previousTxBytes,
};
// P2WSH UTXO (needs witness script)
const p2wshUtxo: UTXO = {
transactionId: 'ghi...',
outputIndex: 0,
value: 20_000n,
scriptPubKey: { hex: '0020...', address: 'bc1q...' },
witnessScript: witnessScriptBytes,
};
```
## See Also
- [P2OP Addresses](./P2OP.md) -- Detailed P2OP documentation
- [P2WDA Addresses](./P2WDA.md) -- Detailed P2WDA documentation
- [AddressVerificator](../keypair/address-verificator.md) -- Address validation API
- [Transaction Types](../api-reference/transaction-types.md) -- `AddressTypes` enum reference
- [Interfaces](../api-reference/interfaces.md) -- `UTXO` interface reference