# voltaire-effect > Effect.ts integration for Voltaire Ethereum primitives - typed errors, composable workflows, and testable Ethereum code. voltaire-effect wraps [Voltaire](https://voltaire.tevm.sh) primitives with [Effect.ts](https://effect.website) for typed errors, dependency injection, and composable pipelines. ## Installation ```bash pnpm add voltaire-effect @tevm/voltaire effect ``` Requires Effect 3.x, Voltaire 0.x, and TypeScript 5.4+. ## Quick Start ```typescript import { Effect, Layer } from 'effect' import { getBlockNumber, Provider, HttpTransport } from 'voltaire-effect' // Compose layers once const ProviderLayer = Provider.pipe( Layer.provide(HttpTransport('https://eth.llamarpc.com')) ) const program = Effect.gen(function* () { return yield* getBlockNumber() }) await Effect.runPromise(program.pipe(Effect.provide(ProviderLayer))) ``` ## Architecture voltaire-effect is organized into three layers: 1. **Schema Layer** - Effect Schema validation that returns Voltaire branded types 2. **Effect Layer** - Composable operations with typed errors 3. **Services Layer** - Dependency injection for providers, signers, and crypto ## Core Patterns ### Schema Validation Schema decode validates input and returns Voltaire branded types: ```typescript import * as Address from 'voltaire-effect/primitives/Address' import * as S from 'effect/Schema' const addr = S.decodeSync(Address.Hex)('0x742d35Cc...') // Returns AddressType (branded Uint8Array), not string // Use with Voltaire functions directly Address.toHex(addr) // "0x742d35cc..." Address.isZero(addr) // false ``` ### Typed Errors Errors appear in the type signature, not as invisible exceptions: ```typescript S.decode(Address.Hex)(input).pipe( Effect.catchTag('ParseError', (e) => Effect.succeed(fallback)) ) // Effect ``` ### Services and Layers Free functions depend on services internally. Layers provide implementations: ```typescript import { getBlockNumber, sendTransaction } from 'voltaire-effect' const program = Effect.gen(function* () { const block = yield* getBlockNumber() return yield* sendTransaction({ to, value }) }) // Compose layers const MainLayer = Layer.mergeAll( Signer.Live, LocalAccount(privateKey), Provider, HttpTransport('https://eth.llamarpc.com'), Secp256k1Live, KeccakLive ) await Effect.runPromise(program.pipe(Effect.provide(MainLayer))) ``` ### Testable Code Swap production layers for test layers without changing business logic: ```typescript // Production await Effect.runPromise(program.pipe(Effect.provide(MainLayer))) // Test - same code, different wiring await Effect.runPromise(program.pipe(Effect.provide(TestLayer))) ``` ## Documentation Structure ### Getting Started - `/index` - Overview, installation, ecosystem links - `/getting-started` - First program, schema validation, checksummed addresses - `/why` - Trade-offs vs viem/ethers, when to use voltaire-effect - `/concepts/effect-primer` - 5-minute Effect.ts intro for Ethereum developers - `/layers` - Schema, Effect, and Service layers explained - `/cheatsheet` - Quick reference for all patterns - `/recipes` - Copy-paste solutions for common tasks - `/testing` - Mock services for unit tests - `/comparisons` - Detailed comparison with viem, ethers, base Voltaire - `/changelog` - Release history ### Concepts - `/concepts/branded-types` - How Voltaire branded types work with Effect Schema - `/concepts/data-first-api` - Data-first functional API design - `/concepts/error-handling` - Typed errors with ParseError, provider error unions, SignerError - `/concepts/dependency-injection` - Services and Layer composition ### Guides - `/guides/hd-wallet` - BIP-39/BIP-44 HD wallet integration with MnemonicAccount - `/guides/debugging` - Debug Effect programs, inspect errors, trace execution - `/guides/migrating-from-viem` - Step-by-step migration guide from viem - `/guides/migrating-from-ethers` - Step-by-step migration guide from ethers.js ### Services Core services for Ethereum operations: - `/services/transport` - HTTP, WebSocket, Browser transports for JSON-RPC - `/services/provider` - JSON-RPC provider (blocks, txs, logs, call, estimateGas, simulations, optional account ops, subscriptions) - `/services/debug` - debug_* tracing, raw blocks/txs, storage inspection - `/services/engine-api` - engine_* consensus and execution client methods - `/services/signer` - Transaction signing and sending: EIP-191, EIP-712, EIP-1559, EIP-4844, EIP-7702 - `/services/account` - Local and JSON-RPC account abstraction - `/services/contract` - Type-safe contract read/write/simulate/getEvents - `/services/block-stream` - Stream blocks with reorg detection - `/services/transaction-stream` - Track transactions through lifecycle - `/services/cache` - Response caching layer - `/services/multicall` - Batch RPC calls via Multicall3 contract - `/services/rate-limiter` - RPC rate limiting - `/services/fee-estimator` - Gas fee estimation (EIP-1559) - `/services/nonce-manager` - Nonce management for concurrent sends - `/services/ccip` - Cross-chain interoperability (ERC-3668) - `/services/rpc-batch` - JSON-RPC request batching - `/services/raw-providers` - Low-level provider access - `/services/chain` - Chain configuration - `/services/abi-encoder` - ABI encoding utilities - `/services/formatter` - Data formatting utilities - `/services/transaction-serializer` - Transaction RLP serialization - `/services/kzg` - KZG commitment utilities (EIP-4844) - `/services/presets` - Pre-composed layer configurations ProviderService is a minimal, request-only Context.Tag that powers all provider free functions. ### Primitives Effect Schema wrappers for all Ethereum data types. Each primitive provides: - Decode from hex/bytes to branded type - Encode back to hex/bytes - Typed ParseError on invalid input - Pure functions for manipulation **Core types:** - `/primitives/address` - 20-byte Ethereum addresses with EIP-55 checksums - `/primitives/hash` - 32-byte hashes (transaction, block, state root) - `/primitives/hex` - Hex string encoding/decoding - `/primitives/bytes` - Raw byte arrays - `/primitives/bytes32` - Fixed 32-byte arrays - `/primitives/signature` - ECDSA signatures (r, s, v) - `/primitives/privatekey` - Private key handling - `/primitives/publickey` - Public key handling **Numeric types:** - `/primitives/uint` - Unsigned integers base - `/primitives/u256` - 256-bit unsigned integers - `/primitives/uint8` through `/primitives/uint256` - Fixed-size unsigned integers - `/primitives/int8` through `/primitives/int256` - Fixed-size signed integers **Block types:** - `/primitives/block` - Full block structure - `/primitives/blockheader` - Block header fields - `/primitives/blockbody` - Block body with transactions - `/primitives/blockhash` - Block hash - `/primitives/blocknumber` - Block number **Transaction types:** - `/primitives/transaction` - Transaction structure (Legacy, EIP-2930, EIP-1559, EIP-4844, EIP-7702) - `/primitives/transactionhash` - Transaction hash - `/primitives/receipt` - Transaction receipt with logs - `/primitives/nonce` - Transaction nonce - `/primitives/accesslist` - EIP-2930 access lists - `/primitives/authorization` - EIP-7702 authorization **Gas & Fees:** - `/primitives/gas` - Gas units - `/primitives/gasprice` - Gas price (legacy) - `/primitives/feemarket` - EIP-1559 fee market data - `/primitives/basefeepergas` - Base fee per gas - `/primitives/maxfeepergas` - Max fee per gas - `/primitives/maxpriorityfeepergas` - Max priority fee (tip) **ABI & Encoding:** - `/primitives/abi` - ABI definitions and parsing - `/primitives/selector` - 4-byte function selectors - `/primitives/calldata` - Encoded call data - `/primitives/rlp` - RLP encoding/decoding - `/primitives/ssz` - SSZ encoding (Beacon chain) **Events & Logs:** - `/primitives/eventlog` - Event log structure - `/primitives/logfilter` - Log filter parameters - `/primitives/topicfilter` - Topic filtering - `/primitives/bloomfilter` - Bloom filter for logs **Account Abstraction (ERC-4337):** - `/primitives/user-operation` - UserOperation structure - `/primitives/packeduseroperation` - Packed UserOperation (v0.7) - `/primitives/entrypoint` - EntryPoint contract - `/primitives/paymaster` - Paymaster data - `/primitives/bundler` - Bundler configuration **EIP-712 & Signing:** - `/primitives/typeddata` - Typed data structure - `/primitives/domain` - EIP-712 domain - `/primitives/domainseparator` - Domain separator hash - `/primitives/siwe` - Sign-In with Ethereum (EIP-4361) - `/primitives/permit` - ERC-2612 permit And 100+ more primitives covering all Ethereum data types. ### Cryptography Effect-wrapped crypto services with Live (production) and Test (mock) layers: **Hashing:** - `/crypto/keccak256` - Ethereum's primary hash (SHA3-256 variant) - `/crypto/sha256` - Standard SHA-256 - `/crypto/blake2` - Blake2b and Blake2s - `/crypto/ripemd160` - For Bitcoin-style addresses **Signatures:** - `/crypto/secp256k1` - Ethereum ECDSA signatures (sign, recover, verify) - `/crypto/ed25519` - EdDSA signatures - `/crypto/p256` - NIST P-256 / secp256r1 (WebAuthn) - `/crypto/bls12381` - BLS signatures (Beacon chain consensus) - `/crypto/signers` - High-level signing interface **Encryption:** - `/crypto/aesgcm` - AES-GCM symmetric encryption - `/crypto/chacha20poly1305` - Modern symmetric encryption - `/crypto/x25519` - ECDH key exchange **Key Derivation:** - `/crypto/hdwallet` - BIP-32/44 hierarchical deterministic keys - `/crypto/bip39` - Mnemonic phrase generation and validation - `/crypto/keystore` - Web3 Secret Storage format (encrypted keystores) - `/crypto/hmac` - Keyed-hash message authentication **Zero Knowledge:** - `/crypto/bn254` - BN254 curve for ZK proofs (ecAdd, ecMul, ecPairing) - `/crypto/kzg` - KZG commitments (EIP-4844 blob transactions) **Utilities:** - `/crypto/eip712` - Typed data hashing and signing - `/crypto/modexp` - Modular exponentiation (EVM precompile) **Combined layers:** - `CryptoLive` - All crypto services bundled for production - `CryptoTest` - Mock layer for deterministic unit testing ### Examples Complete working code examples: - `/examples/index` - Example overview and categories - `/examples/wallet-creation` - Generate and restore HD wallets from mnemonic - `/examples/read-blockchain` - Query blocks, balances, transactions, logs - `/examples/send-transactions` - Sign and broadcast transactions - `/examples/contract-interactions` - Type-safe contract read/write/simulate - `/examples/event-streaming` - Backfill and watch contract events - `/examples/block-streaming` - Stream blocks with reorg detection - `/examples/multicall` - Batch multiple contract calls - `/examples/layer-presets` - Pre-composed layer configurations - `/examples/error-handling` - Retry, timeout, fallback, custom errors - `/examples/schema-validation` - Parse and validate Ethereum data - `/examples/testing` - Mock services for unit tests ### ERC Standards - `/standards` - ERC-20, ERC-721, ERC-1155, ERC-165 utilities with typed encoding/decoding ## Error Types All errors have a `_tag` field for discrimination: | Error | Tag | Source | |-------|-----|--------| | ParseError | `ParseError` | Schema decode failures | | ProviderResponseError | `ProviderResponseError` | Invalid provider response | | ProviderNotFoundError | `ProviderNotFoundError` | Missing block/tx/receipt | | ProviderValidationError | `ProviderValidationError` | Invalid provider inputs | | ProviderTimeoutError | `ProviderTimeoutError` | Provider timeouts | | ProviderStreamError | `ProviderStreamError` | Provider stream failures | | ProviderReceiptPendingError | `ProviderReceiptPendingError` | Receipt not available yet | | ProviderConfirmationsPendingError | `ProviderConfirmationsPendingError` | Confirmations not met | | SignerError | `SignerError` | Transaction signing failures | | TransportError | `TransportError` | Network/HTTP failures | | ContractCallError | `ContractCallError` | Contract read failures | | ContractWriteError | `ContractWriteError` | Contract write failures | | BlockStreamError | `BlockStreamError` | Block streaming failures | | TransactionStreamError | `TransactionStreamError` | Transaction streaming failures | | CryptoError | `CryptoError` | Cryptographic operation failures | | InvalidPrivateKeyError | `InvalidPrivateKeyError` | Invalid private key | | InvalidSignatureError | `InvalidSignatureError` | Invalid signature | | StandardsError | `StandardsError` | ERC standard encoding/decoding failures | ## Key Features ### Typed Errors in Type Signature All errors are values in the type signature, not invisible exceptions: ```typescript Effect.Effect // Success Error types Requirements ``` ### Composable Operations Chain operations with built-in retry, timeout, and fallback: ```typescript program.pipe( Effect.retry(Schedule.exponential('100 millis').pipe(Schedule.recurs(5))), Effect.timeout(Duration.seconds(10)), Effect.orElse(() => fallbackProgram) ) ``` ### Effect Streams Real-time block and event streaming with backpressure: ```typescript yield* Stream.runForEach( blockStream.watch({ include: 'transactions' }), (event) => Effect.log(`Block ${event.blocks[0]?.header.number}`) ) ``` ### Transaction Type Detection The signer automatically detects transaction type based on fields: - Type 0 (Legacy): `gasPrice` only - Type 1 (EIP-2930): `gasPrice` + `accessList` - Type 2 (EIP-1559): `maxFeePerGas` + `maxPriorityFeePerGas` - Type 3 (EIP-4844): `blobVersionedHashes` + `maxFeePerBlobGas` - Type 4 (EIP-7702): `authorizationList` ## Bundle Size - Effect runtime: ~15KB gzipped - Voltaire primitives: Tree-shakeable, 5-50KB depending on usage - Crypto: Individual modules for tree-shaking ## When to Use voltaire-effect **Use voltaire-effect when:** - You want typed errors in the type signature - Building complex workflows with retry/timeout/fallback - Need testable service dependencies without mocking frameworks - Already using Effect.ts in your application - Want composable operations that short-circuit on failure **Use base Voltaire when:** - Bundle size is critical - Simple one-off scripts - You prefer exceptions over typed errors ## Test Examples (Ghost Docs) 170 test examples are available as LLM context at `/docs/ghosts/tests/typescript/tests/voltaire-effect/`. These cover: **Primitives:** Address, Abi, Bytes, Hash, Hex, Rlp, Signature, Transaction, TypedData, Uint, and 50+ more **Crypto:** Keccak256, Secp256k1, Bls12381, Ed25519, P256, HDWallet, Keystore, EIP712, AesGcm, ChaCha20Poly1305, Bip39, KZG, Bn254 **Services:** Provider, Signer, Contract, Transport, BlockStream, TransactionStream, Multicall, Cache, FeeEstimator, NonceManager **Standards:** ERC20, ERC721, ERC1155, ERC165 Each test file shows correct imports (`voltaire-effect/primitives/Address` not `./index.js`) and one-sentence descriptions. ## Related Projects - [Voltaire](https://voltaire.tevm.sh) - Core Ethereum primitives and crypto - [Effect](https://effect.website) - TypeScript library for typed errors and services - [Effect Schema](https://effect.website/docs/schema/introduction/) - Validation and parsing - [Effect Services](https://effect.website/docs/requirements-management/services/) - Dependency injection - [GitHub](https://github.com/evmts/voltaire) - Source code and issues ## Common Import Patterns ```typescript // Effect core import { Effect, Layer, Stream, Schedule, Duration } from 'effect' import * as S from 'effect/Schema' // Primitives (namespace imports) import * as Address from 'voltaire-effect/primitives/Address' import * as Hex from 'voltaire-effect/primitives/Hex' import * as Uint from 'voltaire-effect/primitives/Uint' // Services import { ProviderService, Provider, DebugService, Debug, EngineApiService, EngineApi, SignerService, Signer, Contract, HttpTransport, WebSocketTransport, BrowserTransport, LocalAccount, JsonRpcAccount } from 'voltaire-effect' import { MnemonicAccount } from 'voltaire-effect/native' // Crypto import { KeccakService, KeccakLive, Secp256k1Service, Secp256k1Live, CryptoLive, CryptoTest } from 'voltaire-effect/crypto' // Standards import * as ERC20 from 'voltaire-effect/standards/ERC20' import * as ERC721 from 'voltaire-effect/standards/ERC721' ```