@btc-vision/transaction
Version:
OPNet transaction library allows you to create and sign transactions for the OPNet network.
354 lines (264 loc) • 13.5 kB
Markdown
# Architecture Overview
The OPNet Transaction Library provides a layered system for building, signing, and broadcasting Bitcoin transactions with quantum-resistant cryptography support. It serves as the client-side SDK for the OPNet protocol -- a smart contract layer on Bitcoin.
## Table of Contents
- [Library Purpose](#library-purpose)
- [Architecture](#architecture)
- [Key Concepts](#key-concepts)
- [Two-Transaction Model](#two-transaction-model)
- [UTXO-Based Model](#utxo-based-model)
- [Quantum-Resistant Addresses](#quantum-resistant-addresses)
- [Dual Environment Support](#dual-environment-support)
- [Offline Transaction Signing](#offline-transaction-signing)
- [Transaction Types](#transaction-types)
- [Network Support](#network-support)
- [Address Systems](#address-systems)
- [Class Hierarchy](#class-hierarchy)
## Library Purpose
The library enables developers to:
- **Build Bitcoin transactions** -- Create funding, deployment, interaction, multi-signature, and custom script transactions
- **Sign with quantum resistance** -- Every transaction includes ML-DSA (FIPS 204) post-quantum signatures alongside classical Schnorr signatures
- **Deploy and interact with smart contracts** -- Encode calldata, deploy WASM bytecode, and call contract functions on the OPNet network
- **Work in any environment** -- Identical API for Node.js backends and browser frontends, with built-in support for wallet extensions (Unisat, Xverse, OP_WALLET)
## Architecture
```mermaid
flowchart TB
subgraph EntryPoints["Entry Points"]
TF["TransactionFactory<br/><i>Main API surface</i>"]
OP["OPNetLimitedProvider<br/><i>UTXO fetching</i>"]
end
subgraph Builders["Transaction Builders"]
TT["TweakedTransaction<br/><i>PSBT construction,<br/>Taproot tweaking, signing</i>"]
TB["TransactionBuilder<T><br/><i>Abstract base: UTXO management,<br/>fee calculation, outputs</i>"]
TT --> TB
TB --> FT["FundingTransaction<br/>BTC transfers"]
TB --> DT["DeploymentTransaction<br/>Contract deployment"]
TB --> IT["InteractionTransaction<br/>Contract calls"]
TB --> MT["MultiSignTransaction<br/>Multi-sig operations"]
TB --> CT["CustomScriptTransaction<br/>Custom scripts"]
TB --> XT["CancelTransaction<br/>TX cancellation"]
TB --> CI["ConsolidatedInteractionTransaction<br/>CHCT anti-censorship"]
end
subgraph Generators["Script Generators"]
CG["CalldataGenerator"]
DG["DeploymentGenerator"]
MG["MultiSignGenerator"]
HG["HashCommitmentGenerator"]
end
subgraph KeyManagement["Key Management"]
MN["Mnemonic<br/><i>BIP39 + BIP360</i>"]
WL["Wallet<br/><i>Classical + Quantum keys</i>"]
EC["EcKeyPair<br/><i>Secp256k1 operations</i>"]
MS["MessageSigner<br/><i>Schnorr + ML-DSA signing</i>"]
end
TF --> TT
TT --> Generators
MN --> WL
WL --> TT
```
## Key Concepts
### Two-Transaction Model
OPNet smart contract operations (deployments and interactions) require **two Bitcoin transactions** that are broadcast together:
```mermaid
sequenceDiagram
participant User
participant FundingTx as Funding TX
participant InteractionTx as Interaction TX
participant Network as Bitcoin Network
User->>FundingTx: 1. Create funding transaction
Note over FundingTx: Sends exact amount to<br/>a one-time script address<br/>(P2TR or P2MR)
User->>InteractionTx: 2. Create interaction transaction
Note over InteractionTx: Spends funding output,<br/>embeds calldata in Tapscript
User->>Network: 3. Broadcast both transactions
Note over Network: Funding TX confirms first,<br/>Interaction TX spends its output
```
**Why two transactions?** The interaction transaction embeds contract calldata in a Taproot script path. The funding transaction creates a UTXO with the exact amount needed (fees + priority fee + gas), locked to the script address. The `TransactionFactory` handles this automatically -- you provide parameters and receive both signed transactions ready to broadcast.
Simple BTC transfers (funding-only) use a single transaction.
### UTXO-Based Model
Bitcoin uses Unspent Transaction Outputs (UTXOs), not account balances. Every transaction consumes existing UTXOs as inputs and creates new UTXOs as outputs.
```mermaid
flowchart LR
subgraph Inputs["Inputs (consumed)"]
U1["UTXO: 50,000 sat"]
U2["UTXO: 30,000 sat"]
end
subgraph TX["Your Transaction"]
direction TB
Fee["Fee: 1,500 sat"]
end
subgraph Outputs["Outputs (created)"]
O1["Recipient: 40,000 sat"]
O2["Change: 38,500 sat"]
end
U1 --> TX
U2 --> TX
TX --> O1
TX --> O2
```
The library manages UTXO selection, change calculation, and fee estimation. Each method on `TransactionFactory` returns the new UTXOs (`nextUTXOs`) that your application should track for subsequent transactions.
### Quantum-Resistant Addresses
OPNet implements **BIP360** for quantum-resistant key management using ML-DSA (FIPS 204, formerly CRYSTALS-Dilithium). Every wallet holds two key pairs:
| Key Type | Algorithm | Purpose |
|----------|-----------|---------|
| Classical | secp256k1 (Schnorr) | Bitcoin transaction signing, P2TR/P2MR addresses |
| Quantum | ML-DSA-44/65/87 | OPNet identity, quantum-resistant signatures |
The quantum public key is hashed (SHA-256) to produce a 32-byte **OPNet address** that serves as the user's identity across the protocol. Classical keys handle the Bitcoin layer; quantum keys handle the OPNet protocol layer.
For quantum-safe transaction outputs, the library supports **P2MR (Pay-to-Merkle-Root, BIP 360)** -- a SegWit version 2 output type that commits directly to a Merkle root without exposing an internal public key. All transaction builders accept a `useP2MR` flag to enable P2MR outputs (`bc1z...` addresses) instead of the default P2TR (`bc1p...`).
### Dual Environment Support
The library works identically in Node.js and browsers:
```mermaid
flowchart LR
subgraph API["Unified API"]
TF2["TransactionFactory"]
MS2["MessageSigner"]
end
subgraph NodeJS["Node.js"]
NC["Native crypto"]
NB["Native Buffer"]
end
subgraph Browser["Browser"]
WC["WebCrypto + polyfills"]
BB["Buffer polyfill"]
WE["Wallet Extensions<br/>(Unisat, Xverse, OP_WALLET)"]
end
API --> NodeJS
API --> Browser
```
In the browser, `MessageSigner` auto-detects OP_WALLET extensions. Methods like `signMessageAuto()` and `signMLDSAMessageAuto()` automatically delegate to the browser wallet if available, or fall back to a provided key pair.
### Offline Transaction Signing
Transactions can be built in an online environment (with UTXO data but no private keys), exported as a serialized state, transported to an air-gapped machine for signing, and then returned for broadcast. This is handled by `OfflineTransactionManager`:
1. **Online:** Build transaction, export state (base64)
2. **Offline:** Import state, attach signer, sign, export signed TX hex
3. **Online:** Broadcast the signed transaction
## Transaction Types
The `TransactionType` enum defines all supported operations:
| Type | Value | Description | TX Count |
|------|-------|-------------|----------|
| `GENERIC` | 0 | Generic transaction (base type) | -- |
| `FUNDING` | 1 | Simple BTC transfer between addresses | 1 |
| `DEPLOYMENT` | 2 | Deploy a smart contract (WASM bytecode) | 2 |
| `INTERACTION` | 3 | Call a function on a deployed contract | 2 |
| `MULTI_SIG` | 4 | Multi-signature transaction (M-of-N) | 2 |
| `CUSTOM_CODE` | 5 | Execute a custom Bitcoin script | 2 |
| `CANCEL` | 6 | Cancel/recover a stuck transaction | 1 |
| `CONSOLIDATED_SETUP` | 7 | CHCT setup phase (anti-censorship) | 1 (pair) |
| `CONSOLIDATED_REVEAL` | 8 | CHCT reveal phase (anti-censorship) | 1 (pair) |
```typescript
import { TransactionType } from '@btc-vision/transaction';
// TransactionType.INTERACTION === 3
```
## Network Support
The library supports multiple Bitcoin networks, configured via the `networks` object from `@btc-vision/bitcoin` and the `ChainId` enum:
### Bitcoin Networks
| Network | Bech32 Prefix | Usage |
|---------|--------------|-------|
| `networks.bitcoin` | `bc1` | Bitcoin mainnet |
| `networks.testnet` | `tb1` | Bitcoin testnet |
| `networks.regtest` | `bcrt1` | Local development / regression testing |
### Chain IDs
```typescript
import { ChainId } from '@btc-vision/transaction';
enum ChainId {
Bitcoin = 0, // Bitcoin mainnet, testnet, regtest
Fractal = 1, // Fractal Bitcoin
}
```
The `chainId` parameter is optional on transaction parameters. When omitted, it defaults to `ChainId.Bitcoin`.
### Selecting a Network
```typescript
import { networks } from '@btc-vision/bitcoin';
// Mainnet
const mainnetWallet = mnemonic.derive(0);
// mainnetWallet.p2tr => "bc1p..."
// Testnet
const testnetMnemonic = new Mnemonic(phrase, '', networks.testnet);
const testnetWallet = testnetMnemonic.derive(0);
// testnetWallet.p2tr => "tb1p..."
// Regtest
const regtestMnemonic = new Mnemonic(phrase, '', networks.regtest);
const regtestWallet = regtestMnemonic.derive(0);
// regtestWallet.p2tr => "bcrt1p..."
```
## Address Systems
OPNet uses two complementary address systems:
### Bitcoin Addresses (On-Chain)
Standard Bitcoin addresses used for transaction inputs and outputs. The library generates Taproot (P2TR) addresses by default, with optional P2MR (BIP 360) support:
| Format | Prefix | Example |
|--------|--------|---------|
| P2TR (Taproot) | `bc1p` | `bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297` |
| P2MR (Merkle Root) | `bc1z` | `bc1z...` (quantum-safe, no key-path spend) |
| P2WPKH (SegWit) | `bc1q` | `bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4` |
| P2PKH (Legacy) | `1` | `1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa` |
Access all address formats from a `Wallet` instance:
```typescript
const wallet = mnemonic.derive(0);
wallet.p2tr; // Taproot address (primary for OPNet)
wallet.p2wpkh; // Native SegWit address
wallet.legacy; // Legacy P2PKH address
wallet.segwitLegacy; // Wrapped SegWit P2SH address
wallet.p2wda; // P2WDA address (returns IP2WSHAddress object with .address and .witnessScript)
```
### OPNet Addresses (Protocol Identity)
The OPNet address is the **SHA-256 hash of the ML-DSA public key**, represented as 32 bytes. This serves as the user's universal identifier within the OPNet smart contract layer.
```typescript
import { Address } from '@btc-vision/transaction';
const wallet = mnemonic.derive(0);
// The Address object IS the 32-byte hash (extends Uint8Array)
const opnetAddress: Address = wallet.address;
// Hex representation (64 characters)
console.log(opnetAddress.toHex());
// => "a1b2c3d4e5f6...64 hex chars..."
// The underlying quantum public key (1312 bytes for ML-DSA-44)
console.log(wallet.quantumPublicKey.length);
// => 1312
```
### Address Relationship
```mermaid
flowchart LR
MLDSA["ML-DSA Public Key<br/>(1312 bytes)"] -->|SHA-256| OPNet["OPNet Address<br/>(32 bytes)"]
Secp["secp256k1 Public Key<br/>(33 bytes)"] -->|Taproot tweak| P2TR["Bitcoin P2TR<br/>(bc1p...)"]
Secp -->|Merkle root| P2MR["Bitcoin P2MR<br/>(bc1z...)"]
subgraph Wallet["Wallet Instance"]
MLDSA
Secp
end
subgraph Addresses["Derived Addresses"]
OPNet
P2TR
P2MR
end
```
Both addresses derive from the same `Wallet`, which is derived from a single BIP39 mnemonic via parallel derivation paths:
- **Classical path:** `m/84'/0'/0'/0/0` (BIP84 for secp256k1)
- **Quantum path:** `m/360'/0'/0'/0/0` (BIP360 for ML-DSA)
## Class Hierarchy
### Transaction Building
```
TransactionFactory -- Top-level API (signInteraction, signDeployment, createBTCTransfer)
TweakedTransaction -- PSBT construction, Taproot tweaking, signature orchestration
TransactionBuilder<T> -- Abstract base (UTXO management, fee estimation, outputs)
FundingTransaction -- Simple BTC transfers
DeploymentTransaction -- Contract deployment (bytecode + calldata)
InteractionTransaction -- Contract function calls (calldata)
MultiSignTransaction -- M-of-N multi-signature operations
CustomScriptTransaction -- Custom Bitcoin script execution
CancelTransaction -- Transaction cancellation / recovery
ConsolidatedInteractionTransaction -- CHCT anti-censorship system
```
### Key Management
```
Mnemonic -- BIP39 phrase + BIP360 quantum root
Wallet -- Combined classical + quantum key pair
Address -- 32-byte OPNet address (SHA-256 of ML-DSA pubkey)
EcKeyPair -- secp256k1 key operations
QuantumBIP32Interface -- ML-DSA key derivation and signing
```
### Signing
```
MessageSigner -- Singleton for Schnorr + ML-DSA message signing
TweakedSigner -- Taproot key tweaking for transaction signing
BrowserSignerBase -- Base class for browser wallet integration
UnisatSigner -- Unisat wallet extension adapter
XverseSigner -- Xverse wallet extension adapter
```
---
**Previous:** [Installation & Setup](./installation.md) | **Next:** [Quick Start Guide](./quick-start.md)