Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 131 additions & 16 deletions docs/pages/sdk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -145,6 +155,8 @@ export function Dashboard() {
return () => off(EnclaveEventType.E3_REQUESTED, handle)
}, [isInitialized])

if (error) return <div>Error: {error}</div>

return <button onClick={() => requestE3(/* params */)}>Request E3</button>
}
```
Expand All @@ -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'
Expand All @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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) })`
Expand All @@ -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.

Expand Down
29 changes: 22 additions & 7 deletions packages/enclave-contracts/scripts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
Expand All @@ -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})`,
);
Expand All @@ -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 : ""}`;
}
}

Expand Down Expand Up @@ -333,15 +344,19 @@ 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[] = [];
for (const configKey of missingKeys) {
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})`,
);
Expand Down
Loading