From f36cf6362ac0d2abe9a2925af06051232413998f Mon Sep 17 00:00:00 2001 From: Zeljko Date: Thu, 23 Apr 2026 10:28:01 +0200 Subject: [PATCH 1/4] chore: Improve Zama Relayer integration docs --- .../guides/zama-fhevm-counter-guide.mdx | 102 ++++++++++-------- content/relayer/zama-fhevm.mdx | 73 +++++++------ 2 files changed, 98 insertions(+), 77 deletions(-) diff --git a/content/relayer/guides/zama-fhevm-counter-guide.mdx b/content/relayer/guides/zama-fhevm-counter-guide.mdx index cf3939e9..cde257a9 100644 --- a/content/relayer/guides/zama-fhevm-counter-guide.mdx +++ b/content/relayer/guides/zama-fhevm-counter-guide.mdx @@ -4,20 +4,29 @@ title: Zama FHEVM Counter Guide ## Overview -This guide walks through an end-to-end integration between OpenZeppelin Relayer and a Zama FHEVM contract, using the counter example shipped with the [OpenZeppelin Relayer SDK](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk). The counter contract is deployed from [Zama's fhevm-hardhat-template](https://github.com/zama-ai/fhevm-hardhat-template) and demonstrates the two relayer responsibilities in an FHEVM flow: +This guide walks through an end-to-end integration between the OpenZeppelin Relayer and a Zama FHEVM contract, using the counter example shipped with the [OpenZeppelin Relayer SDK](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk). The counter contract is deployed from [Zama's fhevm-hardhat-template](https://github.com/zama-ai/fhevm-hardhat-template) and demonstrates the two OpenZeppelin Relayer responsibilities in an FHEVM flow: - **Transaction submission**: sending an encrypted `increment()` call on-chain. - **EIP-712 signing**: signing the typed-data payload that authorizes user decryption of the counter's encrypted state. + + +**Terminology.** In this guide: + +- **OpenZeppelin Relayer** (or "OZ Relayer") — this service. It holds an EVM signer, submits on-chain transactions, and signs EIP-712 payloads. +- **Zama Relayer** — the Zama-operated service that the [`@zama-fhe/relayer-sdk`](https://www.npmjs.com/package/@zama-fhe/relayer-sdk) talks to under the hood. It serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. Applications interact with it only indirectly through the Zama Relayer SDK. It holds no OpenZeppelin key material and does not sign EIP-712. + + + By the end of this guide you will have: - Configured a Zama FHE instance in your application. - Read and decrypted an encrypted counter value from the contract. -- Submitted an encrypted increment through the relayer and waited for confirmation. +- Submitted an encrypted increment through the OpenZeppelin Relayer and waited for confirmation. - Re-read and decrypted the updated value. -The FHE encryption/decryption primitives run in your application using the Zama SDK. The relayer never sees cleartext values or your decryption keypair — it only sends transactions and signs EIP-712 payloads. +The FHE encryption/decryption primitives run in your application using the Zama Relayer SDK. The OpenZeppelin Relayer never sees cleartext values or your decryption keypair — it only sends transactions and signs EIP-712 payloads. ## Prerequisites @@ -42,29 +51,32 @@ The rest of this guide explains the moving parts, references the example files, Four components participate in the flow: -- **Your script**: orchestrates the flow and prints progress. -- **OpenZeppelin Relayer**: signs typed data and submits transactions. -- **Zama Relayer SDK instance**: encrypts inputs and manages decryption flows. -- **FHEVM contract**: stores encrypted state on-chain. +- **Your script** — orchestrates the flow and prints progress. +- **OpenZeppelin Relayer** — signs typed data and submits transactions. The only component holding an EVM signer. +- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. The application only interacts with it indirectly through the SDK. +- **FHEVM contract** — stores encrypted state on-chain. -The key boundary is that the relayer does not do any encryption. The Zama SDK handles encryption and decryption primitives; the relayer provides transaction execution and signature authorization. +The key boundary is that the OpenZeppelin Relayer does not do any encryption or decryption. The Zama Relayer SDK (and, behind it, the Zama Relayer service) handles all FHE primitives; the OpenZeppelin Relayer only provides EVM transaction execution and EIP-712 signing. ``` -┌─────────────┐ ┌───────────────────────┐ ┌──────────────┐ -│ Your app │──────▶│ OpenZeppelin Relayer │──────▶│ FHEVM network│ -│ (Zama SDK) │ │ sendTransaction + │ │ Sepolia / │ -│ │◀──────│ signTypedData │ │ Mainnet │ -└─────────────┘ └───────────────────────┘ └──────────────┘ +┌─────────────┐ ┌─────────────────────────┐ ┌──────────────┐ +│ Your app │──────▶│ OpenZeppelin Relayer │──────▶│ FHEVM network│ +│ (Zama SDK) │ │ sendTransaction + │ │ Sepolia / │ +│ │◀──────│ signTypedData │ │ Mainnet │ +└─────────────┘ └─────────────────────────┘ └──────────────┘ │ ▼ - Zama Gateway - (public decrypt / - user decrypt) +┌─────────────────────────────┐ +│ Zama Relayer │ +│ FHE public keys + │ +│ decryption request routing │ +│ (accessed via Zama SDK) │ +└─────────────────────────────┘ ``` -## Relayer Configuration +## OpenZeppelin Relayer Configuration -Zama FHEVM contracts live on standard EVM networks, so the relayer is configured as a regular `evm` relayer. +Zama FHEVM contracts live on standard EVM networks, so the OpenZeppelin Relayer is configured as a regular `evm` relayer. ```json { @@ -96,9 +108,9 @@ Zama FHEVM contracts live on standard EVM networks, so the relayer is configured **Important notes:** -- The relayer signer is used both for submitting the encrypted transaction and for signing the EIP-712 payload consumed by the Zama Gateway during user decryption. The same key backs both operations. +- The OpenZeppelin Relayer's signer is used both for submitting the encrypted transaction and for signing the EIP-712 payload that the Zama Relayer SDK requires for user decryption. The same key backs both operations. - For production, prefer a hosted signer (AWS KMS, Google Cloud KMS, Turnkey, CDP) over `local`. -- The relayer must be funded on the target network so it can pay gas for FHEVM contract calls. +- The OpenZeppelin Relayer must be funded on the target network so it can pay gas for FHEVM contract calls. ## Installation @@ -130,7 +142,7 @@ RELAYER_BASE_PATH=http://localhost:8080 # ZAMA_PRIVATE_KEY= ``` -- `RELAYER_BASE_PATH` defaults to `http://localhost:8080` if not set. +- `RELAYER_BASE_PATH` defaults to `http://localhost:8080` if not set. This points at your OpenZeppelin Relayer. - `RPC_URL` defaults to the public Sepolia RPC if not set. - If `ZAMA_PUBLIC_KEY` and `ZAMA_PRIVATE_KEY` are not set, the script generates a fresh decryption keypair on each run. Reusing the same keypair is useful for consistent user-decryption behavior across runs. @@ -145,8 +157,8 @@ npx ts-node examples/relayers/zama/counter.ts The script should: 1. Read the encrypted counter handle from the contract. -2. Attempt decryption (public first, then user decryption with a relayer-signed EIP-712 payload). -3. Submit an encrypted `increment()` through the relayer and poll until the transaction is mined or confirmed. +2. Attempt decryption (public first, then user decryption with an OpenZeppelin Relayer-signed EIP-712 payload). +3. Submit an encrypted `increment()` through the OpenZeppelin Relayer and poll until the transaction is mined or confirmed. 4. Re-read and decrypt the updated counter value. ## Generating a Reusable Decryption Keypair @@ -160,14 +172,14 @@ npx ts-node examples/relayers/zama/generate-keypair.ts Copy the printed `ZAMA_PUBLIC_KEY` and `ZAMA_PRIVATE_KEY` values into your `.env` file. -The decryption keypair is an application-side secret. Do not pass the private key to the relayer; it is only used by the Zama SDK to decrypt results returned by the Gateway. +The decryption keypair is an application-side secret. Do not pass the private key to the OpenZeppelin Relayer; it is only used by the Zama Relayer SDK to decrypt results returned by the Zama Relayer. ## Walkthrough -The following snippets show the relayer-specific integration points from `counter.ts`. Full code is in the [SDK repository](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/relayers/zama). +The following snippets show the OpenZeppelin Relayer-specific integration points from `counter.ts`. Full code is in the [SDK repository](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/relayers/zama). -### 1. Initialize the relayer client and Zama SDK +### 1. Initialize the OpenZeppelin Relayer client and Zama SDK ```typescript import { Configuration, RelayersApi } from '@openzeppelin/relayer-sdk'; @@ -190,9 +202,9 @@ const provider = new JsonRpcProvider(process.env.RPC_URL!); const instance = await createInstance(zamaConfig); ``` -### 2. Fetch the relayer's on-chain address +### 2. Fetch the OpenZeppelin Relayer's on-chain address -The relayer's EVM address is needed both when building encrypted inputs and when authorizing user decryption. +The OpenZeppelin Relayer's EVM address is needed both when building encrypted inputs and when authorizing user decryption. ```typescript const relayerInfo = await relayersApi.getRelayer(process.env.RELAYER_ID!); @@ -201,7 +213,7 @@ const relayerAddress = getAddress(relayerInfo.data.data!.address!); ### 3. Read and decrypt the encrypted counter -The contract exposes a `getCount()` view that returns the encrypted handle. Decoding the handle is a plain EVM call — no relayer involvement. +The contract exposes a `getCount()` view that returns the encrypted handle. Decoding the handle is a plain EVM call — no OpenZeppelin Relayer involvement. ```typescript import { Interface } from 'ethers'; @@ -218,9 +230,9 @@ async function getCount(contractAddress: string): Promise { The script first attempts public decryption. If the handle is not publicly decryptable, it falls back to user decryption (covered in [Decryption Model](#decryption-model) below). -### 4. Submit an encrypted `increment()` via the relayer +### 4. Submit an encrypted `increment()` via the OpenZeppelin Relayer -Encryption happens locally with the Zama SDK. The encrypted handle plus input proof are encoded into a normal EVM transaction and handed to `sendTransaction`. +Encryption happens locally with the Zama Relayer SDK. The encrypted handle plus input proof are encoded into a normal EVM transaction and handed to the OpenZeppelin Relayer's `sendTransaction`. ```typescript import { Speed } from '@openzeppelin/relayer-sdk'; @@ -244,7 +256,7 @@ const transactionId = txResponse.data.data!.id!; ### 5. Poll for confirmation -Poll `getTransactionById` until the transaction reaches `mined` or `confirmed`: +Poll `getTransactionById` on the OpenZeppelin Relayer until the transaction reaches `mined` or `confirmed`: ```typescript import type { EvmTransactionResponse } from '@openzeppelin/relayer-sdk'; @@ -256,7 +268,7 @@ async function waitForConfirmation(transactionId: string): Promise -Mainnet requires API key authentication with the Zama Gateway. See the [Zama mainnet API key guide](https://docs.zama.org/protocol/relayer-sdk-guides/fhevm-relayer/mainnet-api-key) for instructions on obtaining one. +Mainnet requires API key authentication with the Zama Relayer. See the [Zama mainnet API key guide](https://docs.zama.org/protocol/relayer-sdk-guides/fhevm-relayer/mainnet-api-key) for instructions on obtaining one. ## Current Limitations @@ -366,15 +378,15 @@ Mainnet requires API key authentication with the Zama Gateway. See the [Zama mai - The example is hardcoded for Sepolia via `SepoliaConfig` plus an explicit Sepolia RPC URL. - It assumes a counter contract shape compatible with the included ABI. - Logging and error handling are intentionally simple — this is a demo script, not production code. -- It does not cover relayer creation or contract deployment. +- It does not cover OpenZeppelin Relayer creation or contract deployment. ## Troubleshooting - **`Missing required environment variable`**: one of the required values in `.env` is unset. -- **`did not return an address`**: the configured relayer id is valid for the API, but the response did not include an EVM address. Check that the relayer is fully provisioned and the signer is reachable. +- **`did not return an address`**: the configured `RELAYER_ID` is valid for the API, but the response did not include an EVM address. Check that the OpenZeppelin Relayer is fully provisioned and the signer is reachable. - **`Public decryption failed`**: this can be expected depending on the contract and permissions. The script will then try user decryption. -- **`User decryption failed`**: check that the relayer can sign typed data correctly and that the contract address and decryption keypair are the ones you expect. Confirm the EIP-712 `startTimeStamp`/`durationDays` window is valid. -- **Transaction polling timeout**: the transaction may still be pending, the relayer may be unhealthy, or the target chain may be slow. Inspect `getTransactionById` directly and check relayer logs. +- **`User decryption failed`**: check that the OpenZeppelin Relayer can sign typed data correctly and that the contract address and decryption keypair are the ones you expect. Confirm the EIP-712 `startTimeStamp` / `durationDays` window is valid. +- **Transaction polling timeout**: the transaction may still be pending, the OpenZeppelin Relayer may be unhealthy, or the target chain may be slow. Inspect `getTransactionById` directly and check OpenZeppelin Relayer logs. ## Additional Resources diff --git a/content/relayer/zama-fhevm.mdx b/content/relayer/zama-fhevm.mdx index 5c9c3d42..0601b1d1 100644 --- a/content/relayer/zama-fhevm.mdx +++ b/content/relayer/zama-fhevm.mdx @@ -4,15 +4,26 @@ title: Zama FHEVM Integration ## Overview -OpenZeppelin Relayer supports interacting with [Zama FHEVM](https://docs.zama.org/protocol) contracts — EVM smart contracts that operate on Fully Homomorphic Encryption (FHE) ciphertexts. The relayer provides two capabilities that FHEVM applications need from a backend: +The OpenZeppelin Relayer supports interacting with [Zama FHEVM](https://docs.zama.org/protocol) contracts — EVM smart contracts that operate on Fully Homomorphic Encryption (FHE) ciphertexts. The OpenZeppelin Relayer provides two capabilities that FHEVM applications need from a backend: - **Transaction submission** for encrypted contract calls (e.g. submitting an `increment()` with an encrypted input). -- **EIP-712 typed-data signing** for authorizing user decryption requests against the Zama Gateway. +- **EIP-712 typed-data signing** to authorize user decryption requests served by the Zama Relayer. -Because FHEVM contracts live on standard EVM networks, a Zama FHEVM relayer is configured as a regular `evm` relayer. Encryption and decryption are handled by the [Zama Relayer SDK](https://docs.zama.org/protocol/relayer-sdk-guides) running in your application; the OpenZeppelin Relayer only deals with on-chain transactions and typed-data signatures. +Because FHEVM contracts live on standard EVM networks, an OpenZeppelin Relayer used for Zama FHEVM is configured as a regular `evm` relayer. Encryption and decryption are handled by the [Zama Relayer SDK](https://docs.zama.org/protocol/relayer-sdk-guides) running in your application; the OpenZeppelin Relayer only deals with on-chain transactions and typed-data signatures. + + + +**Terminology.** In this page: + +- **OpenZeppelin Relayer** (or "OZ Relayer") refers to this service. It holds an EVM signer, submits on-chain transactions, and signs EIP-712 payloads. +- **Zama Relayer** refers to the Zama-operated service that the [`@zama-fhe/relayer-sdk`](https://www.npmjs.com/package/@zama-fhe/relayer-sdk) talks to under the hood. It serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. Applications interact with it only indirectly through the Zama Relayer SDK. It holds no OpenZeppelin key material and does not sign EIP-712. + +The two are different systems and do different things. In this flow, only the OpenZeppelin Relayer holds any signer key material. + + -The FHE encryption/decryption primitives run in your application using the Zama SDK. The OpenZeppelin Relayer is not aware of FHE cleartexts and never handles the decryption keypair. +The FHE encryption/decryption primitives run in your application using the Zama Relayer SDK. The OpenZeppelin Relayer is not aware of FHE cleartexts and never handles the decryption keypair. ## Features @@ -27,13 +38,13 @@ The FHE encryption/decryption primitives run in your application using the Zama Zama FHEVM is available on EVM networks where the FHE coprocessor is deployed. At the time of writing, this includes: - Ethereum Sepolia (testnet) -- Ethereum Mainnet (requires a Zama Gateway API key) +- Ethereum Mainnet (requires a Zama Relayer API key) -Because the relayer treats these as regular EVM networks, any network configuration that works for EVM will work here. See the [Network Configuration](/relayer/network_configuration) guide for the full list of options. +Because the OpenZeppelin Relayer treats these as regular EVM networks, any network configuration that works for EVM will work here. See the [Network Configuration](/relayer/network_configuration) guide for the full list of options. ## Supported Signers -All EVM signers are supported: +All EVM signers are supported by the OpenZeppelin Relayer: - `local` (local keystore files) - `vault` (HashiCorp Vault secret storage) @@ -46,12 +57,12 @@ All EVM signers are supported: For signer configuration details, see the [Signers](/relayer/configuration/signers) guide. -For production, prefer hosted signers (AWS KMS, Google Cloud KMS, Turnkey, CDP). The relayer's signer is used both to sign the on-chain encrypted transactions and the EIP-712 payloads consumed by the Zama Gateway, so key availability and security apply to both flows. +For production, prefer hosted signers (AWS KMS, Google Cloud KMS, Turnkey, CDP). The OpenZeppelin Relayer's signer is used both to sign the on-chain encrypted transactions and the EIP-712 payloads consumed by the Zama Relayer, so key availability and security apply to both flows. ## Quickstart -Example relayer configuration for a Sepolia FHEVM relayer: +Example OpenZeppelin Relayer configuration for a Sepolia FHEVM relayer: ```json { @@ -64,35 +75,33 @@ Example relayer configuration for a Sepolia FHEVM relayer: } ``` -Once the relayer is running, you will typically: +Once the OpenZeppelin Relayer is running, you will typically: 1. Create a Zama FHE instance in your application using the Zama Relayer SDK. 2. Read encrypted state from your FHEVM contract via an RPC call. -3. Decrypt the state publicly, or fall back to user decryption authorized by an EIP-712 signature from the relayer. -4. Encrypt any inputs locally with the Zama SDK. +3. Decrypt the state publicly, or fall back to user decryption authorized by an EIP-712 signature from the OpenZeppelin Relayer. +4. Encrypt any inputs locally with the Zama Relayer SDK. 5. Submit the encrypted transaction through the OpenZeppelin Relayer. For a full working walkthrough, see the [Zama FHEVM Counter Guide](/relayer/guides/zama-fhevm-counter-guide). -## How The Relayer Fits Into An FHEVM Flow +## How The OpenZeppelin Relayer Fits Into An FHEVM Flow -A typical FHEVM call with OpenZeppelin Relayer has four moving parts: +A typical FHEVM call has four moving parts: -- **Your application**: orchestrates encryption, decryption, and calls to the relayer. -- **Zama Relayer SDK**: encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads for user decryption. -- **OpenZeppelin Relayer**: - - signs and submits the encrypted transaction on-chain, - - signs EIP-712 payloads for user decryption via `signTypedData`. -- **FHEVM contract**: stores encrypted state on the EVM network. +- **Your application** — orchestrates encryption/decryption and calls both the Zama Relayer (via SDK) and the OpenZeppelin Relayer. +- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests. No OpenZeppelin key material is involved. +- **OpenZeppelin Relayer** — the only component in this diagram that holds an EVM signer. It signs and submits the encrypted transaction on-chain, and signs the EIP-712 user-decryption payload via `signTypedData`. +- **FHEVM contract** — stores encrypted state on the EVM network. -The relayer never encrypts or decrypts data. It only performs two things that require the relayer's key material: sending the encrypted transaction and signing the EIP-712 message that authorizes the Zama Gateway to return a user decryption. +The OpenZeppelin Relayer never encrypts or decrypts FHE data and never sees plaintext. It performs exactly two operations that use its signer: (a) signing and submitting the encrypted on-chain transaction, and (b) signing the EIP-712 user-decryption payload produced by the Zama Relayer SDK. The Zama Relayer is a separate system; it does not hold or use the OpenZeppelin Relayer's key material. ## Decryption Model Zama FHEVM contracts support two decryption paths: -- **Public decryption**: used when an encrypted handle is flagged as publicly decryptable. The Zama SDK can decrypt it directly, with no authorization from the relayer. -- **User decryption**: used when decryption requires authorization. The Zama SDK builds an EIP-712 payload, and the relayer signs it with `signTypedData`. The resulting signature is then passed to `userDecrypt` on the SDK, which retrieves the cleartext from the Zama Gateway. +- **Public decryption** — used when an encrypted handle is flagged as publicly decryptable. The Zama Relayer SDK can decrypt it directly via the Zama Relayer service; the OpenZeppelin Relayer is not involved. +- **User decryption** — used when decryption requires authorization. The Zama Relayer SDK builds an EIP-712 payload, and the **OpenZeppelin Relayer** signs it with `signTypedData`. The resulting signature is then passed to `userDecrypt` on the SDK, which is authorized by the Zama Relayer to return the cleartext. Applications typically try public decryption first and fall back to user decryption. @@ -100,21 +109,21 @@ Applications typically try public decryption first and fall back to user decrypt Running on Ethereum mainnet requires: -- A Zama FHEVM Gateway API key (see the [Zama mainnet API key guide](https://docs.zama.org/protocol/relayer-sdk-guides/fhevm-relayer/mainnet-api-key)). -- The Zama SDK configured with `MainnetConfig` and the API key. -- The relayer pointed at an Ethereum mainnet RPC. +- A Zama Relayer API key for mainnet (see the [Zama mainnet API key guide](https://docs.zama.org/protocol/relayer-sdk-guides/fhevm-relayer/mainnet-api-key)). +- The Zama Relayer SDK configured with `MainnetConfig` and the API key. +- The OpenZeppelin Relayer pointed at an Ethereum mainnet RPC. -The FHEVM flow itself does not change between testnet and mainnet; only the Zama SDK configuration and network selection differ. +The FHEVM flow itself does not change between testnet and mainnet; only the Zama Relayer SDK configuration and network selection differ. ## API Reference -The relayer endpoints most relevant to FHEVM flows are: +The OpenZeppelin Relayer endpoints most relevant to FHEVM flows are: | Method | Purpose | | --- | --- | | [Send Transaction](/relayer/api/sendTransaction) | Submit an encrypted FHEVM contract call on-chain | | [Sign Typed Data](/relayer/api/signTypedData) | Sign the EIP-712 payload used for user decryption | -| [Get Relayer](/relayer/api/getRelayer) | Retrieve the relayer address (needed for Zama user decryption) | +| [Get Relayer](/relayer/api/getRelayer) | Retrieve the OpenZeppelin Relayer's EVM address (needed for Zama user decryption) | | [Get Transaction by ID](/relayer/api/getTransactionById) | Poll for transaction status after submission | See the [API Reference](./api) for complete method documentation. @@ -129,10 +138,10 @@ The example contract is deployed from [Zama's fhevm-hardhat-template](https://gi ## Security -- Do not expose the relayer directly to the public internet. +- Do not expose the OpenZeppelin Relayer directly to the public internet. - Deploy behind a secure backend (reverse proxy, firewall). -- Use hosted signers in production. The relayer signer is used both for on-chain submission and for EIP-712 signing consumed by the Zama Gateway, so key availability and audit trails matter for both. -- Never hand a decryption keypair's private key to the relayer. The decryption keypair is an application-side secret. +- Use hosted signers in production. The OpenZeppelin Relayer's signer is used both for on-chain submission and for EIP-712 signing consumed by the Zama Relayer, so key availability and audit trails matter for both. +- Never hand a Zama decryption keypair's private key to the OpenZeppelin Relayer. The decryption keypair is an application-side secret — it is used only by the Zama Relayer SDK. ## Additional Resources From 2114d5d159e52fe4dd98a324d24805de6ce10c80 Mon Sep 17 00:00:00 2001 From: Zeljko Date: Thu, 23 Apr 2026 11:00:43 +0200 Subject: [PATCH 2/4] chore: Improvements --- .../1.4.x/guides/zama-fhevm-counter-guide.mdx | 102 ++++++++++-------- content/relayer/1.4.x/zama-fhevm.mdx | 73 +++++++------ content/relayer/zama-fhevm.mdx | 4 +- 3 files changed, 100 insertions(+), 79 deletions(-) diff --git a/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx b/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx index cf3939e9..cde257a9 100644 --- a/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx +++ b/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx @@ -4,20 +4,29 @@ title: Zama FHEVM Counter Guide ## Overview -This guide walks through an end-to-end integration between OpenZeppelin Relayer and a Zama FHEVM contract, using the counter example shipped with the [OpenZeppelin Relayer SDK](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk). The counter contract is deployed from [Zama's fhevm-hardhat-template](https://github.com/zama-ai/fhevm-hardhat-template) and demonstrates the two relayer responsibilities in an FHEVM flow: +This guide walks through an end-to-end integration between the OpenZeppelin Relayer and a Zama FHEVM contract, using the counter example shipped with the [OpenZeppelin Relayer SDK](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk). The counter contract is deployed from [Zama's fhevm-hardhat-template](https://github.com/zama-ai/fhevm-hardhat-template) and demonstrates the two OpenZeppelin Relayer responsibilities in an FHEVM flow: - **Transaction submission**: sending an encrypted `increment()` call on-chain. - **EIP-712 signing**: signing the typed-data payload that authorizes user decryption of the counter's encrypted state. + + +**Terminology.** In this guide: + +- **OpenZeppelin Relayer** (or "OZ Relayer") — this service. It holds an EVM signer, submits on-chain transactions, and signs EIP-712 payloads. +- **Zama Relayer** — the Zama-operated service that the [`@zama-fhe/relayer-sdk`](https://www.npmjs.com/package/@zama-fhe/relayer-sdk) talks to under the hood. It serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. Applications interact with it only indirectly through the Zama Relayer SDK. It holds no OpenZeppelin key material and does not sign EIP-712. + + + By the end of this guide you will have: - Configured a Zama FHE instance in your application. - Read and decrypted an encrypted counter value from the contract. -- Submitted an encrypted increment through the relayer and waited for confirmation. +- Submitted an encrypted increment through the OpenZeppelin Relayer and waited for confirmation. - Re-read and decrypted the updated value. -The FHE encryption/decryption primitives run in your application using the Zama SDK. The relayer never sees cleartext values or your decryption keypair — it only sends transactions and signs EIP-712 payloads. +The FHE encryption/decryption primitives run in your application using the Zama Relayer SDK. The OpenZeppelin Relayer never sees cleartext values or your decryption keypair — it only sends transactions and signs EIP-712 payloads. ## Prerequisites @@ -42,29 +51,32 @@ The rest of this guide explains the moving parts, references the example files, Four components participate in the flow: -- **Your script**: orchestrates the flow and prints progress. -- **OpenZeppelin Relayer**: signs typed data and submits transactions. -- **Zama Relayer SDK instance**: encrypts inputs and manages decryption flows. -- **FHEVM contract**: stores encrypted state on-chain. +- **Your script** — orchestrates the flow and prints progress. +- **OpenZeppelin Relayer** — signs typed data and submits transactions. The only component holding an EVM signer. +- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. The application only interacts with it indirectly through the SDK. +- **FHEVM contract** — stores encrypted state on-chain. -The key boundary is that the relayer does not do any encryption. The Zama SDK handles encryption and decryption primitives; the relayer provides transaction execution and signature authorization. +The key boundary is that the OpenZeppelin Relayer does not do any encryption or decryption. The Zama Relayer SDK (and, behind it, the Zama Relayer service) handles all FHE primitives; the OpenZeppelin Relayer only provides EVM transaction execution and EIP-712 signing. ``` -┌─────────────┐ ┌───────────────────────┐ ┌──────────────┐ -│ Your app │──────▶│ OpenZeppelin Relayer │──────▶│ FHEVM network│ -│ (Zama SDK) │ │ sendTransaction + │ │ Sepolia / │ -│ │◀──────│ signTypedData │ │ Mainnet │ -└─────────────┘ └───────────────────────┘ └──────────────┘ +┌─────────────┐ ┌─────────────────────────┐ ┌──────────────┐ +│ Your app │──────▶│ OpenZeppelin Relayer │──────▶│ FHEVM network│ +│ (Zama SDK) │ │ sendTransaction + │ │ Sepolia / │ +│ │◀──────│ signTypedData │ │ Mainnet │ +└─────────────┘ └─────────────────────────┘ └──────────────┘ │ ▼ - Zama Gateway - (public decrypt / - user decrypt) +┌─────────────────────────────┐ +│ Zama Relayer │ +│ FHE public keys + │ +│ decryption request routing │ +│ (accessed via Zama SDK) │ +└─────────────────────────────┘ ``` -## Relayer Configuration +## OpenZeppelin Relayer Configuration -Zama FHEVM contracts live on standard EVM networks, so the relayer is configured as a regular `evm` relayer. +Zama FHEVM contracts live on standard EVM networks, so the OpenZeppelin Relayer is configured as a regular `evm` relayer. ```json { @@ -96,9 +108,9 @@ Zama FHEVM contracts live on standard EVM networks, so the relayer is configured **Important notes:** -- The relayer signer is used both for submitting the encrypted transaction and for signing the EIP-712 payload consumed by the Zama Gateway during user decryption. The same key backs both operations. +- The OpenZeppelin Relayer's signer is used both for submitting the encrypted transaction and for signing the EIP-712 payload that the Zama Relayer SDK requires for user decryption. The same key backs both operations. - For production, prefer a hosted signer (AWS KMS, Google Cloud KMS, Turnkey, CDP) over `local`. -- The relayer must be funded on the target network so it can pay gas for FHEVM contract calls. +- The OpenZeppelin Relayer must be funded on the target network so it can pay gas for FHEVM contract calls. ## Installation @@ -130,7 +142,7 @@ RELAYER_BASE_PATH=http://localhost:8080 # ZAMA_PRIVATE_KEY= ``` -- `RELAYER_BASE_PATH` defaults to `http://localhost:8080` if not set. +- `RELAYER_BASE_PATH` defaults to `http://localhost:8080` if not set. This points at your OpenZeppelin Relayer. - `RPC_URL` defaults to the public Sepolia RPC if not set. - If `ZAMA_PUBLIC_KEY` and `ZAMA_PRIVATE_KEY` are not set, the script generates a fresh decryption keypair on each run. Reusing the same keypair is useful for consistent user-decryption behavior across runs. @@ -145,8 +157,8 @@ npx ts-node examples/relayers/zama/counter.ts The script should: 1. Read the encrypted counter handle from the contract. -2. Attempt decryption (public first, then user decryption with a relayer-signed EIP-712 payload). -3. Submit an encrypted `increment()` through the relayer and poll until the transaction is mined or confirmed. +2. Attempt decryption (public first, then user decryption with an OpenZeppelin Relayer-signed EIP-712 payload). +3. Submit an encrypted `increment()` through the OpenZeppelin Relayer and poll until the transaction is mined or confirmed. 4. Re-read and decrypt the updated counter value. ## Generating a Reusable Decryption Keypair @@ -160,14 +172,14 @@ npx ts-node examples/relayers/zama/generate-keypair.ts Copy the printed `ZAMA_PUBLIC_KEY` and `ZAMA_PRIVATE_KEY` values into your `.env` file. -The decryption keypair is an application-side secret. Do not pass the private key to the relayer; it is only used by the Zama SDK to decrypt results returned by the Gateway. +The decryption keypair is an application-side secret. Do not pass the private key to the OpenZeppelin Relayer; it is only used by the Zama Relayer SDK to decrypt results returned by the Zama Relayer. ## Walkthrough -The following snippets show the relayer-specific integration points from `counter.ts`. Full code is in the [SDK repository](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/relayers/zama). +The following snippets show the OpenZeppelin Relayer-specific integration points from `counter.ts`. Full code is in the [SDK repository](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/relayers/zama). -### 1. Initialize the relayer client and Zama SDK +### 1. Initialize the OpenZeppelin Relayer client and Zama SDK ```typescript import { Configuration, RelayersApi } from '@openzeppelin/relayer-sdk'; @@ -190,9 +202,9 @@ const provider = new JsonRpcProvider(process.env.RPC_URL!); const instance = await createInstance(zamaConfig); ``` -### 2. Fetch the relayer's on-chain address +### 2. Fetch the OpenZeppelin Relayer's on-chain address -The relayer's EVM address is needed both when building encrypted inputs and when authorizing user decryption. +The OpenZeppelin Relayer's EVM address is needed both when building encrypted inputs and when authorizing user decryption. ```typescript const relayerInfo = await relayersApi.getRelayer(process.env.RELAYER_ID!); @@ -201,7 +213,7 @@ const relayerAddress = getAddress(relayerInfo.data.data!.address!); ### 3. Read and decrypt the encrypted counter -The contract exposes a `getCount()` view that returns the encrypted handle. Decoding the handle is a plain EVM call — no relayer involvement. +The contract exposes a `getCount()` view that returns the encrypted handle. Decoding the handle is a plain EVM call — no OpenZeppelin Relayer involvement. ```typescript import { Interface } from 'ethers'; @@ -218,9 +230,9 @@ async function getCount(contractAddress: string): Promise { The script first attempts public decryption. If the handle is not publicly decryptable, it falls back to user decryption (covered in [Decryption Model](#decryption-model) below). -### 4. Submit an encrypted `increment()` via the relayer +### 4. Submit an encrypted `increment()` via the OpenZeppelin Relayer -Encryption happens locally with the Zama SDK. The encrypted handle plus input proof are encoded into a normal EVM transaction and handed to `sendTransaction`. +Encryption happens locally with the Zama Relayer SDK. The encrypted handle plus input proof are encoded into a normal EVM transaction and handed to the OpenZeppelin Relayer's `sendTransaction`. ```typescript import { Speed } from '@openzeppelin/relayer-sdk'; @@ -244,7 +256,7 @@ const transactionId = txResponse.data.data!.id!; ### 5. Poll for confirmation -Poll `getTransactionById` until the transaction reaches `mined` or `confirmed`: +Poll `getTransactionById` on the OpenZeppelin Relayer until the transaction reaches `mined` or `confirmed`: ```typescript import type { EvmTransactionResponse } from '@openzeppelin/relayer-sdk'; @@ -256,7 +268,7 @@ async function waitForConfirmation(transactionId: string): Promise -Mainnet requires API key authentication with the Zama Gateway. See the [Zama mainnet API key guide](https://docs.zama.org/protocol/relayer-sdk-guides/fhevm-relayer/mainnet-api-key) for instructions on obtaining one. +Mainnet requires API key authentication with the Zama Relayer. See the [Zama mainnet API key guide](https://docs.zama.org/protocol/relayer-sdk-guides/fhevm-relayer/mainnet-api-key) for instructions on obtaining one. ## Current Limitations @@ -366,15 +378,15 @@ Mainnet requires API key authentication with the Zama Gateway. See the [Zama mai - The example is hardcoded for Sepolia via `SepoliaConfig` plus an explicit Sepolia RPC URL. - It assumes a counter contract shape compatible with the included ABI. - Logging and error handling are intentionally simple — this is a demo script, not production code. -- It does not cover relayer creation or contract deployment. +- It does not cover OpenZeppelin Relayer creation or contract deployment. ## Troubleshooting - **`Missing required environment variable`**: one of the required values in `.env` is unset. -- **`did not return an address`**: the configured relayer id is valid for the API, but the response did not include an EVM address. Check that the relayer is fully provisioned and the signer is reachable. +- **`did not return an address`**: the configured `RELAYER_ID` is valid for the API, but the response did not include an EVM address. Check that the OpenZeppelin Relayer is fully provisioned and the signer is reachable. - **`Public decryption failed`**: this can be expected depending on the contract and permissions. The script will then try user decryption. -- **`User decryption failed`**: check that the relayer can sign typed data correctly and that the contract address and decryption keypair are the ones you expect. Confirm the EIP-712 `startTimeStamp`/`durationDays` window is valid. -- **Transaction polling timeout**: the transaction may still be pending, the relayer may be unhealthy, or the target chain may be slow. Inspect `getTransactionById` directly and check relayer logs. +- **`User decryption failed`**: check that the OpenZeppelin Relayer can sign typed data correctly and that the contract address and decryption keypair are the ones you expect. Confirm the EIP-712 `startTimeStamp` / `durationDays` window is valid. +- **Transaction polling timeout**: the transaction may still be pending, the OpenZeppelin Relayer may be unhealthy, or the target chain may be slow. Inspect `getTransactionById` directly and check OpenZeppelin Relayer logs. ## Additional Resources diff --git a/content/relayer/1.4.x/zama-fhevm.mdx b/content/relayer/1.4.x/zama-fhevm.mdx index 5c9c3d42..a1977d11 100644 --- a/content/relayer/1.4.x/zama-fhevm.mdx +++ b/content/relayer/1.4.x/zama-fhevm.mdx @@ -4,15 +4,26 @@ title: Zama FHEVM Integration ## Overview -OpenZeppelin Relayer supports interacting with [Zama FHEVM](https://docs.zama.org/protocol) contracts — EVM smart contracts that operate on Fully Homomorphic Encryption (FHE) ciphertexts. The relayer provides two capabilities that FHEVM applications need from a backend: +The OpenZeppelin Relayer supports interacting with [Zama FHEVM](https://docs.zama.org/protocol) contracts — EVM smart contracts that operate on Fully Homomorphic Encryption (FHE) ciphertexts. The OpenZeppelin Relayer provides two capabilities that FHEVM applications need from a backend: - **Transaction submission** for encrypted contract calls (e.g. submitting an `increment()` with an encrypted input). -- **EIP-712 typed-data signing** for authorizing user decryption requests against the Zama Gateway. +- **EIP-712 typed-data signing** to authorize user decryption requests served by the Zama Relayer. -Because FHEVM contracts live on standard EVM networks, a Zama FHEVM relayer is configured as a regular `evm` relayer. Encryption and decryption are handled by the [Zama Relayer SDK](https://docs.zama.org/protocol/relayer-sdk-guides) running in your application; the OpenZeppelin Relayer only deals with on-chain transactions and typed-data signatures. +Because FHEVM contracts live on standard EVM networks, your OpenZeppelin Relayer is configured exactly as a regular `evm` relayer — there is no FHEVM-specific relayer or network type in OpenZeppelin Relayer. All FHE-specific work (encryption, decryption, key handling) is done by the [Zama Relayer SDK](https://docs.zama.org/protocol/relayer-sdk-guides) running in your application, which in turn talks to the Zama Relayer. The OpenZeppelin Relayer only deals with on-chain transactions and EIP-712 typed-data signatures. + + + +**Terminology.** In this page: + +- **OpenZeppelin Relayer** (or "OZ Relayer") refers to this service. It holds an EVM signer, submits on-chain transactions, and signs EIP-712 payloads. +- **Zama Relayer** refers to the Zama-operated service that the [`@zama-fhe/relayer-sdk`](https://www.npmjs.com/package/@zama-fhe/relayer-sdk) talks to under the hood. It serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. Applications interact with it only indirectly through the Zama Relayer SDK. It holds no OpenZeppelin key material and does not sign EIP-712. + +The two are different systems and do different things. In this flow, only the OpenZeppelin Relayer holds any signer key material. + + -The FHE encryption/decryption primitives run in your application using the Zama SDK. The OpenZeppelin Relayer is not aware of FHE cleartexts and never handles the decryption keypair. +The FHE encryption/decryption primitives run in your application using the Zama Relayer SDK. The OpenZeppelin Relayer is not aware of FHE cleartexts and never handles the decryption keypair. ## Features @@ -27,13 +38,13 @@ The FHE encryption/decryption primitives run in your application using the Zama Zama FHEVM is available on EVM networks where the FHE coprocessor is deployed. At the time of writing, this includes: - Ethereum Sepolia (testnet) -- Ethereum Mainnet (requires a Zama Gateway API key) +- Ethereum Mainnet (requires a Zama Relayer API key) -Because the relayer treats these as regular EVM networks, any network configuration that works for EVM will work here. See the [Network Configuration](/relayer/network_configuration) guide for the full list of options. +Because the OpenZeppelin Relayer treats these as regular EVM networks, any network configuration that works for EVM will work here. See the [Network Configuration](/relayer/network_configuration) guide for the full list of options. ## Supported Signers -All EVM signers are supported: +All EVM signers are supported by the OpenZeppelin Relayer: - `local` (local keystore files) - `vault` (HashiCorp Vault secret storage) @@ -46,12 +57,12 @@ All EVM signers are supported: For signer configuration details, see the [Signers](/relayer/configuration/signers) guide. -For production, prefer hosted signers (AWS KMS, Google Cloud KMS, Turnkey, CDP). The relayer's signer is used both to sign the on-chain encrypted transactions and the EIP-712 payloads consumed by the Zama Gateway, so key availability and security apply to both flows. +For production, prefer hosted signers (AWS KMS, Google Cloud KMS, Turnkey, CDP). The OpenZeppelin Relayer's signer is used both to sign the on-chain encrypted transactions and the EIP-712 payloads consumed by the Zama Relayer, so key availability and security apply to both flows. ## Quickstart -Example relayer configuration for a Sepolia FHEVM relayer: +Example OpenZeppelin Relayer configuration for a Zama FHEVM application running on Sepolia (note that it is just a standard `evm` relayer — nothing FHEVM-specific in the config): ```json { @@ -64,35 +75,33 @@ Example relayer configuration for a Sepolia FHEVM relayer: } ``` -Once the relayer is running, you will typically: +Once the OpenZeppelin Relayer is running, you will typically: 1. Create a Zama FHE instance in your application using the Zama Relayer SDK. 2. Read encrypted state from your FHEVM contract via an RPC call. -3. Decrypt the state publicly, or fall back to user decryption authorized by an EIP-712 signature from the relayer. -4. Encrypt any inputs locally with the Zama SDK. +3. Decrypt the state publicly, or fall back to user decryption authorized by an EIP-712 signature from the OpenZeppelin Relayer. +4. Encrypt any inputs locally with the Zama Relayer SDK. 5. Submit the encrypted transaction through the OpenZeppelin Relayer. For a full working walkthrough, see the [Zama FHEVM Counter Guide](/relayer/guides/zama-fhevm-counter-guide). -## How The Relayer Fits Into An FHEVM Flow +## How The OpenZeppelin Relayer Fits Into An FHEVM Flow -A typical FHEVM call with OpenZeppelin Relayer has four moving parts: +A typical FHEVM call has four moving parts: -- **Your application**: orchestrates encryption, decryption, and calls to the relayer. -- **Zama Relayer SDK**: encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads for user decryption. -- **OpenZeppelin Relayer**: - - signs and submits the encrypted transaction on-chain, - - signs EIP-712 payloads for user decryption via `signTypedData`. -- **FHEVM contract**: stores encrypted state on the EVM network. +- **Your application** — orchestrates encryption/decryption and calls both the Zama Relayer (via SDK) and the OpenZeppelin Relayer. +- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests. No OpenZeppelin key material is involved. +- **OpenZeppelin Relayer** — the only component in this diagram that holds an EVM signer. It signs and submits the encrypted transaction on-chain, and signs the EIP-712 user-decryption payload via `signTypedData`. +- **FHEVM contract** — stores encrypted state on the EVM network. -The relayer never encrypts or decrypts data. It only performs two things that require the relayer's key material: sending the encrypted transaction and signing the EIP-712 message that authorizes the Zama Gateway to return a user decryption. +The OpenZeppelin Relayer never encrypts or decrypts FHE data and never sees plaintext. It performs exactly two operations that use its signer: (a) signing and submitting the encrypted on-chain transaction, and (b) signing the EIP-712 user-decryption payload produced by the Zama Relayer SDK. The Zama Relayer is a separate system; it does not hold or use the OpenZeppelin Relayer's key material. ## Decryption Model Zama FHEVM contracts support two decryption paths: -- **Public decryption**: used when an encrypted handle is flagged as publicly decryptable. The Zama SDK can decrypt it directly, with no authorization from the relayer. -- **User decryption**: used when decryption requires authorization. The Zama SDK builds an EIP-712 payload, and the relayer signs it with `signTypedData`. The resulting signature is then passed to `userDecrypt` on the SDK, which retrieves the cleartext from the Zama Gateway. +- **Public decryption** — used when an encrypted handle is flagged as publicly decryptable. The Zama Relayer SDK can decrypt it directly via the Zama Relayer service; the OpenZeppelin Relayer is not involved. +- **User decryption** — used when decryption requires authorization. The Zama Relayer SDK builds an EIP-712 payload, and the **OpenZeppelin Relayer** signs it with `signTypedData`. The resulting signature is then passed to `userDecrypt` on the SDK, which is authorized by the Zama Relayer to return the cleartext. Applications typically try public decryption first and fall back to user decryption. @@ -100,21 +109,21 @@ Applications typically try public decryption first and fall back to user decrypt Running on Ethereum mainnet requires: -- A Zama FHEVM Gateway API key (see the [Zama mainnet API key guide](https://docs.zama.org/protocol/relayer-sdk-guides/fhevm-relayer/mainnet-api-key)). -- The Zama SDK configured with `MainnetConfig` and the API key. -- The relayer pointed at an Ethereum mainnet RPC. +- A Zama Relayer API key for mainnet (see the [Zama mainnet API key guide](https://docs.zama.org/protocol/relayer-sdk-guides/fhevm-relayer/mainnet-api-key)). +- The Zama Relayer SDK configured with `MainnetConfig` and the API key. +- The OpenZeppelin Relayer pointed at an Ethereum mainnet RPC. -The FHEVM flow itself does not change between testnet and mainnet; only the Zama SDK configuration and network selection differ. +The FHEVM flow itself does not change between testnet and mainnet; only the Zama Relayer SDK configuration and network selection differ. ## API Reference -The relayer endpoints most relevant to FHEVM flows are: +The OpenZeppelin Relayer endpoints most relevant to FHEVM flows are: | Method | Purpose | | --- | --- | | [Send Transaction](/relayer/api/sendTransaction) | Submit an encrypted FHEVM contract call on-chain | | [Sign Typed Data](/relayer/api/signTypedData) | Sign the EIP-712 payload used for user decryption | -| [Get Relayer](/relayer/api/getRelayer) | Retrieve the relayer address (needed for Zama user decryption) | +| [Get Relayer](/relayer/api/getRelayer) | Retrieve the OpenZeppelin Relayer's EVM address (needed for Zama user decryption) | | [Get Transaction by ID](/relayer/api/getTransactionById) | Poll for transaction status after submission | See the [API Reference](./api) for complete method documentation. @@ -129,10 +138,10 @@ The example contract is deployed from [Zama's fhevm-hardhat-template](https://gi ## Security -- Do not expose the relayer directly to the public internet. +- Do not expose the OpenZeppelin Relayer directly to the public internet. - Deploy behind a secure backend (reverse proxy, firewall). -- Use hosted signers in production. The relayer signer is used both for on-chain submission and for EIP-712 signing consumed by the Zama Gateway, so key availability and audit trails matter for both. -- Never hand a decryption keypair's private key to the relayer. The decryption keypair is an application-side secret. +- Use hosted signers in production. The OpenZeppelin Relayer's signer is used both for on-chain submission and for EIP-712 signing consumed by the Zama Relayer, so key availability and audit trails matter for both. +- Never hand a Zama decryption keypair's private key to the OpenZeppelin Relayer. The decryption keypair is an application-side secret — it is used only by the Zama Relayer SDK. ## Additional Resources diff --git a/content/relayer/zama-fhevm.mdx b/content/relayer/zama-fhevm.mdx index 0601b1d1..a1977d11 100644 --- a/content/relayer/zama-fhevm.mdx +++ b/content/relayer/zama-fhevm.mdx @@ -9,7 +9,7 @@ The OpenZeppelin Relayer supports interacting with [Zama FHEVM](https://docs.zam - **Transaction submission** for encrypted contract calls (e.g. submitting an `increment()` with an encrypted input). - **EIP-712 typed-data signing** to authorize user decryption requests served by the Zama Relayer. -Because FHEVM contracts live on standard EVM networks, an OpenZeppelin Relayer used for Zama FHEVM is configured as a regular `evm` relayer. Encryption and decryption are handled by the [Zama Relayer SDK](https://docs.zama.org/protocol/relayer-sdk-guides) running in your application; the OpenZeppelin Relayer only deals with on-chain transactions and typed-data signatures. +Because FHEVM contracts live on standard EVM networks, your OpenZeppelin Relayer is configured exactly as a regular `evm` relayer — there is no FHEVM-specific relayer or network type in OpenZeppelin Relayer. All FHE-specific work (encryption, decryption, key handling) is done by the [Zama Relayer SDK](https://docs.zama.org/protocol/relayer-sdk-guides) running in your application, which in turn talks to the Zama Relayer. The OpenZeppelin Relayer only deals with on-chain transactions and EIP-712 typed-data signatures. @@ -62,7 +62,7 @@ For production, prefer hosted signers (AWS KMS, Google Cloud KMS, Turnkey, CDP). ## Quickstart -Example OpenZeppelin Relayer configuration for a Sepolia FHEVM relayer: +Example OpenZeppelin Relayer configuration for a Zama FHEVM application running on Sepolia (note that it is just a standard `evm` relayer — nothing FHEVM-specific in the config): ```json { From 9e0962f748a06edd5bb97d6893da321b2aad7fbf Mon Sep 17 00:00:00 2001 From: Zeljko Date: Mon, 27 Apr 2026 13:52:41 +0200 Subject: [PATCH 3/4] chore: Apply suggestions --- content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx | 2 +- content/relayer/1.4.x/zama-fhevm.mdx | 4 ++-- content/relayer/guides/zama-fhevm-counter-guide.mdx | 2 +- content/relayer/zama-fhevm.mdx | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx b/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx index cde257a9..eb5bdfcd 100644 --- a/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx +++ b/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx @@ -53,7 +53,7 @@ Four components participate in the flow: - **Your script** — orchestrates the flow and prints progress. - **OpenZeppelin Relayer** — signs typed data and submits transactions. The only component holding an EVM signer. -- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. The application only interacts with it indirectly through the SDK. +- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates keypairs for user decryption, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. The application only interacts with it indirectly through the SDK. - **FHEVM contract** — stores encrypted state on-chain. The key boundary is that the OpenZeppelin Relayer does not do any encryption or decryption. The Zama Relayer SDK (and, behind it, the Zama Relayer service) handles all FHE primitives; the OpenZeppelin Relayer only provides EVM transaction execution and EIP-712 signing. diff --git a/content/relayer/1.4.x/zama-fhevm.mdx b/content/relayer/1.4.x/zama-fhevm.mdx index a1977d11..f68fbbbf 100644 --- a/content/relayer/1.4.x/zama-fhevm.mdx +++ b/content/relayer/1.4.x/zama-fhevm.mdx @@ -90,7 +90,7 @@ For a full working walkthrough, see the [Zama FHEVM Counter Guide](/relayer/guid A typical FHEVM call has four moving parts: - **Your application** — orchestrates encryption/decryption and calls both the Zama Relayer (via SDK) and the OpenZeppelin Relayer. -- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests. No OpenZeppelin key material is involved. +- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates keypairs for user decryption, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests. No OpenZeppelin key material is involved. - **OpenZeppelin Relayer** — the only component in this diagram that holds an EVM signer. It signs and submits the encrypted transaction on-chain, and signs the EIP-712 user-decryption payload via `signTypedData`. - **FHEVM contract** — stores encrypted state on the EVM network. @@ -123,7 +123,7 @@ The OpenZeppelin Relayer endpoints most relevant to FHEVM flows are: | --- | --- | | [Send Transaction](/relayer/api/sendTransaction) | Submit an encrypted FHEVM contract call on-chain | | [Sign Typed Data](/relayer/api/signTypedData) | Sign the EIP-712 payload used for user decryption | -| [Get Relayer](/relayer/api/getRelayer) | Retrieve the OpenZeppelin Relayer's EVM address (needed for Zama user decryption) | +| [Get Relayer](/relayer/api/getRelayer) | Retrieve the OpenZeppelin Relayer's EVM address (needed by the Zama SDK for input proofs and decryption requests) | | [Get Transaction by ID](/relayer/api/getTransactionById) | Poll for transaction status after submission | See the [API Reference](./api) for complete method documentation. diff --git a/content/relayer/guides/zama-fhevm-counter-guide.mdx b/content/relayer/guides/zama-fhevm-counter-guide.mdx index cde257a9..eb5bdfcd 100644 --- a/content/relayer/guides/zama-fhevm-counter-guide.mdx +++ b/content/relayer/guides/zama-fhevm-counter-guide.mdx @@ -53,7 +53,7 @@ Four components participate in the flow: - **Your script** — orchestrates the flow and prints progress. - **OpenZeppelin Relayer** — signs typed data and submits transactions. The only component holding an EVM signer. -- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. The application only interacts with it indirectly through the SDK. +- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates keypairs for user decryption, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests to the Zama KMS / coprocessor. The application only interacts with it indirectly through the SDK. - **FHEVM contract** — stores encrypted state on-chain. The key boundary is that the OpenZeppelin Relayer does not do any encryption or decryption. The Zama Relayer SDK (and, behind it, the Zama Relayer service) handles all FHE primitives; the OpenZeppelin Relayer only provides EVM transaction execution and EIP-712 signing. diff --git a/content/relayer/zama-fhevm.mdx b/content/relayer/zama-fhevm.mdx index a1977d11..f68fbbbf 100644 --- a/content/relayer/zama-fhevm.mdx +++ b/content/relayer/zama-fhevm.mdx @@ -90,7 +90,7 @@ For a full working walkthrough, see the [Zama FHEVM Counter Guide](/relayer/guid A typical FHEVM call has four moving parts: - **Your application** — orchestrates encryption/decryption and calls both the Zama Relayer (via SDK) and the OpenZeppelin Relayer. -- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates decryption keypairs, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests. No OpenZeppelin key material is involved. +- **Zama Relayer SDK (client)** + **Zama Relayer (service)** — the SDK encrypts inputs, generates keypairs for user decryption, and builds EIP-712 payloads; the Zama Relayer service serves FHE public keys and routes decryption requests. No OpenZeppelin key material is involved. - **OpenZeppelin Relayer** — the only component in this diagram that holds an EVM signer. It signs and submits the encrypted transaction on-chain, and signs the EIP-712 user-decryption payload via `signTypedData`. - **FHEVM contract** — stores encrypted state on the EVM network. @@ -123,7 +123,7 @@ The OpenZeppelin Relayer endpoints most relevant to FHEVM flows are: | --- | --- | | [Send Transaction](/relayer/api/sendTransaction) | Submit an encrypted FHEVM contract call on-chain | | [Sign Typed Data](/relayer/api/signTypedData) | Sign the EIP-712 payload used for user decryption | -| [Get Relayer](/relayer/api/getRelayer) | Retrieve the OpenZeppelin Relayer's EVM address (needed for Zama user decryption) | +| [Get Relayer](/relayer/api/getRelayer) | Retrieve the OpenZeppelin Relayer's EVM address (needed by the Zama SDK for input proofs and decryption requests) | | [Get Transaction by ID](/relayer/api/getTransactionById) | Poll for transaction status after submission | See the [API Reference](./api) for complete method documentation. From 1f4df869a4ef038c4fbb9e9b9f63d1728faa67d7 Mon Sep 17 00:00:00 2001 From: Zeljko Date: Wed, 29 Apr 2026 08:52:49 +0200 Subject: [PATCH 4/4] chore: apply PR suggestions --- content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx | 8 ++++---- content/relayer/guides/zama-fhevm-counter-guide.mdx | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx b/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx index eb5bdfcd..5ea3b5c4 100644 --- a/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx +++ b/content/relayer/1.4.x/guides/zama-fhevm-counter-guide.mdx @@ -157,7 +157,7 @@ npx ts-node examples/relayers/zama/counter.ts The script should: 1. Read the encrypted counter handle from the contract. -2. Attempt decryption (public first, then user decryption with an OpenZeppelin Relayer-signed EIP-712 payload). +2. Attempt decryption (public first, then user decryption with an OpenZeppelin Relayer signed EIP-712 payload). 3. Submit an encrypted `increment()` through the OpenZeppelin Relayer and poll until the transaction is mined or confirmed. 4. Re-read and decrypt the updated counter value. @@ -172,12 +172,12 @@ npx ts-node examples/relayers/zama/generate-keypair.ts Copy the printed `ZAMA_PUBLIC_KEY` and `ZAMA_PRIVATE_KEY` values into your `.env` file. -The decryption keypair is an application-side secret. Do not pass the private key to the OpenZeppelin Relayer; it is only used by the Zama Relayer SDK to decrypt results returned by the Zama Relayer. +The decryption keypair is an application side secret. Do not pass the private key to the OpenZeppelin Relayer; it is only used by the Zama Relayer SDK to decrypt results returned by the Zama Relayer. ## Walkthrough -The following snippets show the OpenZeppelin Relayer-specific integration points from `counter.ts`. Full code is in the [SDK repository](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/relayers/zama). +The following snippets show the OpenZeppelin Relayer's specific integration points from `counter.ts`. Full code is in the [SDK repository](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/relayers/zama). ### 1. Initialize the OpenZeppelin Relayer client and Zama SDK @@ -291,7 +291,7 @@ const result = await instance.publicDecrypt([encryptedHandle]); const clear = result.clearValues[encryptedHandle as `0x${string}`]; ``` -### 2. User Decryption (OpenZeppelin Relayer-signed EIP-712) +### 2. User Decryption (OpenZeppelin Relayer's signed EIP-712) When decryption requires authorization, the Zama Relayer SDK builds an EIP-712 payload and the **OpenZeppelin Relayer** signs it via `signTypedData`. The resulting signature is passed to `userDecrypt`, which uses it to authorize the Zama Relayer to return the cleartext. diff --git a/content/relayer/guides/zama-fhevm-counter-guide.mdx b/content/relayer/guides/zama-fhevm-counter-guide.mdx index eb5bdfcd..c69fbdd0 100644 --- a/content/relayer/guides/zama-fhevm-counter-guide.mdx +++ b/content/relayer/guides/zama-fhevm-counter-guide.mdx @@ -157,7 +157,7 @@ npx ts-node examples/relayers/zama/counter.ts The script should: 1. Read the encrypted counter handle from the contract. -2. Attempt decryption (public first, then user decryption with an OpenZeppelin Relayer-signed EIP-712 payload). +2. Attempt decryption (public first, then user decryption with an OpenZeppelin Relayer's signed EIP-712 payload). 3. Submit an encrypted `increment()` through the OpenZeppelin Relayer and poll until the transaction is mined or confirmed. 4. Re-read and decrypt the updated counter value. @@ -172,12 +172,12 @@ npx ts-node examples/relayers/zama/generate-keypair.ts Copy the printed `ZAMA_PUBLIC_KEY` and `ZAMA_PRIVATE_KEY` values into your `.env` file. -The decryption keypair is an application-side secret. Do not pass the private key to the OpenZeppelin Relayer; it is only used by the Zama Relayer SDK to decrypt results returned by the Zama Relayer. +The decryption keypair is an application side secret. Do not pass the private key to the OpenZeppelin Relayer; it is only used by the Zama Relayer SDK to decrypt results returned by the Zama Relayer. ## Walkthrough -The following snippets show the OpenZeppelin Relayer-specific integration points from `counter.ts`. Full code is in the [SDK repository](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/relayers/zama). +The following snippets show the OpenZeppelin Relayer's specific integration points from `counter.ts`. Full code is in the [SDK repository](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/relayers/zama). ### 1. Initialize the OpenZeppelin Relayer client and Zama SDK @@ -291,7 +291,7 @@ const result = await instance.publicDecrypt([encryptedHandle]); const clear = result.clearValues[encryptedHandle as `0x${string}`]; ``` -### 2. User Decryption (OpenZeppelin Relayer-signed EIP-712) +### 2. User Decryption (OpenZeppelin Relayer's signed EIP-712) When decryption requires authorization, the Zama Relayer SDK builds an EIP-712 payload and the **OpenZeppelin Relayer** signs it via `signTypedData`. The resulting signature is passed to `userDecrypt`, which uses it to authorize the Zama Relayer to return the cleartext.