Agent Skill
2/7/2026

voltaire-effect-services

This skill should be used when the user asks about "ProviderService", "SignerService", "TransportService", "HttpTransport", "WebSocketTransport", "JSON-RPC Effect", "getBalance", "getBlock", "getBlockNumber", "sendTransaction", "voltaire-effect provider", "Layer.provide", or needs to understand the voltaire-effect service system.

C
cyotee
0GitHub Stars
1Views
npx skills add cyotee/voltaire-skill

SKILL.md

Namevoltaire-effect-services
DescriptionThis skill should be used when the user asks about "ProviderService", "SignerService", "TransportService", "HttpTransport", "WebSocketTransport", "JSON-RPC Effect", "getBalance", "getBlock", "getBlockNumber", "sendTransaction", "voltaire-effect provider", "Layer.provide", or needs to understand the voltaire-effect service system.

name: Voltaire Effect Services description: This skill should be used when the user asks about "ProviderService", "SignerService", "TransportService", "HttpTransport", "WebSocketTransport", "JSON-RPC Effect", "getBalance", "getBlock", "getBlockNumber", "sendTransaction", "voltaire-effect provider", "Layer.provide", or needs to understand the voltaire-effect service system. version: 0.1.0

Voltaire Effect Services

Overview

Services in voltaire-effect are typed dependencies declared in Effect signatures and injected via layers at program boundaries. This eliminates hidden globals and enables seamless test substitution.

┌─────────────────────────────────────────────────────────────────────────────┐
│                        SERVICE ARCHITECTURE                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Application Code                                                           │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  const bal = yield* getBalance(addr)                                  │  │
│  │  // Type: Effect<bigint, GetBalanceError, ProviderService>           │  │
│  └────────────────────────────────┬──────────────────────────────────────┘  │
│                                   │                                          │
│                      Effect.provide(layers)                                 │
│                                   │                                          │
│  Service Implementations          ▼                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                     │
│  │  Provider     │  │  Signer      │  │  Transport   │                     │
│  │  ─────────    │  │  ─────────   │  │  ──────────  │                     │
│  │  getBalance   │  │  sign        │  │  HTTP        │                     │
│  │  getBlock     │  │  signMessage │  │  WebSocket   │                     │
│  │  call         │  │  signTyped   │  │  Browser     │                     │
│  │  getLogs      │  │  sendTx      │  │  Test        │                     │
│  └──────────────┘  └──────────────┘  └──────────────┘                     │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Provider Service

The primary service for reading blockchain state via JSON-RPC:

Free Functions (Preferred)

Use free functions instead of yielding ProviderService directly:

import { getBlockNumber, getBalance, getBlock, getLogs } from 'voltaire-effect'

const program = Effect.gen(function* () {
  const blockNum = yield* getBlockNumber()
  const balance = yield* getBalance(addr)
  const block = yield* getBlock({ blockNumber: blockNum })
  const logs = yield* getLogs({ fromBlock: 0n, toBlock: 'latest' })
  return { blockNum, balance, block, logs }
})

Provider Operations

CategoryFunctions
BlocksgetBlockNumber, getBlock, getBlockReceipts, getUncleCount
AccountsgetBalance, getTransactionCount, getCode, getStorageAt
TransactionsgetTransaction, getTransactionReceipt, waitForTransactionReceipt
SimulationreadContract, multicall, simulateContract, simulateV1, simulateV2
GasgetGasPrice, getMaxPriorityFeePerGas, getFeeHistory
EventsgetLogs
StreamingwatchBlocks, subscribe, unsubscribe

Layer Setup

import { Provider, HttpTransport } from 'voltaire-effect'

const ProviderLayer = Provider.pipe(
  Layer.provide(HttpTransport('https://eth.llamarpc.com'))
)

Transport Service

Manages the network connection. Three production transports and one test transport:

HttpTransport

import { HttpTransport } from 'voltaire-effect'

HttpTransport('https://eth.llamarpc.com')

// With options
HttpTransport({
  url: 'https://eth.llamarpc.com',
  timeout: '30 seconds',
  headers: { 'Authorization': 'Bearer ...' },
  retrySchedule: Schedule.exponential('500 millis').pipe(
    Schedule.jittered,
    Schedule.compose(Schedule.recurs(5))
  )
})

HTTP transport supports automatic request batching - concurrent requests are batched into a single HTTP call.

WebSocketTransport

import { WebSocketTransport } from 'voltaire-effect'
WebSocketTransport('wss://eth.llamarpc.com')

BrowserTransport

import { BrowserTransport } from 'voltaire-effect'
BrowserTransport()  // Uses window.ethereum

TestTransport

import { TestTransport } from 'voltaire-effect'

TestTransport({
  eth_blockNumber: '0x10',
  eth_getBalance: '0xde0b6b3a7640000'
})

Signer Service

For state-changing operations. Unlike Provider, Signer still requires direct yielding:

import { Signer } from 'voltaire-effect'

const program = Effect.gen(function* () {
  const signer = yield* Signer
  const txHash = yield* signer.sendTransaction({
    to: recipient,
    value: 1000000000000000000n
  })
  return txHash
})

Signer from Provider

Create a Signer from an existing Provider and Account:

const SignerLayer = Signer.fromProvider
// Requires ProviderService + AccountService

Layer Composition

Independent Services

const AppLayer = Layer.mergeAll(TransportLayer, CryptoLayer)

Dependent Services

// Provider depends on Transport
const ProviderLayer = Provider.pipe(
  Layer.provide(HttpTransport('https://eth.llamarpc.com'))
)

Full Stack

import { Secp256k1Live } from 'voltaire-effect/crypto/Secp256k1'
import { KeccakLive } from 'voltaire-effect/crypto/Keccak256'

const FullLayer = Layer.mergeAll(
  ProviderLayer,
  Secp256k1Live,
  KeccakLive,
  SignerLayer
)

await Effect.runPromise(program.pipe(Effect.provide(FullLayer)))

Per-Request Configuration

Override settings for individual calls using FiberRef helpers:

import { withTimeout, withRetrySchedule, withoutCache, withTracing } from 'voltaire-effect'

// Timeout
const fast = yield* getBalance(addr).pipe(withTimeout("5 seconds"))

// Custom retry
const resilient = yield* getBalance(addr).pipe(
  withRetrySchedule(Schedule.recurs(1))
)

// Bypass cache
const fresh = yield* getBlockNumber().pipe(withoutCache)

// Debug tracing
const traced = yield* getBlock(n).pipe(withTracing())

Multicall Batching

Reduce network overhead by batching contract reads:

import { multicall } from 'voltaire-effect'

const results = yield* multicall({
  contracts: [
    { address: usdc, abi: erc20Abi, functionName: 'balanceOf', args: [user] },
    { address: dai, abi: erc20Abi, functionName: 'balanceOf', args: [user] },
    { address: weth, abi: erc20Abi, functionName: 'balanceOf', args: [user] },
  ],
  allowFailure: true  // Returns Either[] instead of throwing
})

Reference Files

For detailed service method signatures, see:

Reference

Skills Info
Original Name:voltaire-effect-servicesAuthor:cyotee