Enclave SDK

Enclave SDK Overview

The Enclave SDK (@enclave-e3/sdk) and React helpers (@enclave-e3/react) provide a batteries-included client stack for requesting E3 computations, subscribing to protocol events, and coordinating custom frontends or backend services. Both packages ship in this repository (see packages/enclave-sdk and packages/enclave-react).

Installation

pnpm add @enclave-e3/sdk           # TypeScript SDK
pnpm add @enclave-e3/react         # React hooks (optional)

For browser projects using WASM (encryption helpers, FHE keygen), configure Vite per the SDK README:

// vite.config.ts
import wasm from 'vite-plugin-wasm'
import topLevelAwait from 'vite-plugin-top-level-await'
 
export default defineConfig({
  optimizeDeps: {
    exclude: ['@enclave-e3/wasm'],
  },
  plugins: [wasm(), topLevelAwait()],
})

Core client

import { EnclaveSDK, EnclaveEventType, RegistryEventType } from '@enclave-e3/sdk'
import { createPublicClient, createWalletClient, http, custom } from 'viem'
 
const publicClient = createPublicClient({ transport: http(import.meta.env.VITE_RPC_URL) })
const walletClient = createWalletClient({ transport: custom(window.ethereum) })
 
const sdk = new EnclaveSDK({
  publicClient,
  walletClient,
  contracts: {
    enclave: import.meta.env.VITE_ENCLAVE_ADDRESS,
    ciphernodeRegistry: import.meta.env.VITE_REGISTRY_ADDRESS,
  },
  chainId: 11155111,
})
 
await sdk.initialize()

Requesting computations

const hash = await sdk.requestE3({
  threshold: [2, 3],
  startWindow: [BigInt(Date.now()), BigInt(Date.now() + 5 * 60 * 1000)],
  duration: BigInt(1800),
  e3Program: '0x...',
  e3ProgramParams: '0x',
  computeProviderParams: '0x',
  customParams: '0x',
})

Event subscriptions

const e3Handler = (event) => {
  console.log('New request', event.data)
}
 
sdk.onEnclaveEvent(EnclaveEventType.E3_REQUESTED, e3Handler)
 
sdk.onEnclaveEvent(RegistryEventType.COMMITTEE_REQUESTED, (event) => {
  console.log('Committee requested', event.data)
})
 
// Later, remember to clean up
sdk.off(EnclaveEventType.E3_REQUESTED, e3Handler)

React hook

import { useEnclaveSDK } from '@enclave-e3/react'
 
export function Dashboard() {
  const { isInitialized, requestE3, onEnclaveEvent, EnclaveEventType } = useEnclaveSDK({
    autoConnect: true,
    contracts: {
      enclave: import.meta.env.VITE_ENCLAVE_ADDRESS,
      ciphernodeRegistry: import.meta.env.VITE_REGISTRY_ADDRESS,
    },
    chainId: 31337,
  })
 
  useEffect(() => {
    if (!isInitialized) return
    const handle = (event) => console.log('Activated', event.data)
    onEnclaveEvent(EnclaveEventType.E3_ACTIVATED, handle)
    return () => off(EnclaveEventType.E3_ACTIVATED, handle)
  }, [isInitialized])
 
  return <button onClick={() => requestE3(/* params */)}>Request E3</button>
}

Configuration contract map

Provide both the Enclave and CiphernodeRegistry addresses. The template exposes these via .env / enclave.config.yaml. For multi-chain apps, instantiate multiple SDKs or call sdk.updateConfig({ contracts: { ... }, chainId }) whenever wallets switch networks.

Working with the template

enclave init generates the default template (see Project Template). The client already wires @enclave-e3/sdk and @enclave-e3/react:

  • client/src/sdk.ts builds the shared SDK instance
  • client/src/hooks/useE3.ts uses useEnclaveSDK to expose helper hooks throughout the UI
  • server/src/services/enclave.ts instantiates the SDK with a server wallet using createWalletClient

When you add new contracts or E3 programs, update client/.env and server/.env with the new addresses, then restart the dev server so the SDK reconnects.

Application-specific SDKs

For complex E3 programs with specialized requirements, you may want to build an application-specific SDK on top of or alongside the Enclave SDK. For example, CRISP (opens in a new tab) uses @crisp-e3/sdk, which provides:

  • Zero-knowledge proof generation for votes using Noir circuits
  • Merkle tree utilities for voter eligibility verification
  • Vote encryption helpers using FHE
  • Round management and token operations
  • CRISP server interaction APIs

If your E3 program requires specialized cryptographic operations, domain-specific logic, or application-level abstractions beyond basic protocol interactions, consider building a dedicated SDK that wraps or complements the core Enclave SDK.

Advanced usage

  • Historical events: sdk.getHistoricalEvents(type, fromBlock, toBlock) fetches logs without a WebSocket provider; useful for CRON jobs or health checks.
  • Gas controls: pass gasLimit to requestE3, activateE3, or publishInput if you want fixed limits when interacting with Enclave on L2s.
  • Event polling: sdk.startEventPolling() is handy in serverless environments where websockets are unavailable.
  • Custom transports: on the server, call createWalletClient({ account, transport: http(rpc) }) and load the private key from Vaults/KMS.

Troubleshooting

SymptomTriage
MISSING_PUBLIC_CLIENT errorsEnsure createPublicClient uses an HTTP or WebSocket RPC reachable from the app.
INVALID_ADDRESSDouble-check contract addresses passed into the SDK match the current chain.
Hooks never initializeConfirm autoConnect is true, wallet is connected, and React component is inside a provider that renders on the client.
No events arriveSwitch to a WebSocket RPC or call sdk.startEventPolling() so logs are polled over HTTP.

For additional API surface details see packages/enclave-sdk/README.md inside this repo.