diff --git a/docs/pages/sdk.mdx b/docs/pages/sdk.mdx index 1360b60643..61a321ac50 100644 --- a/docs/pages/sdk.mdx +++ b/docs/pages/sdk.mdx @@ -128,7 +128,17 @@ sdk.off(EnclaveEventType.E3_REQUESTED, e3Handler) import { useEnclaveSDK } from '@enclave-e3/react' export function Dashboard() { - const { isInitialized, requestE3, onEnclaveEvent, off, EnclaveEventType } = useEnclaveSDK({ + const { + sdk, + isInitialized, + error, + requestE3, + getThresholdBfvParamsSet, + onEnclaveEvent, + off, + EnclaveEventType, + RegistryEventType, + } = useEnclaveSDK({ autoConnect: true, contracts: { enclave: import.meta.env.VITE_ENCLAVE_ADDRESS, @@ -145,6 +155,8 @@ export function Dashboard() { return () => off(EnclaveEventType.E3_REQUESTED, handle) }, [isInitialized]) + if (error) return
Error: {error}
+ return } ``` @@ -168,8 +180,8 @@ const { encryptedData: vecData, proof: vecProof } = await sdk.encryptVectorAndGe publicKey, ) -// Generate public inputs without proof (useful for debugging) -const { encryptedData, publicInputs } = await sdk.encryptNumberAndGenInputs(42n, publicKey) +// Generate circuit inputs without proof (useful for debugging) +const { encryptedData, circuitInputs } = await sdk.encryptNumberAndGenInputs(42n, publicKey) // Standalone import (pass preset name explicitly) import { generatePublicKey, encryptNumber } from '@enclave-e3/sdk' @@ -180,17 +192,18 @@ const ct = await encryptNumber(42n, pk, 'INSECURE_THRESHOLD_512') ### Full encryption method reference -| Method | Description | -| ---------------------------------- | ---------------------------------------------------- | -| `generatePublicKey()` | Generate a BFV public key | -| `computePublicKeyCommitment(pk)` | Compute a commitment for a public key | -| `encryptNumber(n, pk)` | Encrypt a single bigint | -| `encryptVector(vec, pk)` | Encrypt a `BigUint64Array` | -| `encryptNumberAndGenInputs(n, pk)` | Encrypt and return public inputs for ZK verification | -| `encryptNumberAndGenProof(n, pk)` | Encrypt and generate a ZK proof of valid encryption | -| `encryptVectorAndGenInputs(v, pk)` | Vector version of `encryptNumberAndGenInputs` | -| `encryptVectorAndGenProof(v, pk)` | Vector version of `encryptNumberAndGenProof` | -| `getThresholdBfvParamsSet()` | Get the parameter set for the configured preset | +| Method | Description | +| ---------------------------------- | ----------------------------------------------------- | +| `generatePublicKey()` | Generate a BFV public key | +| `computePublicKeyCommitment(pk)` | Compute a commitment for a public key | +| `encryptNumber(n, pk)` | Encrypt a single bigint | +| `encryptVector(vec, pk)` | Encrypt a `BigUint64Array` | +| `encryptNumberAndGenInputs(n, pk)` | Encrypt and return circuit inputs for ZK verification | +| `encryptNumberAndGenProof(n, pk)` | Encrypt and generate a ZK proof of valid encryption | +| `encryptVectorAndGenInputs(v, pk)` | Vector version of `encryptNumberAndGenInputs` | +| `encryptVectorAndGenProof(v, pk)` | Vector version of `encryptNumberAndGenProof` | +| `getThresholdBfvParamsSet()` | Get the parameter set for the configured preset | +| `generateProof(circuitInputs)` | Generate a ZK proof from circuit inputs directly | ## Modular submodule imports @@ -205,6 +218,100 @@ import { EventListener, EnclaveEventType } from '@enclave-e3/sdk/events' All exports are also available from the main `@enclave-e3/sdk` entry point. +## Event types + +The SDK provides two event type enums for subscribing to on-chain events: + +### `EnclaveEventType` + +| Enum Key | Solidity Event Name | +| -------------------------------- | ---------------------------- | +| `E3_REQUESTED` | `E3Requested` | +| `CIPHERTEXT_OUTPUT_PUBLISHED` | `CiphertextOutputPublished` | +| `PLAINTEXT_OUTPUT_PUBLISHED` | `PlaintextOutputPublished` | +| `E3_PROGRAM_ENABLED` | `E3ProgramEnabled` | +| `E3_PROGRAM_DISABLED` | `E3ProgramDisabled` | +| `ENCRYPTION_SCHEME_ENABLED` | `EncryptionSchemeEnabled` | +| `ENCRYPTION_SCHEME_DISABLED` | `EncryptionSchemeDisabled` | +| `CIPHERNODE_REGISTRY_SET` | `CiphernodeRegistrySet` | +| `MAX_DURATION_SET` | `MaxDurationSet` | +| `ALLOWED_E3_PROGRAMS_PARAMS_SET` | `AllowedE3ProgramsParamsSet` | +| `OWNERSHIP_TRANSFERRED` | `OwnershipTransferred` | +| `INITIALIZED` | `Initialized` | + +### `RegistryEventType` + +| Enum Key | Solidity Event Name | +| ----------------------- | ---------------------- | +| `COMMITTEE_REQUESTED` | `CommitteeRequested` | +| `COMMITTEE_PUBLISHED` | `CommitteePublished` | +| `COMMITTEE_FINALIZED` | `CommitteeFinalized` | +| `ENCLAVE_SET` | `EnclaveSet` | +| `OWNERSHIP_TRANSFERRED` | `OwnershipTransferred` | +| `INITIALIZED` | `Initialized` | + +## E3 lifecycle enums + +### `E3Stage` + +| Value | Stage | +| ----- | -------------------- | +| 0 | `None` | +| 1 | `Requested` | +| 2 | `CommitteeFinalized` | +| 3 | `KeyPublished` | +| 4 | `CiphertextReady` | +| 5 | `Complete` | +| 6 | `Failed` | + +### `FailureReason` + +| Value | Reason | +| ----- | ------------------------------ | +| 0 | `None` | +| 1 | `CommitteeFormationTimeout` | +| 2 | `InsufficientCommitteeMembers` | +| 3 | `DKGTimeout` | +| 4 | `DKGInvalidShares` | +| 5 | `NoInputsReceived` | +| 6 | `ComputeTimeout` | +| 7 | `ComputeProviderExpired` | +| 8 | `ComputeProviderFailed` | +| 9 | `RequesterCancelled` | +| 10 | `DecryptionTimeout` | +| 11 | `DecryptionInvalidShares` | +| 12 | `VerificationFailed` | + +## Utility exports + +The SDK also exports several utility functions and constants from the main entry point: + +```ts +import { + SDKError, + encodeBfvParams, + encodeComputeProviderParams, + encodeCustomParams, + calculateInputWindow, + decodePlaintextOutput, + getCurrentTimestamp, + DEFAULT_COMPUTE_PROVIDER_PARAMS, + DEFAULT_E3_CONFIG, +} from '@enclave-e3/sdk' +``` + +| Export | Description | +| --------------------------------- | ----------------------------------------------------------------- | +| `SDKError` | Custom error class with an error `code` property | +| `encodeBfvParams(params)` | ABI-encode BFV parameters for smart contract calls | +| `encodeComputeProviderParams` | Encode compute provider params (supports mock mode) | +| `encodeCustomParams(params)` | Encode arbitrary custom parameters as hex | +| `calculateInputWindow` | Compute an input window `[start, end]` from current on-chain time | +| `decodePlaintextOutput(hex)` | Decode a plaintext output hex string to a number | +| `getCurrentTimestamp(client)` | Fetch the current block timestamp from the chain | +| `DEFAULT_COMPUTE_PROVIDER_PARAMS` | Default compute provider configuration object | +| `DEFAULT_E3_CONFIG` | Default E3 config (threshold, duration, payment) | + ## Configuration contract map Provide the Interfold, CiphernodeRegistry, and FeeToken addresses. The template exposes these via @@ -244,11 +351,17 @@ that wraps or complements the core Interfold SDK. - **Historical events**: `sdk.getHistoricalEvents(type, fromBlock, toBlock)` fetches logs without a WebSocket provider; useful for CRON jobs or health checks. +- **Publish ciphertext output**: + `sdk.publishCiphertextOutput(e3Id, ciphertextOutput, proof, gasLimit?)` submits the computed + ciphertext output for an E3. - **Gas controls**: pass `gasLimit` to `requestE3`, `publishCiphertextOutput`, or other write methods if you want fixed limits when interacting with Interfold on L2s. - **Gas estimation**: `sdk.estimateGas(functionName, args, contractAddress, abi)` returns the estimated gas for a contract call before sending. -- **Transaction confirmation**: `sdk.waitForTransaction(hash)` blocks until a transaction is mined. +- **Transaction confirmation**: `sdk.waitForTransaction(hash)` blocks until a transaction is mined + and returns the `TransactionReceipt`. +- **One-shot events**: `sdk.once(eventType, callback)` listens for an event and automatically + unsubscribes after the first occurrence. - **Event polling**: `sdk.startEventPolling()` / `sdk.stopEventPolling()` are handy in serverless environments where websockets are unavailable. - **Custom transports**: on the server, call `createWalletClient({ account, transport: http(rpc) })` @@ -258,9 +371,11 @@ that wraps or complements the core Interfold SDK. - **Fee token approval**: call `sdk.approveFeeToken(amount)` before `requestE3` to approve the fee token spend. - **Query E3 data**: use `sdk.getE3(e3Id)` to read the full E3 struct, `sdk.getE3Stage(e3Id)` for - the current lifecycle stage, and `sdk.getFailureReason(e3Id)` if the E3 has failed. + the current lifecycle stage (returns `E3Stage` enum), and `sdk.getFailureReason(e3Id)` if the E3 + has failed (returns `FailureReason` enum). - **Public key retrieval**: `sdk.getE3PublicKey(e3Id)` returns the committee's aggregated public key for a given E3. +- **Access the public client**: `sdk.getPublicClient()` returns the underlying viem `PublicClient`. - **Cleanup**: call `sdk.cleanup()` when shutting down to unsubscribe all event listeners and stop polling. diff --git a/packages/enclave-contracts/scripts/utils.ts b/packages/enclave-contracts/scripts/utils.ts index e4f527aef1..bd1eeaf2b5 100644 --- a/packages/enclave-contracts/scripts/utils.ts +++ b/packages/enclave-contracts/scripts/utils.ts @@ -236,7 +236,11 @@ export const updateE3Config = ( } // If we hit a top-level key while in the target chain, we've left it - if (inTargetChain && indent <= chainBaseIndent && !trimmed.startsWith("-")) { + if ( + inTargetChain && + indent <= chainBaseIndent && + !trimmed.startsWith("-") + ) { break; } @@ -261,7 +265,10 @@ export const updateE3Config = ( // Detect contract key line (e.g., ` enclave:`) const keyMatch = trimmed.match(/^(\w+):$/); - if (keyMatch && (contractEntryIndent === -1 || indent === contractEntryIndent)) { + if ( + keyMatch && + (contractEntryIndent === -1 || indent === contractEntryIndent) + ) { currentContractKey = keyMatch[1]; if (contractEntryIndent === -1) contractEntryIndent = indent; continue; @@ -276,8 +283,11 @@ export const updateE3Config = ( if (trimmed.startsWith("address:")) { foundKeys.add(currentContractKey); const ws = line.match(/^(\s*)/)?.[1] ?? ""; - const comment = trimmed.match(/^address:\s*["']?[^#"']*["']?\s*(#.*)$/)?.[1]; - lines[i] = `${ws}address: "${update.address}"${comment ? " " + comment : ""}`; + const comment = trimmed.match( + /^address:\s*["']?[^#"']*["']?\s*(#.*)$/, + )?.[1]; + lines[i] = + `${ws}address: "${update.address}"${comment ? " " + comment : ""}`; console.log( `✓ Updated ${currentContractKey}: ${update.address} (block ${update.deployBlock})`, ); @@ -286,7 +296,8 @@ export const updateE3Config = ( if (trimmed.startsWith("deploy_block:")) { const ws = line.match(/^(\s*)/)?.[1] ?? ""; const comment = trimmed.match(/^deploy_block:\s*\S+\s*(#.*)$/)?.[1]; - lines[i] = `${ws}deploy_block: ${update.deployBlock}${comment ? " " + comment : ""}`; + lines[i] = + `${ws}deploy_block: ${update.deployBlock}${comment ? " " + comment : ""}`; } } @@ -333,7 +344,9 @@ export const updateE3Config = ( const missingKeys = [...updates.keys()].filter((k) => !foundKeys.has(k)); if (missingKeys.length > 0 && lastContractsLine !== -1) { const keyIndent = - contractEntryIndent !== -1 ? contractEntryIndent : contractsKeyIndent + 2; + contractEntryIndent !== -1 + ? contractEntryIndent + : contractsKeyIndent + 2; const valIndent = keyIndent + 2; const newLines: string[] = []; @@ -341,7 +354,9 @@ export const updateE3Config = ( const update = updates.get(configKey)!; newLines.push(`${" ".repeat(keyIndent)}${configKey}:`); newLines.push(`${" ".repeat(valIndent)}address: "${update.address}"`); - newLines.push(`${" ".repeat(valIndent)}deploy_block: ${update.deployBlock}`); + newLines.push( + `${" ".repeat(valIndent)}deploy_block: ${update.deployBlock}`, + ); console.log( `✓ Added ${configKey}: ${update.address} (block ${update.deployBlock})`, );