@elpaypes/handles
v0.2.1
Published
SDK for managing confidential handles - encryption, decryption and ACL management for iExec confidential computing
Maintainers
Readme
@iexec/handles
SDK for managing confidential handles — encryption, decryption, and ACL management for iExec confidential computing.
Installation
npm install @iexec/handles
# or
yarn add @iexec/handlesQuick Start
import { Handles } from "@iexec/handles";
// Initialize with your gateway
const handles = new Handles({
gatewayUrl: "https://your-gateway.example.com",
provider: window.ethereum,
});
// Create an encrypted handle
const { handle, inputProof } = await handles.create(100n, "uint256", 1);
// View decrypted value (requires wallet signature)
const { value } = await handles.view(handle);API Reference
new Handles(config)
| Parameter | Type | Required | Description |
| ------------ | ----------------- | -------- | ------------------------------ |
| gatewayUrl | string | ✅ | Gateway endpoint URL |
| provider | EIP1193Provider | ❌ | Wallet provider (for view()) |
handles.create(value, type, chainId, owner?)
Encrypt a value and get a handle + proof.
| Parameter | Type | Description |
| --------- | ----------------------------- | ------------------------------------------------------------------ |
| value | bigint \| string \| boolean | Value to encrypt |
| type | HandleType | Solidity type (uint256, bool, address, etc.) |
| chainId | number | Target chain ID (embedded in the handle for on-chain verification) |
| owner | string | Owner address (optional if provider is set) |
Returns: { handle: string, inputProof: string }
handles.view(handle)
Decrypt a handle's value. Requires a wallet provider to sign an EIP-712 message proving ownership.
Returns: { value: string }
Building a Compatible Gateway
This SDK is gateway-agnostic. To build a compatible gateway, implement these endpoints:
POST /v1/handles
Create an encrypted handle.
Request:
{
"value": "100",
"type": "uint256",
"chainId": 1,
"owner": "0x1234567890123456789012345678901234567890"
}Response:
{
"handle": "0xabc123...",
"inputProof": "0x01abc123...signature"
}POST /v1/handles/:handle/view
Decrypt a handle with signature verification.
Request:
{
"signature": "0x...",
"expiresAt": "1735060000",
"salt": "0x..."
}Response:
{
"value": "100"
}EIP-712 Signature Contracts
ViewRequest Signature
The SDK signs view requests using EIP-712. Your gateway must verify this signature to authorize decryption.
Domain: (chainId is extracted from the handle)
{
"name": "iExec Handles",
"version": "1",
"chainId": "<extracted from handle bytes 22-29>"
}Types:
{
"ViewRequest": [
{ "name": "action", "type": "string" },
{ "name": "handle", "type": "bytes32" },
{ "name": "expiresAt", "type": "string" },
{ "name": "salt", "type": "bytes32" }
]
}Message:
{
"action": "ViewRequest",
"handle": "0x...",
"expiresAt": "1735060000",
"salt": "0x..."
}InputProof Format (Gateway → SDK)
Binary format that can be verified on-chain:
┌──────────────┬─────────────────────────┬──────────────────┐
│ numHandles │ handles[] │ signature │
│ (1 byte) │ (32 bytes × n) │ (65 bytes) │
└──────────────┴─────────────────────────┴──────────────────┘EIP-712 Domain for InputProof:
{
"name": "TEEComputeManager",
"version": "1",
"chainId": 1,
"verifyingContract": "0x0000000000000000000000000000000000000001"
}Types:
{
"CiphertextVerification": [
{ "name": "ctHandles", "type": "bytes32[]" },
{ "name": "userAddress", "type": "address" },
{ "name": "contractAddress", "type": "address" },
{ "name": "contractChainId", "type": "uint256" }
]
}Handle Structure
A handle is a 32-byte identifier encoding metadata:
[0-21] Hash (22 bytes) - Unique ciphertext identifier
[22-29] Chain ID (8 bytes) - Target blockchain
[30] Type (1 byte) - Value type (0=bool, 1=uint8, ...)
[31] Version (1 byte) - Protocol versionParse Handle Utilities
import {
parseHandle,
getChainIdFromHandle,
getTypeFromHandle,
getVersionFromHandle,
} from "@iexec/handles";
// Parse full handle
const { hash, chainId, type, version } = parseHandle(handle);
// Extract individual fields
const chainId = getChainIdFromHandle(handle);
const type = getTypeFromHandle(handle);
const version = getVersionFromHandle(handle);InputProof Verification
import {
parseInputProof,
verifyInputProof,
isHandleInProof,
} from "@iexec/handles";
// Parse binary proof
const { numHandles, handles, signature } = parseInputProof(inputProof);
// Check if a handle is in the proof
const found = isHandleInProof(myHandle, inputProof);
// Verify signature (for gateway trust verification)
const isValid = await verifyInputProof({
inputProof,
userAddress: "0x...",
expectedSigner: "0x...",
});Supported Types
All Solidity types are supported:
booluint8touint256(steps of 8)int8toint256(steps of 8)addressbytes1tobytes32string,bytes
Error Handling
import { HandlesError, GatewayError } from "@iexec/handles";
try {
await handles.create(100n, "uint256");
} catch (error) {
if (error instanceof GatewayError) {
console.log("Gateway error:", error.statusCode, error.code, error.message);
} else if (error instanceof HandlesError) {
console.log("SDK error:", error.code, error.message);
}
}| Error Code | Description |
| ------------------ | --------------------------------- |
| INVALID_CONFIG | Missing or invalid configuration |
| INVALID_CHAIN_ID | chainId must be a positive number |
| NO_OWNER | Owner required but not provided |
| NO_PROVIDER | Provider required for view() |
| NO_SIGNER | Could not get signer address |
| GATEWAY_ERROR | Generic gateway error |
License
Apache-2.0
